2013-10-16 11:12:52 -04:00
// in principle, rt_xxx functions are called only by vm/native/viper and make assumptions about args
// py_xxx functions are safer and can be called by anyone
2013-10-16 15:39:12 -04:00
// note that rt_assign_xxx are called only from emit*, and maybe we can rename them to reflect this
2013-10-16 11:12:52 -04:00
2013-10-04 14:53:11 -04:00
# include <stdint.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <assert.h>
2013-10-15 17:25:17 -04:00
# include "nlr.h"
2013-10-04 14:53:11 -04:00
# include "misc.h"
2013-10-12 09:30:21 -04:00
# include "mpyconfig.h"
2013-10-04 14:53:11 -04:00
# include "runtime.h"
2013-10-10 17:06:54 -04:00
# include "bc.h"
2013-10-04 14:53:11 -04:00
2013-10-10 06:24:39 -04:00
#if 0 // print debugging info
2013-10-10 18:25:50 -04:00
# define DEBUG_PRINT (1)
# define WRITE_NATIVE (1)
2013-10-10 06:24:39 -04:00
# define DEBUG_printf(args...) printf(args)
# define DEBUG_OP_printf(args...) printf(args)
# else // don't print debugging info
2013-10-09 18:10:10 -04:00
# define DEBUG_printf(args...) (void)0
2013-10-04 14:53:11 -04:00
# define DEBUG_OP_printf(args...) (void)0
2013-10-10 06:24:39 -04:00
# endif
2013-10-04 14:53:11 -04:00
typedef machine_int_t py_small_int_t ;
# define IS_O(o, k) (((((py_small_int_t)(o)) & 1) == 0) && (((py_obj_base_t*)(o))->kind == (k)))
# define IS_SMALL_INT(o) (((py_small_int_t)(o)) & 1)
# define FROM_SMALL_INT(o) (((py_small_int_t)(o)) >> 1)
# define TO_SMALL_INT(o) ((py_obj_t)(((o) << 1) | 1))
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-04 14:53:11 -04:00
typedef machine_float_t float_t ;
# endif
typedef enum {
O_CONST ,
O_STR ,
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-04 14:53:11 -04:00
O_FLOAT ,
# endif
2013-10-15 17:25:17 -04:00
O_EXCEPTION_0 ,
2013-10-22 11:05:11 -04:00
O_EXCEPTION_N ,
2013-10-15 17:25:17 -04:00
O_RANGE ,
O_RANGE_IT ,
2013-10-04 14:53:11 -04:00
O_FUN_0 ,
O_FUN_1 ,
O_FUN_2 ,
O_FUN_N ,
O_FUN_BC ,
2013-10-05 18:17:28 -04:00
O_FUN_ASM ,
2013-10-16 15:39:12 -04:00
O_GEN_WRAP ,
O_GEN_INSTANCE ,
2013-10-04 14:53:11 -04:00
O_BOUND_METH ,
2013-10-16 11:12:52 -04:00
O_TUPLE ,
2013-10-04 14:53:11 -04:00
O_LIST ,
2013-10-16 11:12:52 -04:00
O_TUPLE_IT ,
O_LIST_IT ,
2013-10-04 14:53:11 -04:00
O_SET ,
O_MAP ,
O_CLASS ,
2013-10-09 18:10:10 -04:00
O_OBJ ,
2013-10-04 14:53:11 -04:00
} py_obj_kind_t ;
typedef enum {
MAP_QSTR ,
MAP_PY_OBJ ,
} py_map_kind_t ;
typedef struct _py_map_elem_t {
py_obj_t key ;
py_obj_t value ;
} py_map_elem_t ;
typedef struct _py_map_t {
2013-10-22 11:05:11 -04:00
struct {
py_map_kind_t kind : 1 ;
machine_uint_t used : ( 8 * BYTES_PER_WORD - 1 ) ;
} ;
2013-10-04 14:53:11 -04:00
machine_uint_t alloc ;
py_map_elem_t * table ;
} py_map_t ;
2013-10-09 18:10:10 -04:00
typedef struct _py_obj_base_t py_obj_base_t ;
struct _py_obj_base_t {
2013-10-04 14:53:11 -04:00
py_obj_kind_t kind ;
union {
const char * id ;
qstr u_str ;
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-06 07:04:13 -04:00
float_t u_flt ;
2013-10-04 14:53:11 -04:00
# endif
2013-10-15 17:25:17 -04:00
struct { // for O_EXCEPTION_0
qstr id ;
} u_exc0 ;
2013-10-22 11:05:11 -04:00
struct { // for O_EXCEPTION_N
// TODO make generic object or something
2013-10-15 17:25:17 -04:00
qstr id ;
2013-10-22 11:05:11 -04:00
int n_args ;
const void * * args ;
} u_exc_n ;
2013-10-15 17:25:17 -04:00
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 ;
2013-10-04 14:53:11 -04:00
struct { // for O_FUN_[012N]
int n_args ;
2013-10-05 18:17:28 -04:00
void * fun ;
2013-10-04 14:53:11 -04:00
} u_fun ;
struct { // for O_FUN_BC
2013-10-05 18:17:28 -04:00
int n_args ;
2013-10-04 14:53:11 -04:00
byte * code ;
uint len ;
} u_fun_bc ;
2013-10-05 18:17:28 -04:00
struct { // for O_FUN_ASM
int n_args ;
void * fun ;
} u_fun_asm ;
2013-10-16 15:39:12 -04:00
struct { // for O_GEN_WRAP
int n_state ;
py_obj_base_t * fun ;
} u_gen_wrap ;
struct { // for O_GEN_INSTANCE
py_obj_t * state ;
const byte * ip ;
py_obj_t * sp ;
} u_gen_instance ;
2013-10-04 14:53:11 -04:00
struct { // for O_BOUND_METH
py_obj_t meth ;
py_obj_t self ;
} u_bound_meth ;
2013-10-16 11:12:52 -04:00
struct { // for O_TUPLE, O_LIST
2013-10-22 11:05:11 -04:00
machine_uint_t alloc ;
machine_uint_t len ;
2013-10-04 14:53:11 -04:00
py_obj_t * items ;
2013-10-16 11:12:52 -04:00
} u_tuple_list ;
struct { // for O_TUPLE_IT, O_LIST_IT
py_obj_base_t * obj ;
2013-10-22 11:05:11 -04:00
machine_uint_t cur ;
2013-10-16 11:12:52 -04:00
} u_tuple_list_it ;
2013-10-04 14:53:11 -04:00
struct { // for O_SET
2013-10-22 11:05:11 -04:00
machine_uint_t alloc ;
machine_uint_t used ;
2013-10-04 14:53:11 -04:00
py_obj_t * table ;
} u_set ;
py_map_t u_map ; // for O_MAP
struct { // for O_CLASS
2013-10-09 18:10:10 -04:00
py_map_t * locals ;
2013-10-04 14:53:11 -04:00
} u_class ;
2013-10-09 18:10:10 -04:00
struct { // for O_OBJ
py_obj_base_t * class ; // points to a O_CLASS object
py_map_t * members ;
} u_obj ;
2013-10-04 14:53:11 -04:00
} ;
2013-10-09 18:10:10 -04:00
} ;
2013-10-04 14:53:11 -04:00
py_obj_t py_const_none ;
py_obj_t py_const_false ;
py_obj_t py_const_true ;
2013-10-15 17:25:17 -04:00
py_obj_t py_const_stop_iteration ;
2013-10-04 14:53:11 -04:00
2013-10-10 17:06:54 -04:00
// 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_globals ;
2013-10-04 14:53:11 -04:00
py_map_t map_builtins ;
// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
static int doubling_primes [ ] = { 7 , 19 , 43 , 89 , 179 , 347 , 647 , 1229 , 2297 , 4243 , 7829 , 14347 , 26017 , 47149 , 84947 , 152443 , 273253 , 488399 , 869927 , 1547173 , 2745121 , 4861607 } ;
int get_doubling_prime_greater_or_equal_to ( int x ) {
for ( int i = 0 ; i < sizeof ( doubling_primes ) / sizeof ( int ) ; i + + ) {
if ( doubling_primes [ i ] > = x ) {
return doubling_primes [ i ] ;
}
}
// ran out of primes in the table!
// return something sensible, at least make it odd
return x | 1 ;
}
void py_map_init ( py_map_t * map , py_map_kind_t kind , int n ) {
map - > kind = kind ;
map - > used = 0 ;
2013-10-22 11:05:11 -04:00
map - > alloc = get_doubling_prime_greater_or_equal_to ( n + 1 ) ;
2013-10-18 14:58:12 -04:00
map - > table = m_new0 ( py_map_elem_t , map - > alloc ) ;
2013-10-04 14:53:11 -04:00
}
py_map_t * py_map_new ( py_map_kind_t kind , int n ) {
py_map_t * map = m_new ( py_map_t , 1 ) ;
py_map_init ( map , kind , n ) ;
return map ;
}
2013-10-18 14:58:12 -04:00
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 ) ) {
2013-10-04 14:53:11 -04:00
return FROM_SMALL_INT ( o_in ) ;
2013-10-18 14:58:12 -04:00
} else if ( IS_O ( o_in , O_CONST ) ) {
return ( machine_int_t ) o_in ;
2013-10-04 14:53:11 -04:00
} else if ( IS_O ( o_in , O_STR ) ) {
return ( ( py_obj_base_t * ) o_in ) - > u_str ;
} else {
assert ( 0 ) ;
return 0 ;
}
}
2013-10-18 14:58:12 -04:00
// 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
2013-10-04 14:53:11 -04:00
bool py_obj_equal ( py_obj_t o1 , py_obj_t o2 ) {
if ( o1 = = o2 ) {
return true ;
2013-10-18 14:58:12 -04:00
} 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 ;
}
}
2013-10-04 14:53:11 -04:00
} 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 {
assert ( 0 ) ;
return false ;
}
}
py_map_elem_t * py_map_lookup_helper ( py_map_t * map , py_obj_t index , bool add_if_not_found ) {
bool is_map_py_obj = ( map - > kind = = MAP_PY_OBJ ) ;
machine_uint_t hash ;
if ( is_map_py_obj ) {
hash = py_obj_hash ( index ) ;
} else {
hash = ( machine_uint_t ) index ;
}
uint pos = hash % map - > alloc ;
for ( ; ; ) {
py_map_elem_t * elem = & map - > table [ pos ] ;
if ( elem - > key = = NULL ) {
// not in table
if ( add_if_not_found ) {
if ( map - > used + 1 > = map - > alloc ) {
// not enough room in table, rehash it
int old_alloc = map - > alloc ;
py_map_elem_t * old_table = map - > table ;
map - > alloc = get_doubling_prime_greater_or_equal_to ( map - > alloc + 1 ) ;
map - > used = 0 ;
2013-10-18 14:58:12 -04:00
map - > table = m_new0 ( py_map_elem_t , map - > alloc ) ;
2013-10-04 14:53:11 -04:00
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 ;
}
}
m_free ( old_table ) ;
// restart the search for the new element
pos = hash % map - > alloc ;
} else {
map - > used + = 1 ;
elem - > key = index ;
return elem ;
}
} else {
return NULL ;
}
} else if ( elem - > key = = index | | ( is_map_py_obj & & py_obj_equal ( elem - > key , index ) ) ) {
// found it
2013-10-18 14:58:12 -04:00
/* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x
2013-10-04 14:53:11 -04:00
if ( add_if_not_found ) {
elem - > key = index ;
}
2013-10-18 14:58:12 -04:00
*/
2013-10-04 14:53:11 -04:00
return elem ;
} else {
// not yet found, keep searching in this table
pos = ( pos + 1 ) % map - > alloc ;
}
}
}
py_map_elem_t * py_qstr_map_lookup ( py_map_t * map , qstr index , bool add_if_not_found ) {
py_obj_t o = ( py_obj_t ) ( machine_uint_t ) index ;
return py_map_lookup_helper ( map , o , add_if_not_found ) ;
}
py_map_elem_t * py_map_lookup ( py_obj_t o , py_obj_t index , bool add_if_not_found ) {
assert ( IS_O ( o , O_MAP ) ) ;
return py_map_lookup_helper ( & ( ( py_obj_base_t * ) o ) - > u_map , index , add_if_not_found ) ;
}
static bool fit_small_int ( py_small_int_t o ) {
return true ;
}
py_obj_t py_obj_new_const ( const char * id ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_CONST ;
o - > id = id ;
return ( py_obj_t ) o ;
}
py_obj_t py_obj_new_str ( qstr qstr ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_STR ;
o - > u_str = qstr ;
return ( py_obj_t ) o ;
}
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-04 14:53:11 -04:00
py_obj_t py_obj_new_float ( float_t val ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_FLOAT ;
2013-10-06 07:04:13 -04:00
o - > u_flt = val ;
2013-10-04 14:53:11 -04:00
return ( py_obj_t ) o ;
}
# endif
2013-10-15 17:25:17 -04:00
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 ) ;
2013-10-22 11:05:11 -04:00
o - > kind = O_EXCEPTION_N ;
o - > u_exc_n . id = id ;
o - > u_exc_n . n_args = 3 ;
o - > u_exc_n . args = m_new ( const void * , 3 ) ;
o - > u_exc_n . args [ 0 ] = fmt ;
o - > u_exc_n . args [ 1 ] = s1 ;
o - > u_exc_n . args [ 2 ] = s2 ;
2013-10-15 17:25:17 -04:00
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 ;
}
2013-10-16 11:12:52 -04:00
py_obj_t py_obj_new_tuple_iterator ( py_obj_base_t * tuple , int cur ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_TUPLE_IT ;
o - > u_tuple_list_it . obj = tuple ;
o - > u_tuple_list_it . cur = cur ;
return o ;
}
py_obj_t py_obj_new_list_iterator ( py_obj_base_t * list , int cur ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_LIST_IT ;
o - > u_tuple_list_it . obj = list ;
o - > u_tuple_list_it . cur = cur ;
return o ;
}
py_obj_t rt_list_append ( py_obj_t self_in , py_obj_t arg ) {
2013-10-04 14:53:11 -04:00
assert ( IS_O ( self_in , O_LIST ) ) ;
py_obj_base_t * self = self_in ;
2013-10-16 11:12:52 -04:00
if ( self - > u_tuple_list . len > = self - > u_tuple_list . alloc ) {
self - > u_tuple_list . alloc * = 2 ;
self - > u_tuple_list . items = m_renew ( py_obj_t , self - > u_tuple_list . items , self - > u_tuple_list . alloc ) ;
2013-10-04 14:53:11 -04:00
}
2013-10-16 11:12:52 -04:00
self - > u_tuple_list . items [ self - > u_tuple_list . len + + ] = arg ;
2013-10-04 14:53:11 -04:00
return arg ;
}
2013-10-16 15:39:12 -04:00
py_obj_t rt_gen_instance_next ( py_obj_t self_in ) {
py_obj_t ret = rt_iternext ( self_in ) ;
if ( ret = = py_const_stop_iteration ) {
nlr_jump ( py_obj_new_exception_0 ( qstr_from_str_static ( " StopIteration " ) ) ) ;
} else {
return ret ;
}
}
2013-10-04 14:53:11 -04:00
static qstr q_append ;
static qstr q_print ;
static qstr q_len ;
static qstr q___build_class__ ;
2013-10-16 15:39:12 -04:00
static qstr q___next__ ;
2013-10-15 17:25:17 -04:00
static qstr q_AttributeError ;
2013-10-16 11:12:52 -04:00
static qstr q_IndexError ;
2013-10-18 14:58:12 -04:00
static qstr q_KeyError ;
2013-10-15 17:25:17 -04:00
static qstr q_NameError ;
static qstr q_TypeError ;
2013-10-04 14:53:11 -04:00
typedef enum {
2013-10-05 18:17:28 -04:00
PY_CODE_NONE ,
2013-10-04 14:53:11 -04:00
PY_CODE_BYTE ,
2013-10-05 18:17:28 -04:00
PY_CODE_NATIVE ,
PY_CODE_INLINE_ASM ,
2013-10-04 14:53:11 -04:00
} py_code_kind_t ;
typedef struct _py_code_t {
py_code_kind_t kind ;
int n_args ;
2013-10-16 15:39:12 -04:00
int n_locals ;
int n_stack ;
bool is_generator ;
2013-10-04 14:53:11 -04:00
union {
struct {
byte * code ;
uint len ;
} u_byte ;
2013-10-05 18:17:28 -04:00
struct {
py_fun_t fun ;
} u_native ;
struct {
2013-10-06 07:04:13 -04:00
void * fun ;
2013-10-05 18:17:28 -04:00
} u_inline_asm ;
2013-10-04 14:53:11 -04:00
} ;
} py_code_t ;
static int next_unique_code_id ;
static py_code_t * unique_codes ;
py_obj_t fun_list_append ;
2013-10-16 15:39:12 -04:00
py_obj_t fun_gen_instance_next ;
2013-10-04 14:53:11 -04:00
2013-10-18 14:58:12 -04:00
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 ;
}
2013-10-04 14:53:11 -04:00
py_obj_t py_builtin_print ( py_obj_t o ) {
if ( IS_O ( o , O_STR ) ) {
// special case, print string raw
printf ( " %s \n " , qstr_str ( ( ( py_obj_base_t * ) o ) - > u_str ) ) ;
} else {
// print the object Python style
py_obj_print ( o ) ;
printf ( " \n " ) ;
}
return py_const_none ;
}
py_obj_t py_builtin_len ( py_obj_t o_in ) {
py_small_int_t len = 0 ;
2013-10-16 11:12:52 -04:00
if ( IS_O ( o_in , O_TUPLE ) | | IS_O ( o_in , O_LIST ) ) {
2013-10-04 14:53:11 -04:00
py_obj_base_t * o = o_in ;
2013-10-16 11:12:52 -04:00
len = o - > u_tuple_list . len ;
2013-10-04 14:53:11 -04:00
} else if ( IS_O ( o_in , O_MAP ) ) {
py_obj_base_t * o = o_in ;
len = o - > u_map . used ;
} else {
assert ( 0 ) ;
}
return TO_SMALL_INT ( len ) ;
}
2013-10-09 18:10:10 -04:00
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
2013-10-10 17:06:54 -04:00
py_map_t * old_locals = map_locals ;
2013-10-09 18:10:10 -04:00
py_map_t * class_locals = py_map_new ( MAP_QSTR , 0 ) ;
2013-10-10 17:06:54 -04:00
map_locals = class_locals ;
2013-10-09 18:10:10 -04:00
// 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
2013-10-04 14:53:11 -04:00
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_CLASS ;
2013-10-09 18:10:10 -04:00
o - > u_class . locals = class_locals ;
2013-10-04 14:53:11 -04:00
return o ;
}
2013-10-15 17:25:17 -04:00
py_obj_t py_builtin_range ( py_obj_t o_arg ) {
return py_obj_new_range ( 0 , rt_get_int ( o_arg ) , 1 ) ;
}
2013-10-10 18:25:50 -04:00
# ifdef WRITE_NATIVE
2013-10-04 14:53:11 -04:00
FILE * fp_native = NULL ;
2013-10-10 18:25:50 -04:00
# endif
2013-10-04 14:53:11 -04:00
void rt_init ( ) {
q_append = qstr_from_str_static ( " append " ) ;
q_print = qstr_from_str_static ( " print " ) ;
q_len = qstr_from_str_static ( " len " ) ;
q___build_class__ = qstr_from_str_static ( " __build_class__ " ) ;
2013-10-16 15:39:12 -04:00
q___next__ = qstr_from_str_static ( " __next__ " ) ;
2013-10-15 17:25:17 -04:00
q_AttributeError = qstr_from_str_static ( " AttributeError " ) ;
2013-10-16 11:12:52 -04:00
q_IndexError = qstr_from_str_static ( " IndexError " ) ;
2013-10-18 14:58:12 -04:00
q_KeyError = qstr_from_str_static ( " KeyError " ) ;
2013-10-15 17:25:17 -04:00
q_NameError = qstr_from_str_static ( " NameError " ) ;
q_TypeError = qstr_from_str_static ( " TypeError " ) ;
2013-10-04 14:53:11 -04:00
py_const_none = py_obj_new_const ( " None " ) ;
py_const_false = py_obj_new_const ( " False " ) ;
py_const_true = py_obj_new_const ( " True " ) ;
2013-10-15 17:25:17 -04:00
py_const_stop_iteration = py_obj_new_const ( " StopIteration " ) ;
2013-10-04 14:53:11 -04:00
2013-10-10 17:06:54 -04:00
// locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
map_locals = map_globals = py_map_new ( 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__ " ) ) ;
2013-10-04 14:53:11 -04:00
py_map_init ( & map_builtins , MAP_QSTR , 3 ) ;
2013-10-18 14:58:12 -04:00
py_qstr_map_lookup ( & map_builtins , qstr_from_str_static ( " __repl_print__ " ) , true ) - > value = rt_make_function_1 ( py_builtin___repl_print__ ) ;
2013-10-04 14:53:11 -04:00
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__ ) ;
2013-10-15 17:25:17 -04:00
py_qstr_map_lookup ( & map_builtins , qstr_from_str_static ( " range " ) , true ) - > value = rt_make_function_1 ( py_builtin_range ) ;
2013-10-04 14:53:11 -04:00
2013-10-18 14:58:12 -04:00
next_unique_code_id = 2 ; // 1 is reserved for the __main__ module scope
2013-10-04 14:53:11 -04:00
unique_codes = NULL ;
2013-10-16 11:12:52 -04:00
fun_list_append = rt_make_function_2 ( rt_list_append ) ;
2013-10-16 15:39:12 -04:00
fun_gen_instance_next = rt_make_function_1 ( rt_gen_instance_next ) ;
2013-10-04 14:53:11 -04:00
2013-10-10 18:25:50 -04:00
# ifdef WRITE_NATIVE
2013-10-04 14:53:11 -04:00
fp_native = fopen ( " out-native " , " wb " ) ;
2013-10-10 18:25:50 -04:00
# endif
2013-10-04 14:53:11 -04:00
}
void rt_deinit ( ) {
2013-10-10 18:25:50 -04:00
# ifdef WRITE_NATIVE
2013-10-04 14:53:11 -04:00
if ( fp_native ! = NULL ) {
fclose ( fp_native ) ;
}
2013-10-10 18:25:50 -04:00
# endif
2013-10-04 14:53:11 -04:00
}
2013-10-18 14:58:12 -04:00
int rt_get_unique_code_id ( bool is_main_module ) {
if ( is_main_module ) {
return 1 ;
} else {
return next_unique_code_id + + ;
}
2013-10-04 14:53:11 -04:00
}
2013-10-05 18:17:28 -04:00
static void alloc_unique_codes ( ) {
2013-10-04 14:53:11 -04:00
if ( unique_codes = = NULL ) {
unique_codes = m_new ( py_code_t , next_unique_code_id ) ;
2013-10-05 18:17:28 -04:00
for ( int i = 0 ; i < next_unique_code_id ; i + + ) {
unique_codes [ i ] . kind = PY_CODE_NONE ;
}
2013-10-04 14:53:11 -04:00
}
2013-10-05 18:17:28 -04:00
}
2013-10-16 15:39:12 -04:00
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 ) {
2013-10-05 18:17:28 -04:00
alloc_unique_codes ( ) ;
assert ( unique_code_id < next_unique_code_id ) ;
unique_codes [ unique_code_id ] . kind = PY_CODE_BYTE ;
unique_codes [ unique_code_id ] . n_args = n_args ;
2013-10-16 15:39:12 -04:00
unique_codes [ unique_code_id ] . n_locals = n_locals ;
unique_codes [ unique_code_id ] . n_stack = n_stack ;
unique_codes [ unique_code_id ] . is_generator = is_generator ;
2013-10-05 18:17:28 -04:00
unique_codes [ unique_code_id ] . u_byte . code = code ;
unique_codes [ unique_code_id ] . u_byte . len = len ;
DEBUG_printf ( " assign byte code: id=%d code=%p len=%u n_args=%d \n " , unique_code_id , code , len , n_args ) ;
}
void rt_assign_native_code ( int unique_code_id , py_fun_t fun , uint len , int n_args ) {
alloc_unique_codes ( ) ;
2013-10-05 08:37:10 -04:00
assert ( 1 < = unique_code_id & & unique_code_id < next_unique_code_id ) ;
2013-10-04 14:53:11 -04:00
unique_codes [ unique_code_id ] . kind = PY_CODE_NATIVE ;
unique_codes [ unique_code_id ] . n_args = n_args ;
2013-10-16 15:39:12 -04:00
unique_codes [ unique_code_id ] . n_locals = 0 ;
unique_codes [ unique_code_id ] . n_stack = 0 ;
unique_codes [ unique_code_id ] . is_generator = false ;
2013-10-04 14:53:11 -04:00
unique_codes [ unique_code_id ] . u_native . fun = fun ;
2013-10-10 18:25:50 -04:00
# ifdef DEBUG_PRINT
2013-10-04 14:53:11 -04:00
DEBUG_printf ( " assign native code: id=%d fun=%p len=%u n_args=%d \n " , unique_code_id , fun , len , n_args ) ;
byte * fun_data = ( byte * ) ( ( ( machine_uint_t ) fun ) & ( ~ 1 ) ) ; // need to clear lower bit in case it's thumb code
for ( int i = 0 ; i < 128 & & i < len ; i + + ) {
if ( i > 0 & & i % 16 = = 0 ) {
DEBUG_printf ( " \n " ) ;
}
DEBUG_printf ( " %02x " , fun_data [ i ] ) ;
}
DEBUG_printf ( " \n " ) ;
2013-10-10 18:25:50 -04:00
# ifdef WRITE_NATIVE
2013-10-04 14:53:11 -04:00
if ( fp_native ! = NULL ) {
fwrite ( fun_data , len , 1 , fp_native ) ;
2013-10-08 04:05:10 -04:00
fflush ( fp_native ) ;
2013-10-04 14:53:11 -04:00
}
2013-10-10 18:25:50 -04:00
# endif
# endif
2013-10-04 14:53:11 -04:00
}
2013-10-05 18:17:28 -04:00
void rt_assign_inline_asm_code ( int unique_code_id , py_fun_t fun , uint len , int n_args ) {
alloc_unique_codes ( ) ;
assert ( 1 < = unique_code_id & & unique_code_id < next_unique_code_id ) ;
unique_codes [ unique_code_id ] . kind = PY_CODE_INLINE_ASM ;
2013-10-04 14:53:11 -04:00
unique_codes [ unique_code_id ] . n_args = n_args ;
2013-10-16 15:39:12 -04:00
unique_codes [ unique_code_id ] . n_locals = 0 ;
unique_codes [ unique_code_id ] . n_stack = 0 ;
unique_codes [ unique_code_id ] . is_generator = false ;
2013-10-05 18:17:28 -04:00
unique_codes [ unique_code_id ] . u_inline_asm . fun = fun ;
2013-10-04 14:53:11 -04:00
2013-10-10 18:25:50 -04:00
# ifdef DEBUG_PRINT
2013-10-05 18:17:28 -04:00
DEBUG_printf ( " assign inline asm code: id=%d fun=%p len=%u n_args=%d \n " , unique_code_id , fun , len , n_args ) ;
byte * fun_data = ( byte * ) ( ( ( machine_uint_t ) fun ) & ( ~ 1 ) ) ; // need to clear lower bit in case it's thumb code
for ( int i = 0 ; i < 128 & & i < len ; i + + ) {
if ( i > 0 & & i % 16 = = 0 ) {
DEBUG_printf ( " \n " ) ;
}
DEBUG_printf ( " %02x " , fun_data [ i ] ) ;
}
DEBUG_printf ( " \n " ) ;
2013-10-10 18:25:50 -04:00
# ifdef WRITE_NATIVE
2013-10-05 18:17:28 -04:00
if ( fp_native ! = NULL ) {
fwrite ( fun_data , len , 1 , fp_native ) ;
}
2013-10-10 18:25:50 -04:00
# endif
# endif
2013-10-04 14:53:11 -04:00
}
2013-10-09 18:10:10 -04:00
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 :
2013-10-10 17:06:54 -04:00
// what about O_CLASS, and an O_OBJ that has a __call__ method?
2013-10-09 18:10:10 -04:00
return true ;
default :
return false ;
}
}
}
2013-10-04 14:53:11 -04:00
const char * py_obj_get_type_str ( py_obj_t o_in ) {
if ( IS_SMALL_INT ( o_in ) ) {
return " int " ;
} else {
py_obj_base_t * o = o_in ;
switch ( o - > kind ) {
case O_CONST :
if ( o = = py_const_none ) {
return " NoneType " ;
} else {
return " bool " ;
}
case O_STR :
return " str " ;
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-04 14:53:11 -04:00
case O_FLOAT :
return " float " ;
# endif
2013-10-05 13:08:26 -04:00
case O_FUN_0 :
case O_FUN_1 :
case O_FUN_2 :
case O_FUN_N :
case O_FUN_BC :
return " function " ;
2013-10-16 15:39:12 -04:00
case O_GEN_INSTANCE :
return " generator " ;
2013-10-16 11:12:52 -04:00
case O_TUPLE :
return " tuple " ;
2013-10-04 14:53:11 -04:00
case O_LIST :
return " list " ;
2013-10-16 11:12:52 -04:00
case O_TUPLE_IT :
return " tuple_iterator " ;
case O_LIST_IT :
return " list_iterator " ;
2013-10-04 14:53:11 -04:00
case O_SET :
return " set " ;
case O_MAP :
return " dict " ;
2013-10-09 18:10:10 -04:00
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 ) ;
}
2013-10-04 14:53:11 -04:00
default :
assert ( 0 ) ;
return " UnknownType " ;
}
}
}
void py_obj_print ( py_obj_t o_in ) {
if ( IS_SMALL_INT ( o_in ) ) {
printf ( " %d " , ( int ) FROM_SMALL_INT ( o_in ) ) ;
} else {
py_obj_base_t * o = o_in ;
switch ( o - > kind ) {
case O_CONST :
printf ( " %s " , o - > id ) ;
break ;
case O_STR :
// TODO need to escape chars etc
printf ( " '%s' " , qstr_str ( o - > u_str ) ) ;
break ;
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-04 14:53:11 -04:00
case O_FLOAT :
2013-10-06 07:04:13 -04:00
printf ( " %f " , o - > u_flt ) ;
2013-10-04 14:53:11 -04:00
break ;
# endif
2013-10-16 15:39:12 -04:00
case O_EXCEPTION_0 :
printf ( " %s " , qstr_str ( o - > u_exc0 . id ) ) ;
break ;
2013-10-22 11:05:11 -04:00
case O_EXCEPTION_N :
printf ( " %s: " , qstr_str ( o - > u_exc_n . id ) ) ;
printf ( o - > u_exc_n . args [ 0 ] , o - > u_exc_n . args [ 1 ] , o - > u_exc_n . args [ 2 ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-10-16 15:39:12 -04:00
case O_GEN_INSTANCE :
printf ( " <generator object 'fun-name' at %p> " , o ) ;
break ;
2013-10-16 11:12:52 -04:00
case O_TUPLE :
printf ( " ( " ) ;
for ( int i = 0 ; i < o - > u_tuple_list . len ; i + + ) {
if ( i > 0 ) {
printf ( " , " ) ;
}
py_obj_print ( o - > u_tuple_list . items [ i ] ) ;
}
if ( o - > u_tuple_list . len = = 1 ) {
printf ( " , " ) ;
}
printf ( " ) " ) ;
break ;
2013-10-04 14:53:11 -04:00
case O_LIST :
printf ( " [ " ) ;
2013-10-16 11:12:52 -04:00
for ( int i = 0 ; i < o - > u_tuple_list . len ; i + + ) {
2013-10-04 14:53:11 -04:00
if ( i > 0 ) {
printf ( " , " ) ;
}
2013-10-16 11:12:52 -04:00
py_obj_print ( o - > u_tuple_list . items [ i ] ) ;
2013-10-04 14:53:11 -04:00
}
printf ( " ] " ) ;
break ;
case O_SET :
{
bool first = true ;
printf ( " { " ) ;
for ( int i = 0 ; i < o - > u_set . alloc ; i + + ) {
if ( o - > u_set . table [ i ] ! = NULL ) {
if ( ! first ) {
printf ( " , " ) ;
}
first = false ;
py_obj_print ( o - > u_set . table [ i ] ) ;
}
}
printf ( " } " ) ;
break ;
}
case O_MAP :
{
bool first = true ;
printf ( " { " ) ;
for ( int i = 0 ; i < o - > u_map . alloc ; i + + ) {
if ( o - > u_map . table [ i ] . key ! = NULL ) {
if ( ! first ) {
printf ( " , " ) ;
}
first = false ;
py_obj_print ( o - > u_map . table [ i ] . key ) ;
printf ( " : " ) ;
py_obj_print ( o - > u_map . table [ i ] . value ) ;
}
}
printf ( " } " ) ;
break ;
}
default :
2013-10-09 18:10:10 -04:00
printf ( " <? %d> " , o - > kind ) ;
2013-10-04 14:53:11 -04:00
assert ( 0 ) ;
}
}
}
int rt_is_true ( py_obj_t arg ) {
DEBUG_OP_printf ( " is true %p \n " , arg ) ;
if ( IS_SMALL_INT ( arg ) ) {
if ( FROM_SMALL_INT ( arg ) = = 0 ) {
return 0 ;
} else {
return 1 ;
}
} else if ( arg = = py_const_none ) {
return 0 ;
} else if ( arg = = py_const_false ) {
return 0 ;
} else if ( arg = = py_const_true ) {
return 1 ;
} else {
assert ( 0 ) ;
return 0 ;
}
}
int rt_get_int ( py_obj_t arg ) {
2013-10-16 11:12:52 -04:00
if ( arg = = py_const_false ) {
return 0 ;
} else if ( arg = = py_const_true ) {
return 1 ;
} else if ( IS_SMALL_INT ( arg ) ) {
2013-10-04 14:53:11 -04:00
return FROM_SMALL_INT ( arg ) ;
} else {
assert ( 0 ) ;
return 0 ;
}
}
py_obj_t rt_load_const_str ( qstr qstr ) {
DEBUG_OP_printf ( " load '%s' \n " , qstr_str ( qstr ) ) ;
return py_obj_new_str ( qstr ) ;
}
py_obj_t rt_load_name ( qstr qstr ) {
// logic: search locals, globals, builtins
2013-10-09 18:10:10 -04:00
DEBUG_OP_printf ( " load name %s \n " , qstr_str ( qstr ) ) ;
2013-10-10 17:06:54 -04:00
py_map_elem_t * elem = py_qstr_map_lookup ( map_locals , qstr , false ) ;
2013-10-04 14:53:11 -04:00
if ( elem = = NULL ) {
2013-10-10 17:06:54 -04:00
elem = py_qstr_map_lookup ( map_globals , qstr , false ) ;
2013-10-04 14:53:11 -04:00
if ( elem = = NULL ) {
2013-10-09 18:10:10 -04:00
elem = py_qstr_map_lookup ( & map_builtins , qstr , false ) ;
if ( elem = = NULL ) {
2013-10-15 17:25:17 -04:00
nlr_jump ( py_obj_new_exception_2 ( q_NameError , " name '%s' is not defined " , qstr_str ( qstr ) , NULL ) ) ;
2013-10-09 18:10:10 -04:00
}
2013-10-04 14:53:11 -04:00
}
}
return elem - > value ;
}
py_obj_t rt_load_global ( qstr qstr ) {
2013-10-09 18:10:10 -04:00
// logic: search globals, builtins
DEBUG_OP_printf ( " load global %s \n " , qstr_str ( qstr ) ) ;
2013-10-10 17:06:54 -04:00
py_map_elem_t * elem = py_qstr_map_lookup ( map_globals , qstr , false ) ;
2013-10-09 18:10:10 -04:00
if ( elem = = NULL ) {
elem = py_qstr_map_lookup ( & map_builtins , qstr , false ) ;
if ( elem = = NULL ) {
2013-10-15 17:25:17 -04:00
nlr_jump ( py_obj_new_exception_2 ( q_NameError , " name '%s' is not defined " , qstr_str ( qstr ) , NULL ) ) ;
2013-10-09 18:10:10 -04:00
}
}
return elem - > value ;
2013-10-04 14:53:11 -04:00
}
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 ) ;
if ( elem = = NULL ) {
printf ( " name doesn't exist: __build_class__ \n " ) ;
assert ( 0 ) ;
}
return elem - > value ;
}
void rt_store_name ( qstr qstr , py_obj_t obj ) {
2013-10-09 18:10:10 -04:00
DEBUG_OP_printf ( " store name %s <- %p \n " , qstr_str ( qstr ) , obj ) ;
2013-10-10 17:06:54 -04:00
py_qstr_map_lookup ( map_locals , qstr , true ) - > value = obj ;
2013-10-09 18:10:10 -04:00
}
void rt_store_global ( qstr qstr , py_obj_t obj ) {
DEBUG_OP_printf ( " store global %s <- %p \n " , qstr_str ( qstr ) , obj ) ;
2013-10-10 17:06:54 -04:00
py_qstr_map_lookup ( map_globals , qstr , true ) - > value = obj ;
2013-10-04 14:53:11 -04:00
}
py_obj_t rt_unary_op ( int op , py_obj_t arg ) {
assert ( 0 ) ;
return py_const_none ;
}
2013-10-16 11:12:52 -04:00
uint get_index ( py_obj_base_t * base , py_obj_t index ) {
// assumes base is O_TUPLE or O_LIST
// TODO False and True are considered 0 and 1 for indexing purposes
int len = base - > u_tuple_list . len ;
if ( IS_SMALL_INT ( index ) ) {
int i = FROM_SMALL_INT ( index ) ;
if ( i < 0 ) {
i + = len ;
}
if ( i < 0 | | i > = len ) {
nlr_jump ( py_obj_new_exception_2 ( q_IndexError , " %s index out of range " , py_obj_get_type_str ( base ) , NULL ) ) ;
}
return i ;
} else {
nlr_jump ( py_obj_new_exception_2 ( q_TypeError , " %s indices must be integers, not %s " , py_obj_get_type_str ( base ) , py_obj_get_type_str ( index ) ) ) ;
}
}
2013-10-04 14:53:11 -04:00
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 ) {
2013-10-16 11:12:52 -04:00
if ( ( IS_O ( lhs , O_TUPLE ) | | IS_O ( lhs , O_LIST ) ) ) {
2013-10-18 14:58:12 -04:00
// tuple/list load
2013-10-16 11:12:52 -04:00
uint index = get_index ( lhs , rhs ) ;
return ( ( py_obj_base_t * ) lhs ) - > u_tuple_list . items [ index ] ;
2013-10-18 14:58:12 -04:00
} 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 ;
}
2013-10-04 14:53:11 -04:00
} else {
assert ( 0 ) ;
}
} else if ( IS_SMALL_INT ( lhs ) & & IS_SMALL_INT ( rhs ) ) {
py_small_int_t val ;
switch ( op ) {
2013-10-22 11:53:02 -04:00
case RT_BINARY_OP_OR :
case RT_BINARY_OP_INPLACE_OR : val = FROM_SMALL_INT ( lhs ) | FROM_SMALL_INT ( rhs ) ; break ;
case RT_BINARY_OP_XOR :
case RT_BINARY_OP_INPLACE_XOR : val = FROM_SMALL_INT ( lhs ) ^ FROM_SMALL_INT ( rhs ) ; break ;
case RT_BINARY_OP_AND :
case RT_BINARY_OP_INPLACE_AND : val = FROM_SMALL_INT ( lhs ) & FROM_SMALL_INT ( rhs ) ; break ;
case RT_BINARY_OP_LSHIFT :
case RT_BINARY_OP_INPLACE_LSHIFT : val = FROM_SMALL_INT ( lhs ) < < FROM_SMALL_INT ( rhs ) ; break ;
case RT_BINARY_OP_RSHIFT :
case RT_BINARY_OP_INPLACE_RSHIFT : val = FROM_SMALL_INT ( lhs ) > > FROM_SMALL_INT ( rhs ) ; break ;
2013-10-04 14:53:11 -04:00
case RT_BINARY_OP_ADD :
case RT_BINARY_OP_INPLACE_ADD : val = FROM_SMALL_INT ( lhs ) + FROM_SMALL_INT ( rhs ) ; break ;
2013-10-16 15:39:12 -04:00
case RT_BINARY_OP_SUBTRACT :
case RT_BINARY_OP_INPLACE_SUBTRACT : val = FROM_SMALL_INT ( lhs ) - FROM_SMALL_INT ( rhs ) ; break ;
2013-10-22 11:53:02 -04:00
case RT_BINARY_OP_MULTIPLY :
case RT_BINARY_OP_INPLACE_MULTIPLY : val = FROM_SMALL_INT ( lhs ) * FROM_SMALL_INT ( rhs ) ; break ;
case RT_BINARY_OP_FLOOR_DIVIDE :
case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE : val = FROM_SMALL_INT ( lhs ) / FROM_SMALL_INT ( rhs ) ; break ;
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-22 11:53:02 -04:00
case RT_BINARY_OP_TRUE_DIVIDE :
case RT_BINARY_OP_INPLACE_TRUE_DIVIDE : return py_obj_new_float ( ( float_t ) FROM_SMALL_INT ( lhs ) / ( float_t ) FROM_SMALL_INT ( rhs ) ) ;
2013-10-04 14:53:11 -04:00
# endif
default : printf ( " %d \n " , op ) ; assert ( 0 ) ; val = 0 ;
}
if ( fit_small_int ( val ) ) {
return TO_SMALL_INT ( val ) ;
}
} else if ( IS_O ( lhs , O_STR ) & & IS_O ( rhs , O_STR ) ) {
const char * lhs_str = qstr_str ( ( ( py_obj_base_t * ) lhs ) - > u_str ) ;
const char * rhs_str = qstr_str ( ( ( py_obj_base_t * ) rhs ) - > u_str ) ;
char * val ;
switch ( op ) {
case RT_BINARY_OP_ADD :
case RT_BINARY_OP_INPLACE_ADD : val = m_new ( char , strlen ( lhs_str ) + strlen ( rhs_str ) + 1 ) ; strcpy ( val , lhs_str ) ; strcat ( val , rhs_str ) ; break ;
default : printf ( " %d \n " , op ) ; assert ( 0 ) ; val = NULL ;
}
return py_obj_new_str ( qstr_from_str_take ( val ) ) ;
}
assert ( 0 ) ;
return py_const_none ;
}
py_obj_t rt_compare_op ( int op , py_obj_t lhs , py_obj_t rhs ) {
DEBUG_OP_printf ( " compare %d %p %p \n " , op , lhs , rhs ) ;
2013-10-22 11:53:02 -04:00
// deal with == and !=
if ( op = = RT_COMPARE_OP_EQUAL | | op = = RT_COMPARE_OP_NOT_EQUAL ) {
if ( py_obj_equal ( lhs , rhs ) ) {
if ( op = = RT_COMPARE_OP_EQUAL ) {
return py_const_true ;
} else {
return py_const_false ;
}
} else {
if ( op = = RT_COMPARE_OP_EQUAL ) {
return py_const_false ;
} else {
return py_const_true ;
}
}
}
// deal with small ints
2013-10-04 14:53:11 -04:00
if ( IS_SMALL_INT ( lhs ) & & IS_SMALL_INT ( rhs ) ) {
int cmp ;
switch ( op ) {
case RT_COMPARE_OP_LESS : cmp = FROM_SMALL_INT ( lhs ) < FROM_SMALL_INT ( rhs ) ; break ;
case RT_COMPARE_OP_MORE : cmp = FROM_SMALL_INT ( lhs ) > FROM_SMALL_INT ( rhs ) ; break ;
2013-10-22 11:53:02 -04:00
case RT_COMPARE_OP_LESS_EQUAL : cmp = FROM_SMALL_INT ( lhs ) < = FROM_SMALL_INT ( rhs ) ; break ;
case RT_COMPARE_OP_MORE_EQUAL : cmp = FROM_SMALL_INT ( lhs ) > = FROM_SMALL_INT ( rhs ) ; break ;
2013-10-04 14:53:11 -04:00
default : assert ( 0 ) ; cmp = 0 ;
}
if ( cmp ) {
return py_const_true ;
} else {
return py_const_false ;
}
}
2013-10-22 11:53:02 -04:00
// not implemented
2013-10-04 14:53:11 -04:00
assert ( 0 ) ;
return py_const_none ;
}
py_obj_t rt_make_function_from_id ( int unique_code_id ) {
2013-10-05 08:37:10 -04:00
DEBUG_OP_printf ( " make_function_from_id %d \n " , unique_code_id ) ;
if ( unique_code_id < 1 | | unique_code_id > = next_unique_code_id ) {
2013-10-04 14:53:11 -04:00
// illegal code id
return py_const_none ;
}
py_code_t * c = & unique_codes [ unique_code_id ] ;
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
switch ( c - > kind ) {
2013-10-05 18:17:28 -04:00
case PY_CODE_BYTE :
o - > kind = O_FUN_BC ;
o - > u_fun_bc . n_args = c - > n_args ;
o - > u_fun_bc . code = c - > u_byte . code ;
o - > u_fun_bc . len = c - > u_byte . len ;
break ;
2013-10-04 14:53:11 -04:00
case PY_CODE_NATIVE :
switch ( c - > n_args ) {
case 0 : o - > kind = O_FUN_0 ; break ;
case 1 : o - > kind = O_FUN_1 ; break ;
case 2 : o - > kind = O_FUN_2 ; break ;
default : assert ( 0 ) ;
}
o - > u_fun . fun = c - > u_native . fun ;
break ;
2013-10-05 18:17:28 -04:00
case PY_CODE_INLINE_ASM :
o - > kind = O_FUN_ASM ;
o - > u_fun_asm . n_args = c - > n_args ;
o - > u_fun_asm . fun = c - > u_inline_asm . fun ;
2013-10-04 14:53:11 -04:00
break ;
default :
assert ( 0 ) ;
}
2013-10-16 15:39:12 -04:00
// check for generator functions and if so wrap in generator object
if ( c - > is_generator ) {
py_obj_base_t * o2 = m_new ( py_obj_base_t , 1 ) ;
o2 - > kind = O_GEN_WRAP ;
// we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done
o2 - > u_gen_wrap . n_state = ( c - > n_locals < 3 ? 3 : c - > n_locals ) + c - > n_stack ;
o2 - > u_gen_wrap . fun = o ;
o = o2 ;
}
2013-10-04 14:53:11 -04:00
return o ;
}
py_obj_t rt_make_function_0 ( py_fun_0_t fun ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_FUN_0 ;
o - > u_fun . fun = fun ;
return o ;
}
py_obj_t rt_make_function_1 ( py_fun_1_t fun ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_FUN_1 ;
o - > u_fun . fun = fun ;
return o ;
}
py_obj_t rt_make_function_2 ( py_fun_2_t fun ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_FUN_2 ;
o - > u_fun . fun = fun ;
return o ;
}
py_obj_t rt_make_function ( int n_args , py_fun_t code ) {
// assumes code is a pointer to a py_fun_t (i think this is safe...)
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_FUN_N ;
o - > u_fun . n_args = n_args ;
2013-10-05 18:17:28 -04:00
o - > u_fun . fun = code ;
2013-10-04 14:53:11 -04:00
return o ;
}
2013-10-10 17:06:54 -04:00
py_obj_t rt_call_function_0 ( py_obj_t fun ) {
return rt_call_function_n ( fun , 0 , NULL ) ;
}
py_obj_t rt_call_function_1 ( py_obj_t fun , py_obj_t arg ) {
return rt_call_function_n ( fun , 1 , & arg ) ;
}
py_obj_t rt_call_function_2 ( py_obj_t fun , py_obj_t arg1 , py_obj_t arg2 ) {
py_obj_t args [ 2 ] ;
args [ 1 ] = arg1 ;
args [ 0 ] = arg2 ;
return rt_call_function_n ( fun , 2 , args ) ;
}
typedef machine_uint_t ( * inline_asm_fun_0_t ) ( ) ;
typedef machine_uint_t ( * inline_asm_fun_1_t ) ( machine_uint_t ) ;
typedef machine_uint_t ( * inline_asm_fun_2_t ) ( machine_uint_t , machine_uint_t ) ;
typedef machine_uint_t ( * inline_asm_fun_3_t ) ( machine_uint_t , machine_uint_t , machine_uint_t ) ;
2013-10-06 07:04:13 -04:00
// convert a Python object to a sensible value for inline asm
machine_uint_t rt_convert_obj_for_inline_asm ( py_obj_t obj ) {
// TODO for byte_array, pass pointer to the array
if ( IS_SMALL_INT ( obj ) ) {
return FROM_SMALL_INT ( obj ) ;
} else if ( obj = = py_const_none ) {
return 0 ;
} else if ( obj = = py_const_false ) {
return 0 ;
} else if ( obj = = py_const_true ) {
return 1 ;
} else {
py_obj_base_t * o = obj ;
switch ( o - > kind ) {
case O_STR :
// pointer to the string (it's probably constant though!)
return ( machine_uint_t ) qstr_str ( o - > u_str ) ;
2013-10-12 11:53:13 -04:00
# if MICROPY_ENABLE_FLOAT
2013-10-06 07:04:13 -04:00
case O_FLOAT :
// convert float to int (could also pass in float registers)
return ( machine_int_t ) o - > u_flt ;
2013-10-12 09:30:21 -04:00
# endif
2013-10-06 07:04:13 -04:00
2013-10-16 11:12:52 -04:00
case O_TUPLE :
2013-10-06 07:04:13 -04:00
case O_LIST :
2013-10-16 11:12:52 -04:00
// pointer to start of tuple/list (could pass length, but then could use len(x) for that)
return ( machine_uint_t ) o - > u_tuple_list . items ;
2013-10-06 07:04:13 -04:00
default :
// just pass along a pointer to the object
return ( machine_uint_t ) obj ;
}
}
}
// convert a return value from inline asm to a sensible Python object
py_obj_t rt_convert_val_from_inline_asm ( machine_uint_t val ) {
return TO_SMALL_INT ( val ) ;
}
2013-10-10 17:06:54 -04:00
// 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 ) {
int n_args_fun = 0 ;
2013-10-04 14:53:11 -04:00
if ( IS_O ( fun , O_FUN_0 ) ) {
py_obj_base_t * o = fun ;
2013-10-10 17:06:54 -04:00
if ( n_args ! = 0 ) {
n_args_fun = 0 ;
goto bad_n_args ;
}
DEBUG_OP_printf ( " calling native %p() \n " , o - > u_fun . fun ) ;
2013-10-04 14:53:11 -04:00
return ( ( py_fun_0_t ) o - > u_fun . fun ) ( ) ;
2013-10-10 17:06:54 -04:00
} else if ( IS_O ( fun , O_FUN_1 ) ) {
py_obj_base_t * o = fun ;
if ( n_args ! = 1 ) {
n_args_fun = 1 ;
goto bad_n_args ;
}
DEBUG_OP_printf ( " calling native %p(%p) \n " , o - > u_fun . fun , args [ 0 ] ) ;
return ( ( py_fun_1_t ) o - > u_fun . fun ) ( args [ 0 ] ) ;
} else if ( IS_O ( fun , O_FUN_2 ) ) {
py_obj_base_t * o = fun ;
if ( n_args ! = 2 ) {
n_args_fun = 2 ;
goto bad_n_args ;
}
DEBUG_OP_printf ( " calling native %p(%p, %p) \n " , o - > u_fun . fun , args [ 1 ] , args [ 0 ] ) ;
return ( ( py_fun_2_t ) o - > u_fun . fun ) ( args [ 1 ] , args [ 0 ] ) ;
// TODO O_FUN_N
2013-10-04 14:53:11 -04:00
} else if ( IS_O ( fun , O_FUN_BC ) ) {
py_obj_base_t * o = fun ;
2013-10-10 17:06:54 -04:00
if ( n_args ! = o - > u_fun_bc . n_args ) {
n_args_fun = o - > u_fun_bc . n_args ;
goto bad_n_args ;
}
DEBUG_OP_printf ( " calling byte code %p(n_args=%d) \n " , o - > u_fun_bc . code , n_args ) ;
2013-10-16 15:39:12 -04:00
return py_execute_byte_code ( o - > u_fun_bc . code , args , n_args ) ;
2013-10-10 17:06:54 -04:00
2013-10-06 07:04:13 -04:00
} else if ( IS_O ( fun , O_FUN_ASM ) ) {
py_obj_base_t * o = fun ;
2013-10-10 17:06:54 -04:00
if ( n_args ! = o - > u_fun_asm . n_args ) {
n_args_fun = o - > u_fun_asm . n_args ;
goto bad_n_args ;
}
DEBUG_OP_printf ( " calling inline asm %p(n_args=%d) \n " , o - > u_fun_asm . fun , n_args ) ;
machine_uint_t ret ;
if ( n_args = = 0 ) {
ret = ( ( inline_asm_fun_0_t ) o - > u_fun_asm . fun ) ( ) ;
} else if ( n_args = = 1 ) {
ret = ( ( inline_asm_fun_1_t ) o - > u_fun_asm . fun ) ( rt_convert_obj_for_inline_asm ( args [ 0 ] ) ) ;
} else if ( n_args = = 2 ) {
ret = ( ( inline_asm_fun_2_t ) o - > u_fun_asm . fun ) ( rt_convert_obj_for_inline_asm ( args [ 1 ] ) , rt_convert_obj_for_inline_asm ( args [ 0 ] ) ) ;
} else if ( n_args = = 3 ) {
ret = ( ( inline_asm_fun_3_t ) o - > u_fun_asm . fun ) ( rt_convert_obj_for_inline_asm ( args [ 2 ] ) , rt_convert_obj_for_inline_asm ( args [ 1 ] ) , rt_convert_obj_for_inline_asm ( args [ 0 ] ) ) ;
} else {
assert ( 0 ) ;
ret = 0 ;
}
return rt_convert_val_from_inline_asm ( ret ) ;
2013-10-16 15:39:12 -04:00
} else if ( IS_O ( fun , O_GEN_WRAP ) ) {
py_obj_base_t * o = fun ;
py_obj_base_t * o_fun = o - > u_gen_wrap . fun ;
assert ( o_fun - > kind = = O_FUN_BC ) ; // TODO
if ( n_args ! = o_fun - > u_fun_bc . n_args ) {
n_args_fun = o_fun - > u_fun_bc . n_args ;
goto bad_n_args ;
}
py_obj_t * state = m_new ( py_obj_t , 1 + o - > u_gen_wrap . n_state ) ;
// put function object at first slot in state (to keep u_gen_instance small)
state [ 0 ] = o_fun ;
// init args
for ( int i = 0 ; i < n_args ; i + + ) {
state [ 1 + i ] = args [ n_args - 1 - i ] ;
}
py_obj_base_t * o2 = m_new ( py_obj_base_t , 1 ) ;
o2 - > kind = O_GEN_INSTANCE ;
o2 - > u_gen_instance . state = state ;
o2 - > u_gen_instance . ip = o_fun - > u_fun_bc . code ;
o2 - > u_gen_instance . sp = state + o - > u_gen_wrap . n_state ;
return o2 ;
2013-10-09 18:10:10 -04:00
} else if ( IS_O ( fun , O_BOUND_METH ) ) {
py_obj_base_t * o = fun ;
2013-10-10 17:06:54 -04:00
DEBUG_OP_printf ( " calling bound method %p(self=%p, n_args=%d) \n " , o - > u_bound_meth . meth , o - > u_bound_meth . self , n_args ) ;
if ( n_args = = 0 ) {
return rt_call_function_n ( o - > u_bound_meth . meth , 1 , & o - > u_bound_meth . self ) ;
} else if ( n_args = = 1 ) {
py_obj_t args2 [ 2 ] ;
args2 [ 1 ] = o - > u_bound_meth . self ;
args2 [ 0 ] = args [ 0 ] ;
return rt_call_function_n ( o - > u_bound_meth . meth , 2 , args2 ) ;
} else {
// TODO not implemented
assert ( 0 ) ;
return py_const_none ;
//return rt_call_function_2(o->u_bound_meth.meth, n_args + 1, o->u_bound_meth.self + args);
}
2013-10-09 18:10:10 -04:00
} else if ( IS_O ( fun , O_CLASS ) ) {
// instantiate an instance of a class
2013-10-10 17:06:54 -04:00
if ( n_args ! = 0 ) {
n_args_fun = 0 ;
goto bad_n_args ;
}
2013-10-09 18:10:10 -04:00
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 ;
2013-10-04 14:53:11 -04:00
} else {
2013-10-10 17:06:54 -04:00
printf ( " fun %p %d \n " , fun , ( ( py_obj_base_t * ) fun ) - > kind ) ;
2013-10-04 14:53:11 -04:00
assert ( 0 ) ;
return py_const_none ;
}
2013-10-10 17:06:54 -04:00
bad_n_args :
2013-10-16 15:39:12 -04:00
nlr_jump ( py_obj_new_exception_2 ( q_TypeError , " function takes %d positional arguments but %d were given " , ( const char * ) ( machine_int_t ) n_args_fun , ( const char * ) ( machine_int_t ) n_args ) ) ;
2013-10-04 14:53:11 -04:00
}
2013-10-09 18:10:10 -04:00
// 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 ) {
2013-10-10 06:24:39 -04:00
DEBUG_OP_printf ( " call method %p(self=%p, n_args=%d) \n " , args [ n_args + 1 ] , args [ n_args ] , n_args ) ;
2013-10-09 18:10:10 -04:00
return rt_call_function_n ( args [ n_args + 1 ] , n_args + ( ( args [ n_args ] = = NULL ) ? 0 : 1 ) , args ) ;
}
2013-10-16 11:12:52 -04:00
// items are in reverse order
py_obj_t rt_build_tuple ( int n_args , py_obj_t * items ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_TUPLE ;
o - > u_tuple_list . alloc = n_args < 4 ? 4 : n_args ;
o - > u_tuple_list . len = n_args ;
o - > u_tuple_list . items = m_new ( py_obj_t , o - > u_tuple_list . alloc ) ;
for ( int i = 0 ; i < n_args ; i + + ) {
o - > u_tuple_list . items [ i ] = items [ n_args - i - 1 ] ;
}
return o ;
}
2013-10-04 14:53:11 -04:00
// 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 ) ;
o - > kind = O_LIST ;
2013-10-16 11:12:52 -04:00
o - > u_tuple_list . alloc = n_args < 4 ? 4 : n_args ;
o - > u_tuple_list . len = n_args ;
o - > u_tuple_list . items = m_new ( py_obj_t , o - > u_tuple_list . alloc ) ;
2013-10-04 14:53:11 -04:00
for ( int i = 0 ; i < n_args ; i + + ) {
2013-10-16 11:12:52 -04:00
o - > u_tuple_list . items [ i ] = items [ n_args - i - 1 ] ;
2013-10-04 14:53:11 -04:00
}
return o ;
}
py_obj_t py_set_lookup ( py_obj_t o_in , py_obj_t index , bool add_if_not_found ) {
assert ( IS_O ( o_in , O_SET ) ) ;
py_obj_base_t * o = o_in ;
int hash = py_obj_hash ( index ) ;
int pos = hash % o - > u_set . alloc ;
for ( ; ; ) {
py_obj_t elem = o - > u_set . table [ pos ] ;
if ( elem = = NULL ) {
// not in table
if ( add_if_not_found ) {
if ( o - > u_set . used + 1 > = o - > u_set . alloc ) {
// not enough room in table, rehash it
int old_alloc = o - > u_set . alloc ;
py_obj_t * old_table = o - > u_set . table ;
o - > u_set . alloc = get_doubling_prime_greater_or_equal_to ( o - > u_set . alloc + 1 ) ;
o - > u_set . used = 0 ;
o - > u_set . table = m_new ( py_obj_t , o - > u_set . alloc ) ;
for ( int i = 0 ; i < old_alloc ; i + + ) {
if ( old_table [ i ] ! = NULL ) {
py_set_lookup ( o , old_table [ i ] , true ) ;
}
}
m_free ( old_table ) ;
// restart the search for the new element
pos = hash % o - > u_set . alloc ;
} else {
o - > u_set . used + = 1 ;
o - > u_set . table [ pos ] = index ;
return index ;
}
} else {
return NULL ;
}
} else if ( py_obj_equal ( elem , index ) ) {
// found it
return elem ;
} else {
// not yet found, keep searching in this table
pos = ( pos + 1 ) % o - > u_set . alloc ;
}
}
}
py_obj_t rt_build_set ( int n_args , py_obj_t * items ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_SET ;
o - > u_set . alloc = get_doubling_prime_greater_or_equal_to ( n_args + 1 ) ;
o - > u_set . used = 0 ;
o - > u_set . table = m_new ( py_obj_t , o - > u_set . alloc ) ;
for ( int i = 0 ; i < o - > u_set . alloc ; i + + ) {
o - > u_set . table [ i ] = NULL ;
}
for ( int i = 0 ; i < n_args ; i + + ) {
py_set_lookup ( o , items [ i ] , true ) ;
}
return o ;
}
2013-10-16 15:57:49 -04:00
py_obj_t rt_store_set ( py_obj_t set , py_obj_t item ) {
py_set_lookup ( set , item , true ) ;
return set ;
}
2013-10-04 14:53:11 -04:00
py_obj_t rt_build_map ( int n_args ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_MAP ;
py_map_init ( & o - > u_map , MAP_PY_OBJ , n_args ) ;
return o ;
}
py_obj_t rt_store_map ( py_obj_t map , py_obj_t key , py_obj_t value ) {
assert ( IS_O ( map , O_MAP ) ) ; // should always be
py_map_lookup ( map , key , true ) - > value = 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 ) {
2013-10-09 18:10:10 -04:00
DEBUG_OP_printf ( " load attr %s \n " , qstr_str ( attr ) ) ;
2013-10-04 14:53:11 -04:00
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 ;
2013-10-09 18:10:10 -04:00
py_map_elem_t * elem = py_qstr_map_lookup ( o - > u_class . locals , attr , false ) ;
2013-10-04 14:53:11 -04:00
if ( elem = = NULL ) {
2013-10-09 18:10:10 -04:00
goto no_attr ;
2013-10-04 14:53:11 -04:00
}
return elem - > value ;
2013-10-09 18:10:10 -04:00
} 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 ;
2013-10-04 14:53:11 -04:00
}
2013-10-09 18:10:10 -04:00
no_attr :
2013-10-15 17:25:17 -04:00
nlr_jump ( py_obj_new_exception_2 ( q_AttributeError , " '%s' object has no attribute '%s' " , py_obj_get_type_str ( base ) , qstr_str ( attr ) ) ) ;
2013-10-04 14:53:11 -04:00
}
void rt_load_method ( py_obj_t base , qstr attr , py_obj_t * dest ) {
DEBUG_OP_printf ( " load method %s \n " , qstr_str ( attr ) ) ;
2013-10-16 15:39:12 -04:00
if ( IS_O ( base , O_GEN_INSTANCE ) & & attr = = q___next__ ) {
dest [ 1 ] = fun_gen_instance_next ;
dest [ 0 ] = base ;
return ;
} else if ( IS_O ( base , O_LIST ) & & attr = = q_append ) {
2013-10-04 14:53:11 -04:00
dest [ 1 ] = fun_list_append ;
dest [ 0 ] = base ;
2013-10-09 18:10:10 -04:00
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 ;
}
2013-10-18 14:58:12 -04:00
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 ) ;
2013-10-22 17:58:17 -04:00
if ( IS_O ( base , O_CLASS ) ) {
// TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
py_obj_base_t * o = base ;
py_qstr_map_lookup ( o - > u_class . locals , attr , true ) - > value = value ;
} else if ( IS_O ( base , O_OBJ ) ) {
2013-10-09 18:10:10 -04:00
// 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 ) {
2013-10-18 14:58:12 -04:00
elem - > value = value ;
2013-10-09 18:10:10 -04:00
} else {
2013-10-22 17:58:17 -04:00
py_qstr_map_lookup ( o - > u_obj . members , attr , true ) - > value = value ;
2013-10-09 18:10:10 -04:00
}
} 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 ) {
2013-10-18 14:58:12 -04:00
DEBUG_OP_printf ( " store subscr %p[%p] <- %p \n " , base , index , value ) ;
2013-10-16 11:12:52 -04:00
if ( IS_O ( base , O_LIST ) ) {
2013-10-09 18:10:10 -04:00
// list store
2013-10-16 11:12:52 -04:00
uint i = get_index ( base , index ) ;
( ( py_obj_base_t * ) base ) - > u_tuple_list . items [ i ] = value ;
2013-10-09 18:10:10 -04:00
} else if ( IS_O ( base , O_MAP ) ) {
// map store
py_map_lookup ( base , index , true ) - > value = value ;
2013-10-04 14:53:11 -04:00
} else {
2013-10-09 18:10:10 -04:00
assert ( 0 ) ;
2013-10-04 14:53:11 -04:00
}
}
2013-10-15 17:25:17 -04:00
py_obj_t rt_getiter ( py_obj_t o_in ) {
2013-10-16 15:39:12 -04:00
if ( IS_O ( o_in , O_GEN_INSTANCE ) ) {
return o_in ;
} else if ( IS_O ( o_in , O_RANGE ) ) {
2013-10-15 17:25:17 -04:00
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 ) ;
2013-10-16 11:12:52 -04:00
} else if ( IS_O ( o_in , O_TUPLE ) ) {
return py_obj_new_tuple_iterator ( o_in , 0 ) ;
} else if ( IS_O ( o_in , O_LIST ) ) {
return py_obj_new_list_iterator ( o_in , 0 ) ;
2013-10-15 17:25:17 -04:00
} 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 ) {
2013-10-16 15:39:12 -04:00
if ( IS_O ( o_in , O_GEN_INSTANCE ) ) {
py_obj_base_t * self = o_in ;
py_obj_base_t * fun = self - > u_gen_instance . state [ 0 ] ;
assert ( fun - > kind = = O_FUN_BC ) ;
bool yield = py_execute_byte_code_2 ( fun - > u_fun_bc . code , & self - > u_gen_instance . ip , & self - > u_gen_instance . state [ 1 ] , & self - > u_gen_instance . sp ) ;
if ( yield ) {
return * self - > u_gen_instance . sp ;
} else {
if ( * self - > u_gen_instance . sp = = py_const_none ) {
return py_const_stop_iteration ;
} else {
// TODO return StopIteration with value *self->u_gen_instance.sp
return py_const_stop_iteration ;
}
}
} else if ( IS_O ( o_in , O_RANGE_IT ) ) {
2013-10-15 17:25:17 -04:00
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 ;
}
2013-10-16 15:39:12 -04:00
2013-10-16 11:12:52 -04:00
} else if ( IS_O ( o_in , O_TUPLE_IT ) | | IS_O ( o_in , O_LIST_IT ) ) {
py_obj_base_t * o = o_in ;
if ( o - > u_tuple_list_it . cur < o - > u_tuple_list_it . obj - > u_tuple_list . len ) {
py_obj_t o_out = o - > u_tuple_list_it . obj - > u_tuple_list . items [ o - > u_tuple_list_it . cur ] ;
o - > u_tuple_list_it . cur + = 1 ;
return o_out ;
} else {
return py_const_stop_iteration ;
}
2013-10-16 15:39:12 -04:00
2013-10-15 17:25:17 -04:00
} else {
nlr_jump ( py_obj_new_exception_2 ( q_TypeError , " ? '%s' object is not iterable " , py_obj_get_type_str ( o_in ) , NULL ) ) ;
}
}
2013-10-19 13:28:01 -04:00
void * const rt_fun_table [ RT_F_NUMBER_OF ] = {
2013-10-04 14:53:11 -04:00
rt_load_const_str ,
rt_load_name ,
rt_load_global ,
2013-10-10 06:24:39 -04:00
rt_load_build_class ,
2013-10-04 14:53:11 -04:00
rt_load_attr ,
rt_load_method ,
rt_store_name ,
2013-10-10 06:24:39 -04:00
rt_store_attr ,
2013-10-04 14:53:11 -04:00
rt_store_subscr ,
rt_is_true ,
rt_unary_op ,
2013-10-16 18:58:48 -04:00
rt_build_tuple ,
2013-10-04 14:53:11 -04:00
rt_build_list ,
2013-10-16 18:58:48 -04:00
rt_list_append ,
2013-10-04 14:53:11 -04:00
rt_build_map ,
rt_store_map ,
rt_build_set ,
2013-10-16 18:58:48 -04:00
rt_store_set ,
2013-10-04 14:53:11 -04:00
rt_make_function_from_id ,
2013-10-10 17:06:54 -04:00
rt_call_function_n ,
2013-10-10 06:24:39 -04:00
rt_call_method_n ,
2013-10-04 14:53:11 -04:00
rt_binary_op ,
rt_compare_op ,
2013-10-16 18:58:48 -04:00
rt_getiter ,
rt_iternext ,
2013-10-04 14:53:11 -04:00
} ;
/*
void rt_f_vector ( rt_fun_kind_t fun_kind ) {
( rt_f_table [ fun_kind ] ) ( ) ;
}
*/
2013-10-22 17:58:17 -04:00
// temporary way of making C modules
// hack: use class to mimic a module
py_obj_t py_module_new ( ) {
py_obj_base_t * o = m_new ( py_obj_base_t , 1 ) ;
o - > kind = O_CLASS ;
o - > u_class . locals = py_map_new ( MAP_QSTR , 0 ) ;
return o ;
}