Report syntax errors when reading in the REPL
This commit is contained in:
parent
5cb8921c42
commit
1958cfb285
9 changed files with 175 additions and 52 deletions
|
@ -62,6 +62,18 @@ Result<Symbol> Symbol::create(String& rhs) {
|
||||||
return Symbol(TRY(MkGcRoot(pod)));
|
return Symbol(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> String::create(const Symbol& rhs) {
|
||||||
|
uint64_t rhs_size = rhs.size();
|
||||||
|
uint64_t res_size = rhs_size;
|
||||||
|
|
||||||
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
|
pod->header.tag = Tag::String;
|
||||||
|
pod->size = res_size;
|
||||||
|
memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size);
|
||||||
|
|
||||||
|
return String(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
Result<ByteArray> ByteArray::create(const String& str) {
|
Result<ByteArray> ByteArray::create(const String& str) {
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
for (uint64_t i = 0; i < str.size(); i++) {
|
for (uint64_t i = 0; i < str.size(); i++) {
|
||||||
|
@ -491,6 +503,11 @@ Result<Value> reverse(Value& val) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> debug_print(const char* val) {
|
||||||
|
std::cout << val << "\n";
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> debug_print(const String& val) {
|
Result<void> debug_print(const String& val) {
|
||||||
auto ba = TRY(ByteArray::create(val));
|
auto ba = TRY(ByteArray::create(val));
|
||||||
|
|
||||||
|
@ -841,6 +858,8 @@ Result<Value> Syntax::rest() const {
|
||||||
return val.rest();
|
return val.rest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> build_string(const String& value) { return value.copy(); }
|
||||||
|
|
||||||
Result<String> build_string(const Value& value) {
|
Result<String> build_string(const Value& value) {
|
||||||
if (value.is<String>()) {
|
if (value.is<String>()) {
|
||||||
return value.to<String>()->copy();
|
return value.to<String>()->copy();
|
||||||
|
@ -850,3 +869,13 @@ Result<String> build_string(const Value& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> build_string(const char* value) { return String::create(value); }
|
Result<String> build_string(const char* value) { return String::create(value); }
|
||||||
|
|
||||||
|
Result<String> build_string(int64_t value) {
|
||||||
|
auto val = Value(TRY(Int64::create(value)));
|
||||||
|
return write_one(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> build_string(uint64_t value) {
|
||||||
|
auto val = Value(TRY(Int64::create((int64_t)value)));
|
||||||
|
return write_one(val);
|
||||||
|
}
|
||||||
|
|
|
@ -476,6 +476,8 @@ class String : public Object {
|
||||||
return String(TRY(MkGcRoot(pod)));
|
return String(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result<String> create(const Symbol& sym);
|
||||||
|
|
||||||
static Result<String> create(const char* str) {
|
static Result<String> create(const char* str) {
|
||||||
uint64_t size = strlen(str);
|
uint64_t size = strlen(str);
|
||||||
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
||||||
|
@ -557,6 +559,8 @@ class String : public Object {
|
||||||
|
|
||||||
class Symbol : public Object {
|
class Symbol : public Object {
|
||||||
public:
|
public:
|
||||||
|
friend class String;
|
||||||
|
|
||||||
Symbol() {}
|
Symbol() {}
|
||||||
Symbol(Symbol&& rhs) : _value(std::move(rhs._value)) {}
|
Symbol(Symbol&& rhs) : _value(std::move(rhs._value)) {}
|
||||||
Symbol(GcRoot<PodSymbol>&& val) : _value(std::move(val)) {}
|
Symbol(GcRoot<PodSymbol>&& val) : _value(std::move(val)) {}
|
||||||
|
@ -1166,6 +1170,16 @@ class Error : public Object {
|
||||||
return Error(TRY(MkGcRoot(pod)));
|
return Error(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result<Error> create(const Symbol& name, const String& message) {
|
||||||
|
auto pod = TRY(arena_alloc<PodError>());
|
||||||
|
pod->header.tag = Tag::Error;
|
||||||
|
|
||||||
|
pod->name = name.pod();
|
||||||
|
pod->message = message.pod();
|
||||||
|
|
||||||
|
return Error(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> name() const;
|
Result<Value> name() const;
|
||||||
Result<Value> message() const;
|
Result<Value> message() const;
|
||||||
|
|
||||||
|
@ -1273,6 +1287,7 @@ Result<Value> reverse(Value& val);
|
||||||
|
|
||||||
Result<void> debug_print(const String& val);
|
Result<void> debug_print(const String& val);
|
||||||
Result<void> debug_print(const Value& val);
|
Result<void> debug_print(const Value& val);
|
||||||
|
Result<void> debug_print(const char* val);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Result<void> debug_print(const T& val)
|
Result<void> debug_print(const T& val)
|
||||||
|
@ -1301,7 +1316,10 @@ Result<Value> syntax_unwrap(const Value& value);
|
||||||
Result<Value> syntax_unwrap_all(const Value& value);
|
Result<Value> syntax_unwrap_all(const Value& value);
|
||||||
|
|
||||||
Result<String> build_string(const Value& value);
|
Result<String> build_string(const Value& value);
|
||||||
|
Result<String> build_string(const String& value);
|
||||||
Result<String> build_string(const char* value);
|
Result<String> build_string(const char* value);
|
||||||
|
Result<String> build_string(int64_t value);
|
||||||
|
Result<String> build_string(uint64_t value);
|
||||||
|
|
||||||
template <class T, class... Args>
|
template <class T, class... Args>
|
||||||
Result<String> build_string(const T& value, Args&&... args) {
|
Result<String> build_string(const T& value, Args&&... args) {
|
||||||
|
|
|
@ -16,3 +16,12 @@ Result<void> seterrobj(const Value& val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void reseterrobj() { errobj = Value(); }
|
void reseterrobj() { errobj = Value(); }
|
||||||
|
|
||||||
|
const char* errname(ErrorCode errcode) {
|
||||||
|
switch (errcode) {
|
||||||
|
case ErrorCode::SyntaxError:
|
||||||
|
return "syntax-error";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ class Value;
|
||||||
template <class T>
|
template <class T>
|
||||||
class Result;
|
class Result;
|
||||||
|
|
||||||
|
const char* errname(ErrorCode errcode);
|
||||||
|
|
||||||
void seterr(const char* err);
|
void seterr(const char* err);
|
||||||
const char* geterr(void);
|
const char* geterr(void);
|
||||||
|
|
||||||
|
@ -43,3 +45,13 @@ void reseterrobj();
|
||||||
seterr("Error " STRINGIZE(code) " at " __FILE__ ":" STRINGIZE(__LINE__)); \
|
seterr("Error " STRINGIZE(code) " at " __FILE__ ":" STRINGIZE(__LINE__)); \
|
||||||
ErrorCode::code; \
|
ErrorCode::code; \
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
#define ERROR_FMT(code, ...) \
|
||||||
|
(({ \
|
||||||
|
auto name = TRY(Symbol::create(errname(ErrorCode::code))); \
|
||||||
|
auto message = TRY(build_string(__VA_ARGS__)); \
|
||||||
|
auto err = Value(TRY(Error::create(name, message))); \
|
||||||
|
TRY(seterrobj(err)); \
|
||||||
|
seterr("Error " STRINGIZE(code) " at " __FILE__ ":" STRINGIZE(__LINE__)); \
|
||||||
|
ErrorCode::code; \
|
||||||
|
}))
|
||||||
|
|
|
@ -72,7 +72,7 @@ Result<Value> Reader::read_one() {
|
||||||
return read_symbol();
|
return read_symbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR(ReadError);
|
return syntax_error(saved_position, "unknown token");
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> Reader::read_multiple() {
|
Result<Value> Reader::read_multiple() {
|
||||||
|
@ -88,29 +88,10 @@ Result<Value> Reader::read_multiple() {
|
||||||
res = Value(TRY(Pair::create(val, res)));
|
res = Value(TRY(Pair::create(val, res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> Reader::read_list_rec() {
|
|
||||||
forward_whitespace();
|
|
||||||
|
|
||||||
if (is_eof()) {
|
|
||||||
return ERROR(ReadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match(')')) {
|
|
||||||
forward();
|
|
||||||
return Value(TRY(Nil::create()));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto val = TRY(read_one());
|
|
||||||
auto rest = TRY(read_list_rec());
|
|
||||||
|
|
||||||
auto res = Value(TRY(Pair::create(val, rest)));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<Value> Reader::read_list() {
|
Result<Value> Reader::read_list() {
|
||||||
if (!match('(')) return ERROR(ReadError);
|
if (!match('(')) return ERROR(ReadError);
|
||||||
|
|
||||||
|
@ -123,7 +104,7 @@ Result<Value> Reader::read_list() {
|
||||||
forward_whitespace();
|
forward_whitespace();
|
||||||
|
|
||||||
if (is_eof()) {
|
if (is_eof()) {
|
||||||
return ERROR(ReadError);
|
return syntax_error(start, "unterminated list");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(')')) {
|
if (match(')')) {
|
||||||
|
@ -143,6 +124,7 @@ Result<Value> Reader::read_list() {
|
||||||
res = TRY(Pair::create(val, res));
|
res = TRY(Pair::create(val, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +141,7 @@ Result<Value> Reader::read_array_code() {
|
||||||
forward_whitespace();
|
forward_whitespace();
|
||||||
|
|
||||||
if (is_eof()) {
|
if (is_eof()) {
|
||||||
return ERROR(ReadError);
|
return syntax_error(start, "unterminated array");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(']')) {
|
if (match(']')) {
|
||||||
|
@ -180,6 +162,7 @@ Result<Value> Reader::read_array_code() {
|
||||||
res = TRY(Pair::create(val, res));
|
res = TRY(Pair::create(val, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +178,7 @@ Result<Value> Reader::read_array_data() {
|
||||||
forward_whitespace();
|
forward_whitespace();
|
||||||
|
|
||||||
if (is_eof()) {
|
if (is_eof()) {
|
||||||
return ERROR(ReadError);
|
return syntax_error(start, "unterminated array");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(']')) {
|
if (match(']')) {
|
||||||
|
@ -215,6 +198,7 @@ Result<Value> Reader::read_array_data() {
|
||||||
res = TRY(res.append(val));
|
res = TRY(res.append(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +221,7 @@ Result<Value> Reader::read_dict_code() {
|
||||||
forward_whitespace();
|
forward_whitespace();
|
||||||
|
|
||||||
if (is_eof()) {
|
if (is_eof()) {
|
||||||
return ERROR(ReadError);
|
return syntax_error(start, "unterminated dict");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match('}')) {
|
if (match('}')) {
|
||||||
|
@ -260,6 +244,7 @@ Result<Value> Reader::read_dict_code() {
|
||||||
res = TRY(Pair::create(val2, res));
|
res = TRY(Pair::create(val2, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +260,7 @@ Result<Value> Reader::read_dict_data() {
|
||||||
forward_whitespace();
|
forward_whitespace();
|
||||||
|
|
||||||
if (is_eof()) {
|
if (is_eof()) {
|
||||||
return ERROR(ReadError);
|
return syntax_error(start, "unterminated dict");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match('}')) {
|
if (match('}')) {
|
||||||
|
@ -296,6 +281,7 @@ Result<Value> Reader::read_dict_data() {
|
||||||
res = TRY(res.insert(val1, val2));
|
res = TRY(res.insert(val1, val2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +295,8 @@ Result<Value> Reader::read_bool() {
|
||||||
SourcePosition start = position_;
|
SourcePosition start = position_;
|
||||||
if (match("true")) {
|
if (match("true")) {
|
||||||
forward(4);
|
forward(4);
|
||||||
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
// We don't report full error here, because it's not propagated to the user
|
||||||
|
if (!is_separator(get()) && !is_eof()) return ERROR(SyntaxError);
|
||||||
SourcePosition end = position_;
|
SourcePosition end = position_;
|
||||||
|
|
||||||
auto res = Value(TRY(Bool::create(true)));
|
auto res = Value(TRY(Bool::create(true)));
|
||||||
|
@ -321,7 +308,8 @@ Result<Value> Reader::read_bool() {
|
||||||
}
|
}
|
||||||
if (match("false")) {
|
if (match("false")) {
|
||||||
forward(5);
|
forward(5);
|
||||||
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
// We don't report full error here, because it's not propagated to the user
|
||||||
|
if (!is_separator(get()) && !is_eof()) return ERROR(SyntaxError);
|
||||||
SourcePosition end = position_;
|
SourcePosition end = position_;
|
||||||
|
|
||||||
auto res = Value(TRY(Bool::create(false)));
|
auto res = Value(TRY(Bool::create(false)));
|
||||||
|
@ -332,6 +320,7 @@ Result<Value> Reader::read_bool() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't report full error here, because it's not propagated to the user
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +328,7 @@ Result<Value> Reader::read_nil() {
|
||||||
SourcePosition start = position_;
|
SourcePosition start = position_;
|
||||||
if (match("nil")) {
|
if (match("nil")) {
|
||||||
forward(3);
|
forward(3);
|
||||||
|
// We don't report full error here, because it's not propagated to the user
|
||||||
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
||||||
SourcePosition end = position_;
|
SourcePosition end = position_;
|
||||||
|
|
||||||
|
@ -350,6 +340,7 @@ Result<Value> Reader::read_nil() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't report full error here, because it's not propagated to the user
|
||||||
return ERROR(ReadError);
|
return ERROR(ReadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +379,9 @@ Result<Value> Reader::read_string() {
|
||||||
forward();
|
forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match('"')) return ERROR(UnterminatedStringLiteral);
|
if (!match('"')) {
|
||||||
|
return syntax_error(startloc, "unterminated string");
|
||||||
|
}
|
||||||
|
|
||||||
forward();
|
forward();
|
||||||
|
|
||||||
|
@ -434,7 +427,9 @@ Result<Value> Reader::read_string() {
|
||||||
result = TRY(result.concat(&next, 1));
|
result = TRY(result.concat(&next, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
if (!is_separator(get()) && !is_eof()) {
|
||||||
|
return syntax_error(position_, "string followed by invalid tokens");
|
||||||
|
}
|
||||||
SourcePosition endloc = position_;
|
SourcePosition endloc = position_;
|
||||||
|
|
||||||
auto res = Value(std::move(result));
|
auto res = Value(std::move(result));
|
||||||
|
@ -462,13 +457,19 @@ 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 ERROR(InvalidNumericLiteral);
|
if (!forward_exponent()) {
|
||||||
|
return syntax_error(startloc, "invalid numeric literal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (match('e') || match('E')) {
|
} else if (match('e') || match('E')) {
|
||||||
is_float = true;
|
is_float = true;
|
||||||
if (!forward_exponent()) return ERROR(InvalidNumericLiteral);
|
if (!forward_exponent()) {
|
||||||
|
return syntax_error(startloc, "invalid numeric literal");
|
||||||
|
}
|
||||||
} else if (match('x') || match('X')) {
|
} else if (match('x') || match('X')) {
|
||||||
if (!forward_hex_number()) return ERROR(InvalidNumericLiteral);
|
if (!forward_hex_number()) {
|
||||||
|
return syntax_error(startloc, "invalid numeric literal");
|
||||||
|
}
|
||||||
} else if (is_digit(get())) {
|
} else if (is_digit(get())) {
|
||||||
do {
|
do {
|
||||||
forward();
|
forward();
|
||||||
|
@ -483,13 +484,17 @@ 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 ERROR(InvalidNumericLiteral);
|
if (!forward_exponent()) {
|
||||||
|
return syntax_error(startloc, "invalid numeric literal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value res;
|
Value res;
|
||||||
|
|
||||||
if (position_.offset - start >= 32) return ERROR(InvalidNumericLiteral);
|
if (position_.offset - start >= 32) {
|
||||||
|
return syntax_error(startloc, "numeric literal is too large");
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -506,7 +511,9 @@ 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 ERROR(ReadError);
|
if (!is_separator(get()) && !is_eof()) {
|
||||||
|
return syntax_error(startloc, "number is followed by invalid tokens");
|
||||||
|
}
|
||||||
|
|
||||||
SourcePosition endloc = position_;
|
SourcePosition endloc = position_;
|
||||||
|
|
||||||
|
@ -529,7 +536,9 @@ Result<Value> Reader::read_symbol() {
|
||||||
|
|
||||||
String str = TRY(_str.slice(start, end));
|
String str = TRY(_str.slice(start, end));
|
||||||
|
|
||||||
if (!is_separator(get()) && !is_eof()) return ERROR(ReadError);
|
if (!is_separator(get()) && !is_eof()) {
|
||||||
|
return syntax_error(startloc, "symbol is followed by invalid tokens");
|
||||||
|
}
|
||||||
|
|
||||||
SourcePosition endloc = position_;
|
SourcePosition endloc = position_;
|
||||||
|
|
||||||
|
@ -647,26 +656,31 @@ bool Reader::forward_exponent() {
|
||||||
return forward_decimal_number();
|
return forward_decimal_number();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Value> Reader::syntax_error(SourcePosition pos, const char* msg) {
|
||||||
|
return ERROR_FMT(SyntaxError, _fname, ":", pos.line, ":", pos.column,
|
||||||
|
" Syntax error: ", msg);
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> read_one(const Value& value, bool syntax, bool as_code) {
|
Result<Value> read_one(const Value& value, bool syntax, bool as_code) {
|
||||||
if (!value.is<String>()) return ERROR(TypeMismatch);
|
if (!value.is<String>()) return ERROR(TypeMismatch);
|
||||||
auto fname = TRY(String::create(""));
|
auto fname = TRY(String::create("<unknown>"));
|
||||||
auto r = Reader(fname, *value.to<String>(), syntax, as_code);
|
auto r = Reader(fname, *value.to<String>(), syntax, as_code);
|
||||||
return r.read_one();
|
return r.read_one();
|
||||||
}
|
}
|
||||||
Result<Value> read_one(const String& value, bool syntax, bool as_code) {
|
Result<Value> read_one(const String& value, bool syntax, bool as_code) {
|
||||||
auto fname = TRY(String::create(""));
|
auto fname = TRY(String::create("<unknown>"));
|
||||||
auto r = Reader(fname, value, syntax, as_code);
|
auto r = Reader(fname, value, syntax, as_code);
|
||||||
return r.read_one();
|
return r.read_one();
|
||||||
}
|
}
|
||||||
Result<Value> read_one(const char* value, bool syntax, bool as_code) {
|
Result<Value> read_one(const char* value, bool syntax, bool as_code) {
|
||||||
auto fname = TRY(String::create(""));
|
auto fname = TRY(String::create("<unknown>"));
|
||||||
auto s = TRY(String::create(value));
|
auto s = TRY(String::create(value));
|
||||||
auto r = Reader(fname, s, syntax, as_code);
|
auto r = Reader(fname, s, syntax, as_code);
|
||||||
return r.read_one();
|
return r.read_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> read_multiple(const String& value, bool syntax, bool as_code) {
|
Result<Value> read_multiple(const String& value, bool syntax, bool as_code) {
|
||||||
auto fname = TRY(String::create(""));
|
auto fname = TRY(String::create("<unknown>"));
|
||||||
auto r = Reader(fname, value, syntax, as_code);
|
auto r = Reader(fname, value, syntax, as_code);
|
||||||
return r.read_multiple();
|
return r.read_multiple();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ class Reader {
|
||||||
bool is_string_start();
|
bool is_string_start();
|
||||||
|
|
||||||
Result<Value> read_list();
|
Result<Value> read_list();
|
||||||
Result<Value> read_list_rec();
|
|
||||||
Result<Value> read_string();
|
Result<Value> read_string();
|
||||||
Result<Value> read_array();
|
Result<Value> read_array();
|
||||||
Result<Value> read_array_code();
|
Result<Value> read_array_code();
|
||||||
|
@ -43,6 +42,8 @@ class Reader {
|
||||||
Result<Value> read_nil();
|
Result<Value> read_nil();
|
||||||
Result<Value> read_quote();
|
Result<Value> read_quote();
|
||||||
|
|
||||||
|
Result<Value> syntax_error(SourcePosition pos, const char* message);
|
||||||
|
|
||||||
char32_t get(size_t offset = 0);
|
char32_t get(size_t offset = 0);
|
||||||
bool match(const char* str);
|
bool match(const char* str);
|
||||||
bool match(char c);
|
bool match(char c);
|
||||||
|
|
|
@ -11,8 +11,8 @@ class Result {
|
||||||
Result(T&& res) : _value(std::move(res)), _error(ErrorCode::Success) {}
|
Result(T&& res) : _value(std::move(res)), _error(ErrorCode::Success) {}
|
||||||
Result(ErrorCode err) : _error(err) {}
|
Result(ErrorCode err) : _error(err) {}
|
||||||
|
|
||||||
bool has_error() { return _error != ErrorCode::Success; }
|
bool has_error() const { return _error != ErrorCode::Success; }
|
||||||
bool has_value() { return !has_error(); }
|
bool has_value() const { return !has_error(); }
|
||||||
|
|
||||||
T& value() { return _value; }
|
T& value() { return _value; }
|
||||||
T& operator*() { return _value; }
|
T& operator*() { return _value; }
|
||||||
|
@ -36,8 +36,8 @@ class Result<void> {
|
||||||
|
|
||||||
Result& operator=(Result&& res) = default;
|
Result& operator=(Result&& res) = default;
|
||||||
|
|
||||||
bool has_error() { return err != ErrorCode::Success; }
|
bool has_error() const { return err != ErrorCode::Success; }
|
||||||
bool has_value() { return !has_error(); }
|
bool has_value() const { return !has_error(); }
|
||||||
|
|
||||||
void value() {}
|
void value() {}
|
||||||
void release_value() {}
|
void release_value() {}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "compiler.hpp"
|
#include "compiler.hpp"
|
||||||
#include "die.hpp"
|
#include "die.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
#include "fio.hpp"
|
#include "fio.hpp"
|
||||||
#include "lineedit.hpp"
|
#include "lineedit.hpp"
|
||||||
#include "reader.hpp"
|
#include "reader.hpp"
|
||||||
|
@ -27,21 +28,47 @@ Result<Value> run_string(const String& src) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> print_error(const Result<Value>& res) {
|
||||||
|
if (res.has_error()) {
|
||||||
|
auto errobj = TRY(geterrobj().copy());
|
||||||
|
if (errobj.is<Nil>()) {
|
||||||
|
debug_print(geterr());
|
||||||
|
} else {
|
||||||
|
debug_print(errobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> run_repl() {
|
Result<void> run_repl() {
|
||||||
Dict globals = TRY(Dict::create());
|
Dict globals = TRY(Dict::create());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto src = TRY(read_line("valeri> "));
|
auto src = TRY(read_line("valeri> "));
|
||||||
auto parsed = TRY(read_multiple(src));
|
auto maybe_parsed = read_multiple(src);
|
||||||
|
if (maybe_parsed.has_error()) {
|
||||||
|
print_error(maybe_parsed);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parsed = maybe_parsed.release_value();
|
||||||
auto compiled = TRY(compile(parsed));
|
auto compiled = TRY(compile(parsed));
|
||||||
Module& mod = *compiled.to<Module>();
|
Module& mod = *compiled.to<Module>();
|
||||||
auto vm = TRY(VM::create());
|
auto vm = TRY(VM::create());
|
||||||
auto res = TRY(vm.run(mod, globals));
|
auto maybe_res = vm.run(mod, globals);
|
||||||
|
|
||||||
|
if (maybe_res.has_value()) {
|
||||||
|
auto res = maybe_res.release_value();
|
||||||
globals = TRY(vm.globals());
|
globals = TRY(vm.globals());
|
||||||
|
|
||||||
if (!res.is<Nil>()) {
|
if (!res.is<Nil>()) {
|
||||||
TRY(debug_print(res));
|
TRY(debug_print(res));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Need to print the error
|
||||||
|
print_error(maybe_res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
|
|
|
@ -379,7 +379,20 @@ Result<String> Writer::write_stack(const Stack& val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> Writer::write_error(const Error& val) {
|
Result<String> Writer::write_error(const Error& val) {
|
||||||
return TRY(String::create("#<error>"));
|
auto res = TRY(String::create("#<error:"));
|
||||||
|
auto name = TRY(val.name());
|
||||||
|
auto name_str = TRY(String::create(*name.to<Symbol>()));
|
||||||
|
|
||||||
|
auto message = TRY(val.message());
|
||||||
|
auto message_str = TRY(write_one(message));
|
||||||
|
|
||||||
|
res = TRY(res.concat(name_str));
|
||||||
|
res = TRY(res.concat(" "));
|
||||||
|
res = TRY(res.concat(message_str));
|
||||||
|
|
||||||
|
res = TRY(res.concat(">"));
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> write_one(const Value& value) {
|
Result<String> write_one(const Value& value) {
|
||||||
|
|
Loading…
Reference in a new issue