diff --git a/py/compile.c b/py/compile.c index 0967c855c..d622242b6 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 339acca0c..c15b40aa6 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 7c45cd7d7..b0aeb1ab5 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 a87ee08b9..722d9f6c2 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 5c9d154e2..d367530cc 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, "", 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 8d68adccf..e676f14c0 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); diff --git a/unix/Makefile b/unix/Makefile index 0c8c449e7..a2c9b9f5f 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -31,7 +31,7 @@ PY_O = \ vm.o \ OBJ = $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(PY_O)) -LIB = +LIB = -lreadline PROG = py $(PROG): $(BUILD) $(OBJ) diff --git a/unix/main.c b/unix/main.c index 8ceaf4264..018e1a970 100644 --- a/unix/main.c +++ b/unix/main.c @@ -10,61 +10,152 @@ #include "compile.h" #include "runtime.h" -int main(int argc, char **argv) { - qstr_init(); - rt_init(); +#include - if (argc != 2) { - printf("usage: py \n"); - return 1; +bool str_startswith_word(const char *str, const char *head) { + int i; + for (i = 0; str[i] && head[i]; i++) { + if (str[i] != head[i]) { + return false; + } } - py_lexer_t *lex = py_lexer_from_file(argv[1]); + return head[i] == '\0' && (str[i] == '\0' || !g_unichar_isalpha(str[i])); +} + +bool is_compound_stmt(const char *line) { + // TODO also "compound" if unmatched open bracket + return + str_startswith_word(line, "if") + || str_startswith_word(line, "while") + || str_startswith_word(line, "for") + || str_startswith_word(line, "true") + || str_startswith_word(line, "with") + || str_startswith_word(line, "def") + || str_startswith_word(line, "class") + || str_startswith_word(line, "@"); +} + +char *str_join(const char *s1, int sep_char, const char *s2) { + int l1 = strlen(s1); + int l2 = strlen(s2); + char *s = m_new(char, l1 + l2 + 2); + memcpy(s, s1, l1); + if (sep_char != 0) { + s[l1] = sep_char; + l1 += 1; + } + memcpy(s + l1, s2, l2); + return s; +} + +void do_repl() { + for (;;) { + char *line = readline(">>> "); + if (line == NULL) { + // EOF + return; + } + if (is_compound_stmt(line)) { + for (;;) { + char *line2 = readline("... "); + if (line2 == NULL || strlen(line2) == 0) { + break; + } + char *line3 = str_join(line, '\n', line2); + m_free(line); + m_free(line2); + line = line3; + } + } + py_lexer_t *lex = py_lexer_from_str_len("", line, strlen(line), false); + py_parse_node_t pn = py_parse(lex, PY_PARSE_SINGLE_INPUT); + if (pn != PY_PARSE_NODE_NULL) { + //py_parse_node_show(pn, 0); + bool comp_ok = py_compile(pn, true); + if (comp_ok) { + py_obj_t module_fun = rt_make_function_from_id(1); + if (module_fun != py_const_none) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + rt_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + py_obj_print((py_obj_t)nlr.ret_val); + printf("\n"); + } + } + } + } + } +} + +void do_file(const char *file) { + py_lexer_t *lex = py_lexer_from_file(file); //const char *pysrc = "def f():\n x=x+1\n print(42)\n"; //py_lexer_t *lex = py_lexer_from_str_len("<>", pysrc, strlen(pysrc), false); if (lex == NULL) { - return 1; + return; } if (0) { + // just tokenise while (!py_lexer_is_kind(lex, PY_TOKEN_END)) { py_token_show(py_lexer_cur(lex)); py_lexer_to_next(lex); } + py_lexer_free(lex); + } else { - py_parse_node_t pn = py_parse(lex, 0); + // compile + + py_parse_node_t pn = py_parse(lex, PY_PARSE_FILE_INPUT); if (pn != PY_PARSE_NODE_NULL) { //printf("----------------\n"); //parse_node_show(pn, 0); //printf("----------------\n"); - py_compile(pn); + bool comp_ok = py_compile(pn, false); //printf("----------------\n"); - } - } - py_lexer_free(lex); + py_lexer_free(lex); #if !MICROPY_EMIT_CPYTHON - if (1) { - // execute it - py_obj_t module_fun = rt_make_function_from_id(1); - if (module_fun != py_const_none) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - py_obj_t ret = rt_call_function_0(module_fun); - printf("done! got: "); - py_obj_print(ret); - printf("\n"); - nlr_pop(); - } else { - // uncaught exception - printf("exception: "); - py_obj_print((py_obj_t)nlr.ret_val); - printf("\n"); + if (1 && comp_ok) { + // execute it + py_obj_t module_fun = rt_make_function_from_id(1); + if (module_fun != py_const_none) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + py_obj_t ret = rt_call_function_0(module_fun); + printf("done! got: "); + py_obj_print(ret); + printf("\n"); + nlr_pop(); + } else { + // uncaught exception + printf("exception: "); + py_obj_print((py_obj_t)nlr.ret_val); + printf("\n"); + } + } } +#endif } } -#endif +} +int main(int argc, char **argv) { + qstr_init(); + rt_init(); + + if (argc == 1) { + do_repl(); + } else if (argc == 2) { + do_file(argv[1]); + } else { + printf("usage: py []\n"); + return 1; + } rt_deinit(); //printf("total bytes = %d\n", m_get_total_bytes_allocated());