adjust errors

This commit is contained in:
blueloveTH 2022-11-09 18:30:25 +08:00
parent 01bbda85ec
commit 5c7f1e6dd8
7 changed files with 128 additions and 95 deletions

View File

@ -593,6 +593,7 @@ __LISTCOMP:
} }
consume(TK("@indent")); consume(TK("@indent"));
while (peek() != TK("@dedent")) { while (peek() != TK("@dedent")) {
matchNewLines();
(this->*action)(); (this->*action)();
matchNewLines(); matchNewLines();
} }
@ -624,17 +625,13 @@ __LISTCOMP:
void parsePrecedence(Precedence precedence) { void parsePrecedence(Precedence precedence) {
lexToken(); lexToken();
GrammarFn prefix = rules[parser->previous.type].prefix; GrammarFn prefix = rules[parser->previous.type].prefix;
if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->previous.type));
if (prefix == nullptr) syntaxError("expected an expression");
(this->*prefix)(); (this->*prefix)();
while (rules[peek()].precedence >= precedence) { while (rules[peek()].precedence >= precedence) {
lexToken(); lexToken();
_TokenType op = parser->previous.type; _TokenType op = parser->previous.type;
GrammarFn infix = rules[op].infix; GrammarFn infix = rules[op].infix;
if(infix == nullptr) { if(infix == nullptr) throw UnexpectedError("(infix == nullptr) is true");
throw UnexpectedError("(infix == nullptr) is true");
}
(this->*infix)(); (this->*infix)();
} }
} }
@ -874,23 +871,18 @@ __LITERAL_EXIT:
} }
} }
/**** Error Reporter ***/ /***** Error Reporter *****/
LineSnapshot getLineSnapshot(){ LineSnapshot getLineSnapshot(){
LineSnapshot snapshot; const char* line_start = parser->line_starts.at(parser->previous.line-1);
snapshot.filename = path; const char* i = line_start;
snapshot.lineno = parser->previous.line; while(*i != '\n' && *i != '\0') i++;
snapshot.source = "<?>"; return LineSnapshot(path, parser->previous.line, _Str(line_start, i-line_start));
return snapshot;
} }
void syntaxError(_Str msg){ void syntaxError(_Str msg){
throw CompileError("SyntaxError", msg, getLineSnapshot()); throw CompileError("SyntaxError", msg, getLineSnapshot());
} }
void unknownSyntaxError(){
throw CompileError("SyntaxError", "invalid syntax", getLineSnapshot());
}
void indentationError(_Str msg){ void indentationError(_Str msg){
throw CompileError("IndentationError", msg, getLineSnapshot()); throw CompileError("IndentationError", msg, getLineSnapshot());
} }

View File

