mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
...
This commit is contained in:
parent
8f97e9419f
commit
20cd2064d4
@ -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);
|
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);
|
bool py_dict__contains(const py_Ref self, const py_Ref key);
|
||||||
int py_dict__len(const py_Ref self);
|
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.
|
/// Search the magic method from the given type to the base type.
|
||||||
/// Return the reference or NULL if not found.
|
/// Return the reference or NULL if not found.
|
||||||
|
@ -1385,6 +1385,7 @@ static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int l
|
|||||||
|
|
||||||
// emit top -> pop -> delete
|
// emit top -> pop -> delete
|
||||||
static void Ctx__s_emit_top(Ctx* self) {
|
static void Ctx__s_emit_top(Ctx* self) {
|
||||||
|
assert(self->s_expr.count);
|
||||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||||
vtemit_(top, self);
|
vtemit_(top, self);
|
||||||
vtdelete(top);
|
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); }
|
static void Ctx__s_push(Ctx* self, Expr* expr) { c11_vector__push(Expr*, &self->s_expr, expr); }
|
||||||
|
|
||||||
// top
|
// 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
|
// size
|
||||||
static int Ctx__s_size(Ctx* self) { return self->s_expr.count; }
|
static int Ctx__s_size(Ctx* self) { return self->s_expr.count; }
|
||||||
|
|
||||||
// pop -> delete
|
// pop -> delete
|
||||||
static void Ctx__s_pop(Ctx* self) {
|
static void Ctx__s_pop(Ctx* self) {
|
||||||
|
assert(self->s_expr.count);
|
||||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||||
vtdelete(top);
|
vtdelete(top);
|
||||||
c11_vector__pop(&self->s_expr);
|
c11_vector__pop(&self->s_expr);
|
||||||
@ -1409,6 +1414,7 @@ static void Ctx__s_pop(Ctx* self) {
|
|||||||
|
|
||||||
// pop move
|
// pop move
|
||||||
static Expr* Ctx__s_popx(Ctx* self) {
|
static Expr* Ctx__s_popx(Ctx* self) {
|
||||||
|
assert(self->s_expr.count);
|
||||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||||
c11_vector__pop(&self->s_expr);
|
c11_vector__pop(&self->s_expr);
|
||||||
return top;
|
return top;
|
||||||
@ -1475,7 +1481,11 @@ static NameScope name_scope(Compiler* self) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SyntaxError(...) NULL
|
Error* SyntaxError(const char* fmt, ...) {
|
||||||
|
printf("%s\n", fmt);
|
||||||
|
abort();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Matchers */
|
/* Matchers */
|
||||||
static bool is_expression(Compiler* self, bool allow_slice) {
|
static bool is_expression(Compiler* self, bool allow_slice) {
|
||||||
@ -2108,7 +2118,7 @@ static Error* compile_for_loop(Compiler* self) {
|
|||||||
vtdelete(vars);
|
vtdelete(vars);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
// this error occurs in `vars` instead of this line, but...nevermind
|
// this error occurs in `vars` instead of this line, but...nevermind
|
||||||
return SyntaxError();
|
return SyntaxError("invalid syntax");
|
||||||
}
|
}
|
||||||
check(compile_block_body(self, compile_stmt));
|
check(compile_block_body(self, compile_stmt));
|
||||||
Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
|
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_IAND:
|
||||||
case TK_IOR:
|
case TK_IOR:
|
||||||
case TK_IXOR: {
|
case TK_IXOR: {
|
||||||
if(Ctx__s_top(ctx())->vt->is_starred) return SyntaxError();
|
if(Ctx__s_top(ctx())->vt->is_starred)
|
||||||
if(ctx()->is_compiling_class) {
|
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");
|
return SyntaxError("can't use inplace operator in class definition");
|
||||||
}
|
|
||||||
advance();
|
advance();
|
||||||
// a[x] += 1; a and x should be evaluated only once
|
// a[x] += 1; a and x should be evaluated only once
|
||||||
// a.x += 1; a 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);
|
TokenIndex op = (TokenIndex)(prev()->type - 1);
|
||||||
// [lhs]
|
// [lhs]
|
||||||
check(EXPR_TUPLE(self)); // [lhs, rhs]
|
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);
|
BinaryExpr* e = BinaryExpr__new(line, op, true);
|
||||||
e->rhs = Ctx__s_popx(ctx()); // [lhs]
|
e->rhs = Ctx__s_popx(ctx()); // [lhs]
|
||||||
e->lhs = Ctx__s_popx(ctx()); // []
|
e->lhs = Ctx__s_popx(ctx()); // []
|
||||||
vtemit_((Expr*)e, ctx());
|
vtemit_((Expr*)e, ctx());
|
||||||
bool ok = vtemit_istore(e->lhs, ctx());
|
bool ok = vtemit_istore(e->lhs, ctx());
|
||||||
vtdelete((Expr*)e);
|
vtdelete((Expr*)e);
|
||||||
if(!ok) return SyntaxError();
|
if(!ok) return SyntaxError("invalid syntax");
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -2169,11 +2180,12 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
|||||||
for(int j = 1; j < n; j++)
|
for(int j = 1; j < n; j++)
|
||||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
for(int j = 0; j < n; j++) {
|
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());
|
Expr* e = Ctx__s_top(ctx());
|
||||||
bool ok = vtemit_store(e, ctx());
|
bool ok = vtemit_store(e, ctx());
|
||||||
Ctx__s_pop(ctx());
|
Ctx__s_pop(ctx());
|
||||||
if(!ok) return SyntaxError();
|
if(!ok) return SyntaxError("invalid syntax");
|
||||||
}
|
}
|
||||||
*is_assign = true;
|
*is_assign = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2213,7 +2225,7 @@ static Error* read_literal(Compiler* self, py_Ref out) {
|
|||||||
} else if(value->index == TokenValue_F64) {
|
} else if(value->index == TokenValue_F64) {
|
||||||
py_newfloat(out, negated ? -value->_f64 : value->_f64);
|
py_newfloat(out, negated ? -value->_f64 : value->_f64);
|
||||||
} else {
|
} else {
|
||||||
return SyntaxError();
|
c11__unreachedable();
|
||||||
}
|
}
|
||||||
return NULL;
|
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
|
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||||
Error* err;
|
Error* err;
|
||||||
do {
|
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();
|
match_newlines();
|
||||||
if(match(TK_MUL)) {
|
if(match(TK_MUL)) {
|
||||||
if(state < 1)
|
if(state < 1)
|
||||||
@ -2554,7 +2565,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
case TK_DEL: {
|
case TK_DEL: {
|
||||||
check(EXPR_TUPLE(self));
|
check(EXPR_TUPLE(self));
|
||||||
Expr* e = Ctx__s_top(ctx());
|
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());
|
Ctx__s_pop(ctx());
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
@ -2622,7 +2633,7 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
check(try_compile_assignment(self, &is_assign));
|
check(try_compile_assignment(self, &is_assign));
|
||||||
if(!is_assign) {
|
if(!is_assign) {
|
||||||
if(Ctx__s_size(ctx()) > 0 && Ctx__s_top(ctx())->vt->is_starred) {
|
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) {
|
if(!is_typed_name) {
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
|
@ -59,6 +59,18 @@ static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
|
|||||||
} \
|
} \
|
||||||
} while(0)
|
} 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) {
|
pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||||
Frame* frame = self->top_frame;
|
Frame* frame = self->top_frame;
|
||||||
const Frame* base_frame = frame;
|
const Frame* base_frame = frame;
|
||||||
@ -624,63 +636,58 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_CALL_VARGS: {
|
case OP_CALL_VARGS: {
|
||||||
|
// [_0, _1, _2 | k1, v1, k2, v2]
|
||||||
uint16_t argc = byte.arg & 0xFF;
|
uint16_t argc = byte.arg & 0xFF;
|
||||||
uint16_t kwargc = byte.arg >> 8;
|
uint16_t kwargc = byte.arg >> 8;
|
||||||
int size = 0;
|
|
||||||
|
int n = 0;
|
||||||
|
py_TValue* sp = SP();
|
||||||
|
py_TValue* p1 = sp - kwargc * 2;
|
||||||
|
py_TValue* base = p1 - argc;
|
||||||
py_TValue* buf = self->__vectorcall_buffer;
|
py_TValue* buf = self->__vectorcall_buffer;
|
||||||
|
|
||||||
// if(size == PK_MAX_CO_VARNAMES) {
|
for(py_TValue* curr = base; curr != p1; curr++) {
|
||||||
// ValueError("**kwargs is too large to unpack");
|
if(curr->type != tp_star_wrapper) {
|
||||||
// goto __ERROR;
|
buf[n++] = *curr;
|
||||||
// }
|
|
||||||
|
|
||||||
uint16_t new_argc = argc;
|
|
||||||
uint16_t new_kwargc = kwargc;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
goto __ERROR;
|
|
||||||
}
|
|
||||||
new_kwargc += (0) - 1;
|
|
||||||
} else {
|
} else {
|
||||||
buf[size++] = value;
|
py_TValue* args = py_getslot(curr, 0);
|
||||||
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;
|
int length;
|
||||||
py_TValue* p = pk_arrayview(&value, &length);
|
py_TValue* p = pk_arrayview(args, &length);
|
||||||
if(!p) {
|
if(p) {
|
||||||
TypeError("*args should be a list or tuple, got '%t'", value.type);
|
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;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
for(int j = 0; j < length; j++) {
|
|
||||||
buf[size++] = p[j];
|
|
||||||
}
|
}
|
||||||
new_argc += length - 1;
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
buf[size++] = value;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// push everything back in reversed order
|
memcpy(base, buf, n * sizeof(py_TValue));
|
||||||
for(int i = size - 1; i >= 0; i--) {
|
SP() = base + n;
|
||||||
PUSH(buf + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
vectorcall_opcall(new_argc, new_kwargc);
|
vectorcall_opcall(argc, kwargc);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_RETURN_VALUE: {
|
case OP_RETURN_VALUE: {
|
||||||
|
@ -520,6 +520,16 @@ int py_dict__len(const py_Ref self) {
|
|||||||
return ud->length;
|
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*)) {
|
void pk_dict__mark(void* ud, void (*marker)(py_TValue*)) {
|
||||||
Dict* self = ud;
|
Dict* self = ud;
|
||||||
for(int i = 0; i < self->entries.count; i++) {
|
for(int i = 0; i < self->entries.count; i++) {
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
# dict delete test
|
|
||||||
data = []
|
|
||||||
j = 6
|
|
||||||
for i in range(65535):
|
|
||||||
j = ((j*5+1) % 65535)
|
|
||||||
data.append(str(j))
|
|
@ -31,6 +31,23 @@ assert f(b=5) == 6
|
|||||||
assert f(a=5) == 4
|
assert f(a=5) == 4
|
||||||
assert f(b=5, a=5) == 10
|
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):
|
def f(*args):
|
||||||
return 10 * sum(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) == 17
|
||||||
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
|
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, 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, e=1, d=2) == 58
|
||||||
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1) == 61
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1) == 61
|
||||||
|
Loading…
x
Reference in New Issue
Block a user