mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 04:50:17 +00:00
improve error report
This commit is contained in:
parent
5c7f1e6dd8
commit
24f3628b8d
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
56
src/error.h
56
src/error.h
@ -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)) {}
|
||||
};
|
||||
|
||||
|
17
src/parser.h
17
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<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);
|
||||
}
|
||||
|
7
src/vm.h
7
src/vm.h
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user