From 671cbc3f24ce6efa9bd7d70548fbf89ef4f1b103 Mon Sep 17 00:00:00 2001 From: BLUELOVETH Date: Sun, 4 Jun 2023 17:01:12 +0800 Subject: [PATCH 1/7] ... --- src/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index a546509e..21e40c49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,11 @@ int main(int argc, char** argv){ pkpy::VM* vm = pkpy_new_vm(); vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ - return VAR(pkpy::getline()); + // TODO: we do not use pkpy::getline() here. It doesn't accept unicode characters. + // pkpy::getline() has bugs for PIPE input + static std::string buffer; + std::cin >> buffer; + return VAR(buffer); }); if(argc == 1){ pkpy::REPL* repl = pkpy_new_repl(vm); From 9182ba5fc5a1bda418ced0bc8dfd6e8da77dc381 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 18:56:58 +0800 Subject: [PATCH 2/7] ... --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4a68cd23..3118c8b4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,9 +21,9 @@ plugins/macos/pocketpy/pocketpy.* src/_generated.h profile.sh test -tmp.rar src/httplib.h pocketpy.exe main.obj pocketpy.exp pocketpy.lib +APPS \ No newline at end of file From 8e104627cbdfd22b4902dc45b3d352d324dae02d Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 19:04:52 +0800 Subject: [PATCH 3/7] ... --- src/expr.h | 2 ++ src/main.cpp | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/expr.h b/src/expr.h index c735186d..2cfc71f8 100644 --- a/src/expr.h +++ b/src/expr.h @@ -531,6 +531,7 @@ struct FStringExpr: Expr{ } void _load_simple_expr(CodeEmitContext* ctx, Str expr){ + // TODO: pre compile this into a function int dot = expr.index("."); if(dot < 0){ ctx->emit(OP_LOAD_NAME, StrName(expr.sv()).index, line); @@ -700,6 +701,7 @@ struct BinaryExpr: Expr{ case TK("!="): ctx->emit(OP_COMPARE_NE, BC_NOARG, line); break; case TK(">"): ctx->emit(OP_COMPARE_GT, BC_NOARG, line); break; case TK(">="): ctx->emit(OP_COMPARE_GE, BC_NOARG, line); break; + case TK("in"): ctx->emit(OP_CONTAINS_OP, 0, line); break; case TK("not in"): ctx->emit(OP_CONTAINS_OP, 1, line); break; case TK("is"): ctx->emit(OP_IS_OP, 0, line); break; diff --git a/src/main.cpp b/src/main.cpp index 21e40c49..c18f546e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,11 +8,8 @@ int main(int argc, char** argv){ pkpy::VM* vm = pkpy_new_vm(); vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ - // TODO: we do not use pkpy::getline() here. It doesn't accept unicode characters. - // pkpy::getline() has bugs for PIPE input - static std::string buffer; - std::cin >> buffer; - return VAR(buffer); + // pkpy::getline() has bugs for PIPE input on Windows + return VAR(pkpy::getline()); }); if(argc == 1){ pkpy::REPL* repl = pkpy_new_repl(vm); From 919d7a465c1dddd19d26879f36066baf6f53c018 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 21:03:14 +0800 Subject: [PATCH 4/7] ... --- src/ceval.h | 12 ++++++++++++ src/compiler.h | 12 ++++++------ src/expr.h | 47 +++++++++++++++++++++++++++++++++++++++++++++-- src/lexer.h | 9 ++++++--- src/opcodes.h | 2 ++ 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/ceval.h b/src/ceval.h index 523339b6..0a8c94c9 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -69,6 +69,12 @@ __NEXT_STEP:; TARGET(POP_TOP) POP(); DISPATCH(); TARGET(DUP_TOP) PUSH(TOP()); DISPATCH(); TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH(); + TARGET(ROT_THREE) + _0 = TOP(); + TOP() = SECOND(); + SECOND() = THIRD(); + THIRD() = _0; + DISPATCH(); TARGET(PRINT_EXPR) if(TOP() != None) _stdout(this, CAST(Str&, py_repr(TOP())) + "\n"); POP(); @@ -408,6 +414,12 @@ __NEXT_STEP:; if(py_bool(TOP()) == false) frame->jump_abs(byte.arg); else POP(); DISPATCH(); + TARGET(SHORTCUT_IF_FALSE_OR_POP) + if(py_bool(TOP()) == false){ // [b, False] + STACK_SHRINK(2); // [] + PUSH(vm->False); // [False] + frame->jump_abs(byte.arg); + } else POP(); // [b] TARGET(LOOP_CONTINUE) frame->jump_abs(co_blocks[byte.block].start); DISPATCH(); diff --git a/src/compiler.h b/src/compiler.h index f8a18ee9..fc01d199 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -93,12 +93,12 @@ class Compiler { rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT }; rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; - rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; + rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; - rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT }; rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT }; rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND }; @@ -107,8 +107,8 @@ class Compiler { rules[TK("@")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("if")] = { nullptr, METHOD(exprTernary), PREC_TERNARY }; rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE }; - rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; - rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; + rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; + rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND }; rules[TK("or")] = { nullptr, METHOD(exprOr), PREC_LOGICAL_OR }; rules[TK("not")] = { METHOD(exprNot), nullptr, PREC_LOGICAL_NOT }; diff --git a/src/expr.h b/src/expr.h index 2cfc71f8..a654f77c 100644 --- a/src/expr.h +++ b/src/expr.h @@ -23,6 +23,7 @@ struct Expr{ virtual bool is_literal() const { return false; } virtual bool is_json_object() const { return false; } virtual bool is_attrib() const { return false; } + virtual bool is_compare() const { return false; } // for OP_DELETE_XXX [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; } @@ -683,8 +684,50 @@ struct BinaryExpr: Expr{ Expr_ rhs; std::string str() const override { return TK_STR(op); } + bool is_compare() const override { + switch(op){ + case TK("<"): case TK("<="): case TK("=="): + case TK("!="): case TK(">"): case TK(">="): return true; + default: return false; + } + } + + void _emit_compare(CodeEmitContext* ctx, std::vector& jmps){ + if(lhs->is_compare()){ + static_cast(lhs.get())->_emit_compare(ctx, jmps); + }else{ + lhs->emit(ctx); // [a] + } + rhs->emit(ctx); // [a, b] + ctx->emit(OP_DUP_TOP, BC_NOARG, line); // [a, b, b] + ctx->emit(OP_ROT_THREE, BC_NOARG, line); // [b, a, b] + switch(op){ + case TK("<"): ctx->emit(OP_COMPARE_LT, BC_NOARG, line); break; + case TK("<="): ctx->emit(OP_COMPARE_LE, BC_NOARG, line); break; + case TK("=="): ctx->emit(OP_COMPARE_EQ, BC_NOARG, line); break; + case TK("!="): ctx->emit(OP_COMPARE_NE, BC_NOARG, line); break; + case TK(">"): ctx->emit(OP_COMPARE_GT, BC_NOARG, line); break; + case TK(">="): ctx->emit(OP_COMPARE_GE, BC_NOARG, line); break; + default: UNREACHABLE(); + } + // [b, RES] + int index = ctx->emit(OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, line); + jmps.push_back(index); + } + void emit(CodeEmitContext* ctx) override { - lhs->emit(ctx); + + if(is_compare() && lhs->is_compare()){ + // (a < b) < c + std::vector jmps; + static_cast(lhs.get())->_emit_compare(ctx, jmps); + // [b, RES] + for(int i: jmps) ctx->patch_jump(i); + }else{ + // (1 + 2) < c + lhs->emit(ctx); + } + rhs->emit(ctx); switch (op) { case TK("+"): ctx->emit(OP_BINARY_ADD, BC_NOARG, line); break; @@ -701,7 +744,7 @@ struct BinaryExpr: Expr{ case TK("!="): ctx->emit(OP_COMPARE_NE, BC_NOARG, line); break; case TK(">"): ctx->emit(OP_COMPARE_GT, BC_NOARG, line); break; case TK(">="): ctx->emit(OP_COMPARE_GE, BC_NOARG, line); break; - + case TK("in"): ctx->emit(OP_CONTAINS_OP, 0, line); break; case TK("not in"): ctx->emit(OP_CONTAINS_OP, 1, line); break; case TK("is"): ctx->emit(OP_IS_OP, 0, line); break; diff --git a/src/lexer.h b/src/lexer.h index 6055831f..c3f09fd6 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -79,9 +79,12 @@ enum Precedence { PREC_LOGICAL_OR, // or PREC_LOGICAL_AND, // and PREC_LOGICAL_NOT, // not - PREC_EQUALITY, // == != - PREC_TEST, // in / is / is not / not in - PREC_COMPARISION, // < > <= >= + /* https://docs.python.org/3/reference/expressions.html#comparisons + * Unlike C, all comparison operations in Python have the same priority, + * which is lower than that of any arithmetic, shifting or bitwise operation. + * Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics. + */ + PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in PREC_BITWISE_OR, // | PREC_BITWISE_XOR, // ^ PREC_BITWISE_AND, // & diff --git a/src/opcodes.h b/src/opcodes.h index 739b2c37..4fdfba5d 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -6,6 +6,7 @@ OPCODE(NO_OP) OPCODE(POP_TOP) OPCODE(DUP_TOP) OPCODE(ROT_TWO) +OPCODE(ROT_THREE) OPCODE(PRINT_EXPR) /**************************/ OPCODE(LOAD_CONST) @@ -75,6 +76,7 @@ OPCODE(JUMP_ABSOLUTE) OPCODE(POP_JUMP_IF_FALSE) OPCODE(JUMP_IF_TRUE_OR_POP) OPCODE(JUMP_IF_FALSE_OR_POP) +OPCODE(SHORTCUT_IF_FALSE_OR_POP) OPCODE(LOOP_CONTINUE) OPCODE(LOOP_BREAK) OPCODE(GOTO) From caadfefc017d5dc93154d78dbccbb86cbd34e4a1 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 21:28:23 +0800 Subject: [PATCH 5/7] add `aFalse); // [False] frame->jump_abs(byte.arg); } else POP(); // [b] + DISPATCH(); TARGET(LOOP_CONTINUE) frame->jump_abs(co_blocks[byte.block].start); DISPATCH(); diff --git a/src/common.h b/src/common.h index 56aff1bd..dc5db29a 100644 --- a/src/common.h +++ b/src/common.h @@ -178,9 +178,9 @@ inline PyObject* const PY_OP_CALL = (PyObject*)0b100011; inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011; #ifdef _WIN32 - char kPlatformSep = '\\'; + inline const char kPlatformSep = '\\'; #else - char kPlatformSep = '/'; + inline const char kPlatformSep = '/'; #endif } // namespace pkpy \ No newline at end of file diff --git a/src/expr.h b/src/expr.h index a654f77c..ceda17fc 100644 --- a/src/expr.h +++ b/src/expr.h @@ -716,13 +716,11 @@ struct BinaryExpr: Expr{ } void emit(CodeEmitContext* ctx) override { - + std::vector jmps; if(is_compare() && lhs->is_compare()){ // (a < b) < c - std::vector jmps; static_cast(lhs.get())->_emit_compare(ctx, jmps); // [b, RES] - for(int i: jmps) ctx->patch_jump(i); }else{ // (1 + 2) < c lhs->emit(ctx); @@ -759,6 +757,8 @@ struct BinaryExpr: Expr{ case TK("@"): ctx->emit(OP_BINARY_MATMUL, BC_NOARG, line); break; default: FATAL_ERROR(); } + + for(int i: jmps) ctx->patch_jump(i); } }; diff --git a/src/vm.h b/src/vm.h index afe81a59..604e7f30 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1005,7 +1005,7 @@ inline Str VM::disassemble(CodeObject_ co){ std::vector jumpTargets; for(auto byte : co->codes){ - if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){ + if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE || byte.op == OP_POP_JUMP_IF_FALSE || byte.op == OP_SHORTCUT_IF_FALSE_OR_POP){ jumpTargets.push_back(byte.arg); } } @@ -1027,11 +1027,12 @@ inline Str VM::disassemble(CodeObject_ co){ pointer = " "; } ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); - ss << " " << pad(OP_NAMES[byte.op], 20) << " "; + ss << " " << pad(OP_NAMES[byte.op], 25) << " "; // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5); std::string argStr = _opcode_argstr(this, byte, co.get()); - ss << pad(argStr, 40); // may overflow - ss << co->blocks[byte.block].type; + ss << argStr; + // ss << pad(argStr, 40); // may overflow + // ss << co->blocks[byte.block].type; if(i != co->codes.size() - 1) ss << '\n'; } diff --git a/tests/31_cmp.py b/tests/31_cmp.py new file mode 100644 index 00000000..8a3a7649 --- /dev/null +++ b/tests/31_cmp.py @@ -0,0 +1,16 @@ +assert 1<2 +assert 1+1==2 +assert 2+1>=2 + +assert 1<2<3 +assert 1<2<3<4 +assert 1<2<3<4<5 + +assert 1<1+1<3 +assert 1<1+1<3<4 +assert 1<1+1<3<2+2<5 + +a = [1,2,3] +assert a[0] < a[1] < a[2] +assert a[0]+1 == a[1] < a[2] +assert a[0]+1 == a[1] < a[2]+1 < 5 \ No newline at end of file From f16518e439dac9d483fd7a2fbf617c1c71605661 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 22:20:42 +0800 Subject: [PATCH 6/7] ... --- python/builtins.py | 52 ++++++++++++++++++++++++++++++++++++++++--- python/collections.py | 36 ++++++++++++++++++++++++++++++ src/compiler.h | 6 +++-- src/main.cpp | 3 ++- src/pocketpy.h | 6 +++++ 5 files changed, 97 insertions(+), 6 deletions(-) diff --git a/python/builtins.py b/python/builtins.py index 1d7e8f4d..6e615ee4 100644 --- a/python/builtins.py +++ b/python/builtins.py @@ -104,7 +104,8 @@ def sorted(iterable, reverse=False, key=None): return a ##### str ##### -def __f(self, sep): +def __f(self, sep=None): + sep = sep or ' ' if sep == "": return list(self) res = [] @@ -130,6 +131,22 @@ def __f(self, *args): return self str.format = __f +def __f(self, chars=None): + chars = chars or ' \t\n\r' + i = 0 + while i < len(self) and self[i] in chars: + ++i + return self[i:] +str.lstrip = __f + +def __f(self, chars=None): + chars = chars or ' \t\n\r' + j = len(self) - 1 + while j >= 0 and self[j] in chars: + --j + return self[:j+1] +str.rstrip = __f + def __f(self, chars=None): chars = chars or ' \t\n\r' i = 0 @@ -169,8 +186,37 @@ def __f(self, reverse=False, key=None): self.reverse() list.sort = __f -def staticmethod(f): - return f # no effect +def __f(self, other): + for i, j in zip(self, other): + if i != j: + return i < j + return len(self) < len(other) +tuple.__lt__ = __f +list.__lt__ = __f + +def __f(self, other): + for i, j in zip(self, other): + if i != j: + return i > j + return len(self) > len(other) +tuple.__gt__ = __f +list.__gt__ = __f + +def __f(self, other): + for i, j in zip(self, other): + if i != j: + return i <= j + return len(self) <= len(other) +tuple.__le__ = __f +list.__le__ = __f + +def __f(self, other): + for i, j in zip(self, other): + if i != j: + return i >= j + return len(self) >= len(other) +tuple.__ge__ = __f +list.__ge__ = __f type.__repr__ = lambda self: "" diff --git a/python/collections.py b/python/collections.py index 385997e5..0f526d4d 100644 --- a/python/collections.py +++ b/python/collections.py @@ -81,3 +81,39 @@ def Counter(iterable): else: a[x] = 1 return a + +class defaultdict: + def __init__(self, default_factory) -> None: + self.default_factory = default_factory + self._a = {} + + def __getitem__(self, key): + if key not in self._a: + self._a[key] = self.default_factory() + return self._a[key] + + def __setitem__(self, key, value): + self._a[key] = value + + def __repr__(self) -> str: + return f"defaultdict({self.default_factory}, {self._a})" + + def __eq__(self, __o: object) -> bool: + if not isinstance(__o, defaultdict): + return False + if self.default_factory != __o.default_factory: + return False + return self._a == __o._a + + def __len__(self): + return len(self._a) + + def keys(self): + return self._a.keys() + + def values(self): + return self._a.values() + + def items(self): + return self._a.items() + diff --git a/src/compiler.h b/src/compiler.h index fc01d199..4e762c1e 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -856,8 +856,10 @@ __SUBSCR_END: consume(TK("@id")); int namei = StrName(prev().str()).index; int super_namei = -1; - if(match(TK("(")) && match(TK("@id"))){ - super_namei = StrName(prev().str()).index; + if(match(TK("("))){ + if(match(TK("@id"))){ + super_namei = StrName(prev().str()).index; + } consume(TK(")")); } if(super_namei == -1) ctx()->emit(OP_LOAD_NONE, BC_NOARG, prev().line); diff --git a/src/main.cpp b/src/main.cpp index c18f546e..5596db15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,10 +7,11 @@ int main(int argc, char** argv){ pkpy::VM* vm = pkpy_new_vm(); - vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ + pkpy::PyObject* input_f = vm->bind_builtin_func<0>("input", [](pkpy::VM* vm, pkpy::ArgsView args){ // pkpy::getline() has bugs for PIPE input on Windows return VAR(pkpy::getline()); }); + vm->_modules["sys"]->attr("stdin")->attr().set("readline", input_f); if(argc == 1){ pkpy::REPL* repl = pkpy_new_repl(vm); bool need_more_lines = false; diff --git a/src/pocketpy.h b/src/pocketpy.h index 58e7848c..361cf6a3 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -104,6 +104,10 @@ inline void init_builtins(VM* _vm) { return VAR_T(VoidP, obj); }); + _vm->bind_builtin_func<1>("staticmethod", [](VM* vm, ArgsView args) { + return args[0]; + }); + _vm->bind_builtin_func<1>("__import__", [](VM* vm, ArgsView args) { return vm->py_import(CAST(Str&, args[0])); }); @@ -1110,8 +1114,10 @@ inline void add_module_sys(VM* vm){ PyObject* stdout_ = vm->heap.gcnew(vm->tp_object, {}); PyObject* stderr_ = vm->heap.gcnew(vm->tp_object, {}); + PyObject* stdin_ = vm->heap.gcnew(vm->tp_object, {}); vm->setattr(mod, "stdout", stdout_); vm->setattr(mod, "stderr", stderr_); + vm->setattr(mod, "stdin", stdin_); vm->bind_func<1>(stdout_, "write", [](VM* vm, ArgsView args) { vm->_stdout(vm, CAST(Str&, args[0])); From ada232c079e59987fe3cd17196962b374c4939f2 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Jun 2023 22:30:32 +0800 Subject: [PATCH 7/7] ... --- c_bindings/test.c | 8 ++++---- c_bindings/test_answers.txt | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/c_bindings/test.c b/c_bindings/test.c index 9f9ae8fa..c74ecbd3 100644 --- a/c_bindings/test.c +++ b/c_bindings/test.c @@ -328,10 +328,10 @@ int main(int argc, char** argv) { //at such a time this interferes with a real world use case of the bindings //we can revisit it // - //check(pkpy_vm_run(vm, "def error_from_python() : raise NotImplementedError()")); - //check(pkpy_push_function(vm, test_nested_error, 0)); - //check(pkpy_set_global(vm, "test_nested_error")); - //error(pkpy_vm_run(vm, "test_nested_error()")); + check(pkpy_vm_run(vm, "def error_from_python() : raise NotImplementedError()")); + check(pkpy_push_function(vm, test_nested_error, 0)); + check(pkpy_set_global(vm, "test_nested_error")); + error(pkpy_vm_run(vm, "test_nested_error()")); check(pkpy_vm_run(vm, "import math")); check(pkpy_get_global(vm, "math")); diff --git a/c_bindings/test_answers.txt b/c_bindings/test_answers.txt index 5d23e763..1430abc7 100644 --- a/c_bindings/test_answers.txt +++ b/c_bindings/test_answers.txt @@ -63,6 +63,13 @@ NameError: testing error throwing from python successfully errored with this message: Traceback (most recent call last): _: test direct error mechanism +successfully errored with this message: +Traceback (most recent call last): + File "", line 1 + test_nested_error() + File "", line 1 + def error_from_python() : raise NotImplementedError() +NotImplementedError pi: 3.14 pi: 3.14 2