Implement basic class/object functionality in runtime.
This commit is contained in:
parent
91d387de7d
commit
a397776d6b
@ -57,8 +57,8 @@ typedef struct _emit_method_table_t {
|
||||
void (*store_global)(emit_t *emit, qstr qstr);
|
||||
void (*store_deref)(emit_t *emit, qstr qstr);
|
||||
void (*store_attr)(emit_t *emit, qstr qstr);
|
||||
void (*store_locals)(emit_t *emit);
|
||||
void (*store_subscr)(emit_t *emit);
|
||||
void (*store_locals)(emit_t *emit);
|
||||
void (*delete_fast)(emit_t *emit, qstr qstr, int local_num);
|
||||
void (*delete_name)(emit_t *emit, qstr qstr);
|
||||
void (*delete_global)(emit_t *emit, qstr qstr);
|
||||
|
12
py/emitbc.c
12
py/emitbc.c
@ -348,16 +348,16 @@ static void emit_bc_store_attr(emit_t *emit, qstr qstr) {
|
||||
emit_write_byte_1_qstr(emit, PYBC_STORE_ATTR, qstr);
|
||||
}
|
||||
|
||||
static void emit_bc_store_locals(emit_t *emit) {
|
||||
emit_pre(emit, -1);
|
||||
emit_write_byte_1(emit, PYBC_STORE_LOCALS);
|
||||
}
|
||||
|
||||
static void emit_bc_store_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -3);
|
||||
emit_write_byte_1(emit, PYBC_STORE_SUBSCR);
|
||||
}
|
||||
|
||||
static void emit_bc_store_locals(emit_t *emit) {
|
||||
// not needed for byte code
|
||||
emit_pre(emit, -1);
|
||||
}
|
||||
|
||||
static void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
assert(local_num >= 0);
|
||||
emit_pre(emit, 0);
|
||||
@ -718,8 +718,8 @@ const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_store_global,
|
||||
emit_bc_store_deref,
|
||||
emit_bc_store_attr,
|
||||
emit_bc_store_locals,
|
||||
emit_bc_store_subscr,
|
||||
emit_bc_store_locals,
|
||||
emit_bc_delete_fast,
|
||||
emit_bc_delete_name,
|
||||
emit_bc_delete_global,
|
||||
|
16
py/emitcpy.c
16
py/emitcpy.c
@ -352,13 +352,6 @@ static void emit_cpy_store_attr(emit_t *emit, qstr qstr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_cpy_store_locals(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
printf("STORE_LOCALS\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_cpy_store_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -3, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
@ -366,6 +359,13 @@ static void emit_cpy_store_subscr(emit_t *emit) {
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_cpy_store_locals(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == PASS_3) {
|
||||
printf("STORE_LOCALS\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_cpy_delete_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == PASS_3) {
|
||||
@ -870,8 +870,8 @@ const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_store_global,
|
||||
emit_cpy_store_deref,
|
||||
emit_cpy_store_attr,
|
||||
emit_cpy_store_locals,
|
||||
emit_cpy_store_subscr,
|
||||
emit_cpy_store_locals,
|
||||
emit_cpy_delete_fast,
|
||||
emit_cpy_delete_name,
|
||||
emit_cpy_delete_global,
|
||||
|
@ -731,11 +731,6 @@ static void emit_native_store_attr(emit_t *emit, qstr qstr) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void emit_native_store_locals(emit_t *emit) {
|
||||
// not supported
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void emit_native_store_subscr(emit_t *emit) {
|
||||
// depends on type of subject:
|
||||
// - integer, function, pointer to structure: error
|
||||
@ -749,6 +744,13 @@ static void emit_native_store_subscr(emit_t *emit) {
|
||||
emit_call(emit, RT_F_STORE_SUBSCR, rt_store_subscr);
|
||||
}
|
||||
|
||||
static void emit_native_store_locals(emit_t *emit) {
|
||||
// not needed
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
static void emit_native_delete_fast(emit_t *emit, qstr qstr, int local_num) {
|
||||
// not implemented
|
||||
// could support for Python types, just set to None (so GC can reclaim it)
|
||||
@ -1146,8 +1148,8 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
|
||||
emit_native_store_global,
|
||||
emit_native_store_deref,
|
||||
emit_native_store_attr,
|
||||
emit_native_store_locals,
|
||||
emit_native_store_subscr,
|
||||
emit_native_store_locals,
|
||||
emit_native_delete_fast,
|
||||
emit_native_delete_name,
|
||||
emit_native_delete_global,
|
||||
|
@ -33,7 +33,7 @@ int main(int argc, char **argv) {
|
||||
py_parse_node_t pn = py_parse(lex, 0);
|
||||
if (pn != PY_PARSE_NODE_NULL) {
|
||||
//printf("----------------\n");
|
||||
parse_node_show(pn, 0);
|
||||
//parse_node_show(pn, 0);
|
||||
//printf("----------------\n");
|
||||
py_compile(pn);
|
||||
//printf("----------------\n");
|
||||
|
291
py/runtime.c
291
py/runtime.c
@ -9,8 +9,8 @@
|
||||
#include "runtime.h"
|
||||
#include "vm.h"
|
||||
|
||||
//#define DEBUG_printf(args...) (void)0
|
||||
#define DEBUG_printf(args...) printf(args)
|
||||
#define DEBUG_printf(args...) (void)0
|
||||
//#define DEBUG_printf(args...) printf(args)
|
||||
|
||||
#define DEBUG_OP_printf(args...) (void)0
|
||||
//#define DEBUG_OP_printf(args...) printf(args)
|
||||
@ -46,6 +46,7 @@ typedef enum {
|
||||
O_SET,
|
||||
O_MAP,
|
||||
O_CLASS,
|
||||
O_OBJ,
|
||||
} py_obj_kind_t;
|
||||
|
||||
typedef enum {
|
||||
@ -59,13 +60,15 @@ typedef struct _py_map_elem_t {
|
||||
} py_map_elem_t;
|
||||
|
||||
typedef struct _py_map_t {
|
||||
py_map_kind_t kind;
|
||||
py_map_kind_t kind; // TODO merge this 1-bit field into alloc or used
|
||||
machine_uint_t alloc;
|
||||
machine_uint_t used;
|
||||
py_map_elem_t *table;
|
||||
} py_map_t;
|
||||
|
||||
typedef struct _py_obj_base_t {
|
||||
typedef struct _py_obj_base_t py_obj_base_t;
|
||||
|
||||
struct _py_obj_base_t {
|
||||
py_obj_kind_t kind;
|
||||
union {
|
||||
const char *id;
|
||||
@ -101,24 +104,22 @@ typedef struct _py_obj_base_t {
|
||||
py_obj_t *table;
|
||||
} u_set;
|
||||
py_map_t u_map; // for O_MAP
|
||||
/*
|
||||
struct { // for O_MAP
|
||||
int alloc;
|
||||
int used;
|
||||
py_map_elem_t *table;
|
||||
} u_map;
|
||||
*/
|
||||
struct { // for O_CLASS
|
||||
py_map_t *map;
|
||||
py_map_t *locals;
|
||||
} u_class;
|
||||
struct { // for O_OBJ
|
||||
py_obj_base_t *class; // points to a O_CLASS object
|
||||
py_map_t *members;
|
||||
} u_obj;
|
||||
};
|
||||
};
|
||||
} py_obj_base_t;
|
||||
|
||||
py_obj_t py_const_none;
|
||||
py_obj_t py_const_false;
|
||||
py_obj_t py_const_true;
|
||||
|
||||
py_map_t map_name;
|
||||
py_map_t map_locals;
|
||||
py_map_t map_globals;
|
||||
py_map_t map_builtins;
|
||||
|
||||
// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
|
||||
@ -334,10 +335,22 @@ py_obj_t py_builtin_len(py_obj_t o_in) {
|
||||
return TO_SMALL_INT(len);
|
||||
}
|
||||
|
||||
py_obj_t py_builtin___build_class__(py_obj_t o1, py_obj_t o2) {
|
||||
py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) {
|
||||
// we differ from CPython: we set the new __locals__ object here
|
||||
py_map_t old_locals = map_locals;
|
||||
py_map_t *class_locals = py_map_new(MAP_QSTR, 0);
|
||||
map_locals = *class_locals;
|
||||
|
||||
// call the class code
|
||||
rt_call_function_1(o_class_fun, (py_obj_t)0xdeadbeef);
|
||||
|
||||
// restore old __locals__ object
|
||||
map_locals = old_locals;
|
||||
|
||||
// create and return the new class
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_CLASS;
|
||||
o->u_class.map = py_map_new(MAP_QSTR, 0);
|
||||
o->u_class.locals = class_locals;
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -353,7 +366,10 @@ void rt_init() {
|
||||
py_const_false = py_obj_new_const("False");
|
||||
py_const_true = py_obj_new_const("True");
|
||||
|
||||
py_map_init(&map_name, MAP_QSTR, 0);
|
||||
py_map_init(&map_locals, MAP_QSTR, 0);
|
||||
|
||||
py_map_init(&map_globals, MAP_QSTR, 1);
|
||||
py_qstr_map_lookup(&map_globals, qstr_from_str_static("__name__"), true)->value = py_obj_new_str(qstr_from_str_static("__main__"));
|
||||
|
||||
py_map_init(&map_builtins, MAP_QSTR, 3);
|
||||
py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print);
|
||||
@ -446,6 +462,25 @@ void rt_assign_inline_asm_code(int unique_code_id, py_fun_t fun, uint len, int n
|
||||
}
|
||||
}
|
||||
|
||||
bool py_obj_is_callable(py_obj_t o_in) {
|
||||
if (IS_SMALL_INT(o_in)) {
|
||||
return false;
|
||||
} else {
|
||||
py_obj_base_t *o = o_in;
|
||||
switch (o->kind) {
|
||||
case O_FUN_0:
|
||||
case O_FUN_1:
|
||||
case O_FUN_2:
|
||||
case O_FUN_N:
|
||||
case O_FUN_BC:
|
||||
case O_FUN_ASM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *py_obj_get_type_str(py_obj_t o_in) {
|
||||
if (IS_SMALL_INT(o_in)) {
|
||||
return "int";
|
||||
@ -476,6 +511,13 @@ const char *py_obj_get_type_str(py_obj_t o_in) {
|
||||
return "set";
|
||||
case O_MAP:
|
||||
return "dict";
|
||||
case O_OBJ:
|
||||
{
|
||||
py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false);
|
||||
assert(qn != NULL);
|
||||
assert(IS_O(qn->value, O_STR));
|
||||
return qstr_str(((py_obj_base_t*)qn->value)->u_str);
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
return "UnknownType";
|
||||
@ -546,6 +588,7 @@ void py_obj_print(py_obj_t o_in) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("<? %d>", o->kind);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
@ -587,8 +630,25 @@ py_obj_t rt_load_const_str(qstr qstr) {
|
||||
|
||||
py_obj_t rt_load_name(qstr qstr) {
|
||||
// logic: search locals, globals, builtins
|
||||
DEBUG_OP_printf("load %s\n", qstr_str(qstr));
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(&map_name, qstr, false);
|
||||
DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(&map_locals, qstr, false);
|
||||
if (elem == NULL) {
|
||||
elem = py_qstr_map_lookup(&map_globals, qstr, false);
|
||||
if (elem == NULL) {
|
||||
elem = py_qstr_map_lookup(&map_builtins, qstr, false);
|
||||
if (elem == NULL) {
|
||||
printf("name doesn't exist: %s\n", qstr_str(qstr));
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return elem->value;
|
||||
}
|
||||
|
||||
py_obj_t rt_load_global(qstr qstr) {
|
||||
// logic: search globals, builtins
|
||||
DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(&map_globals, qstr, false);
|
||||
if (elem == NULL) {
|
||||
elem = py_qstr_map_lookup(&map_builtins, qstr, false);
|
||||
if (elem == NULL) {
|
||||
@ -599,10 +659,6 @@ py_obj_t rt_load_name(qstr qstr) {
|
||||
return elem->value;
|
||||
}
|
||||
|
||||
py_obj_t rt_load_global(qstr qstr) {
|
||||
return rt_load_name(qstr); // TODO
|
||||
}
|
||||
|
||||
py_obj_t rt_load_build_class() {
|
||||
DEBUG_OP_printf("load_build_class\n");
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(&map_builtins, q___build_class__, false);
|
||||
@ -614,8 +670,13 @@ py_obj_t rt_load_build_class() {
|
||||
}
|
||||
|
||||
void rt_store_name(qstr qstr, py_obj_t obj) {
|
||||
DEBUG_OP_printf("store %s <- %p\n", qstr_str(qstr), obj);
|
||||
py_qstr_map_lookup(&map_name, qstr, true)->value = obj;
|
||||
DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
|
||||
py_qstr_map_lookup(&map_locals, qstr, true)->value = obj;
|
||||
}
|
||||
|
||||
void rt_store_global(qstr qstr, py_obj_t obj) {
|
||||
DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
|
||||
py_qstr_map_lookup(&map_globals, qstr, true)->value = obj;
|
||||
}
|
||||
|
||||
py_obj_t rt_unary_op(int op, py_obj_t arg) {
|
||||
@ -803,6 +864,18 @@ py_obj_t rt_call_function_0(py_obj_t fun) {
|
||||
assert(o->u_fun_asm.n_args == 0);
|
||||
DEBUG_OP_printf("calling inline asm %p with no args\n", o->u_fun_asm.fun);
|
||||
return rt_convert_val_from_inline_asm(((inline_asm_fun_0_t)o->u_fun_asm.fun)());
|
||||
} else if (IS_O(fun, O_BOUND_METH)) {
|
||||
py_obj_base_t *o = fun;
|
||||
DEBUG_OP_printf("calling bound method %p with self and no args\n", o->u_bound_meth.meth);
|
||||
return rt_call_function_1(o->u_bound_meth.meth, o->u_bound_meth.self);
|
||||
} else if (IS_O(fun, O_CLASS)) {
|
||||
// instantiate an instance of a class
|
||||
DEBUG_OP_printf("instantiate object of class %p with no args\n", fun);
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_OBJ;
|
||||
o->u_obj.class = fun;
|
||||
o->u_obj.members = py_map_new(MAP_QSTR, 0);
|
||||
return o;
|
||||
} else {
|
||||
printf("fun0:%p\n", fun);
|
||||
assert(0);
|
||||
@ -817,7 +890,10 @@ py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg) {
|
||||
return ((py_fun_1_t)o->u_fun.fun)(arg);
|
||||
} else if (IS_O(fun, O_FUN_BC)) {
|
||||
py_obj_base_t *o = fun;
|
||||
assert(o->u_fun_bc.n_args == 1);
|
||||
if (o->u_fun_bc.n_args != 1) {
|
||||
printf("rt_call_function_1: trying to pass 1 argument to a function that takes %d arguments\n", o->u_fun_bc.n_args);
|
||||
assert(0);
|
||||
}
|
||||
DEBUG_OP_printf("calling byte code %p with 1 arg\n", o->u_fun_bc.code);
|
||||
return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, &arg, 1);
|
||||
} else if (IS_O(fun, O_FUN_ASM)) {
|
||||
@ -845,8 +921,8 @@ py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2) {
|
||||
assert(o->u_fun_bc.n_args == 2);
|
||||
DEBUG_OP_printf("calling byte code %p with 2 args\n", o->u_fun_bc.code);
|
||||
py_obj_t args[2];
|
||||
args[0] = arg1;
|
||||
args[1] = arg2;
|
||||
args[1] = arg1;
|
||||
args[0] = arg2;
|
||||
return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, &args[0], 2);
|
||||
} else if (IS_O(fun, O_FUN_ASM)) {
|
||||
py_obj_base_t *o = fun;
|
||||
@ -859,6 +935,19 @@ py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2) {
|
||||
}
|
||||
}
|
||||
|
||||
// args are in reverse order in the array
|
||||
py_obj_t rt_call_function_n(py_obj_t fun, int n_args, const py_obj_t *args) {
|
||||
if (IS_O(fun, O_FUN_BC)) {
|
||||
py_obj_base_t *o = fun;
|
||||
assert(o->u_fun_bc.n_args == n_args);
|
||||
DEBUG_OP_printf("calling byte code %p with %d args\n", o->u_fun_bc.code, n_args);
|
||||
return py_execute_byte_code(o->u_fun_bc.code, o->u_fun_bc.len, args, n_args);
|
||||
} else {
|
||||
assert(0);
|
||||
return py_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
py_obj_t rt_call_method_1(py_obj_t fun, py_obj_t self) {
|
||||
DEBUG_OP_printf("call method %p %p\n", fun, self);
|
||||
if (self == NULL) {
|
||||
@ -877,6 +966,13 @@ py_obj_t rt_call_method_2(py_obj_t fun, py_obj_t self, py_obj_t arg) {
|
||||
}
|
||||
}
|
||||
|
||||
// args contains: arg(n_args-1) arg(n_args-2) ... arg(0) self/NULL fun
|
||||
// if n_args==0 then there are only self/NULL and fun
|
||||
py_obj_t rt_call_method_n(int n_args, const py_obj_t *args) {
|
||||
DEBUG_OP_printf("call method %p %p %d args\n", args[n_args + 1], args[n_args] , n_args);
|
||||
return rt_call_function_n(args[n_args + 1], n_args + ((args[n_args] == NULL) ? 0 : 1), args);
|
||||
}
|
||||
|
||||
// items are in reverse order
|
||||
py_obj_t rt_build_list(int n_args, py_obj_t *items) {
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
@ -964,6 +1060,107 @@ py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value) {
|
||||
return map;
|
||||
}
|
||||
|
||||
py_obj_t build_bound_method(py_obj_t self, py_obj_t meth) {
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_BOUND_METH;
|
||||
o->u_bound_meth.meth = meth;
|
||||
o->u_bound_meth.self = self;
|
||||
return o;
|
||||
}
|
||||
|
||||
py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
|
||||
DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
|
||||
if (IS_O(base, O_LIST) && attr == q_append) {
|
||||
return build_bound_method(base, fun_list_append);
|
||||
} else if (IS_O(base, O_CLASS)) {
|
||||
py_obj_base_t *o = base;
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.locals, attr, false);
|
||||
if (elem == NULL) {
|
||||
goto no_attr;
|
||||
}
|
||||
return elem->value;
|
||||
} else if (IS_O(base, O_OBJ)) {
|
||||
// logic: look in obj members then class locals (TODO check this against CPython)
|
||||
py_obj_base_t *o = base;
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
|
||||
if (elem != NULL) {
|
||||
// object member, always treated as a value
|
||||
return elem->value;
|
||||
}
|
||||
elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
|
||||
if (elem != NULL) {
|
||||
if (py_obj_is_callable(elem->value)) {
|
||||
// class member is callable so build a bound method
|
||||
return build_bound_method(base, elem->value);
|
||||
} else {
|
||||
// class member is a value, so just return that value
|
||||
return elem->value;
|
||||
}
|
||||
}
|
||||
goto no_attr;
|
||||
}
|
||||
|
||||
no_attr:
|
||||
printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
|
||||
assert(0);
|
||||
return py_const_none;
|
||||
}
|
||||
|
||||
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
|
||||
DEBUG_OP_printf("load method %s\n", qstr_str(attr));
|
||||
if (IS_O(base, O_LIST) && attr == q_append) {
|
||||
dest[1] = fun_list_append;
|
||||
dest[0] = base;
|
||||
return;
|
||||
} else if (IS_O(base, O_OBJ)) {
|
||||
// logic: look in obj members then class locals (TODO check this against CPython)
|
||||
py_obj_base_t *o = base;
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.members, attr, false);
|
||||
if (elem != NULL) {
|
||||
// object member, always treated as a value
|
||||
dest[1] = elem->value;
|
||||
dest[0] = NULL;
|
||||
return;
|
||||
}
|
||||
elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
|
||||
if (elem != NULL) {
|
||||
if (py_obj_is_callable(elem->value)) {
|
||||
// class member is callable so build a bound method
|
||||
dest[1] = elem->value;
|
||||
dest[0] = base;
|
||||
return;
|
||||
} else {
|
||||
// class member is a value, so just return that value
|
||||
dest[1] = elem->value;
|
||||
dest[0] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
goto no_attr;
|
||||
}
|
||||
|
||||
no_attr:
|
||||
dest[1] = rt_load_attr(base, attr);
|
||||
dest[0] = NULL;
|
||||
}
|
||||
|
||||
void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val) {
|
||||
DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), val);
|
||||
if (IS_O(base, O_OBJ)) {
|
||||
// logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
|
||||
py_obj_base_t *o = base;
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
|
||||
if (elem != NULL) {
|
||||
elem->value = val;
|
||||
} else {
|
||||
elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = val;
|
||||
}
|
||||
} else {
|
||||
printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
|
||||
if (IS_O(base, O_LIST) && IS_SMALL_INT(index)) {
|
||||
// list store
|
||||
@ -985,44 +1182,6 @@ void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
py_obj_t build_bound_method(py_obj_t self, py_obj_t meth) {
|
||||
py_obj_base_t *o = m_new(py_obj_base_t, 1);
|
||||
o->kind = O_BOUND_METH;
|
||||
o->u_bound_meth.meth = meth;
|
||||
o->u_bound_meth.self = self;
|
||||
return o;
|
||||
}
|
||||
|
||||
py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
|
||||
DEBUG_OP_printf("load %s\n", qstr_str(attr));
|
||||
if (IS_O(base, O_LIST) && attr == q_append) {
|
||||
return build_bound_method(base, fun_list_append);
|
||||
} else if (IS_O(base, O_CLASS)) {
|
||||
py_obj_base_t *o = base;
|
||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_class.map, attr, false);
|
||||
if (elem == NULL) {
|
||||
printf("Nope! %s\n", qstr_str(attr));
|
||||
assert(0);
|
||||
}
|
||||
return elem->value;
|
||||
} else {
|
||||
printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
|
||||
assert(0);
|
||||
return py_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
|
||||
DEBUG_OP_printf("load method %s\n", qstr_str(attr));
|
||||
if (IS_O(base, O_LIST) && attr == q_append) {
|
||||
dest[1] = fun_list_append;
|
||||
dest[0] = base;
|
||||
} else {
|
||||
dest[1] = rt_load_attr(base, attr);
|
||||
dest[0] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *rt_fun_table[RT_F_NUMBER_OF] = {
|
||||
rt_load_const_str,
|
||||
rt_load_name,
|
||||
|
@ -100,6 +100,7 @@ py_obj_t rt_load_name(qstr qstr);
|
||||
py_obj_t rt_load_global(qstr qstr);
|
||||
py_obj_t rt_load_build_class();
|
||||
void rt_store_name(qstr qstr, py_obj_t obj);
|
||||
void rt_store_global(qstr qstr, py_obj_t obj);
|
||||
py_obj_t rt_unary_op(int op, py_obj_t arg);
|
||||
py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs);
|
||||
py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs);
|
||||
@ -113,10 +114,12 @@ py_obj_t rt_call_function_1(py_obj_t fun, py_obj_t arg);
|
||||
py_obj_t rt_call_function_2(py_obj_t fun, py_obj_t arg1, py_obj_t arg2);
|
||||
py_obj_t rt_call_method_1(py_obj_t fun, py_obj_t self);
|
||||
py_obj_t rt_call_method_2(py_obj_t fun, py_obj_t self, py_obj_t arg);
|
||||
py_obj_t rt_call_method_n(int n_args, const py_obj_t *args);
|
||||
py_obj_t rt_build_list(int n_args, py_obj_t *items);
|
||||
py_obj_t rt_build_map(int n_args);
|
||||
py_obj_t rt_store_map(py_obj_t map, py_obj_t key, py_obj_t value);
|
||||
py_obj_t rt_build_set(int n_args, py_obj_t *items);
|
||||
void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t val);
|
||||
py_obj_t rt_load_attr(py_obj_t base, qstr attr);
|
||||
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest);
|
||||
void rt_store_attr(py_obj_t base, qstr attr, py_obj_t val);
|
||||
void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t val);
|
||||
|
26
py/vm.c
26
py/vm.c
@ -14,8 +14,9 @@
|
||||
#define PUSH(val) *--sp = (val)
|
||||
#define POP() (*sp++)
|
||||
|
||||
py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args) {
|
||||
byte *ip = code;
|
||||
// args are in reverse order in array
|
||||
py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args, uint n_args) {
|
||||
const byte *ip = code;
|
||||
py_obj_t stack[10];
|
||||
py_obj_t *sp = &stack[10]; // stack grows down, sp points to top of stack
|
||||
machine_uint_t unum;
|
||||
@ -27,14 +28,14 @@ py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args)
|
||||
// init args
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
if (i == 0) {
|
||||
fast0 = args[0];
|
||||
fast0 = args[n_args - 1];
|
||||
} else if (i == 1) {
|
||||
fast1 = args[1];
|
||||
fast1 = args[n_args - 2];
|
||||
} else if (i == 2) {
|
||||
fast2 = args[2];
|
||||
fast2 = args[n_args - 3];
|
||||
} else {
|
||||
assert(i - 3 < 4);
|
||||
fastn[i - 3] = args[i];
|
||||
fastn[i - 3] = args[n_args - 1 - i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +138,12 @@ py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args)
|
||||
rt_store_name(qstr, POP());
|
||||
break;
|
||||
|
||||
case PYBC_STORE_ATTR:
|
||||
DECODE_QSTR;
|
||||
rt_store_attr(sp[0], qstr, sp[1]);
|
||||
sp += 2;
|
||||
break;
|
||||
|
||||
case PYBC_STORE_SUBSCR:
|
||||
rt_store_subscr(sp[1], sp[0], sp[2]);
|
||||
sp += 3;
|
||||
@ -254,9 +261,12 @@ py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args)
|
||||
} else if ((unum & 0xff) == 1) {
|
||||
obj2 = *sp++; // the first argument
|
||||
obj1 = *sp++; // the self object (or NULL)
|
||||
*sp = rt_call_function_2(*sp, obj1, obj2);
|
||||
*sp = rt_call_method_2(*sp, obj1, obj2);
|
||||
} else {
|
||||
assert(0);
|
||||
unum = unum & 0xff;
|
||||
obj1 = rt_call_method_n(unum, sp);
|
||||
sp += unum + 1;
|
||||
*sp = obj1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
5
py/vm.h
5
py/vm.h
@ -25,8 +25,7 @@
|
||||
#define PYBC_STORE_NAME (0x34) // qstr
|
||||
#define PYBC_STORE_GLOBAL (0x35) // qstr
|
||||
#define PYBC_STORE_ATTR (0x36) // qstr
|
||||
#define PYBC_STORE_LOCALS (0x37)
|
||||
#define PYBC_STORE_SUBSCR (0x38)
|
||||
#define PYBC_STORE_SUBSCR (0x37)
|
||||
|
||||
#define PYBC_DELETE_FAST_N (0x39) // uint
|
||||
#define PYBC_DELETE_NAME (0x3a) // qstr
|
||||
@ -94,4 +93,4 @@
|
||||
#define PYBC_IMPORT_FROM (0xe1)
|
||||
#define PYBC_IMPORT_STAR (0xe2)
|
||||
|
||||
py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args);
|
||||
py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args, uint n_args);
|
||||
|
Loading…
Reference in New Issue
Block a user