diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/compile.c | 56 | ||||
-rw-r--r-- | py/compile.h | 2 | ||||
-rw-r--r-- | py/parse.c | 17 | ||||
-rw-r--r-- | py/parse.h | 10 | ||||
-rw-r--r-- | py/runtime.c | 84 | ||||
-rw-r--r-- | py/runtime.h | 2 |
6 files changed, 131 insertions, 40 deletions
diff --git a/py/compile.c b/py/compile.c index 0967c855c4..d622242b62 100644 --- a/py/compile.c +++ b/py/compile.c @@ -44,11 +44,14 @@ typedef struct _compiler_t { qstr qstr___doc__; qstr qstr_assertion_error; qstr qstr_micropython; + qstr qstr_byte_code; qstr qstr_native; qstr qstr_viper; qstr qstr_asm_thumb; + bool is_repl; pass_kind_t pass; + bool had_error; // try to keep compiler clean from nlr int next_label; @@ -196,7 +199,7 @@ static int comp_next_label(compiler_t *comp) { } static scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, py_parse_node_t pn, uint emit_options) { - scope_t *scope = scope_new(kind, pn, rt_get_new_unique_code_id(), emit_options); + scope_t *scope = scope_new(kind, pn, rt_get_unique_code_id(kind == SCOPE_MODULE), emit_options); scope->parent = comp->scope_cur; scope->next = NULL; if (comp->scope_head == NULL) { @@ -855,7 +858,8 @@ static bool compile_built_in_decorator(compiler_t *comp, int name_len, py_parse_ } qstr attr = PY_PARSE_NODE_LEAF_ARG(name_nodes[1]); - if (0) { + if (attr == comp->qstr_byte_code) { + *emit_options = EMIT_OPT_BYTE_CODE; #if MICROPY_EMIT_NATIVE } else if (attr == comp->qstr_native) { *emit_options = EMIT_OPT_NATIVE_PYTHON; @@ -1046,7 +1050,13 @@ void compile_continue_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { } void compile_return_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { + if (comp->scope_cur->kind != SCOPE_FUNCTION) { + printf("SyntaxError: 'return' outside function\n"); + comp->had_error = true; + return; + } if (PY_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // no argument to 'return', so return None EMIT(load_const_tok, PY_TOKEN_KW_NONE); } else if (PY_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) { // special case when returning an if-expression; to match CPython optimisation @@ -1566,11 +1576,21 @@ void compile_with_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { void compile_expr_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { if (PY_PARSE_NODE_IS_NULL(pns->nodes[1])) { - if (PY_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !PY_PARSE_NODE_IS_ID(pns->nodes[0])) { - // do nothing with a lonely constant + if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { + // for REPL, evaluate then print the expression + EMIT(load_id, qstr_from_str_static("__repl_print__")); + compile_node(comp, pns->nodes[0]); + EMIT(call_function, 1, 0, false, false); + EMIT(pop_top); + } else { - compile_node(comp, pns->nodes[0]); // just an expression - EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack + // for non-REPL, evaluate then discard the expression + if (PY_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !PY_PARSE_NODE_IS_ID(pns->nodes[0])) { + // do nothing with a lonely constant + } else { + compile_node(comp, pns->nodes[0]); // just an expression + EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack + } } } else { py_parse_node_struct_t *pns1 = (py_parse_node_struct_t*)pns->nodes[1]; @@ -2287,6 +2307,7 @@ void compile_node(compiler_t *comp, py_parse_node_t pn) { case PY_PARSE_NODE_TOKEN: if (arg == PY_TOKEN_NEWLINE) { // this can occur when file_input lets through a NEWLINE (eg if file starts with a newline) + // or when single_input lets through a NEWLINE (user enters a blank line) // do nothing } else { EMIT(load_const_tok, arg); @@ -2299,7 +2320,7 @@ void compile_node(compiler_t *comp, py_parse_node_t pn) { compile_function_t f = compile_function[PY_PARSE_NODE_STRUCT_KIND(pns)]; if (f == NULL) { printf("node %u cannot be compiled\n", (uint)PY_PARSE_NODE_STRUCT_KIND(pns)); - parse_node_show(pn, 0); + py_parse_node_show(pn, 0); assert(0); } else { f(comp, pns); @@ -2481,14 +2502,17 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { scope->stack_size = 0; } +#if MICROPY_EMIT_CPYTHON if (comp->pass == PASS_3) { - //printf("----\n"); scope_print_info(scope); } +#endif // compile if (scope->kind == SCOPE_MODULE) { - check_for_doc_string(comp, scope->pn); + if (!comp->is_repl) { + check_for_doc_string(comp, scope->pn); + } compile_node(comp, scope->pn); EMIT(load_const_tok, PY_TOKEN_KW_NONE); EMIT(return_value); @@ -2731,7 +2755,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { } } -void py_compile(py_parse_node_t pn) { +bool py_compile(py_parse_node_t pn, bool is_repl) { compiler_t *comp = m_new(compiler_t, 1); comp->qstr___class__ = qstr_from_str_static("__class__"); @@ -2742,10 +2766,14 @@ void py_compile(py_parse_node_t pn) { comp->qstr___doc__ = qstr_from_str_static("__doc__"); comp->qstr_assertion_error = qstr_from_str_static("AssertionError"); comp->qstr_micropython = qstr_from_str_static("micropython"); + comp->qstr_byte_code = qstr_from_str_static("byte_code"); comp->qstr_native = qstr_from_str_static("native"); comp->qstr_viper = qstr_from_str_static("viper"); comp->qstr_asm_thumb = qstr_from_str_static("asm_thumb"); + comp->is_repl = is_repl; + comp->had_error = false; + comp->break_label = 0; comp->continue_label = 0; comp->except_nest_level = 0; @@ -2764,7 +2792,7 @@ void py_compile(py_parse_node_t pn) { comp->emit_inline_asm = NULL; comp->emit_inline_asm_method_table = NULL; uint max_num_labels = 0; - for (scope_t *s = comp->scope_head; s != NULL; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { if (false) { #if MICROPY_EMIT_INLINE_THUMB } else if (s->emit_options == EMIT_OPT_ASM_THUMB) { @@ -2781,7 +2809,7 @@ void py_compile(py_parse_node_t pn) { } // compute some things related to scope and identifiers - for (scope_t *s = comp->scope_head; s != NULL; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { compile_scope_compute_things(comp, s); } @@ -2796,7 +2824,7 @@ void py_compile(py_parse_node_t pn) { #if MICROPY_EMIT_INLINE_THUMB emit_inline_asm_t *emit_inline_thumb = NULL; #endif - for (scope_t *s = comp->scope_head; s != NULL; s = s->next) { + for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) { if (false) { // dummy @@ -2857,4 +2885,6 @@ void py_compile(py_parse_node_t pn) { } m_free(comp); + + return !comp->had_error; } diff --git a/py/compile.h b/py/compile.h index 339acca0c0..c15b40aa67 100644 --- a/py/compile.h +++ b/py/compile.h @@ -1 +1 @@ -void py_compile(py_parse_node_t pn); +bool py_compile(py_parse_node_t pn, bool is_repl); diff --git a/py/parse.c b/py/parse.c index 7c45cd7d75..b0aeb1ab52 100644 --- a/py/parse.c +++ b/py/parse.c @@ -128,7 +128,7 @@ py_parse_node_struct_t *parse_node_new_struct(int rule_id, int num_args) { return pn; } -void parse_node_show(py_parse_node_t pn, int indent) { +void py_parse_node_show(py_parse_node_t pn, int indent) { for (int i = 0; i < indent; i++) { printf(" "); } @@ -155,7 +155,7 @@ void parse_node_show(py_parse_node_t pn, int indent) { printf("rule(%u) (n=%d)\n", (uint)PY_PARSE_NODE_STRUCT_KIND(pns2), n); #endif for (int i = 0; i < n; i++) { - parse_node_show(pns2->nodes[i], indent + 2); + py_parse_node_show(pns2->nodes[i], indent + 2); } } } @@ -164,7 +164,7 @@ void parse_node_show(py_parse_node_t pn, int indent) { static void result_stack_show(parser_t *parser) { printf("result stack, most recent first\n"); for (int i = parser->result_stack_top - 1; i >= 0; i--) { - parse_node_show(parser->result_stack[i], 0); + py_parse_node_show(parser->result_stack[i], 0); } } */ @@ -251,8 +251,7 @@ static void push_result_rule(parser_t *parser, rule_t *rule, int num_args) { push_result_node(parser, (py_parse_node_t)pn); } -py_parse_node_t py_parse(py_lexer_t *lex, int wanted_rule) { - wanted_rule = RULE_file_input; +py_parse_node_t py_parse(py_lexer_t *lex, py_parse_input_kind_t input_kind) { parser_t *parser = m_new(parser_t, 1); parser->rule_stack_alloc = 64; parser->rule_stack_top = 0; @@ -261,7 +260,13 @@ py_parse_node_t py_parse(py_lexer_t *lex, int wanted_rule) { parser->result_stack = m_new(py_parse_node_t, 1000); parser->result_stack_top = 0; - push_rule(parser, rules[wanted_rule], 0); + int top_level_rule; + switch (input_kind) { + case PY_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; + //case PY_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; + default: top_level_rule = RULE_file_input; + } + push_rule(parser, rules[top_level_rule], 0); uint n, i; bool backtrack = false; diff --git a/py/parse.h b/py/parse.h index a87ee08b90..722d9f6c20 100644 --- a/py/parse.h +++ b/py/parse.h @@ -54,6 +54,12 @@ typedef struct _py_parse_node_struct_t { py_parse_node_t py_parse_node_new_leaf(machine_int_t kind, machine_int_t arg); -void parse_node_show(py_parse_node_t pn, int indent); +void py_parse_node_show(py_parse_node_t pn, int indent); -py_parse_node_t py_parse(struct _py_lexer_t *lex, int wanted_rule); +typedef enum { + PY_PARSE_SINGLE_INPUT, + PY_PARSE_FILE_INPUT, + PY_PARSE_EVAL_INPUT, +} py_parse_input_kind_t; + +py_parse_node_t py_parse(struct _py_lexer_t *lex, py_parse_input_kind_t input_kind); diff --git a/py/runtime.c b/py/runtime.c index 5c9d154e2f..d367530ccc 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -192,11 +192,7 @@ void py_map_init(py_map_t *map, py_map_kind_t kind, int n) { map->kind = kind; map->alloc = get_doubling_prime_greater_or_equal_to(n + 1); map->used = 0; - map->table = m_new(py_map_elem_t, map->alloc); - for (int i = 0; i < map->alloc; i++) { - map->table[i].key = NULL; - map->table[i].value = NULL; - } + map->table = m_new0(py_map_elem_t, map->alloc); } py_map_t *py_map_new(py_map_kind_t kind, int n) { @@ -205,9 +201,15 @@ py_map_t *py_map_new(py_map_kind_t kind, int n) { return map; } -int py_obj_hash(py_obj_t o_in) { - if (IS_SMALL_INT(o_in)) { +machine_int_t py_obj_hash(py_obj_t o_in) { + if (o_in == py_const_false) { + return 0; // needs to hash to same as the integer 0, since False==0 + } else if (o_in == py_const_true) { + return 1; // needs to hash to same as the integer 1, since True==1 + } else if (IS_SMALL_INT(o_in)) { return FROM_SMALL_INT(o_in); + } else if (IS_O(o_in, O_CONST)) { + return (machine_int_t)o_in; } else if (IS_O(o_in, O_STR)) { return ((py_obj_base_t*)o_in)->u_str; } else { @@ -216,11 +218,32 @@ int py_obj_hash(py_obj_t o_in) { } } +// this function implements the '==' operator (and so the inverse of '!=') +// from the python language reference: +// "The objects need not have the same type. If both are numbers, they are converted +// to a common type. Otherwise, the == and != operators always consider objects of +// different types to be unequal." +// note also that False==0 and True==1 are true expressions bool py_obj_equal(py_obj_t o1, py_obj_t o2) { if (o1 == o2) { return true; - } else if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) { - return false; + } else if (IS_SMALL_INT(o1) || IS_SMALL_INT(o2)) { + if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) { + return false; + } else { + if (IS_SMALL_INT(o2)) { + py_obj_t temp = o1; o1 = o2; o2 = temp; + } + // o1 is the SMALL_INT, o2 is not + py_small_int_t val = FROM_SMALL_INT(o1); + if (o2 == py_const_false) { + return val == 0; + } else if (o2 == py_const_true) { + return val == 1; + } else { + return false; + } + } } else if (IS_O(o1, O_STR) && IS_O(o2, O_STR)) { return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str; } else { @@ -249,7 +272,7 @@ py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_n py_map_elem_t *old_table = map->table; map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1); map->used = 0; - map->table = m_new(py_map_elem_t, map->alloc); + map->table = m_new0(py_map_elem_t, map->alloc); for (int i = 0; i < old_alloc; i++) { if (old_table[i].key != NULL) { py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value; @@ -268,9 +291,11 @@ py_map_elem_t* py_map_lookup_helper(py_map_t *map, py_obj_t index, bool add_if_n } } else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) { // found it + /* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x if (add_if_not_found) { elem->key = index; } + */ return elem; } else { // not yet found, keep searching in this table @@ -395,6 +420,7 @@ static qstr q___build_class__; static qstr q___next__; static qstr q_AttributeError; static qstr q_IndexError; +static qstr q_KeyError; static qstr q_NameError; static qstr q_TypeError; @@ -431,6 +457,14 @@ static py_code_t *unique_codes; py_obj_t fun_list_append; py_obj_t fun_gen_instance_next; +py_obj_t py_builtin___repl_print__(py_obj_t o) { + if (o != py_const_none) { + py_obj_print(o); + printf("\n"); + } + return py_const_none; +} + py_obj_t py_builtin_print(py_obj_t o) { if (IS_O(o, O_STR)) { // special case, print string raw @@ -492,6 +526,7 @@ void rt_init() { q___next__ = qstr_from_str_static("__next__"); q_AttributeError = qstr_from_str_static("AttributeError"); q_IndexError = qstr_from_str_static("IndexError"); + q_KeyError = qstr_from_str_static("KeyError"); q_NameError = qstr_from_str_static("NameError"); q_TypeError = qstr_from_str_static("TypeError"); @@ -505,12 +540,13 @@ void rt_init() { 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, qstr_from_str_static("__repl_print__"), true)->value = rt_make_function_1(py_builtin___repl_print__); py_qstr_map_lookup(&map_builtins, q_print, true)->value = rt_make_function_1(py_builtin_print); py_qstr_map_lookup(&map_builtins, q_len, true)->value = rt_make_function_1(py_builtin_len); py_qstr_map_lookup(&map_builtins, q___build_class__, true)->value = rt_make_function_2(py_builtin___build_class__); py_qstr_map_lookup(&map_builtins, qstr_from_str_static("range"), true)->value = rt_make_function_1(py_builtin_range); - next_unique_code_id = 1; + next_unique_code_id = 2; // 1 is reserved for the __main__ module scope unique_codes = NULL; fun_list_append = rt_make_function_2(rt_list_append); @@ -529,8 +565,12 @@ void rt_deinit() { #endif } -int rt_get_new_unique_code_id() { - return next_unique_code_id++; +int rt_get_unique_code_id(bool is_main_module) { + if (is_main_module) { + return 1; + } else { + return next_unique_code_id++; + } } static void alloc_unique_codes() { @@ -896,8 +936,17 @@ py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) { DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs); if (op == RT_BINARY_OP_SUBSCR) { if ((IS_O(lhs, O_TUPLE) || IS_O(lhs, O_LIST))) { + // tuple/list load uint index = get_index(lhs, rhs); return ((py_obj_base_t*)lhs)->u_tuple_list.items[index]; + } else if (IS_O(lhs, O_MAP)) { + // map load + py_map_elem_t *elem = py_map_lookup(lhs, rhs, false); + if (elem == NULL) { + nlr_jump(py_obj_new_exception_2(q_KeyError, "<value>", NULL, NULL)); + } else { + return elem->value; + } } else { assert(0); } @@ -1409,16 +1458,16 @@ no_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); +void rt_store_attr(py_obj_t base, qstr attr, py_obj_t value) { + DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); 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; + elem->value = value; } else { - elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = val; + elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, true)->value = value; } } else { printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr)); @@ -1427,6 +1476,7 @@ 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 value) { + DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value); if (IS_O(base, O_LIST)) { // list store uint i = get_index(base, index); diff --git a/py/runtime.h b/py/runtime.h index 8d68adccf5..e676f14c08 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -91,7 +91,7 @@ extern py_obj_t py_const_stop_iteration; // special object indicating end of ite void rt_init(); void rt_deinit(); -int rt_get_new_unique_code_id(); +int rt_get_unique_code_id(bool is_main_module); void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); void rt_assign_native_code(int unique_code_id, py_fun_t f, uint len, int n_args); void rt_assign_inline_asm_code(int unique_code_id, py_fun_t f, uint len, int n_args); |