From 24f3628b8dacc6609b52d7dbc56cc003ddd28684 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Wed, 9 Nov 2022 19:09:27 +0800 Subject: [PATCH] improve error report --- src/codeobject.h | 21 ++++++++++++------ src/compiler.h | 44 ++++++++++++++----------------------- src/error.h | 56 +++++++++++++++++++++++++++++++----------------- src/parser.h | 17 ++++++--------- src/vm.h | 7 ++---- 5 files changed, 74 insertions(+), 71 deletions(-) diff --git a/src/codeobject.h b/src/codeobject.h index 4f0765c7..2fb6f5a6 100644 --- a/src/codeobject.h +++ b/src/codeobject.h @@ -2,6 +2,7 @@ #include "obj.h" #include "pointer.h" +#include "error.h" enum Opcode { #define OPCODE(name) OP_##name, @@ -32,12 +33,17 @@ enum CompileMode { }; struct CodeObject { - CompileMode mode = EXEC_MODE; + _Source src; + _Str co_name; + CompileMode mode; + + CodeObject(_Source src, _Str co_name, CompileMode mode=EXEC_MODE) { + this->src = src; + this->co_name = co_name; + this->mode = mode; + } std::vector co_code; - _Str co_filename; - _Str co_name; - PyVarList co_consts; std::vector> co_names; @@ -118,9 +124,10 @@ public: return code->co_code[ip++]; } - int currentLine(){ - if(isEnd()) return -1; - return code->co_code[ip].line; + _Str errorSnapshot(){ + int line = -1; + if(!isEnd()) line = code->co_code[ip].line; + return code->src->snapshot(line); } int stackSize() const { diff --git a/src/compiler.h b/src/compiler.h index 81b6a917..4ce3ea79 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -61,12 +61,10 @@ public: return loops.top(); } - Compiler(VM* vm, const char* source, _Code code){ + Compiler(VM* vm, const char* source, _Str filename, CompileMode mode){ this->vm = vm; - this->codes.push(code); - this->mode = code->mode; - if (!code->co_filename.empty()) path = code->co_filename; - this->parser = std::make_unique(source); + this->mode = mode; + this->parser = std::make_unique(filename, source); // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ #define METHOD(name) &Compiler::name @@ -340,9 +338,7 @@ public: func.name = ""; __compileFunctionArgs(func); consume(TK(":")); - func.code = std::make_shared(); - func.code->co_name = func.name; - func.code->co_filename = path; + func.code = std::make_shared(parser->src, func.name); this->codes.push(func.code); EXPR_TUPLE(); emitCode(OP_RETURN_VALUE); @@ -820,9 +816,7 @@ __LISTCOMP: consume(TK(")")); } - func.code = std::make_shared(); - func.code->co_name = func.name; - func.code->co_filename = path; + func.code = std::make_shared(parser->src, func.name); this->codes.push(func.code); compileBlockBody(); this->codes.pop(); @@ -853,7 +847,10 @@ __LITERAL_EXIT: } } - void __fillCode(){ + _Code __fillCode(){ + _Code code = std::make_shared(parser->src, _Str(""), mode); + codes.push(code); + // Lex initial tokens. current <-- next. lexToken(); lexToken(); @@ -862,21 +859,20 @@ __LITERAL_EXIT: if(mode == EVAL_MODE) { EXPR_TUPLE(); consume(TK("@eof")); - return; + return code; } while (!match(TK("@eof"))) { compileTopLevelStatement(); matchNewLines(); } + return code; } /***** Error Reporter *****/ - LineSnapshot getLineSnapshot(){ - const char* line_start = parser->line_starts.at(parser->previous.line-1); - const char* i = line_start; - while(*i != '\n' && *i != '\0') i++; - return LineSnapshot(path, parser->previous.line, _Str(line_start, i-line_start)); + _Str getLineSnapshot(){ + int lineno = parser->previous.line; + return parser->src->snapshot(lineno); } void syntaxError(_Str msg){ @@ -889,14 +885,6 @@ __LITERAL_EXIT: }; _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) { - // Skip utf8 BOM if there is any. - if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3; - - _Code code = std::make_shared(); - code->co_filename = filename; - code->mode = mode; - - Compiler compiler(vm, source, code); - compiler.__fillCode(); - return code; + Compiler compiler(vm, source, filename, mode); + return compiler.__fillCode(); } \ No newline at end of file diff --git a/src/error.h b/src/error.h index b23df1a8..e28d4b28 100644 --- a/src/error.h +++ b/src/error.h @@ -12,6 +12,37 @@ public: bool isClassDef; }; +struct SourceMetadata { + _Str filename; + const char* source; + std::vector lineStarts; + + _Str getLine(int lineno) const { + if(lineno == -1) return ""; + const char* _start = lineStarts.at(lineno-1); + const char* i = _start; + while(*i != '\n' && *i != '\0') i++; + return _Str(_start, i-_start); + } + + SourceMetadata(_Str filename, const char* source) { + // Skip utf8 BOM if there is any. + if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3; + this->filename = filename; + this->source = source; + lineStarts.push_back(source); + } + + _Str snapshot(int lineno){ + _StrStream ss; + ss << " " << "File \"" << filename << "\", line " << lineno << '\n'; + ss << " " << getLine(lineno) << '\n'; + return ss.str(); + } +}; + +typedef std::shared_ptr _Source; + class _Error : public std::exception { private: _Str _what; @@ -25,40 +56,25 @@ public: } }; -class LineSnapshot { - _Str filename; - int lineno; - _Str source; -public: - LineSnapshot(_Str filename, int lineno, _Str source="") : filename(filename), lineno(lineno), source(source) {} - - _Str str() const { - _StrStream ss; - ss << " " << "File \"" << filename << "\", line " << lineno << '\n'; - ss << " " << source << '\n'; - return ss.str(); - } -}; - class CompileError : public _Error { public: - CompileError(_Str type, _Str msg, const LineSnapshot& snapshot) - : _Error(type, msg, snapshot.str()) {} + CompileError(_Str type, _Str msg, _Str snapshot) + : _Error(type, msg, snapshot) {} }; class RuntimeError : public _Error { private: - static _Str __concat(std::stack snapshots){ + static _Str __concat(std::stack<_Str> snapshots){ _StrStream ss; ss << "Traceback (most recent call last):" << '\n'; while(!snapshots.empty()){ - ss << snapshots.top().str(); + ss << snapshots.top(); snapshots.pop(); } return ss.str(); } public: - RuntimeError(_Str type, _Str msg, std::stack snapshots) + RuntimeError(_Str type, _Str msg, std::stack<_Str> snapshots) : _Error(type, msg, __concat(snapshots)) {} }; diff --git a/src/parser.h b/src/parser.h index fd3f190d..0fe9ea6e 100644 --- a/src/parser.h +++ b/src/parser.h @@ -84,17 +84,13 @@ enum Precedence { // The context of the parsing phase for the compiler. struct Parser { - const char* source; //< Currently compiled source. - const char* token_start; //< Start of the currently parsed token. - const char* current_char; //< Current char position in the source. + _Source src; + const char* token_start; + const char* current_char; int current_line = 1; - - std::vector line_starts; - Token previous, current; std::queue nexts; - std::stack indents; Token nextToken(){ @@ -160,7 +156,7 @@ struct Parser { current_char++; if (c == '\n'){ current_line++; - line_starts.push_back(current_char); + src->lineStarts.push_back(current_char); } return c; } @@ -232,11 +228,10 @@ struct Parser { else setNextToken(one); } - Parser(const char* source) { - this->source = source; + Parser(_Str filename, const char* source) { + this->src = std::make_shared(filename, source); this->token_start = source; this->current_char = source; - this->line_starts.push_back(source); this->nexts.push(Token{TK("@sof"), token_start, 0, current_line}); this->indents.push(0); } diff --git a/src/vm.h b/src/vm.h index cd1ad3f1..0b9e6a51 100644 --- a/src/vm.h +++ b/src/vm.h @@ -634,13 +634,10 @@ public: /***** Error Reporter *****/ private: void _error(const _Str& name, const _Str& msg){ - std::stack snapshots; + std::stack<_Str> snapshots; while (!callstack.empty()){ auto frame = callstack.top(); - snapshots.push(LineSnapshot( - frame->code->co_filename, - frame->currentLine() - )); + snapshots.push(frame->errorSnapshot()); callstack.pop(); } throw RuntimeError(name, msg, snapshots);