@ -25,10 +25,12 @@ public:
} }
}; };
struct LineSnapshot { class LineSnapshot {
_Str filename; _Str filename;
int lineno; int lineno;
_Str source; _Str source;
public:
LineSnapshot(_Str filename, int lineno, _Str source="<?>") : filename(filename), lineno(lineno), source(source) {}
_Str str() const { _Str str() const {
_StrStream ss; _StrStream ss;

View File

@ -48,7 +48,7 @@ void REPL(){
while(true){ while(true){
CompileMode mode = SINGLE_MODE; CompileMode mode = SINGLE_MODE;
vm->printFn(need_more_lines ? "... " : ">>> "); vm->_stdout(need_more_lines ? "... " : ">>> ");
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
@ -86,8 +86,8 @@ __NOT_ENOUGH_LINES:
buffer += '\n'; buffer += '\n';
need_more_lines = ne->isClassDef ? 3 : 2; need_more_lines = ne->isClassDef ? 3 : 2;
}else{ }else{
vm->printFn(e.what()); vm->_stdout(e.what());
vm->printFn("\n"); vm->_stdout("\n");
vm->cleanError(); vm->cleanError();
} }
} }

View File

@ -87,10 +87,11 @@ struct Parser {
const char* source; //< Currently compiled source. const char* source; //< Currently compiled source.
const char* token_start; //< Start of the currently parsed token. const char* token_start; //< Start of the currently parsed token.
const char* current_char; //< Current char position in the source. const char* current_char; //< Current char position in the source.
const char* line_start; //< Start of the current line.
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;
@ -159,7 +160,7 @@ struct Parser {
current_char++; current_char++;
if (c == '\n'){ if (c == '\n'){
current_line++; current_line++;
line_start = current_char; line_starts.push_back(current_char);
} }
return c; return c;
} }
@ -235,8 +236,7 @@ struct Parser {
this->source = source; this->source = source;
this->token_start = source; this->token_start = source;
this->current_char = source; this->current_char = source;
this->line_start = 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

@ -11,7 +11,7 @@ inline int _round(float f){
#define BIND_NUM_ARITH_OPT(name, op) \ #define BIND_NUM_ARITH_OPT(name, op) \
_vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \ _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \
if(!vm->isIntOrFloat(args[0], args[1])) \ if(!vm->isIntOrFloat(args[0], args[1])) \
vm->_error("TypeError", "unsupported operand type(s) for " #op ); \ vm->typeError("unsupported operand type(s) for " #op ); \
if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){ \ if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){ \
return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \ return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \
}else{ \ }else{ \
@ -23,7 +23,7 @@ inline int _round(float f){
_vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \ _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \
if(!vm->isIntOrFloat(args[0], args[1])){ \ if(!vm->isIntOrFloat(args[0], args[1])){ \
if constexpr(fallback) return vm->PyBool(args[0] op args[1]); \ if constexpr(fallback) return vm->PyBool(args[0] op args[1]); \
vm->_error("TypeError", "unsupported operand type(s) for " #op ); \ vm->typeError("unsupported operand type(s) for " #op ); \
} \ } \
return vm->PyBool(vm->numToFloat(args[0]) op vm->numToFloat(args[1])); \ return vm->PyBool(vm->numToFloat(args[0]) op vm->numToFloat(args[1])); \
}); });
@ -44,14 +44,14 @@ void __initializeBuiltinFunctions(VM* _vm) {
#undef BIND_NUM_LOGICAL_OPT #undef BIND_NUM_LOGICAL_OPT
_vm->bindBuiltinFunc("print", [](VM* vm, PyVarList args) { _vm->bindBuiltinFunc("print", [](VM* vm, PyVarList args) {
for (auto& arg : args) vm->printFn(vm->PyStr_AS_C(vm->asStr(arg)) + " "); for (auto& arg : args) vm->_stdout(vm->PyStr_AS_C(vm->asStr(arg)) + " ");
vm->printFn("\n"); vm->_stdout("\n");
return vm->None; return vm->None;
}); });
_vm->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) { _vm->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) {
if (args.size() != 1) vm->_error("TypeError", "eval() takes exactly one argument"); if (args.size() != 1) vm->typeError("eval() takes exactly one argument");
if (!args[0]->isType(vm->_tp_str)) vm->_error("TypeError", "eval() argument must be a string"); if (!args[0]->isType(vm->_tp_str)) vm->typeError("eval() argument must be a string");
const _Str& expr = vm->PyStr_AS_C(args[0]); const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr, "<f-string>", EVAL_MODE); _Code code = compile(vm, expr, "<f-string>", EVAL_MODE);
return vm->exec(code); // not working in function return vm->exec(code); // not working in function
@ -67,7 +67,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("chr", [](VM* vm, PyVarList args) { _vm->bindBuiltinFunc("chr", [](VM* vm, PyVarList args) {
int i = vm->PyInt_AS_C(args.at(0)); int i = vm->PyInt_AS_C(args.at(0));
if (i < 0 || i > 128) vm->_error("ValueError", "chr() arg not in range(128)"); if (i < 0 || i > 128) vm->valueError("chr() arg not in range(128)");
return vm->PyStr(_Str(1, (char)i)); return vm->PyStr(_Str(1, (char)i));
}); });
@ -77,7 +77,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("ord", [](VM* vm, PyVarList args) { _vm->bindBuiltinFunc("ord", [](VM* vm, PyVarList args) {
_Str s = vm->PyStr_AS_C(args.at(0)); _Str s = vm->PyStr_AS_C(args.at(0));
if (s.size() != 1) vm->_error("TypeError", "ord() expected an ASCII character"); if (s.size() != 1) vm->typeError("ord() expected an ASCII character");
return vm->PyInt((int)s[0]); return vm->PyInt((int)s[0]);
}); });
@ -104,7 +104,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
case 1: r.stop = vm->PyInt_AS_C(args[0]); break; case 1: r.stop = vm->PyInt_AS_C(args[0]); break;
case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break; case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break;
case 3: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); r.step = vm->PyInt_AS_C(args[2]); break; case 3: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); r.step = vm->PyInt_AS_C(args[2]); break;
default: vm->_error("TypeError", "range expected 1-3 arguments, got " + std::to_string(args.size())); default: vm->typeError("range expected 1-3 arguments, got " + std::to_string(args.size()));
} }
return vm->PyRange(r); return vm->PyRange(r);
}); });
@ -121,13 +121,13 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindMethodMulti({"int", "float"}, "__truediv__", [](VM* vm, PyVarList args) { _vm->bindMethodMulti({"int", "float"}, "__truediv__", [](VM* vm, PyVarList args) {
if(!vm->isIntOrFloat(args[0], args[1])) if(!vm->isIntOrFloat(args[0], args[1]))
vm->_error("TypeError", "unsupported operand type(s) for " "/" ); vm->typeError("unsupported operand type(s) for " "/" );
return vm->PyFloat(vm->numToFloat(args[0]) / vm->numToFloat(args[1])); return vm->PyFloat(vm->numToFloat(args[0]) / vm->numToFloat(args[1]));
}); });
_vm->bindMethodMulti({"int", "float"}, "__pow__", [](VM* vm, PyVarList args) { _vm->bindMethodMulti({"int", "float"}, "__pow__", [](VM* vm, PyVarList args) {
if(!vm->isIntOrFloat(args[0], args[1])) if(!vm->isIntOrFloat(args[0], args[1]))
vm->_error("TypeError", "unsupported operand type(s) for " "**" ); vm->typeError("unsupported operand type(s) for " "**" );
if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){ if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){
return vm->PyInt(_round(pow(vm->PyInt_AS_C(args[0]), vm->PyInt_AS_C(args[1])))); return vm->PyInt(_round(pow(vm->PyInt_AS_C(args[0]), vm->PyInt_AS_C(args[1]))));
}else{ }else{
@ -138,19 +138,19 @@ void __initializeBuiltinFunctions(VM* _vm) {
/************ PyInt ************/ /************ PyInt ************/
_vm->bindMethod("int", "__floordiv__", [](VM* vm, PyVarList args) { _vm->bindMethod("int", "__floordiv__", [](VM* vm, PyVarList args) {
if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int))
vm->_error("TypeError", "unsupported operand type(s) for " "//" ); vm->typeError("unsupported operand type(s) for " "//" );
return vm->PyInt(vm->PyInt_AS_C(args[0]) / vm->PyInt_AS_C(args[1])); return vm->PyInt(vm->PyInt_AS_C(args[0]) / vm->PyInt_AS_C(args[1]));
}); });
_vm->bindMethod("int", "__mod__", [](VM* vm, PyVarList args) { _vm->bindMethod("int", "__mod__", [](VM* vm, PyVarList args) {
if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int))
vm->_error("TypeError", "unsupported operand type(s) for " "%" ); vm->typeError("unsupported operand type(s) for " "%" );
return vm->PyInt(vm->PyInt_AS_C(args[0]) % vm->PyInt_AS_C(args[1])); return vm->PyInt(vm->PyInt_AS_C(args[0]) % vm->PyInt_AS_C(args[1]));
}); });
_vm->bindMethod("int", "__neg__", [](VM* vm, PyVarList args) { _vm->bindMethod("int", "__neg__", [](VM* vm, PyVarList args) {
if(!args[0]->isType(vm->_tp_int)) if(!args[0]->isType(vm->_tp_int))
vm->_error("TypeError", "unsupported operand type(s) for " "-" ); vm->typeError("unsupported operand type(s) for " "-" );
return vm->PyInt(-1 * vm->PyInt_AS_C(args[0])); return vm->PyInt(-1 * vm->PyInt_AS_C(args[0]));
}); });
@ -175,7 +175,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindMethod("str", "__add__", [](VM* vm, PyVarList args) { _vm->bindMethod("str", "__add__", [](VM* vm, PyVarList args) {
if(!args[0]->isType(vm->_tp_str) || !args[1]->isType(vm->_tp_str)) if(!args[0]->isType(vm->_tp_str) || !args[1]->isType(vm->_tp_str))
vm->_error("TypeError", "unsupported operand type(s) for " "+" ); vm->typeError("unsupported operand type(s) for " "+" );
const _Str& lhs = vm->PyStr_AS_C(args[0]); const _Str& lhs = vm->PyStr_AS_C(args[0]);
const _Str& rhs = vm->PyStr_AS_C(args[1]); const _Str& rhs = vm->PyStr_AS_C(args[1]);
return vm->PyStr(lhs + rhs); return vm->PyStr(lhs + rhs);
@ -317,7 +317,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindMethod("list", "pop", [](VM* vm, PyVarList args) { _vm->bindMethod("list", "pop", [](VM* vm, PyVarList args) {
PyVarList& _self = vm->PyList_AS_C(args[0]); PyVarList& _self = vm->PyList_AS_C(args[0]);
if(_self.empty()) vm->_error("IndexError", "pop from empty list"); if(_self.empty()) vm->indexError("pop from empty list");
PyVar ret = _self.back(); PyVar ret = _self.back();
_self.pop_back(); _self.pop_back();
return ret; return ret;
@ -428,12 +428,12 @@ void __addModuleRandom(VM* vm){
extern "C" { extern "C" {
__EXPORT __EXPORT
VM* createVM(PrintFn printFn){ VM* createVM(PrintFn _stdout){
VM* vm = new VM(); VM* vm = new VM();
__initializeBuiltinFunctions(vm); __initializeBuiltinFunctions(vm);
__runCodeBuiltins(vm, __BUILTINS_CODE); __runCodeBuiltins(vm, __BUILTINS_CODE);
__addModuleRandom(vm); __addModuleRandom(vm);
vm->printFn = printFn; vm->_stdout = _stdout;
return vm; return vm;
} }
@ -448,8 +448,8 @@ extern "C" {
_Code code = compile(vm, source, "main.py"); _Code code = compile(vm, source, "main.py");
vm->exec(code); vm->exec(code);
}catch(std::exception& e){ }catch(std::exception& e){
vm->printFn(e.what()); vm->_stdout(e.what());
vm->printFn("\n"); vm->_stdout("\n");
vm->cleanError(); vm->cleanError();
} }
} }

124
src/vm.h
View File

@ -2,6 +2,7 @@
#include "codeobject.h" #include "codeobject.h"
#include "iter.h" #include "iter.h"
#include "error.h"
#define __DEF_PY_AS_C(type, ctype, ptype) \ #define __DEF_PY_AS_C(type, ctype, ptype) \
inline ctype& Py##type##_AS_C(const PyVar& obj) { \ inline ctype& Py##type##_AS_C(const PyVar& obj) { \
@ -18,7 +19,6 @@
__DEF_PY(type, ctype, ptype) \ __DEF_PY(type, ctype, ptype) \
__DEF_PY_AS_C(type, ctype, ptype) __DEF_PY_AS_C(type, ctype, ptype)
// TODO: we should split this into stdout and stderr
typedef void(*PrintFn)(const char*); typedef void(*PrintFn)(const char*);
#define NUM_POOL_MAX_SIZE 1024 #define NUM_POOL_MAX_SIZE 1024
@ -31,7 +31,8 @@ public:
PyVarDict _types; // builtin types PyVarDict _types; // builtin types
PyVar None, True, False; PyVar None, True, False;
PrintFn printFn = [](auto s){}; PrintFn _stdout = [](auto s){};
PrintFn _stderr = [](auto s){};
PyVar builtins; // builtins module PyVar builtins; // builtins module
PyVar _main; // __main__ module PyVar _main; // __main__ module
@ -41,24 +42,6 @@ public:
initializeBuiltinClasses(); initializeBuiltinClasses();
} }
void cleanError(){
while(!callstack.empty()) callstack.pop();
}
void nameError(const _Str& name){
_error("NameError", "name '" + name + "' is not defined");
}
void attributeError(PyVar obj, const _Str& name){
_error("AttributeError", "type '" + obj->getTypeName() + "' has no attribute '" + name + "'");
}
inline void __checkType(const PyVar& obj, const PyVar& type){
if(!obj->isType(type)){
_error("TypeError", "expected '" + type->getName() + "', but got '" + obj->getTypeName() + "'");
}
}
PyVar asStr(const PyVar& obj){ PyVar asStr(const PyVar& obj){
PyVarOrNull str_fn = getAttr(obj, __str__, false); PyVarOrNull str_fn = getAttr(obj, __str__, false);
if(str_fn != nullptr) return call(str_fn, {}); if(str_fn != nullptr) return call(str_fn, {});
@ -130,7 +113,7 @@ public:
if(i < args.size()) { if(i < args.size()) {
locals[name] = args[i++]; locals[name] = args[i++];
}else{ }else{
_error("TypeError", "missing positional argument '" + name + "'"); typeError("missing positional argument '" + name + "'");
} }
} }
// handle *args // handle *args
@ -148,12 +131,12 @@ public:
} }
} }
if(i < args.size()) _error("TypeError", "too many arguments"); if(i < args.size()) typeError("too many arguments");
// TODO: handle **kwargs // TODO: handle **kwargs
return exec(fn.code, locals); return exec(fn.code, locals);
} }
_error("TypeError", "'" + callable->getTypeName() + "' object is not callable"); typeError("'" + callable->getTypeName() + "' object is not callable");
return None; return None;
} }
@ -264,8 +247,8 @@ public:
{ {
const PyVar& expr = frame->topValue(this); const PyVar& expr = frame->topValue(this);
if(expr == None) break; if(expr == None) break;
printFn(PyStr_AS_C(asRepr(expr))); _stdout(PyStr_AS_C(asRepr(expr)));
printFn("\n"); _stdout("\n");
} break; } break;
case OP_POP_TOP: frame->popValue(this); break; case OP_POP_TOP: frame->popValue(this); break;
case OP_BINARY_OP: case OP_BINARY_OP:
@ -318,7 +301,7 @@ public:
case OP_ASSERT: case OP_ASSERT:
{ {
PyVar expr = frame->popValue(this); PyVar expr = frame->popValue(this);
if(!PyBool_AS_C(expr)) _error("AssertionError", "assertion failed"); _assert(PyBool_AS_C(expr), "assertion failed");
} break; } break;
case OP_RAISE_ERROR: case OP_RAISE_ERROR:
{ {
@ -357,7 +340,7 @@ public:
PyIter_AS_C(tmp)->var = PyPointer_AS_C(frame->__pop()); PyIter_AS_C(tmp)->var = PyPointer_AS_C(frame->__pop());
frame->push(tmp); frame->push(tmp);
}else{ }else{
_error("TypeError", "'" + obj->getTypeName() + "' object is not iterable"); typeError("'" + obj->getTypeName() + "' object is not iterable");
} }
} break; } break;
case OP_FOR_ITER: case OP_FOR_ITER:
@ -404,19 +387,19 @@ public:
} }
} break; } break;
default: default:
_error("SystemError", _Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
break; break;
} }
} }
if(frame->code->mode == EVAL_MODE) { if(frame->code->mode == EVAL_MODE) {
if(frame->stackSize() != 1) { if(frame->stackSize() != 1) {
_error("SystemError", "stack size is not 1 in EVAL_MODE"); systemError("stack size is not 1 in EVAL_MODE");
} }
return frame->popValue(this); return frame->popValue(this);
} }
if(frame->stackSize() != 0) _error("SystemError", "stack not empty in EXEC_MODE"); if(frame->stackSize() != 0) systemError("stack not empty in EXEC_MODE");
callstack.pop(); callstack.pop();
return None; return None;
} }
@ -431,19 +414,6 @@ public:
return runFrame(frame); return runFrame(frame);
} }
void _assert(bool val, const _Str& msg){
if (!val) _error("AssertionError", msg);
}
void _error(const _Str& name, const _Str& msg){
_StrStream ss;
auto frame = callstack.top();
ss << "Traceback (most recent call last):" << std::endl;
ss << " File '" << frame->code->co_filename << "', line ";
ss << frame->currentLine() << '\n' << name << ": " << msg;
throw std::runtime_error(ss.str());
}
PyVar newUserClassType(_Str name, PyVar base){ PyVar newUserClassType(_Str name, PyVar base){
PyVar obj = newClassType(name, base); PyVar obj = newClassType(name, base);
setAttr(obj, "__name__", PyStr(name)); setAttr(obj, "__name__", PyStr(name));
@ -469,7 +439,7 @@ public:
PyVar newNumber(PyVar type, _Value _native) { PyVar newNumber(PyVar type, _Value _native) {
if(type != _tp_int && type != _tp_float) if(type != _tp_int && type != _tp_float)
_error("SystemError", "type is not a number type"); systemError("type is not a number type");
PyObject* _raw = nullptr; PyObject* _raw = nullptr;
if(numPool.size() > 0) { if(numPool.size() > 0) {
_raw = numPool.back(); _raw = numPool.back();
@ -567,7 +537,7 @@ public:
int normalizedIndex(int index, int size){ int normalizedIndex(int index, int size){
if(index < 0) index += size; if(index < 0) index += size;
if(index < 0 || index >= size){ if(index < 0 || index >= size){
_error("IndexError", "index out of range, " + std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); indexError("index out of range, " + std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
} }
return index; return index;
} }
@ -651,7 +621,7 @@ public:
} }
if (obj->isType(_tp_str)) return PyStr_AS_C(obj).hash(); if (obj->isType(_tp_str)) return PyStr_AS_C(obj).hash();
if (obj->isType(_tp_type)) return (int64_t)obj.get(); if (obj->isType(_tp_type)) return (int64_t)obj.get();
_error("TypeError", "unhashable type: " + obj->getTypeName()); typeError("unhashable type: " + obj->getTypeName());
return 0; return 0;
} }
@ -660,9 +630,61 @@ public:
exec(code, {}, _m); exec(code, {}, _m);
_modules[name] = _m; _modules[name] = _m;
} }
/***** Error Reporter *****/
private:
void _error(const _Str& name, const _Str& msg){
std::stack<LineSnapshot> snapshots;
while (!callstack.empty()){
auto frame = callstack.top();
snapshots.push(LineSnapshot(
frame->code->co_filename,
frame->currentLine()
));
callstack.pop();
}
throw RuntimeError(name, msg, snapshots);
}
public:
void cleanError(){
while(!callstack.empty()) callstack.pop();
}
void typeError(const _Str& msg){
typeError(msg);
}
void systemError(const _Str& msg){
systemError(msg);
}
void indexError(const _Str& msg){
_error("IndexError", msg);
}
void valueError(const _Str& msg){
_error("ValueError", msg);
}
void nameError(const _Str& name){
_error("NameError", "name '" + name + "' is not defined");
}
void attributeError(PyVar obj, const _Str& name){
_error("AttributeError", "type '" + obj->getTypeName() + "' has no attribute '" + name + "'");
}
inline void __checkType(const PyVar& obj, const PyVar& type){
if(!obj->isType(type)) typeError("expected '" + type->getName() + "', but got '" + obj->getTypeName() + "'");
}
void _assert(bool val, const _Str& msg){
if (!val) _error("AssertionError", msg);
}
}; };
/**************** Pointers' Impl ****************/ /***** Pointers' Impl *****/
PyVar NamePointer::get(VM* vm, Frame* frame) const{ PyVar NamePointer::get(VM* vm, Frame* frame) const{
auto it = frame->f_locals.find(name); auto it = frame->f_locals.find(name);
@ -724,7 +746,7 @@ void AttrPointer::set(VM* vm, Frame* frame, PyVar val) const{
} }
void AttrPointer::del(VM* vm, Frame* frame) const{ void AttrPointer::del(VM* vm, Frame* frame) const{
vm->_error("AttributeError", "can't delete attribute"); vm->typeError("cannot delete attribute");
} }
PyVar IndexPointer::get(VM* vm, Frame* frame) const{ PyVar IndexPointer::get(VM* vm, Frame* frame) const{
@ -749,11 +771,11 @@ PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
void CompoundPointer::set(VM* vm, Frame* frame, PyVar val) const{ void CompoundPointer::set(VM* vm, Frame* frame, PyVar val) const{
if(!val->isType(vm->_tp_tuple) && !val->isType(vm->_tp_list)){ if(!val->isType(vm->_tp_tuple) && !val->isType(vm->_tp_list)){
vm->_error("TypeError", "only tuple or list can be unpacked"); vm->typeError("only tuple or list can be unpacked");
} }
const PyVarList& args = std::get<PyVarList>(val->_native); const PyVarList& args = std::get<PyVarList>(val->_native);
if(args.size() > pointers.size()) vm->_error("ValueError", "too many values to unpack"); if(args.size() > pointers.size()) vm->valueError("too many values to unpack");
if(args.size() < pointers.size()) vm->_error("ValueError", "not enough values to unpack"); if(args.size() < pointers.size()) vm->valueError("not enough values to unpack");
for (int i = 0; i < pointers.size(); i++) { for (int i = 0; i < pointers.size(); i++) {
pointers[i]->set(vm, frame, args[i]); pointers[i]->set(vm, frame, args[i]);
} }

17
tests/errors/1.py Normal file
View File

@ -0,0 +1,17 @@
def is_prime(x):
if x<2:
return False
for i in range(2,x):
if x%i == 0:
return False1
return True
def test(n):
k = 0
for i in range(n):
if is_prime(i):
k += 1
return k
print(test(100))