Add error location reporting

This commit is contained in:
Konstantin Nazarov 2024-08-10 11:17:20 +01:00
parent 4c7b44ff01
commit 935c629460
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
13 changed files with 127 additions and 64 deletions

View file

@ -14,6 +14,7 @@ target_sources(vm_lib
src/vm.cpp src/vm.cpp
src/common.cpp src/common.cpp
src/arena.cpp src/arena.cpp
src/error.cpp
src/reader.cpp src/reader.cpp
src/writer.cpp src/writer.cpp
src/utf8.cpp src/utf8.cpp

View file

@ -81,7 +81,7 @@ Result<PodObject*> Arena::gc_pod(PodObject* obj) {
return gc_dict((PodDict*)obj); return gc_dict((PodDict*)obj);
} }
return ErrorCode::TypeMismatch; return ERROR(TypeMismatch);
} }
Result<PodObject*> Arena::gc_nil(PodNil* obj) { Result<PodObject*> Arena::gc_nil(PodNil* obj) {
@ -128,7 +128,7 @@ Result<PodObject*> Arena::gc_symbol(PodSymbol* obj) {
} }
Result<PodObject*> Arena::gc_syntax(PodSyntax* obj) { Result<PodObject*> Arena::gc_syntax(PodSyntax* obj) {
return ErrorCode::NotImplemented; return ERROR(NotImplemented);
} }
Result<PodObject*> Arena::gc_pair(PodPair* obj) { Result<PodObject*> Arena::gc_pair(PodPair* obj) {
@ -176,7 +176,6 @@ Result<PodObject*> Arena::gc_dict(PodDict* obj) {
nobj->data[i] = TRY(gc_pod(val)); nobj->data[i] = TRY(gc_pod(val));
} }
return nobj; return nobj;
// return ErrorCode::NotImplemented;
} }
Arena& get_arena() { Arena& get_arena() {

View file

@ -102,8 +102,7 @@ class ArenaHeap {
// padding for guard value // padding for guard value
uint64_t boundary_size = 8; uint64_t boundary_size = 8;
if (boundary + size + boundary_size >= bufsize) if (boundary + size + boundary_size >= bufsize) return ERROR(OutOfMemory);
return ErrorCode::OutOfMemory;
void* res = buf + boundary; void* res = buf + boundary;
boundary += size; boundary += size;
ASAN_UNPOISON_MEMORY_REGION(res, size); ASAN_UNPOISON_MEMORY_REGION(res, size);

View file

@ -120,13 +120,13 @@ Result<Value> Pair::rest() {
} }
Result<Value> reverse(Value& val) { Result<Value> reverse(Value& val) {
if (!val.is<Pair>()) return ErrorCode::TypeMismatch; if (!val.is<Pair>()) return ERROR(TypeMismatch);
auto res = Value(TRY(Nil::create())); auto res = Value(TRY(Nil::create()));
auto cur = TRY(val.copy()); auto cur = TRY(val.copy());
while (!cur.is<Nil>()) { while (!cur.is<Nil>()) {
if (!cur.is<Pair>()) return ErrorCode::TypeMismatch; if (!cur.is<Pair>()) return ERROR(TypeMismatch);
Pair& pair = *cur.to<Pair>(); Pair& pair = *cur.to<Pair>();
Value first = TRY(pair.first()); Value first = TRY(pair.first());
cur = TRY(pair.rest()); cur = TRY(pair.rest());
@ -153,13 +153,13 @@ Result<void> debug_print(Value& val) {
} }
Result<Value> Array::get(uint64_t idx) { Result<Value> Array::get(uint64_t idx) {
if (idx >= _value->size) return ErrorCode::IndexOutOfRange; if (idx >= _value->size) return ERROR(IndexOutOfRange);
auto val = _value->data[idx].get(); auto val = _value->data[idx].get();
return Value::create(val); return Value::create(val);
} }
Result<Value> Array::get(Value& key) { Result<Value> Array::get(Value& key) {
if (!key.is<Int64>()) return ErrorCode::TypeMismatch; if (!key.is<Int64>()) return ERROR(TypeMismatch);
return get(key.to<Int64>()->value()); return get(key.to<Int64>()->value());
} }
@ -185,11 +185,11 @@ short cmp_tag(Tag lhs, Tag rhs) {
Result<Value> Dict::get(Value& key) { Result<Value> Dict::get(Value& key) {
auto pos = TRY(find(key)); auto pos = TRY(find(key));
if (pos > size()) return ErrorCode::KeyError; if (pos > size()) return ERROR(KeyError);
auto k = TRY(Value::create(_value->data[pos * 2].get())); auto k = TRY(Value::create(_value->data[pos * 2].get()));
if (TRY(k.cmp(key)) != 0) { if (TRY(k.cmp(key)) != 0) {
return ErrorCode::KeyError; return ERROR(KeyError);
} }
return TRY(Value::create(_value->data[pos * 2 + 1].get())); return TRY(Value::create(_value->data[pos * 2 + 1].get()));
@ -280,4 +280,4 @@ Result<short> Dict::cmp(Dict& rhs) {
return 0; return 0;
} }
Result<Value> Object::get(Value& key) { return ErrorCode::TypeMismatch; } Result<Value> Object::get(Value& key) { return ERROR(TypeMismatch); }

View file

@ -143,7 +143,7 @@ class Array : public Object {
} }
Result<Array> sub(uint64_t start, uint64_t end) { Result<Array> sub(uint64_t start, uint64_t end) {
if (start > end) return ErrorCode::IndexOutOfRange; if (start > end) return ERROR(IndexOutOfRange);
uint64_t res_size = end - start; uint64_t res_size = end - start;
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*))); auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
pod->size = res_size; pod->size = res_size;
@ -208,7 +208,7 @@ class ByteArray : public Object {
virtual Result<Value> copy() const final; virtual Result<Value> copy() const final;
Result<char> operator[](uint64_t idx) { Result<char> operator[](uint64_t idx) {
if (idx >= _value->size) return ErrorCode::IndexOutOfRange; if (idx >= _value->size) return ERROR(IndexOutOfRange);
return _value->data[idx]; return _value->data[idx];
} }
@ -251,7 +251,7 @@ class ByteArray : public Object {
} }
Result<ByteArray> sub(uint64_t start, uint64_t end) { Result<ByteArray> sub(uint64_t start, uint64_t end) {
if (start > end) return ErrorCode::IndexOutOfRange; if (start > end) return ERROR(IndexOutOfRange);
uint64_t res_size = end - start; uint64_t res_size = end - start;
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char))); auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
pod->size = res_size; pod->size = res_size;
@ -393,7 +393,7 @@ class String : public Object {
virtual Result<Value> copy() const final; virtual Result<Value> copy() const final;
Result<char32_t> operator[](uint64_t idx) { Result<char32_t> operator[](uint64_t idx) {
if (idx >= _value->size) return ErrorCode::IndexOutOfRange; if (idx >= _value->size) return ERROR(IndexOutOfRange);
return _value->data[idx]; return _value->data[idx];
} }
@ -439,7 +439,7 @@ class String : public Object {
} }
Result<String> sub(uint64_t start, uint64_t end) { Result<String> sub(uint64_t start, uint64_t end) {
if (start > end) return ErrorCode::IndexOutOfRange; if (start > end) return ERROR(IndexOutOfRange);
uint64_t res_size = end - start; uint64_t res_size = end - start;
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t))); auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
pod->header.tag = Tag::String; pod->header.tag = Tag::String;
@ -483,6 +483,26 @@ class Symbol : public Object {
} }
return 0; return 0;
} }
virtual Result<short> cmp(const char* rhs) final {
auto lsize = size();
auto rsize = strlen(rhs);
uint64_t i = 0;
uint64_t j = 0;
while (1) {
if (i == lsize && j == lsize) return 0;
short cmp = short(i == lsize) - short(j == rsize);
if (cmp != 0) return cmp;
char32_t lc = _value->data[i];
char32_t rc = rhs[j];
cmp = (lc > rc) - (lc < rc);
if (cmp != 0) return cmp;
i++;
j++;
}
return 0;
}
virtual void move(Object* obj) final { new (obj) Symbol(std::move(_value)); } virtual void move(Object* obj) final { new (obj) Symbol(std::move(_value)); }
static Result<Symbol> create(PodSymbol* obj) { static Result<Symbol> create(PodSymbol* obj) {
@ -515,7 +535,7 @@ class Symbol : public Object {
uint64_t size() { return _value->size; } uint64_t size() { return _value->size; }
Result<char32_t> operator[](uint64_t idx) { Result<char32_t> operator[](uint64_t idx) {
if (idx >= _value->size) return ErrorCode::IndexOutOfRange; if (idx >= _value->size) return ERROR(IndexOutOfRange);
return _value->data[idx]; return _value->data[idx];
} }

View file

@ -21,8 +21,9 @@ struct Context {
uint64_t maxconst; uint64_t maxconst;
}; };
bool is_primitive_op(Symbol& sym) { Result<bool> is_primitive_op(Symbol& sym) {
// return (sym.cmp("+") == 0); return TRY(sym.cmp("+")) == 0 || TRY(sym.cmp("-")) == 0 ||
TRY(sym.cmp("*")) == 0 || TRY(sym.cmp("/")) == 0;
return false; return false;
} }
@ -30,7 +31,7 @@ Result<Value> Compiler::compile(Value& expr) {
auto context = TRY(Context::create()); auto context = TRY(Context::create());
TRY(compile_expr(context, expr)); TRY(compile_expr(context, expr));
return ErrorCode::NotImplemented; return ERROR(NotImplemented);
} }
Result<Expression> Compiler::compile_expr(Context& context, Value& expr) { Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
switch (expr.tag()) { switch (expr.tag()) {
@ -46,16 +47,36 @@ Result<Expression> Compiler::compile_expr(Context& context, Value& expr) {
case Tag::Array: case Tag::Array:
case Tag::ByteArray: case Tag::ByteArray:
case Tag::Dict: case Tag::Dict:
return ErrorCode::TypeMismatch; return ERROR(TypeMismatch);
} }
return ErrorCode::TypeMismatch; return ERROR(TypeMismatch);
} }
Result<Expression> Compiler::compile_primop(Context& context, Symbol& op,
Pair& expr) {
std::cout << "primop\n";
Value cur = TRY(expr.rest());
Array code = TRY(Array::create());
while (!cur.is<Nil>()) {
Pair& pair = *cur.to<Pair>();
auto subexpr = TRY(pair.first());
auto comp = TRY(compile_expr(context, subexpr));
cur = TRY(pair.rest());
}
return ERROR(TypeMismatch);
}
Result<Expression> Compiler::compile_list(Context& context, Pair& expr) { Result<Expression> Compiler::compile_list(Context& context, Pair& expr) {
auto first = TRY(expr.first()); auto first = TRY(expr.first());
if (first.is<Symbol>()) { if (first.is<Symbol>()) {
Symbol& sym = *first.to<Symbol>(); Symbol& sym = *first.to<Symbol>();
if (TRY(is_primitive_op(sym))) {
return compile_primop(context, sym, expr);
}
} }
return ErrorCode::TypeMismatch; return ERROR(TypeMismatch);
} }

View file

@ -18,4 +18,5 @@ class Compiler {
Result<Value> compile(Value& expr); Result<Value> compile(Value& expr);
Result<Expression> compile_expr(Context& context, Value& expr); Result<Expression> compile_expr(Context& context, Value& expr);
Result<Expression> compile_list(Context& context, Pair& expr); Result<Expression> compile_list(Context& context, Pair& expr);
Result<Expression> compile_primop(Context& context, Symbol& op, Pair& expr);
}; };

