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