improve error report

This commit is contained in:
blueloveTH 2022-11-09 19:09:27 +08:00
parent 5c7f1e6dd8
commit 24f3628b8d
5 changed files with 74 additions and 71 deletions

View File

@ -2,6 +2,7 @@
#include "obj.h" #include "obj.h"
#include "pointer.h" #include "pointer.h"
#include "error.h"
enum Opcode { enum Opcode {
#define OPCODE(name) OP_##name, #define OPCODE(name) OP_##name,
@ -32,12 +33,17 @@ enum CompileMode {
}; };
struct CodeObject { 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<ByteCode> co_code; std::vector<ByteCode> co_code;
_Str co_filename;
_Str co_name;
PyVarList co_consts; PyVarList co_consts;
std::vector<std::shared_ptr<NamePointer>> co_names; std::vector<std::shared_ptr<NamePointer>> co_names;
@ -118,9 +124,10 @@ public:
return code->co_code[ip++]; return code->co_code[ip++];
} }
int currentLine(){ _Str errorSnapshot(){
if(isEnd()) return -1; int line = -1;
return code->co_code[ip].line; if(!isEnd()) line = code->co_code[ip].line;
return code->src->snapshot(line);
} }
int stackSize() const { int stackSize() const {

View File

@ -61,12 +61,10 @@ public:
return loops.top(); 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->vm = vm;
this->codes.push(code); this->mode = mode;
this->mode = code->mode; this->parser = std::make_unique<Parser>(filename, source);
if (!code->co_filename.empty()) path = code->co_filename;
this->parser = std::make_unique<Parser>(source);
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
#define METHOD(name) &Compiler::name #define METHOD(name) &Compiler::name
@ -340,9 +338,7 @@ public:
func.name = "<lambda>"; func.name = "<lambda>";
__compileFunctionArgs(func); __compileFunctionArgs(func);
consume(TK(":")); consume(TK(":"));
func.code = std::make_shared<CodeObject>(); func.code = std::make_shared<CodeObject>(parser->src, func.name);
func.code->co_name = func.name;
func.code->co_filename = path;
this->codes.push(func.code); this->codes.push(func.code);
EXPR_TUPLE(); EXPR_TUPLE();
emitCode(OP_RETURN_VALUE); emitCode(OP_RETURN_VALUE);
@ -820,9 +816,7 @@ __LISTCOMP:
consume(TK(")")); consume(TK(")"));
} }
func.code = std::make_shared<CodeObject>(); func.code = std::make_shared<CodeObject>(parser->src, func.name);
func.code->co_name = func.name;
func.code->co_filename = path;
this->codes.push(func.code); this->codes.push(func.code);
compileBlockBody(); compileBlockBody();
this->codes.pop(); this->codes.pop();
@ -853,7 +847,10 @@ __LITERAL_EXIT:
} }
} }
void __fillCode(){ _Code __fillCode(){
_Code code = std::make_shared<CodeObject>(parser->src, _Str("<module>"), mode);
codes.push(code);
// Lex initial tokens. current <-- next. // Lex initial tokens. current <-- next.
lexToken(); lexToken();
lexToken(); lexToken();
@ -862,21 +859,20 @@ __LITERAL_EXIT:
if(mode == EVAL_MODE) { if(mode == EVAL_MODE) {
EXPR_TUPLE(); EXPR_TUPLE();
consume(TK("@eof")); consume(TK("@eof"));
return; return code;
} }
while (!match(TK("@eof"))) { while (!match(TK("@eof"))) {
compileTopLevelStatement(); compileTopLevelStatement();
matchNewLines(); matchNewLines();
} }
return code;
} }
/***** Error Reporter *****/ /***** Error Reporter *****/
LineSnapshot getLineSnapshot(){ _Str getLineSnapshot(){
const char* line_start = parser->line_starts.at(parser->previous.line-1); int lineno = parser->previous.line;
const char* i = line_start; return parser->src->snapshot(lineno);
while(*i != '\n' && *i != '\0') i++;
return LineSnapshot(path, parser->previous.line, _Str(line_start, i-line_start));
} }
void syntaxError(_Str msg){ void syntaxError(_Str msg){
@ -889,14 +885,6 @@ __LITERAL_EXIT:
}; };
_Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) { _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) {
// Skip utf8 BOM if there is any. Compiler compiler(vm, source, filename, mode);
if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3; return compiler.__fillCode();
_Code code = std::make_shared<CodeObject>();
code->co_filename = filename;
code->mode = mode;
Compiler compiler(vm, source, code);
compiler.__fillCode();
return code;
} }

