blueloveTH 1 год назад
Родитель
Сommit
20cd2064d4
8 измененных файлов с 107 добавлено и 64 удалено
  1. 3 0
      include/pocketpy/pocketpy.h
  2. 26 15
      src/compiler/compiler.c
  3. 50 43
      src/interpreter/ceval.c
  4. 10 0
      src/public/py_dict.c
  5. 0 6
      tests/00_tmp.py
  6. 18 0
      tests/16_functions.py
  7. 0 0
      tests/80_cmath.py
  8. 0 0
      tests/80_long.py

+ 3 - 0
include/pocketpy/pocketpy.h

@@ -361,6 +361,9 @@ py_TmpRef py_dict__getitem(const py_Ref self, const py_Ref key);
 void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val);
 bool py_dict__contains(const py_Ref self, const py_Ref key);
 int py_dict__len(const py_Ref self);
+bool py_dict__apply(const py_Ref self,
+                    bool (*f)(const py_Ref key, const py_Ref val, void* ctx),
+                    void* ctx);
 
 /// Search the magic method from the given type to the base type.
 /// Return the reference or NULL if not found.

+ 26 - 15
src/compiler/compiler.c

@@ -1385,6 +1385,7 @@ static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int l
 
 // emit top -> pop -> delete
 static void Ctx__s_emit_top(Ctx* self) {
+    assert(self->s_expr.count);
     Expr* top = c11_vector__back(Expr*, &self->s_expr);
     vtemit_(top, self);
     vtdelete(top);
@@ -1395,13 +1396,17 @@ static void Ctx__s_emit_top(Ctx* self) {
 static void Ctx__s_push(Ctx* self, Expr* expr) { c11_vector__push(Expr*, &self->s_expr, expr); }
 
 // top
-static Expr* Ctx__s_top(Ctx* self) { return c11_vector__back(Expr*, &self->s_expr); }
+static Expr* Ctx__s_top(Ctx* self) {
+    assert(self->s_expr.count);
+    return c11_vector__back(Expr*, &self->s_expr);
+}
 
 // size
 static int Ctx__s_size(Ctx* self) { return self->s_expr.count; }
 
 // pop -> delete
 static void Ctx__s_pop(Ctx* self) {
+    assert(self->s_expr.count);
     Expr* top = c11_vector__back(Expr*, &self->s_expr);
     vtdelete(top);
     c11_vector__pop(&self->s_expr);
@@ -1409,6 +1414,7 @@ static void Ctx__s_pop(Ctx* self) {
 
 // pop move
 static Expr* Ctx__s_popx(Ctx* self) {
+    assert(self->s_expr.count);
     Expr* top = c11_vector__back(Expr*, &self->s_expr);
     c11_vector__pop(&self->s_expr);
     return top;
@@ -1475,7 +1481,11 @@ static NameScope name_scope(Compiler* self) {
     return s;
 }
 
-#define SyntaxError(...) NULL
+Error* SyntaxError(const char* fmt, ...) {
+    printf("%s\n", fmt);
+    abort();
+    return NULL;
+}
 
 /* Matchers */
 static bool is_expression(Compiler* self, bool allow_slice) {
@@ -2108,7 +2118,7 @@ static Error* compile_for_loop(Compiler* self) {
     vtdelete(vars);
     if(!ok) {
         // this error occurs in `vars` instead of this line, but...nevermind
-        return SyntaxError();
+        return SyntaxError("invalid syntax");
     }
     check(compile_block_body(self, compile_stmt));
     Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
@@ -2135,10 +2145,10 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
         case TK_IAND:
         case TK_IOR:
         case TK_IXOR: {
-            if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
-            if(ctx()->is_compiling_class) {
+            if(Ctx__s_top(ctx())->vt->is_starred)
+                return SyntaxError("can't use inplace operator with starred expression");
+            if(ctx()->is_compiling_class)
                 return SyntaxError("can't use inplace operator in class definition");
-            }
             advance();
             // a[x] += 1;   a and x should be evaluated only once
             // a.x += 1;    a should be evaluated only once
@@ -2147,14 +2157,15 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
             TokenIndex op = (TokenIndex)(prev()->type - 1);
             // [lhs]
             check(EXPR_TUPLE(self));  // [lhs, rhs]
-            if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
+            if(Ctx__s_top(ctx())->vt->is_starred)
+                return SyntaxError("can't use starred expression here");
             BinaryExpr* e = BinaryExpr__new(line, op, true);
             e->rhs = Ctx__s_popx(ctx());  // [lhs]
             e->lhs = Ctx__s_popx(ctx());  // []
             vtemit_((Expr*)e, ctx());
             bool ok = vtemit_istore(e->lhs, ctx());
             vtdelete((Expr*)e);
-            if(!ok) return SyntaxError();
+            if(!ok) return SyntaxError("invalid syntax");
             *is_assign = true;
             return NULL;
         }
@@ -2169,11 +2180,12 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
             for(int j = 1; j < n; j++)
                 Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
             for(int j = 0; j < n; j++) {
-                if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
+                if(Ctx__s_top(ctx())->vt->is_starred)
+                    return SyntaxError("can't use starred expression here");
                 Expr* e = Ctx__s_top(ctx());
                 bool ok = vtemit_store(e, ctx());
                 Ctx__s_pop(ctx());
-                if(!ok) return SyntaxError();
+                if(!ok) return SyntaxError("invalid syntax");
             }
             *is_assign = true;
             return NULL;
@@ -2213,7 +2225,7 @@ static Error* read_literal(Compiler* self, py_Ref out) {
             } else if(value->index == TokenValue_F64) {
                 py_newfloat(out, negated ? -value->_f64 : value->_f64);
             } else {
-                return SyntaxError();
+                c11__unreachedable();
             }
             return NULL;
         }
@@ -2248,8 +2260,7 @@ static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_h
     int state = 0;  // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
     Error* err;
     do {
-        if(state > 3) return SyntaxError();
-        if(state == 3) return SyntaxError("**kwargs should be the last argument");
+        if(state >= 3) return SyntaxError("**kwargs should be the last argument");
         match_newlines();
         if(match(TK_MUL)) {
             if(state < 1)
@@ -2554,7 +2565,7 @@ static Error* compile_stmt(Compiler* self) {
         case TK_DEL: {
             check(EXPR_TUPLE(self));
             Expr* e = Ctx__s_top(ctx());
-            if(!vtemit_del(e, ctx())) return SyntaxError();
+            if(!vtemit_del(e, ctx())) return SyntaxError("invalid syntax");
             Ctx__s_pop(ctx());
             consume_end_stmt();
         } break;
@@ -2622,7 +2633,7 @@ static Error* compile_stmt(Compiler* self) {
             check(try_compile_assignment(self, &is_assign));
             if(!is_assign) {
                 if(Ctx__s_size(ctx()) > 0 && Ctx__s_top(ctx())->vt->is_starred) {
-                    return SyntaxError();
+                    return SyntaxError("can't use starred expression here");
                 }
                 if(!is_typed_name) {
                     Ctx__s_emit_top(ctx());

+ 50 - 43
src/interpreter/ceval.c

@@ -59,6 +59,18 @@ static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
         }                                                                                          \
     } while(0)
 
+static bool unpack_dict_to_buffer(const py_Ref key, const py_Ref val, void* ctx) {
+    py_TValue** p = ctx;
+    if(py_isstr(key)) {
+        py_Name name = py_namev(py_tosv(key));
+        py_newint(*p, name);
+        py_assign(*p + 1, val);
+        (*p) += 2;
+        return true;
+    }
+    return TypeError("keywords must be strings, not '%t'", key->type);
+}
+
 pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
     Frame* frame = self->top_frame;
     const Frame* base_frame = frame;
@@ -624,63 +636,58 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                 DISPATCH();
             }
             case OP_CALL_VARGS: {
+                // [_0, _1, _2 | k1, v1, k2, v2]
                 uint16_t argc = byte.arg & 0xFF;
                 uint16_t kwargc = byte.arg >> 8;
-                int size = 0;
-                py_TValue* buf = self->__vectorcall_buffer;
 
-                // if(size == PK_MAX_CO_VARNAMES) {
-                //     ValueError("**kwargs is too large to unpack");
-                //     goto __ERROR;
-                // }
-
-                uint16_t new_argc = argc;
-                uint16_t new_kwargc = kwargc;
+                int n = 0;
+                py_TValue* sp = SP();
+                py_TValue* p1 = sp - kwargc * 2;
+                py_TValue* base = p1 - argc;
+                py_TValue* buf = self->__vectorcall_buffer;
 
-                // pop kwargc
-                for(int i = 0; i < kwargc; i++) {
-                    // [k1, v1, k2, v2, ...] -> reversed
-                    py_TValue value = POPX();
-                    py_TValue key = POPX();
-                    if(value.type == tp_star_wrapper) {
-                        value = *py_getslot(&value, 0);
-                        // unpack dict
-                        if(value.type != tp_dict) {
-                            TypeError("**kwargs should be a dict, got '%t'", value.type);
+                for(py_TValue* curr = base; curr != p1; curr++) {
+                    if(curr->type != tp_star_wrapper) {
+                        buf[n++] = *curr;
+                    } else {
+                        py_TValue* args = py_getslot(curr, 0);
+                        int length;
+                        py_TValue* p = pk_arrayview(args, &length);
+                        if(p) {
+                            for(int j = 0; j < length; j++) {
+                                buf[n++] = p[j];
+                            }
+                            argc += length - 1;
+                        } else {
+                            TypeError("*args must be a list or tuple, got '%t'", args->type);
                             goto __ERROR;
                         }
-                        new_kwargc += (0) - 1;
-                    } else {
-                        buf[size++] = value;
-                        buf[size++] = key;
                     }
                 }
-                // pop argc
-                for(int i = 0; i < argc; i++) {
-                    py_TValue value = POPX();
-                    if(value.type == tp_star_wrapper) {
-                        value = *py_getslot(&value, 0);
-                        int length;
-                        py_TValue* p = pk_arrayview(&value, &length);
-                        if(!p) {
-                            TypeError("*args should be a list or tuple, got '%t'", value.type);
+
+                for(py_TValue* curr = p1; curr != sp; curr += 2) {
+                    if(curr[1].type != tp_star_wrapper) {
+                        buf[n++] = curr[0];
+                        buf[n++] = curr[1];
+                    } else {
+                        assert(py_toint(&curr[0]) == 0);
+                        py_TValue* kwargs = py_getslot(&curr[1], 0);
+                        if(kwargs->type == tp_dict) {
+                            py_TValue* p = buf + n;
+                            if(!py_dict__apply(kwargs, unpack_dict_to_buffer, &p)) goto __ERROR;
+                            n = p - buf;
+                            kwargc += py_dict__len(kwargs) - 1;
+                        } else {
+                            TypeError("*kwargs must be a dict, got '%t'", kwargs->type);
                             goto __ERROR;
                         }
-                        for(int j = 0; j < length; j++) {
-                            buf[size++] = p[j];
-                        }
-                        new_argc += length - 1;
-                    } else {
-                        buf[size++] = value;
                     }
                 }
 
-                // push everything back in reversed order
-                for(int i = size - 1; i >= 0; i--) {
-                    PUSH(buf + i);
-                }
+                memcpy(base, buf, n * sizeof(py_TValue));
+                SP() = base + n;
 
-                vectorcall_opcall(new_argc, new_kwargc);
+                vectorcall_opcall(argc, kwargc);
                 DISPATCH();
             }
             case OP_RETURN_VALUE: {

+ 10 - 0
src/public/py_dict.c

@@ -520,6 +520,16 @@ int py_dict__len(const py_Ref self) {
     return ud->length;
 }
 
+bool py_dict__apply(const py_Ref self, bool (*f)(const py_Ref, const py_Ref, void *), void *ctx){
+    Dict* ud = py_touserdata(self);
+    for(int i = 0; i < ud->entries.count; i++) {
+        DictEntry* entry = c11__at(DictEntry, &ud->entries, i);
+        if(py_isnil(&entry->key)) continue;
+        if(!f(&entry->key, &entry->val, ctx)) return false;
+    }
+    return true;
+}
+
 void pk_dict__mark(void* ud, void (*marker)(py_TValue*)) {
     Dict* self = ud;
     for(int i = 0; i < self->entries.count; i++) {

+ 0 - 6
tests/00_tmp.py

@@ -1,6 +0,0 @@
-# dict delete test
-data = []
-j = 6
-for i in range(65535):
-    j = ((j*5+1) % 65535)
-    data.append(str(j))

+ 18 - 0
tests/16_functions.py

@@ -31,6 +31,23 @@ assert f(b=5) == 6
 assert f(a=5) == 4
 assert f(b=5, a=5) == 10
 
+# test args unpack
+def f(a, b, *args):
+    assert a == 1
+    assert b == 2
+    assert args == (3, 4)
+
+f(1, 2, 3, 4)
+
+# test kwargs unpack
+def f(a=1, b=2, **kwargs):
+    assert a == 10
+    assert b == 2
+    assert kwargs == {'c': 3, 'd': 4}
+
+f(10, c=3, d=4)
+f(a=10, c=3, d=4)
+
 def f(*args):
     return 10 * sum(args)
 
@@ -61,6 +78,7 @@ assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
 
 assert g(1, 2, 3, 4) == 17
 assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
+assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
 assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
 assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1, d=2) == 58
 assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1) == 61

+ 0 - 0
tests/19_cmath.py → tests/80_cmath.py


+ 0 - 0
tests/23_long.py → tests/80_long.py