Implement REPL.
This commit is contained in:
parent
7bbd110691
commit
5ac1b2efbd
56
py/compile.c
56
py/compile.c
@ -44,11 +44,14 @@ typedef struct _compiler_t {
|
|||||||
qstr qstr___doc__;
|
qstr qstr___doc__;
|
||||||
qstr qstr_assertion_error;
|
qstr qstr_assertion_error;
|
||||||
qstr qstr_micropython;
|
qstr qstr_micropython;
|
||||||
|
qstr qstr_byte_code;
|
||||||
qstr qstr_native;
|
qstr qstr_native;
|
||||||
qstr qstr_viper;
|
qstr qstr_viper;
|
||||||
qstr qstr_asm_thumb;
|
qstr qstr_asm_thumb;
|
||||||
|
|
||||||
|
bool is_repl;
|
||||||
pass_kind_t pass;
|
pass_kind_t pass;
|
||||||
|
bool had_error; // try to keep compiler clean from nlr
|
||||||
|
|
||||||
int next_label;
|
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) {
|
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->parent = comp->scope_cur;
|
||||||
scope->next = NULL;
|
scope->next = NULL;
|
||||||
if (comp->scope_head == 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]);
|
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
|
#if MICROPY_EMIT_NATIVE
|
||||||
} else if (attr == comp->qstr_native) {
|
} else if (attr == comp->qstr_native) {
|
||||||
*emit_options = EMIT_OPT_NATIVE_PYTHON;
|
*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) {
|
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])) {
|
if (PY_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
||||||
|
// no argument to 'return', so return None
|
||||||
EMIT(load_const_tok, PY_TOKEN_KW_NONE);
|
EMIT(load_const_tok, PY_TOKEN_KW_NONE);
|
||||||
} else if (PY_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {
|
} 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
|
// 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) {
|
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_NULL(pns->nodes[1])) {
|
||||||
if (PY_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !PY_PARSE_NODE_IS_ID(pns->nodes[0])) {
|
if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) {
|
||||||
// do nothing with a lonely constant
|
// 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 {
|
} else {
|
||||||
compile_node(comp, pns->nodes[0]); // just an expression
|
// for non-REPL, evaluate then discard the expression
|
||||||
EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack
|
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 {
|
} else {
|
||||||
py_parse_node_struct_t *pns1 = (py_parse_node_struct_t*)pns->nodes[1];
|
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:
|
case PY_PARSE_NODE_TOKEN:
|
||||||
if (arg == PY_TOKEN_NEWLINE) {
|
if (arg == PY_TOKEN_NEWLINE) {
|
||||||
// this can occur when file_input lets through a NEWLINE (eg if file starts with a 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
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
EMIT(load_const_tok, arg);
|
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)];
|
compile_function_t f = compile_function[PY_PARSE_NODE_STRUCT_KIND(pns)];
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
printf("node %u cannot be compiled\n", (uint)PY_PARSE_NODE_STRUCT_KIND(pns));
|
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);
|
assert(0);
|
||||||
} else {
|
} else {
|
||||||
f(comp, pns);
|
f(comp, pns);
|
||||||
@ -2481,14 +2502,17 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
|||||||
scope->stack_size = 0;
|
scope->stack_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_EMIT_CPYTHON
|
||||||
if (comp->pass == PASS_3) {
|
if (comp->pass == PASS_3) {
|
||||||
//printf("----\n");
|
|
||||||
scope_print_info(scope);
|
scope_print_info(scope);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// compile
|
// compile
|
||||||
if (scope->kind == SCOPE_MODULE) {
|
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);
|
compile_node(comp, scope->pn);
|
||||||
EMIT(load_const_tok, PY_TOKEN_KW_NONE);
|
EMIT(load_const_tok, PY_TOKEN_KW_NONE);
|
||||||
EMIT(return_value);
|
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);
|
compiler_t *comp = m_new(compiler_t, 1);
|
||||||
|
|
||||||
comp->qstr___class__ = qstr_from_str_static("__class__");
|
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___doc__ = qstr_from_str_static("__doc__");
|
||||||
comp->qstr_assertion_error = qstr_from_str_static("AssertionError");
|
comp->qstr_assertion_error = qstr_from_str_static("AssertionError");
|
||||||
comp->qstr_micropython = qstr_from_str_static("micropython");
|
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_native = qstr_from_str_static("native");
|
||||||
comp->qstr_viper = qstr_from_str_static("viper");
|
comp->qstr_viper = qstr_from_str_static("viper");
|
||||||
comp->qstr_asm_thumb = qstr_from_str_static("asm_thumb");
|
comp->qstr_asm_thumb = qstr_from_str_static("asm_thumb");
|
||||||
|
|
||||||
|
comp->is_repl = is_repl;
|
||||||
|
comp->had_error = false;
|
||||||
|
|
||||||
comp->break_label = 0;
|
comp->break_label = 0;
|
||||||
comp->continue_label = 0;
|
comp->continue_label = 0;
|
||||||
comp->except_nest_level = 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 = NULL;
|
||||||
comp->emit_inline_asm_method_table = NULL;
|
comp->emit_inline_asm_method_table = NULL;
|
||||||
uint max_num_labels = 0;
|
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 (false) {
|
||||||
#if MICROPY_EMIT_INLINE_THUMB
|
#if MICROPY_EMIT_INLINE_THUMB
|
||||||
} else if (s->emit_options == EMIT_OPT_ASM_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
|
// 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);
|
compile_scope_compute_things(comp, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2796,7 +2824,7 @@ void py_compile(py_parse_node_t pn) {
|
|||||||
#if MICROPY_EMIT_INLINE_THUMB
|
#if MICROPY_EMIT_INLINE_THUMB
|
||||||
emit_inline_asm_t *emit_inline_thumb = NULL;
|
emit_inline_asm_t *emit_inline_thumb = NULL;
|
||||||
#endif
|
#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) {
|
if (false) {
|
||||||
// dummy
|
// dummy
|
||||||
|
|
||||||
@ -2857,4 +2885,6 @@ void py_compile(py_parse_node_t pn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_free(comp);
|
m_free(comp);
|
||||||
|
|
||||||
|
return !comp->had_error;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
void py_compile(py_parse_node_t pn);
|
bool py_compile(py_parse_node_t pn, bool is_repl);
|
||||||
|
17
py/parse.c
17
py/parse.c
@ -128,7 +128,7 @@ py_parse_node_struct_t *parse_node_new_struct(int rule_id, int num_args) {
|
|||||||
return pn;
|
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++) {
|
for (int i = 0; i < indent; i++) {
|
||||||
printf(" ");
|
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);
|
printf("rule(%u) (n=%d)\n", (uint)PY_PARSE_NODE_STRUCT_KIND(pns2), n);
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < n; i++) {
|
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) {
|
static void result_stack_show(parser_t *parser) {
|
||||||
printf("result stack, most recent first\n");
|
printf("result stack, most recent first\n");
|
||||||
for (int i = parser->result_stack_top - 1; i >= 0; i--) {
|
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);
|
push_result_node(parser, (py_parse_node_t)pn);
|
||||||
}
|
}
|
||||||
|
|
||||||
py_parse_node_t py_parse(py_lexer_t *lex, int wanted_rule) {
|
py_parse_node_t py_parse(py_lexer_t *lex, py_parse_input_kind_t input_kind) {
|
||||||
wanted_rule = RULE_file_input;
|
|
||||||
parser_t *parser = m_new(parser_t, 1);
|
parser_t *parser = m_new(parser_t, 1);
|
||||||
parser->rule_stack_alloc = 64;
|
parser->rule_stack_alloc = 64;
|
||||||
parser->rule_stack_top = 0;
|
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 = m_new(py_parse_node_t, 1000);
|
||||||
parser->result_stack_top = 0;
|
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;
|
uint n, i;
|
||||||
bool backtrack = false;
|
bool backtrack = false;
|
||||||
|
10
py/parse.h
10
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);
|
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);
|
||||||
|
84
py/runtime.c
84
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->kind = kind;
|
||||||
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
|
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
|
||||||
map->used = 0;
|
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 < map->alloc; i++) {
|
|
||||||
map->table[i].key = NULL;
|
|
||||||
map->table[i].value = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
py_map_t *py_map_new(py_map_kind_t kind, int n) {
|
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;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
int py_obj_hash(py_obj_t o_in) {
|
machine_int_t py_obj_hash(py_obj_t o_in) {
|
||||||
if (IS_SMALL_INT(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);
|
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)) {
|
} else if (IS_O(o_in, O_STR)) {
|
||||||
return ((py_obj_base_t*)o_in)->u_str;
|
return ((py_obj_base_t*)o_in)->u_str;
|
||||||
} else {
|
} 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) {
|
bool py_obj_equal(py_obj_t o1, py_obj_t o2) {
|
||||||
if (o1 == o2) {
|
if (o1 == o2) {
|
||||||
return true;
|
return true;
|
||||||
} else if (IS_SMALL_INT(o1) && IS_SMALL_INT(o2)) {
|
} else if (IS_SMALL_INT(o1) || IS_SMALL_INT(o2)) {
|
||||||
return false;
|
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)) {
|
} 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;
|
return ((py_obj_base_t*)o1)->u_str == ((py_obj_base_t*)o2)->u_str;
|
||||||
} else {
|
} 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;
|
py_map_elem_t *old_table = map->table;
|
||||||
map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
|
map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
|
||||||
map->used = 0;
|
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++) {
|
for (int i = 0; i < old_alloc; i++) {
|
||||||
if (old_table[i].key != NULL) {
|
if (old_table[i].key != NULL) {
|
||||||
py_map_lookup_helper(map, old_table[i].key, true)->value = old_table[i].value;
|
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))) {
|
} else if (elem->key == index || (is_map_py_obj && py_obj_equal(elem->key, index))) {
|
||||||
// found it
|
// found it
|
||||||
|
/* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x
|
||||||
if (add_if_not_found) {
|
if (add_if_not_found) {
|
||||||
elem->key = index;
|
elem->key = index;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return elem;
|
return elem;
|
||||||
} else {
|
} else {
|
||||||
// not yet found, keep searching in this table
|
// not yet found, keep searching in this table
|
||||||
@ -395,6 +420,7 @@ static qstr q___build_class__;
|
|||||||
static qstr q___next__;
|
static qstr q___next__;
|
||||||
static qstr q_AttributeError;
|
static qstr q_AttributeError;
|
||||||
static qstr q_IndexError;
|
static qstr q_IndexError;
|
||||||
|
static qstr q_KeyError;
|
||||||
static qstr q_NameError;
|
static qstr q_NameError;
|
||||||
static qstr q_TypeError;
|
static qstr q_TypeError;
|
||||||
|
|
||||||
@ -431,6 +457,14 @@ static py_code_t *unique_codes;
|
|||||||
py_obj_t fun_list_append;
|
py_obj_t fun_list_append;
|
||||||
py_obj_t fun_gen_instance_next;
|
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) {
|
py_obj_t py_builtin_print(py_obj_t o) {
|
||||||
if (IS_O(o, O_STR)) {
|
if (IS_O(o, O_STR)) {
|
||||||
// special case, print string raw
|
// special case, print string raw
|
||||||
@ -492,6 +526,7 @@ void rt_init() {
|
|||||||
q___next__ = qstr_from_str_static("__next__");
|
q___next__ = qstr_from_str_static("__next__");
|
||||||
q_AttributeError = qstr_from_str_static("AttributeError");
|
q_AttributeError = qstr_from_str_static("AttributeError");
|
||||||
q_IndexError = qstr_from_str_static("IndexError");
|
q_IndexError = qstr_from_str_static("IndexError");
|
||||||
|
q_KeyError = qstr_from_str_static("KeyError");
|
||||||
q_NameError = qstr_from_str_static("NameError");
|
q_NameError = qstr_from_str_static("NameError");
|
||||||
q_TypeError = qstr_from_str_static("TypeError");
|
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_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_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_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_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, 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);
|
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;
|
unique_codes = NULL;
|
||||||
|
|
||||||
fun_list_append = rt_make_function_2(rt_list_append);
|
fun_list_append = rt_make_function_2(rt_list_append);
|
||||||
@ -529,8 +565,12 @@ void rt_deinit() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int rt_get_new_unique_code_id() {
|
int rt_get_unique_code_id(bool is_main_module) {
|
||||||
return next_unique_code_id++;
|
if (is_main_module) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return next_unique_code_id++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alloc_unique_codes() {
|
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);
|
DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
|
||||||
if (op == RT_BINARY_OP_SUBSCR) {
|
if (op == RT_BINARY_OP_SUBSCR) {
|
||||||
if ((IS_O(lhs, O_TUPLE) || IS_O(lhs, O_LIST))) {
|
if ((IS_O(lhs, O_TUPLE) || IS_O(lhs, O_LIST))) {
|
||||||
|
// tuple/list load
|
||||||
uint index = get_index(lhs, rhs);
|
uint index = get_index(lhs, rhs);
|
||||||
return ((py_obj_base_t*)lhs)->u_tuple_list.items[index];
|
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 {
|
} else {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
@ -1409,16 +1458,16 @@ no_attr:
|
|||||||
dest[0] = NULL;
|
dest[0] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_store_attr(py_obj_t base, qstr attr, py_obj_t 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), val);
|
DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
|
||||||
if (IS_O(base, O_OBJ)) {
|
if (IS_O(base, O_OBJ)) {
|
||||||
// logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
|
// logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
|
||||||
py_obj_base_t *o = base;
|
py_obj_base_t *o = base;
|
||||||
py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
|
py_map_elem_t *elem = py_qstr_map_lookup(o->u_obj.class->u_class.locals, attr, false);
|
||||||
if (elem != NULL) {
|
if (elem != NULL) {
|
||||||
elem->value = val;
|
elem->value = value;
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
printf("?AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr));
|
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) {
|
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)) {
|
if (IS_O(base, O_LIST)) {
|
||||||
// list store
|
// list store
|
||||||
uint i = get_index(base, index);
|
uint i = get_index(base, index);
|
||||||
|
@ -91,7 +91,7 @@ extern py_obj_t py_const_stop_iteration; // special object indicating end of ite
|
|||||||
|
|
||||||
void rt_init();
|
void rt_init();
|
||||||
void rt_deinit();
|
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_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_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);
|
void rt_assign_inline_asm_code(int unique_code_id, py_fun_t f, uint len, int n_args);
|
||||||
|
@ -31,7 +31,7 @@ PY_O = \
|
|||||||
vm.o \
|
vm.o \
|
||||||
|
|
||||||
OBJ = $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(PY_O))
|
OBJ = $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(PY_O))
|
||||||
LIB =
|
LIB = -lreadline
|
||||||
PROG = py
|
PROG = py
|
||||||
|
|
||||||
$(PROG): $(BUILD) $(OBJ)
|
$(PROG): $(BUILD) $(OBJ)
|
||||||
|
151
unix/main.c
151
unix/main.c
@ -10,61 +10,152 @@
|
|||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
#include <readline/readline.h>
|
||||||
qstr_init();
|
|
||||||
rt_init();
|
|
||||||
|
|
||||||
if (argc != 2) {
|
bool str_startswith_word(const char *str, const char *head) {
|
||||||
printf("usage: py <file>\n");
|
int i;
|
||||||
return 1;
|
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("<stdin>", 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";
|
//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);
|
//py_lexer_t *lex = py_lexer_from_str_len("<>", pysrc, strlen(pysrc), false);
|
||||||
if (lex == NULL) {
|
if (lex == NULL) {
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
|
// just tokenise
|
||||||
while (!py_lexer_is_kind(lex, PY_TOKEN_END)) {
|
while (!py_lexer_is_kind(lex, PY_TOKEN_END)) {
|
||||||
py_token_show(py_lexer_cur(lex));
|
py_token_show(py_lexer_cur(lex));
|
||||||
py_lexer_to_next(lex);
|
py_lexer_to_next(lex);
|
||||||
}
|
}
|
||||||
|
py_lexer_free(lex);
|
||||||
|
|
||||||
} else {
|
} 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) {
|
if (pn != PY_PARSE_NODE_NULL) {
|
||||||
//printf("----------------\n");
|
//printf("----------------\n");
|
||||||
//parse_node_show(pn, 0);
|
//parse_node_show(pn, 0);
|
||||||
//printf("----------------\n");
|
//printf("----------------\n");
|
||||||
py_compile(pn);
|
bool comp_ok = py_compile(pn, false);
|
||||||
//printf("----------------\n");
|
//printf("----------------\n");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
py_lexer_free(lex);
|
py_lexer_free(lex);
|
||||||
|
|
||||||
#if !MICROPY_EMIT_CPYTHON
|
#if !MICROPY_EMIT_CPYTHON
|
||||||
if (1) {
|
if (1 && comp_ok) {
|
||||||
// execute it
|
// execute it
|
||||||
py_obj_t module_fun = rt_make_function_from_id(1);
|
py_obj_t module_fun = rt_make_function_from_id(1);
|
||||||
if (module_fun != py_const_none) {
|
if (module_fun != py_const_none) {
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
py_obj_t ret = rt_call_function_0(module_fun);
|
py_obj_t ret = rt_call_function_0(module_fun);
|
||||||
printf("done! got: ");
|
printf("done! got: ");
|
||||||
py_obj_print(ret);
|
py_obj_print(ret);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
} else {
|
} else {
|
||||||
// uncaught exception
|
// uncaught exception
|
||||||
printf("exception: ");
|
printf("exception: ");
|
||||||
py_obj_print((py_obj_t)nlr.ret_val);
|
py_obj_print((py_obj_t)nlr.ret_val);
|
||||||
printf("\n");
|
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 [<file>]\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
rt_deinit();
|
rt_deinit();
|
||||||
|
|
||||||
//printf("total bytes = %d\n", m_get_total_bytes_allocated());
|
//printf("total bytes = %d\n", m_get_total_bytes_allocated());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user