Compare commits

...

2 Commits

Author SHA1 Message Date
blueloveTH
20cd2064d4 ... 2024-07-14 16:24:13 +08:00
blueloveTH
8f97e9419f ... 2024-07-14 13:46:56 +08:00
13 changed files with 153 additions and 113 deletions

View File

@ -324,6 +324,8 @@ bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
/// The result will be set to `py_retval()`.
/// The stack remains unchanged after the operation.
bool py_callmagic(py_Name name, int argc, py_Ref argv);
/// Call a `py_CFunction` in a safe way.
bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv);
bool py_str(py_Ref val);
#define py_repr(val) py_callmagic(__repr__, 1, val)
@ -359,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.

View File

@ -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());

View File

@ -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;
@ -267,10 +279,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = TOP();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
SP() = next_sp;
py_TValue* p0 = TOP();
if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR;
*TOP() = self->last_retval;
} else {
INSERT_THIRD(); // [?, a, b]
@ -321,10 +331,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
if(magic) {
PUSH(THIRD()); // [val, a, b, val]
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = FOURTH();
bool ok = magic->_cfunc(3, THIRD());
if(!ok) goto __ERROR;
SP() = next_sp;
py_TValue* p0 = FOURTH();
if(!py_callcfunc(p0, magic->_cfunc, 3, THIRD())) goto __ERROR;
} else {
*FOURTH() = *magic; // [__selitem__, a, b, val]
if(!py_vectorcall(2, 0)) goto __ERROR;
@ -391,10 +399,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = SECOND();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
SP() = next_sp;
py_TValue* p0 = SECOND();
if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR;
} else {
INSERT_THIRD(); // [?, a, b]
*THIRD() = *magic; // [__delitem__, a, b]
@ -533,10 +539,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = TOP();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
SP() = next_sp;
py_TValue* p0 = TOP();
if(!py_callcfunc(p0, magic->_cfunc, 2, SECOND())) goto __ERROR;
*TOP() = self->last_retval;
} else {
INSERT_THIRD(); // [?, b, a]
@ -632,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;
int n = 0;
py_TValue* sp = SP();
py_TValue* p1 = sp - kwargc * 2;
py_TValue* base = p1 - argc;
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;
// 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;
for(py_TValue* curr = base; curr != p1; curr++) {
if(curr->type != tp_star_wrapper) {
buf[n++] = *curr;
} 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);
py_TValue* args = py_getslot(curr, 0);
int length;
py_TValue* p = pk_arrayview(&value, &length);
if(!p) {
TypeError("*args should be a list or tuple, got '%t'", value.type);
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;
}
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);
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;
}
}
}
vectorcall_opcall(new_argc, new_kwargc);
memcpy(base, buf, n * sizeof(py_TValue));
SP() = base + n;
vectorcall_opcall(argc, kwargc);
DISPATCH();
}
case OP_RETURN_VALUE: {

View File

@ -391,8 +391,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co));
return opcall ? RES_CALL : pk_VM__run_top_frame(self);
} else {
bool ok = fn->cfunc(co->nlocals, argv);
self->stack.sp = p0;
bool ok = py_callcfunc(p0, fn->cfunc, co->nlocals, argv);
return ok ? RES_RETURN : RES_ERROR;
}
}
@ -431,32 +430,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
}
if(p0->type == tp_nativefunc) {
// const auto& f = PK_OBJ_GET(NativeFunc, callable);
// PyVar ret;
// if(f.decl != nullptr) {
// int co_nlocals = f.decl->code->nlocals;
// prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
// // copy buffer back to stack
// s_data.reset(_base + co_nlocals);
// for(int j = 0; j < co_nlocals; j++)
// _base[j] = __vectorcall_buffer[j];
// ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
// } else {
// if(f.argc != -1) {
// if(KWARGC != 0)
// TypeError(
// "old-style native_func does not accept keyword arguments. If you want to
// skip this check, specify `argc` to -1");
// if(args.size() != f.argc) {
// vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
// }
// }
// ret = f.call(this, args);
// }
// `argc` passed to _cfunc must include self if exists
if(!p0->_cfunc(p1 - argv, argv)) return RES_ERROR;
self->stack.sp = p0;
if(!py_callcfunc(p0, p0->_cfunc, p1 - argv, argv)) return RES_ERROR;
return RES_RETURN;
}

View File

@ -178,6 +178,27 @@ static bool _py_builtins__sum(int argc, py_Ref argv) {
return true;
}
static bool _py_builtins__print(int argc, py_Ref argv) {
int length;
py_TValue* args = pk_arrayview(argv, &length);
assert(args != NULL);
c11_sv sep = py_tosv(py_arg(1));
c11_sv end = py_tosv(py_arg(2));
c11_sbuf buf;
c11_sbuf__ctor(&buf);
for(int i = 0; i < length; i++) {
if(i > 0) c11_sbuf__write_sv(&buf, sep);
if(!py_str(&args[i])) return false;
c11_sbuf__write_sv(&buf, py_tosv(py_retval()));
}
c11_sbuf__write_sv(&buf, end);
c11_string* res = c11_sbuf__submit(&buf);
pk_current_vm->_stdout("%s", res->data);
c11_string__delete(res);
py_newnone(py_retval());
return true;
}
py_TValue pk_builtins__register() {
py_Ref builtins = py_newmodule("builtins", NULL);
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
@ -191,6 +212,7 @@ py_TValue pk_builtins__register() {
py_bindnativefunc(builtins, "abs", _py_builtins__abs);
py_bindnativefunc(builtins, "sum", _py_builtins__sum);
py_bind(builtins, "print(*args, sep=' ', end='\\n')", _py_builtins__print);
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
return *builtins;
}

View File

@ -250,7 +250,6 @@ static bool _py_dict__delitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
Dict* self = py_touserdata(argv);
if(!Dict__pop(self, py_arg(1))) return false;
py_newnone(py_retval());
return true;
}
@ -521,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++) {

View File

@ -174,6 +174,7 @@ static bool _py_list__delitem__(int argc, py_Ref argv) {
int index = py_toint(py_arg(1));
if(!pk__normalize_index(&index, self->count)) return false;
c11_vector__erase(py_TValue, self, index);
py_newnone(py_retval());
return true;
}

View File

@ -66,7 +66,7 @@ void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f) {
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
py_TValue tmp;
do{
do {
char buffer[256];
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
// fn(a, b, *c, d=1) -> None
@ -82,7 +82,7 @@ void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
ud->cfunc = f;
CodeObject__dtor(&code);
PK_DECREF(source);
}while(0);
} while(0);
Function* ud = py_touserdata(&tmp);
py_Name name = py_name(ud->decl->code.name->data);
py_setdict(obj, name, &tmp);

View File

@ -203,7 +203,8 @@ bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode
bool py_call(py_Ref f, int argc, py_Ref argv) {
if(f->type == tp_nativefunc) {
return f->_cfunc(argc, argv);
py_TValue* p0 = pk_current_vm->stack.sp;
return py_callcfunc(p0, f->_cfunc, argc, argv);
} else {
py_push(f);
py_pushnil();
@ -311,6 +312,12 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) {
return py_call(tmp, argc, argv);
}
bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv) {
bool ok = cfunc(argc, argv);
pk_current_vm->stack.sp = p0;
return ok;
}
bool StopIteration() {
pk_VM* vm = pk_current_vm;
assert(!vm->is_stopiteration); // flag is already set

View File

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

View File

@ -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