Просмотр исходного кода

experimental support for `try..except..as`

blueloveTH 2 лет назад
Родитель
Сommit
f6942e0caf
6 измененных файлов с 43 добавлено и 5 удалено
  1. 3 1
      include/pocketpy/error.h
  2. 0 1
      python/builtins.py
  3. 11 1
      src/compiler.cpp
  4. 11 0
      src/pocketpy.cpp
  5. 1 1
      src/vm.cpp
  6. 17 1
      tests/41_exception.py

+ 3 - 1
include/pocketpy/error.h

@@ -61,7 +61,9 @@ struct Exception {
 
     Exception(StrName type, Str msg): 
         type(type), msg(msg), is_re(true), _ip_on_error(-1), _code_on_error(nullptr) {}
-    bool match_type(StrName t) const { return this->type == t;}
+    bool match_type(StrName t) const {
+        return this->type==t || t.sv()=="Exception";
+    }
 
     template<typename... Args>
     void st_push(Args&&... args){

+ 0 - 1
python/builtins.py

@@ -258,7 +258,6 @@ def help(obj):
 
 class Exception: pass
 
-
 class classmethod:
     def __init__(self, f):
         self.f = f

+ 11 - 1
src/compiler.cpp

@@ -677,14 +677,24 @@ __EAT_DOTS_END:
         };
         ctx()->exit_block();
         do {
+            StrName as_name;
             consume(TK("except"));
             if(match(TK("@id"))){
                 ctx()->emit_(OP_EXCEPTION_MATCH, StrName(prev().sv()).index, prev().line);
+                if(match(TK("as"))){
+                    consume(TK("@id"));
+                    as_name = StrName(prev().sv());
+                }
             }else{
                 ctx()->emit_(OP_LOAD_TRUE, BC_NOARG, BC_KEEPLINE);
             }
             int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
-            // pop the exception on match
+            // on match
+            if(!as_name.empty()){
+                ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
+                ctx()->emit_store_name(name_scope(), as_name, BC_KEEPLINE);
+            }
+            // pop the exception 
             ctx()->emit_(OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE);
             compile_block_body();
             patches.push_back(ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE));

+ 11 - 0
src/pocketpy.cpp

@@ -1318,6 +1318,17 @@ void init_builtins(VM* _vm) {
     //     return args[0];
     // });
 
+    // Exception
+    _vm->bind__repr__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
+        Exception& self = _CAST(Exception&, obj);
+        return VAR(fmt(self.type.sv(), '(', self.msg.escape(), ')'));
+    });
+
+    _vm->bind__str__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
+        Exception& self = _CAST(Exception&, obj);
+        return VAR(self.msg);
+    });
+
     RangeIter::register_class(_vm, _vm->builtins);
     ArrayIter::register_class(_vm, _vm->builtins);
     StringIter::register_class(_vm, _vm->builtins);

+ 1 - 1
src/vm.cpp

@@ -724,7 +724,7 @@ void VM::init_builtin_types(){
     tp_native_func = _new_type_object("native_func");
     tp_bound_method = _new_type_object("bound_method");
     tp_super = _new_type_object("super");
-    tp_exception = _new_type_object("Exception");
+    tp_exception = _new_type_object("_Exception");
     tp_bytes = _new_type_object("bytes");
     tp_mappingproxy = _new_type_object("mappingproxy");
     tp_dict = _new_type_object("dict");

+ 17 - 1
tests/41_exception.py

@@ -81,4 +81,20 @@ def f(a: list):
     a[0] = 1
 a = [0]
 f(a)
-assert a == [1]
+assert a == [1]
+
+try:
+    a = [][3]
+except IndexError as e:
+    assert str(e) == '3 not in [0, 0)'
+    assert repr(e).startswith('IndexError(')
+
+try:
+    a = {}[2]
+except IndexError as e:
+    exit(1)
+except Exception as e:
+    assert str(e) == '2'
+    assert repr(e).startswith('KeyError(')
+except:
+    exit(1)