View File

@ -12,6 +12,37 @@ public:
bool isClassDef; bool isClassDef;
}; };
struct SourceMetadata {
_Str filename;
const char* source;
std::vector<const char*> 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<SourceMetadata> _Source;
class _Error : public std::exception { class _Error : public std::exception {
private: private:
_Str _what; _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 { class CompileError : public _Error {
public: public:
CompileError(_Str type, _Str msg, const LineSnapshot& snapshot) CompileError(_Str type, _Str msg, _Str snapshot)
: _Error(type, msg, snapshot.str()) {} : _Error(type, msg, snapshot) {}
}; };
class RuntimeError : public _Error { class RuntimeError : public _Error {
private: private:
static _Str __concat(std::stack<LineSnapshot> snapshots){ static _Str __concat(std::stack<_Str> snapshots){
_StrStream ss; _StrStream ss;
ss << "Traceback (most recent call last):" << '\n'; ss << "Traceback (most recent call last):" << '\n';
while(!snapshots.empty()){ while(!snapshots.empty()){
ss << snapshots.top().str(); ss << snapshots.top();
snapshots.pop(); snapshots.pop();
} }
return ss.str(); return ss.str();
} }
public: public:
RuntimeError(_Str type, _Str msg, std::stack<LineSnapshot> snapshots) RuntimeError(_Str type, _Str msg, std::stack<_Str> snapshots)
: _Error(type, msg, __concat(snapshots)) {} : _Error(type, msg, __concat(snapshots)) {}
}; };

View File

@ -84,17 +84,13 @@ enum Precedence {
// The context of the parsing phase for the compiler. // The context of the parsing phase for the compiler.
struct Parser { struct Parser {
const char* source; //< Currently compiled source. _Source src;
const char* token_start; //< Start of the currently parsed token.
const char* current_char; //< Current char position in the source.
const char* token_start;
const char* current_char;
int current_line = 1; int current_line = 1;
std::vector<const char*> line_starts;
Token previous, current; Token previous, current;
std::queue<Token> nexts; std::queue<Token> nexts;
std::stack<int> indents; std::stack<int> indents;
Token nextToken(){ Token nextToken(){
@ -160,7 +156,7 @@ struct Parser {
current_char++; current_char++;
if (c == '\n'){ if (c == '\n'){
current_line++; current_line++;
line_starts.push_back(current_char); src->lineStarts.push_back(current_char);
} }
return c; return c;
} }
@ -232,11 +228,10 @@ struct Parser {
else setNextToken(one); else setNextToken(one);
} }
Parser(const char* source) { Parser(_Str filename, const char* source) {
this->source = source; this->src = std::make_shared<SourceMetadata>(filename, source);
this->token_start = source; this->token_start = source;
this->current_char = source; this->current_char = source;
this->line_starts.push_back(source);
this->nexts.push(Token{TK("@sof"), token_start, 0, current_line}); this->nexts.push(Token{TK("@sof"), token_start, 0, current_line});
this->indents.push(0); this->indents.push(0);
} }

View File

@ -634,13 +634,10 @@ public:
/***** Error Reporter *****/ /***** Error Reporter *****/
private: private:
void _error(const _Str& name, const _Str& msg){ void _error(const _Str& name, const _Str& msg){
std::stack<LineSnapshot> snapshots; std::stack<_Str> snapshots;
while (!callstack.empty()){ while (!callstack.empty()){
auto frame = callstack.top(); auto frame = callstack.top();
snapshots.push(LineSnapshot( snapshots.push(frame->errorSnapshot());
frame->code->co_filename,
frame->currentLine()
));
callstack.pop(); callstack.pop();
} }
throw RuntimeError(name, msg, snapshots); throw RuntimeError(name, msg, snapshots);