6
src/error.cpp Normal file
View file

@ -0,0 +1,6 @@
#include "error.hpp"
static const char* curerr = 0;
void seterr(const char* err) { curerr = err; }
const char* geterr(void) { return curerr; }

View file

@ -13,3 +13,15 @@ enum class ErrorCode {
MalformedList, MalformedList,
KeyError, KeyError,
}; };
void seterr(const char* err);
const char* geterr(void);
#define STRINGIZE_NESTED(A) #A
#define STRINGIZE(A) STRINGIZE_NESTED(A)
#define ERROR(code) \
(({ \
seterr("Error " STRINGIZE(code) " at " __FILE__ ":" STRINGIZE(__LINE__)); \
ErrorCode::code; \
}))

View file

@ -153,12 +153,12 @@ class Ptr {
T* operator->() { return _ptr; } T* operator->() { return _ptr; }
Result<int64_t> get_int() { Result<int64_t> get_int() {
if (_ptr->tag != Tag::Int64) return ErrorCode::TypeMismatch; if (_ptr->tag != Tag::Int64) return ERROR(TypeMismatch);
return ((PodInt64*)_ptr)->value; return ((PodInt64*)_ptr)->value;
} }
Result<double> get_float() { Result<double> get_float() {
if (_ptr->tag != Tag::Float) return ErrorCode::TypeMismatch; if (_ptr->tag != Tag::Float) return ERROR(TypeMismatch);
return ((PodFloat*)_ptr)->value; return ((PodFloat*)_ptr)->value;
} }

View file

@ -58,10 +58,10 @@ Result<Value> Reader::read_one() {
} else if (match('[')) { } else if (match('[')) {
// TODO: implement array // TODO: implement array
// return read_array(); // return read_array();
return ErrorCode::ReadError; return ERROR(ReadError);
} else if (match('{')) { } else if (match('{')) {
return read_dict(); return read_dict();
return ErrorCode::ReadError; return ERROR(ReadError);
} }
position_ = saved_position; position_ = saved_position;
@ -69,7 +69,7 @@ Result<Value> Reader::read_one() {
return read_symbol(); return read_symbol();
} }
return ErrorCode::ReadError; return ERROR(ReadError);
} }
Result<Value> Reader::read_multiple() { Result<Value> Reader::read_multiple() {
@ -85,11 +85,11 @@ Result<Value> Reader::read_multiple() {
res = Value(TRY(Pair::create(val, res))); res = Value(TRY(Pair::create(val, res)));
} }
return ErrorCode::ReadError; return ERROR(ReadError);
} }
Result<Value> Reader::read_list() { Result<Value> Reader::read_list() {
if (!match('(')) return ErrorCode::ReadError; if (!match('(')) return ERROR(ReadError);
forward(); forward();
@ -99,7 +99,7 @@ Result<Value> Reader::read_list() {
forward_whitespace(); forward_whitespace();
if (is_eof()) { if (is_eof()) {
return ErrorCode::ReadError; return ERROR(ReadError);
} }
if (match(')')) { if (match(')')) {
@ -112,11 +112,11 @@ Result<Value> Reader::read_list() {
res = Value(TRY(Pair::create(val, res))); res = Value(TRY(Pair::create(val, res)));
} }
return ErrorCode::ReadError; return ERROR(ReadError);
} }
Result<Value> Reader::read_dict() { Result<Value> Reader::read_dict() {
if (!match('{')) return ErrorCode::ReadError; if (!match('{')) return ERROR(ReadError);
forward(); forward();
@ -126,7 +126,7 @@ Result<Value> Reader::read_dict() {
forward_whitespace(); forward_whitespace();
if (is_eof()) { if (is_eof()) {
return ErrorCode::ReadError; return ERROR(ReadError);
} }
if (match('}')) { if (match('}')) {
@ -140,25 +140,25 @@ Result<Value> Reader::read_dict() {
res = TRY(res.insert(val1, val2)); res = TRY(res.insert(val1, val2));
} }
return ErrorCode::ReadError; return ERROR(ReadError);
} }
Result<Value> Reader::read_bool() { Result<Value> Reader::read_bool() {
if (match("true")) { if (match("true")) {
forward(4); forward(4);
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError; if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
return Value(TRY(Bool::create(true))); return Value(TRY(Bool::create(true)));
} }
if (match("false")) { if (match("false")) {
forward(5); forward(5);
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError; if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
return Value(TRY(Bool::create(false))); return Value(TRY(Bool::create(false)));
} }
return ErrorCode::ReadError; return ERROR(ReadError);
} }
Result<Value> Reader::read_string() { Result<Value> Reader::read_string() {
if (!match('"')) return ErrorCode::ReadError; if (!match('"')) return ERROR(ReadError);
size_t start = position_.offset + 1; size_t start = position_.offset + 1;
forward(); forward();
@ -171,7 +171,7 @@ Result<Value> Reader::read_string() {
forward(); forward();
} }
if (!match('"')) return ErrorCode::UnterminatedStringLiteral; if (!match('"')) return ERROR(UnterminatedStringLiteral);
forward(); forward();
@ -217,13 +217,13 @@ Result<Value> Reader::read_string() {
result = TRY(result.concat(&next, 1)); result = TRY(result.concat(&next, 1));
} }
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError; if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
return Value(std::move(result)); return Value(std::move(result));
} }
Result<Value> Reader::read_number() { Result<Value> Reader::read_number() {
if (!is_numeric_start()) return ErrorCode::ReadError; if (!is_numeric_start()) return ERROR(ReadError);
size_t start = position_.offset; size_t start = position_.offset;
bool is_float = false; bool is_float = false;
@ -238,13 +238,13 @@ Result<Value> Reader::read_number() {
while (is_digit(get())) forward(); while (is_digit(get())) forward();
if (match('e') || match('E')) { if (match('e') || match('E')) {
if (!forward_exponent()) return ErrorCode::InvalidNumericLiteral; if (!forward_exponent()) return ERROR(InvalidNumericLiteral);
} }
} else if (match('e') || match('E')) { } else if (match('e') || match('E')) {
is_float = true; is_float = true;
if (!forward_exponent()) return ErrorCode::InvalidNumericLiteral; if (!forward_exponent()) return ERROR(InvalidNumericLiteral);
} else if (match('x') || match('X')) { } else if (match('x') || match('X')) {
if (!forward_hex_number()) return ErrorCode::InvalidNumericLiteral; if (!forward_hex_number()) return ERROR(InvalidNumericLiteral);
} else if (is_digit(get())) { } else if (is_digit(get())) {
do { do {
forward(); forward();
@ -259,13 +259,13 @@ Result<Value> Reader::read_number() {
} }
if (match('e') || match('E')) { if (match('e') || match('E')) {
is_float = true; is_float = true;
if (!forward_exponent()) return ErrorCode::InvalidNumericLiteral; if (!forward_exponent()) return ERROR(InvalidNumericLiteral);
} }
} }
Value res; Value res;
if (position_.offset - start >= 32) return ErrorCode::InvalidNumericLiteral; if (position_.offset - start >= 32) return ERROR(InvalidNumericLiteral);
char buf[32]; char buf[32];
for (size_t i = 0; i < position_.offset - start; ++i) { for (size_t i = 0; i < position_.offset - start; ++i) {
@ -282,13 +282,13 @@ Result<Value> Reader::read_number() {
res = Value(TRY(Int64::create(strtoll(buf, 0, 10)))); res = Value(TRY(Int64::create(strtoll(buf, 0, 10))));
} }
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError; if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
return res; return res;
} }
Result<Value> Reader::read_symbol() { Result<Value> Reader::read_symbol() {
if (!is_symbol_char(get())) return ErrorCode::ReadError; if (!is_symbol_char(get())) return ERROR(ReadError);
size_t start = position_.offset; size_t start = position_.offset;
@ -298,7 +298,7 @@ Result<Value> Reader::read_symbol() {
String str = TRY(_str.sub(start, end)); String str = TRY(_str.sub(start, end));
if (!is_separator(get()) && !is_eof()) return ErrorCode::ReadError; if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
return Value(TRY(Symbol::create(str))); return Value(TRY(Symbol::create(str)));
} }
@ -410,7 +410,7 @@ bool Reader::forward_exponent() {
} }
Result<Value> read_one(Value& value) { Result<Value> read_one(Value& value) {
if (!value.is<String>()) return ErrorCode::TypeMismatch; if (!value.is<String>()) return ERROR(TypeMismatch);
auto r = Reader(*value.to<String>()); auto r = Reader(*value.to<String>());
return r.read_one(); return r.read_one();
} }

View file

@ -55,12 +55,16 @@ class Result<void> {
std::move(___res); \ std::move(___res); \
}).release_value()) }).release_value())
#define DIEX(m) \ #define DIEX(m) \
(({ \ (({ \
auto ___res = (m); \ auto ___res = (m); \
if (!___res.has_value()) { \ if (!___res.has_value()) { \
fprintf(stderr, "%s:%d assertion failed\n", __FILE__, __LINE__); \ const char* err = geterr(); \
exit(EXIT_FAILURE); \ if (err == 0) \
} \ fprintf(stderr, "%s:%d assertion failed\n", __FILE__, __LINE__); \
std::move(___res); \ else \
fprintf(stderr, "%s\n", err); \
exit(EXIT_FAILURE); \
} \
std::move(___res); \
}).release_value()) }).release_value())

