Commit ce89a21e authored by Damien's avatar Damien
Browse files

Implement basic exception framework, and simple for loop.

parent 5dd455d0
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
// TODO need to mangle __attr names // TODO need to mangle __attr names
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
typedef enum { typedef enum {
PN_none = 0, PN_none = 0,
#define DEF_RULE(rule, comp, kind, arg...) PN_##rule, #define DEF_RULE(rule, comp, kind, arg...) PN_##rule,
...@@ -853,16 +855,19 @@ static bool compile_built_in_decorator(compiler_t *comp, int name_len, py_parse_ ...@@ -853,16 +855,19 @@ 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 (attr == comp->qstr_native) { if (0) {
#if MICROPY_EMIT_NATIVE
} else if (attr == comp->qstr_native) {
*emit_options = EMIT_OPT_NATIVE_PYTHON; *emit_options = EMIT_OPT_NATIVE_PYTHON;
} else if (attr == comp->qstr_viper) { } else if (attr == comp->qstr_viper) {
*emit_options = EMIT_OPT_VIPER; *emit_options = EMIT_OPT_VIPER;
#endif
#if MICROPY_EMIT_INLINE_THUMB #if MICROPY_EMIT_INLINE_THUMB
} else if (attr == comp->qstr_asm_thumb) { } else if (attr == comp->qstr_asm_thumb) {
*emit_options = EMIT_OPT_ASM_THUMB; *emit_options = EMIT_OPT_ASM_THUMB;
#endif #endif
} else { } else {
printf("SyntaxError: invalid micropython decorator\n"); printf("SyntaxError: invalid micropython decorator '%s'\n", qstr_str(attr));
} }
return true; return true;
...@@ -1302,15 +1307,16 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { ...@@ -1302,15 +1307,16 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
int old_break_label = comp->break_label; int old_break_label = comp->break_label;
int old_continue_label = comp->continue_label; int old_continue_label = comp->continue_label;
int done_label = comp_next_label(comp);
int end_label = comp_next_label(comp);
int break_label = comp_next_label(comp); int break_label = comp_next_label(comp);
int continue_label = comp_next_label(comp); int continue_label = comp_next_label(comp);
comp->break_label = break_label; comp->break_label = break_label;
comp->continue_label = continue_label; comp->continue_label = continue_label;
EMIT(setup_loop, end_label); // compared to CPython, we have an optimised version of while loops
#if MICROPY_EMIT_CPYTHON
int done_label = comp_next_label(comp);
EMIT(setup_loop, break_label);
EMIT(label_assign, continue_label); EMIT(label_assign, continue_label);
c_if_cond(comp, pns->nodes[0], false, done_label); // condition c_if_cond(comp, pns->nodes[0], false, done_label); // condition
compile_node(comp, pns->nodes[1]); // body compile_node(comp, pns->nodes[1]); // body
...@@ -1318,21 +1324,27 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { ...@@ -1318,21 +1324,27 @@ void compile_while_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
EMIT(jump, continue_label); EMIT(jump, continue_label);
} }
EMIT(label_assign, done_label); EMIT(label_assign, done_label);
// break/continue apply to outer loop (if any) in the else block
comp->break_label = old_break_label;
comp->continue_label = old_continue_label;
// CPython does not emit POP_BLOCK if the condition was a constant; don't undertand why // CPython does not emit POP_BLOCK if the condition was a constant; don't undertand why
// this is a small hack to agree with CPython // this is a small hack to agree with CPython
if (!node_is_const_true(pns->nodes[0])) { if (!node_is_const_true(pns->nodes[0])) {
EMIT(pop_block); EMIT(pop_block);
} }
#else
int top_label = comp_next_label(comp);
EMIT(jump, continue_label);
EMIT(label_assign, top_label);
compile_node(comp, pns->nodes[1]); // body
EMIT(label_assign, continue_label);
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
#endif
// break/continue apply to outer loop (if any) in the else block
comp->break_label = old_break_label;
comp->continue_label = old_continue_label;
compile_node(comp, pns->nodes[2]); // else compile_node(comp, pns->nodes[2]); // else
EMIT(label_assign, break_label); EMIT(label_assign, break_label);
EMIT(label_assign, end_label);
} }
void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
...@@ -1348,7 +1360,11 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { ...@@ -1348,7 +1360,11 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
comp->continue_label = for_label; comp->continue_label = for_label;
comp->break_label = break_label; comp->break_label = break_label;
// I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements
#if MICROPY_EMIT_CPYTHON
EMIT(setup_loop, end_label); EMIT(setup_loop, end_label);
#endif
compile_node(comp, pns->nodes[1]); // iterator compile_node(comp, pns->nodes[1]); // iterator
EMIT(get_iter); EMIT(get_iter);
EMIT(label_assign, for_label); EMIT(label_assign, for_label);
...@@ -1365,7 +1381,9 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) { ...@@ -1365,7 +1381,9 @@ void compile_for_stmt(compiler_t *comp, py_parse_node_struct_t *pns) {
comp->break_label = old_break_label; comp->break_label = old_break_label;
comp->continue_label = old_continue_label; comp->continue_label = old_continue_label;
#if MICROPY_EMIT_CPYTHON
EMIT(pop_block); EMIT(pop_block);
#endif
compile_node(comp, pns->nodes[3]); // else (not tested) compile_node(comp, pns->nodes[3]); // else (not tested)
......
// non-local return
// exception handling, basically a stack of setjmp/longjmp buffers
#include <limits.h>
#ifndef __WORDSIZE
#error __WORDSIZE needs to be defined
#endif
typedef struct _nlr_buf_t nlr_buf_t;
struct _nlr_buf_t {
// the entries here must all be machine word size
nlr_buf_t *prev;
void *ret_val;
#if __WORDSIZE == 32
void *regs[6];
#elif __WORDSIZE == 64
void *regs[8];
#else
#error Unsupported __WORDSIZE
#endif
};
unsigned int nlr_push(nlr_buf_t *);
void nlr_pop();
void nlr_jump(void *val) __attribute__((noreturn));
# x64 callee save: bx, bp, sp, r12, r14, r14, r15
.file "nlr.s"
.text
# uint nlr_push(rdi=nlr_buf_t *nlr)
.globl nlr_push
.type nlr_push, @function
nlr_push:
movq (%rsp), %rax # load return %rip
movq %rax, 16(%rdi) # store %rip into nlr_buf
movq %rbp, 24(%rdi) # store %rbp into nlr_buf
movq %rsp, 32(%rdi) # store %rsp into nlr_buf
movq %rbx, 40(%rdi) # store %rbx into nlr_buf
movq %r12, 48(%rdi) # store %r12 into nlr_buf
movq %r13, 56(%rdi) # store %r13 into nlr_buf
movq %r14, 64(%rdi) # store %r14 into nlr_buf
movq %r15, 72(%rdi) # store %r15 into nlr_buf
movq nlr_top(%rip), %rax # get last nlr_buf
movq %rax, (%rdi) # store it
movq %rdi, nlr_top(%rip) # stor new nlr_buf (to make linked list)
xorq %rax, %rax # return 0, normal return
ret # return
.size nlr_push, .-nlr_push
# void nlr_pop()
.globl nlr_pop
.type nlr_pop, @function
nlr_pop:
movq nlr_top(%rip), %rax # get nlr_top into %rax
movq (%rax), %rax # load prev nlr_buf
movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
ret # return
.size nlr_pop, .-nlr_pop
# void nlr_jump(rdi=uint val)
.globl nlr_jump
.type nlr_jump, @function
nlr_jump:
movq %rdi, %rax # put return value in %rax
movq nlr_top(%rip), %rdi # get nlr_top into %rdi
movq %rax, 8(%rdi) # store return value
movq (%rdi), %rax # load prev nlr_buf
movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list)
movq 72(%rdi), %r15 # load saved %r15
movq 64(%rdi), %r14 # load saved %r14
movq 56(%rdi), %r13 # load saved %r13
movq 48(%rdi), %r12 # load saved %r12
movq 40(%rdi), %rbx # load saved %rbx
movq 32(%rdi), %rsp # load saved %rsp
movq 24(%rdi), %rbp # load saved %rbp
movq 16(%rdi), %rax # load saved %rip
movq %rax, (%rsp) # store saved %rip to stack
xorq %rax, %rax # clear return register
inc %al # increase to make 1, non-local return
ret # return
.size nlr_jump, .-nlr_jump
.local nlr_top
.comm nlr_top,8,8
# x86 callee save: bx, di, si, bp, sp
.file "nlr.s"
.text
# uint nlr_push(4(%esp)=nlr_buf_t *nlr)
.globl nlr_push
.type nlr_push, @function
nlr_push:
mov 4(%esp), %edx # load nlr_buf
mov (%esp), %eax # load return %ip
mov %eax, 8(%edx) # store %ip into nlr_buf+8
mov %ebp, 12(%edx) # store %bp into nlr_buf+12
mov %esp, 16(%edx) # store %sp into nlr_buf+16
mov %ebx, 20(%edx) # store %bx into nlr_buf+20
mov %edi, 24(%edx) # store %di into nlr_buf
mov %esi, 28(%edx) # store %si into nlr_buf
mov nlr_top, %eax # load nlr_top
mov %eax, (%edx) # store it
mov %edx, nlr_top # stor new nlr_buf (to make linked list)
xor %eax, %eax # return 0, normal return
ret # return
.size nlr_push, .-nlr_push
# void nlr_pop()
.globl nlr_pop
.type nlr_pop, @function
nlr_pop:
mov nlr_top, %eax # load nlr_top
mov (%eax), %eax # load prev nlr_buf
mov %eax, nlr_top # store nlr_top (to unlink list)
ret # return
.size nlr_pop, .-nlr_pop
# void nlr_jump(4(%esp)=uint val)
.globl nlr_jump
.type nlr_jump, @function
nlr_jump:
mov nlr_top, %edx # load nlr_top
mov 4(%esp), %eax # load return value
mov %eax, 4(%edx) # store return value
mov (%edx), %eax # load prev nlr_top
mov %eax, nlr_top # store nlr_top (to unlink list)
mov 28(%edx), %esi # load saved %si
mov 24(%edx), %edi # load saved %di
mov 20(%edx), %ebx # load saved %bx
mov 16(%edx), %esp # load saved %sp
mov 12(%edx), %ebp # load saved %bp
mov 8(%edx), %eax # load saved %ip
mov %eax, (%esp) # store saved %ip to stack
xor %eax, %eax # clear return register
inc %al # increase to make 1, non-local return
ret # return
.size nlr_jump, .-nlr_jump
.local nlr_top
.comm nlr_top,4,4
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "nlr.h"
#include "misc.h" #include "misc.h"
#include "mpyconfig.h" #include "mpyconfig.h"
#include "runtime.h" #include "runtime.h"
...@@ -36,6 +37,10 @@ typedef enum { ...@@ -36,6 +37,10 @@ typedef enum {
#if MICROPY_ENABLE_FLOAT #if MICROPY_ENABLE_FLOAT
O_FLOAT, O_FLOAT,
#endif #endif
O_EXCEPTION_0,
O_EXCEPTION_2,
O_RANGE,
O_RANGE_IT,
O_FUN_0, O_FUN_0,
O_FUN_1, O_FUN_1,
O_FUN_2, O_FUN_2,
...@@ -77,6 +82,28 @@ struct _py_obj_base_t { ...@@ -77,6 +82,28 @@ struct _py_obj_base_t {
#if MICROPY_ENABLE_FLOAT #if MICROPY_ENABLE_FLOAT
float_t u_flt; float_t u_flt;
#endif #endif
struct { // for O_EXCEPTION_0
qstr id;
} u_exc0;
struct { // for O_EXCEPTION_2
// TODO reduce size or make generic object or something
qstr id;
const char *fmt;
const char *s1;
const char *s2;
} u_exc2;
struct { // for O_RANGE
// TODO make generic object or something
machine_int_t start;
machine_int_t stop;
machine_int_t step;
} u_range;
struct { // for O_RANGE_IT
// TODO make generic object or something
machine_int_t cur;
machine_int_t stop;
machine_int_t step;
} u_range_it;
struct { // for O_FUN_[012N] struct { // for O_FUN_[012N]
int n_args; int n_args;
void *fun; void *fun;
...@@ -118,6 +145,7 @@ struct _py_obj_base_t { ...@@ -118,6 +145,7 @@ struct _py_obj_base_t {
py_obj_t py_const_none; py_obj_t py_const_none;
py_obj_t py_const_false; py_obj_t py_const_false;
py_obj_t py_const_true; py_obj_t py_const_true;
py_obj_t py_const_stop_iteration;
// locals and globals need to be pointers because they can be the same in outer module scope // locals and globals need to be pointers because they can be the same in outer module scope
py_map_t *map_locals; py_map_t *map_locals;
...@@ -266,6 +294,42 @@ py_obj_t py_obj_new_float(float_t val) { ...@@ -266,6 +294,42 @@ py_obj_t py_obj_new_float(float_t val) {
} }
#endif #endif
py_obj_t py_obj_new_exception_0(qstr id) {
py_obj_base_t *o = m_new(py_obj_base_t, 1);
o->kind = O_EXCEPTION_0;
o->u_exc0.id = id;
return (py_obj_t)o;
}
py_obj_t py_obj_new_exception_2(qstr id, const char *fmt, const char *s1, const char *s2) {
py_obj_base_t *o = m_new(py_obj_base_t, 1);
o->kind = O_EXCEPTION_2;
o->u_exc2.id = id;
o->u_exc2.fmt = fmt;
o->u_exc2.s1 = s1;
o->u_exc2.s2 = s2;
return (py_obj_t)o;
}
// range is a class and instances are immutable sequence objects
py_obj_t py_obj_new_range(int start, int stop, int step) {
py_obj_base_t *o = m_new(py_obj_base_t, 1);
o->kind = O_RANGE;
o->u_range.start = start;
o->u_range.stop = stop;
o->u_range.step = step;
return o;
}
py_obj_t py_obj_new_range_iterator(int cur, int stop, int step) {
py_obj_base_t *o = m_new(py_obj_base_t, 1);
o->kind = O_RANGE_IT;
o->u_range_it.cur = cur;
o->u_range_it.stop = stop;
o->u_range_it.step = step;
return o;
}
py_obj_t list_append(py_obj_t self_in, py_obj_t arg) { py_obj_t list_append(py_obj_t self_in, py_obj_t arg) {
assert(IS_O(self_in, O_LIST)); assert(IS_O(self_in, O_LIST));
py_obj_base_t *self = self_in; py_obj_base_t *self = self_in;
...@@ -281,6 +345,9 @@ static qstr q_append; ...@@ -281,6 +345,9 @@ static qstr q_append;
static qstr q_print; static qstr q_print;
static qstr q_len; static qstr q_len;
static qstr q___build_class__; static qstr q___build_class__;
static qstr q_AttributeError;
static qstr q_NameError;
static qstr q_TypeError;
typedef enum { typedef enum {
PY_CODE_NONE, PY_CODE_NONE,
...@@ -356,6 +423,10 @@ py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name) ...@@ -356,6 +423,10 @@ py_obj_t py_builtin___build_class__(py_obj_t o_class_fun, py_obj_t o_class_name)
return o; return o;
} }
py_obj_t py_builtin_range(py_obj_t o_arg) {
return py_obj_new_range(0, rt_get_int(o_arg), 1);
}
#ifdef WRITE_NATIVE #ifdef WRITE_NATIVE
FILE *fp_native = NULL; FILE *fp_native = NULL;
#endif #endif
...@@ -365,10 +436,14 @@ void rt_init() { ...@@ -365,10 +436,14 @@ void rt_init() {
q_print = qstr_from_str_static("print"); q_print = qstr_from_str_static("print");
q_len = qstr_from_str_static("len"); q_len = qstr_from_str_static("len");
q___build_class__ = qstr_from_str_static("__build_class__"); q___build_class__ = qstr_from_str_static("__build_class__");
q_AttributeError = qstr_from_str_static("AttributeError");
q_NameError = qstr_from_str_static("NameError");
q_TypeError = qstr_from_str_static("TypeError");
py_const_none = py_obj_new_const("None"); py_const_none = py_obj_new_const("None");
py_const_false = py_obj_new_const("False"); py_const_false = py_obj_new_const("False");
py_const_true = py_obj_new_const("True"); py_const_true = py_obj_new_const("True");
py_const_stop_iteration = py_obj_new_const("StopIteration");
// locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
map_locals = map_globals = py_map_new(MAP_QSTR, 1); map_locals = map_globals = py_map_new(MAP_QSTR, 1);
...@@ -378,6 +453,7 @@ void rt_init() { ...@@ -378,6 +453,7 @@ void rt_init() {
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);
next_unique_code_id = 1; next_unique_code_id = 1;
unique_codes = NULL; unique_codes = NULL;
...@@ -559,6 +635,10 @@ void py_obj_print(py_obj_t o_in) { ...@@ -559,6 +635,10 @@ void py_obj_print(py_obj_t o_in) {
printf("%f", o->u_flt); printf("%f", o->u_flt);
break; break;
#endif #endif
case O_EXCEPTION_2:
printf("%s: ", qstr_str(o->u_exc2.id));
printf(o->u_exc2.fmt, o->u_exc2.s1, o->u_exc2.s2);
break;
case O_LIST: case O_LIST:
printf("["); printf("[");
for (int i = 0; i < o->u_list.len; i++) { for (int i = 0; i < o->u_list.len; i++) {
...@@ -653,8 +733,7 @@ py_obj_t rt_load_name(qstr qstr) { ...@@ -653,8 +733,7 @@ py_obj_t rt_load_name(qstr qstr) {
if (elem == NULL) { if (elem == NULL) {
elem = py_qstr_map_lookup(&map_builtins, qstr, false); elem = py_qstr_map_lookup(&map_builtins, qstr, false);
if (elem == NULL) { if (elem == NULL) {
printf("name doesn't exist: %s\n", qstr_str(qstr)); nlr_jump(py_obj_new_exception_2(q_NameError, "name '%s' is not defined", qstr_str(qstr), NULL));
assert(0);
} }
} }
} }
...@@ -668,8 +747,7 @@ py_obj_t rt_load_global(qstr qstr) { ...@@ -668,8 +747,7 @@ py_obj_t rt_load_global(qstr qstr) {
if (elem == NULL) { if (elem == NULL) {
elem = py_qstr_map_lookup(&map_builtins, qstr, false); elem = py_qstr_map_lookup(&map_builtins, qstr, false);
if (elem == NULL) { if (elem == NULL) {
printf("name doesn't exist: %s\n", qstr_str(qstr)); nlr_jump(py_obj_new_exception_2(q_NameError, "name '%s' is not defined", qstr_str(qstr), NULL));
assert(0);
} }
} }
return elem->value; return elem->value;
...@@ -1123,9 +1201,7 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr) { ...@@ -1123,9 +1201,7 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr) {
} }
no_attr: no_attr:
printf("AttributeError: '%s' object has no attribute '%s'\n", py_obj_get_type_str(base), qstr_str(attr)); nlr_jump(py_obj_new_exception_2(q_AttributeError, "'%s' object has no attribute '%s'", 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) { void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
...@@ -1204,6 +1280,30 @@ void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) { ...@@ -1204,6 +1280,30 @@ void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t value) {
} }
} }
py_obj_t rt_getiter(py_obj_t o_in) {
if (IS_O(o_in, O_RANGE)) {
py_obj_base_t *o = o_in;
return py_obj_new_range_iterator(o->u_range.start, o->u_range.stop, o->u_range.step);
} else {
nlr_jump(py_obj_new_exception_2(q_TypeError, "'%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
}
}
py_obj_t rt_iternext(py_obj_t o_in) {
if (IS_O(o_in, O_RANGE_IT)) {
py_obj_base_t *o = o_in;
if ((o->u_range_it.step > 0 && o->u_range_it.cur < o->u_range_it.stop) || (o->u_range_it.step < 0 && o->u_range_it.cur > o->u_range_it.stop)) {
py_obj_t o_out = TO_SMALL_INT(o->u_range_it.cur);
o->u_range_it.cur += o->u_range_it.step;
return o_out;
} else {
return py_const_stop_iteration;
}
} else {
nlr_jump(py_obj_new_exception_2(q_TypeError, "? '%s' object is not iterable", py_obj_get_type_str(o_in), NULL));
}
}
void *rt_fun_table[RT_F_NUMBER_OF] = { void *rt_fun_table[RT_F_NUMBER_OF] = {
rt_load_const_str, rt_load_const_str,
rt_load_name, rt_load_name,
......
...@@ -82,6 +82,7 @@ typedef py_obj_t (*py_fun_t)(); ...@@ -82,6 +82,7 @@ typedef py_obj_t (*py_fun_t)();
extern py_obj_t py_const_none; extern py_obj_t py_const_none;
extern py_obj_t py_const_false; extern py_obj_t py_const_false;
extern py_obj_t py_const_true; extern py_obj_t py_const_true;
extern py_obj_t py_const_stop_iteration; // special object indicating end of iteration (not StopIteration exception!)
void rt_init(); void rt_init();
void rt_deinit(); void rt_deinit();
...@@ -123,3 +124,5 @@ py_obj_t rt_load_attr(py_obj_t base, qstr attr); ...@@ -123,3 +124,5 @@ 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_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_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); void rt_store_subscr(py_obj_t base, py_obj_t index, py_obj_t val);
py_obj_t rt_getiter(py_obj_t o);
py_obj_t rt_iternext(py_obj_t o);
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "nlr.h"
#include "misc.h" #include "misc.h"
#include "mpyconfig.h" #include "mpyconfig.h"
#include "runtime.h" #include "runtime.h"
...@@ -24,6 +25,7 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args, ...@@ -24,6 +25,7 @@ py_obj_t py_execute_byte_code(const byte *code, uint len, const py_obj_t *args,
qstr qstr; qstr qstr;
py_obj_t obj1, obj2; py_obj_t obj1, obj2;
py_obj_t fast0 = NULL, fast1 = NULL, fast2 = NULL, fastn[4] = {NULL, NULL, NULL, NULL}; py_obj_t fast0 = NULL, fast1 = NULL, fast2 = NULL, fastn[4] = {NULL, NULL, NULL, NULL};