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 "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<ByteCode> co_code;
_Str co_filename;
_Str co_name;
PyVarList co_consts;
std::vector<std::shared_ptr<NamePointer>> 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 {

View File

@ -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<Parser>(source);
this->mode = mode;
this->parser = std::make_unique<Parser>(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 = "<lambda>";
__compileFunctionArgs(func);
consume(TK(":"));
func.code = std::make_shared<CodeObject>();
func.code->co_name = func.name;
func.code->co_filename = path;
func.code = std::make_shared<CodeObject>(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<CodeObject>();
func.code->co_name = func.name;
func.code->co_filename = path;
func.code = std::make_shared<CodeObject>(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<CodeObject>(parser->src, _Str("<module>"), 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<CodeObject>();
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();
}

View File

@ -12,6 +12,37 @@ public:
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 {
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<LineSnapshot> 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<LineSnapshot> snapshots)
RuntimeError(_Str type, _Str msg, std::stack<_Str> snapshots)
: _Error(type, msg, __concat(snapshots)) {}
};

View File

@ -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<const char*> line_starts;
Token previous, current;
std::queue<Token> nexts;
std::stack<int> 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<SourceMetadata>(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);
}

View File

@ -634,13 +634,10 @@ public:
/***** Error Reporter *****/
private:
void _error(const _Str& name, const _Str& msg){
std::stack<LineSnapshot> 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);