View file

@ -70,7 +70,7 @@ Result<String> Writer::write_bool(Bool& val) {
} }
Result<String> Writer::write_bytearray(ByteArray& val) { Result<String> Writer::write_bytearray(ByteArray& val) {
return ErrorCode::NotImplemented; return ERROR(NotImplemented);
} }
Result<String> Writer::write_string(String& val) { Result<String> Writer::write_string(String& val) {
@ -131,7 +131,7 @@ Result<String> Writer::write_symbol(Symbol& val) {
for (uint64_t i = 0; i < val.size(); i++) { for (uint64_t i = 0; i < val.size(); i++) {
char32_t c = TRY(val[i]); char32_t c = TRY(val[i]);
if (!is_valid_symbol_char(c)) return ErrorCode::InvalidSymbol; if (!is_valid_symbol_char(c)) return ERROR(InvalidSymbol);
res = TRY(res.concat(&c, 1)); res = TRY(res.concat(&c, 1));
} }
@ -140,7 +140,7 @@ Result<String> Writer::write_symbol(Symbol& val) {
} }
Result<String> Writer::write_syntax(Syntax& val) { Result<String> Writer::write_syntax(Syntax& val) {
return ErrorCode::NotImplemented; return ERROR(NotImplemented);
} }
Result<String> Writer::write_pair(Pair& val) { Result<String> Writer::write_pair(Pair& val) {
@ -150,7 +150,7 @@ Result<String> Writer::write_pair(Pair& val) {
bool is_first = true; bool is_first = true;
while (!cur.is<Nil>()) { while (!cur.is<Nil>()) {
if (!cur.is<Pair>()) return ErrorCode::MalformedList; if (!cur.is<Pair>()) return ERROR(MalformedList);
Pair& pair = *cur.to<Pair>(); Pair& pair = *cur.to<Pair>();