Implement: str.join, more float support, ROT_TWO in VM.

This commit is contained in:
Damien 2013-11-02 14:33:10 +00:00
parent 4c51cbdc0b
commit 4ebb32fb95
3 changed files with 154 additions and 36 deletions

View File

@ -165,15 +165,27 @@ struct _py_obj_base_t {
};
};
static qstr q_append;
static qstr q_join;
static qstr q_print;
static qstr q_len;
static qstr q___build_class__;
static qstr q___next__;
static qstr q_AttributeError;
static qstr q_IndexError;
static qstr q_KeyError;
static qstr q_NameError;
static qstr q_TypeError;
py_obj_t py_const_none;
py_obj_t py_const_false;
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
py_map_t *map_locals;
py_map_t *map_globals;
py_map_t map_builtins;
static py_map_t *map_locals;
static py_map_t *map_globals;
static 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};
@ -319,7 +331,7 @@ static bool fit_small_int(py_small_int_t o) {
return true;
}
py_obj_t py_obj_new_int(int value) {
py_obj_t py_obj_new_int(machine_int_t value) {
return TO_SMALL_INT(value);
}
@ -400,6 +412,39 @@ py_obj_t py_obj_new_list_iterator(py_obj_base_t *list, int cur) {
return o;
}
py_obj_t rt_str_join(py_obj_t self_in, py_obj_t arg) {
assert(IS_O(self_in, O_STR));
py_obj_base_t *self = self_in;
int required_len = strlen(qstr_str(self->u_str));
// process arg, count required chars
if (!IS_O(arg, O_TUPLE) && !IS_O(arg, O_LIST)) {
goto bad_arg;
}
py_obj_base_t *tuple_list = arg;
for (int i = 0; i < tuple_list->u_tuple_list.len; i++) {
if (!IS_O(tuple_list->u_tuple_list.items[i], O_STR)) {
goto bad_arg;
}
required_len += strlen(qstr_str(((py_obj_base_t*)tuple_list->u_tuple_list.items[i])->u_str));
}
// make joined string
char *joined_str = m_new(char, required_len + 1);
joined_str[0] = 0;
for (int i = 0; i < tuple_list->u_tuple_list.len; i++) {
const char *s2 = qstr_str(((py_obj_base_t*)tuple_list->u_tuple_list.items[i])->u_str);
if (i > 0) {
strcat(joined_str, qstr_str(self->u_str));
}
strcat(joined_str, s2);
}
return py_obj_new_str(qstr_from_str_take(joined_str));
bad_arg:
nlr_jump(py_obj_new_exception_2(q_TypeError, "?str.join expecting a list of str's", NULL, NULL));
}
py_obj_t rt_list_append(py_obj_t self_in, py_obj_t arg) {
assert(IS_O(self_in, O_LIST));
py_obj_base_t *self = self_in;
@ -420,17 +465,6 @@ py_obj_t rt_gen_instance_next(py_obj_t self_in) {
}
}
static qstr q_append;
static qstr q_print;
static qstr q_len;
static qstr q___build_class__;
static qstr q___next__;
static qstr q_AttributeError;
static qstr q_IndexError;
static qstr q_KeyError;
static qstr q_NameError;
static qstr q_TypeError;
typedef enum {
PY_CODE_NONE,
PY_CODE_BYTE,
@ -461,6 +495,7 @@ typedef struct _py_code_t {
static int next_unique_code_id;
static py_code_t *unique_codes;
py_obj_t fun_str_join;
py_obj_t fun_list_append;
py_obj_t fun_gen_instance_next;
@ -527,6 +562,7 @@ FILE *fp_native = NULL;
void rt_init(void) {
q_append = qstr_from_str_static("append");
q_join = qstr_from_str_static("join");
q_print = qstr_from_str_static("print");
q_len = qstr_from_str_static("len");
q___build_class__ = qstr_from_str_static("__build_class__");
@ -556,6 +592,7 @@ void rt_init(void) {
next_unique_code_id = 2; // 1 is reserved for the __main__ module scope
unique_codes = NULL;
fun_str_join = rt_make_function_2(rt_str_join);
fun_list_append = rt_make_function_2(rt_list_append);
fun_gen_instance_next = rt_make_function_1(rt_gen_instance_next);
@ -849,7 +886,7 @@ int rt_is_true(py_obj_t arg) {
}
}
int py_get_int(py_obj_t arg) {
machine_int_t py_get_int(py_obj_t arg) {
if (arg == py_const_false) {
return 0;
} else if (arg == py_const_true) {
@ -862,6 +899,21 @@ int py_get_int(py_obj_t arg) {
}
}
machine_float_t py_obj_get_float(py_obj_t arg) {
if (arg == py_const_false) {
return 0;
} else if (arg == py_const_true) {
return 1;
} else if (IS_SMALL_INT(arg)) {
return FROM_SMALL_INT(arg);
} else if (IS_O(arg, O_FLOAT)) {
return ((py_obj_base_t*)arg)->u_flt;
} else {
assert(0);
return 0;
}
}
qstr py_get_qstr(py_obj_t arg) {
if (IS_O(arg, O_STR)) {
return ((py_obj_base_t*)arg)->u_str;
@ -871,7 +923,7 @@ qstr py_get_qstr(py_obj_t arg) {
}
}
py_obj_t *py_get_array_fixed_n(py_obj_t o_in, int n) {
py_obj_t *py_get_array_fixed_n(py_obj_t o_in, machine_int_t n) {
if (IS_O(o_in, O_TUPLE) || IS_O(o_in, O_LIST)) {
py_obj_base_t *o = o_in;
if (o->u_tuple_list.len != n) {
@ -979,35 +1031,66 @@ py_obj_t rt_binary_op(int op, py_obj_t lhs, py_obj_t rhs) {
assert(0);
}
} else if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
py_small_int_t lhs_val = FROM_SMALL_INT(lhs);
py_small_int_t rhs_val = FROM_SMALL_INT(rhs);
py_small_int_t val;
switch (op) {
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_INPLACE_OR: val = lhs_val | rhs_val; 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_INPLACE_XOR: val = lhs_val ^ rhs_val; 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_INPLACE_AND: val = lhs_val & rhs_val; 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_INPLACE_LSHIFT: val = lhs_val << rhs_val; break;
case RT_BINARY_OP_RSHIFT:
case RT_BINARY_OP_INPLACE_RSHIFT: val = FROM_SMALL_INT(lhs) >> FROM_SMALL_INT(rhs); break;
case RT_BINARY_OP_INPLACE_RSHIFT: val = lhs_val >> rhs_val; break;
case RT_BINARY_OP_ADD:
case RT_BINARY_OP_INPLACE_ADD: val = FROM_SMALL_INT(lhs) + FROM_SMALL_INT(rhs); break;
case RT_BINARY_OP_INPLACE_ADD: val = lhs_val + rhs_val; break;
case RT_BINARY_OP_SUBTRACT:
case RT_BINARY_OP_INPLACE_SUBTRACT: val = FROM_SMALL_INT(lhs) - FROM_SMALL_INT(rhs); break;
case RT_BINARY_OP_INPLACE_SUBTRACT: val = lhs_val - rhs_val; break;
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_INPLACE_MULTIPLY: val = lhs_val * rhs_val; break;
case RT_BINARY_OP_FLOOR_DIVIDE:
case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = FROM_SMALL_INT(lhs) / FROM_SMALL_INT(rhs); break;
case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = lhs_val / rhs_val; break;
#if MICROPY_ENABLE_FLOAT
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));
case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: return py_obj_new_float((float_t)lhs_val / (float_t)rhs_val);
#endif
case RT_BINARY_OP_POWER:
case RT_BINARY_OP_INPLACE_POWER:
// TODO
if (rhs_val == 2) {
val = lhs_val * lhs_val;
break;
}
default: printf("%d\n", op); assert(0); val = 0;
}
if (fit_small_int(val)) {
return TO_SMALL_INT(val);
}
#if MICROPY_ENABLE_FLOAT
} else if (IS_O(lhs, O_FLOAT) || IS_O(rhs, O_FLOAT)) {
float_t lhs_val = py_obj_get_float(lhs);
float_t rhs_val = py_obj_get_float(rhs);
float_t val;
switch (op) {
case RT_BINARY_OP_ADD:
case RT_BINARY_OP_INPLACE_ADD: val = lhs_val + rhs_val; break;
case RT_BINARY_OP_SUBTRACT:
case RT_BINARY_OP_INPLACE_SUBTRACT: val = lhs_val - rhs_val; break;
case RT_BINARY_OP_MULTIPLY:
case RT_BINARY_OP_INPLACE_MULTIPLY: val = lhs_val * rhs_val; break;
/* TODO floor(?) the value
case RT_BINARY_OP_FLOOR_DIVIDE:
case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = lhs_val / rhs_val; break;
*/
case RT_BINARY_OP_TRUE_DIVIDE:
case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: val = lhs_val / rhs_val; break;
default: printf("%d\n", op); assert(0); val = 0;
}
return py_obj_new_float(val);
#endif
} 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);
@ -1045,12 +1128,14 @@ py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs) {
// deal with small ints
if (IS_SMALL_INT(lhs) && IS_SMALL_INT(rhs)) {
py_small_int_t lhs_val = FROM_SMALL_INT(lhs);
py_small_int_t rhs_val = FROM_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;
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;
case RT_COMPARE_OP_LESS: cmp = lhs_val < rhs_val; break;
case RT_COMPARE_OP_MORE: cmp = lhs_val > rhs_val; break;
case RT_COMPARE_OP_LESS_EQUAL: cmp = lhs_val <= rhs_val; break;
case RT_COMPARE_OP_MORE_EQUAL: cmp = lhs_val >= rhs_val; break;
default: assert(0); cmp = 0;
}
if (cmp) {
@ -1060,6 +1145,27 @@ py_obj_t rt_compare_op(int op, py_obj_t lhs, py_obj_t rhs) {
}
}
#if MICROPY_ENABLE_FLOAT
// deal with floats
if (IS_O(lhs, O_FLOAT) || IS_O(rhs, O_FLOAT)) {
float_t lhs_val = py_obj_get_float(lhs);
float_t rhs_val = py_obj_get_float(rhs);
int cmp;
switch (op) {
case RT_COMPARE_OP_LESS: cmp = lhs_val < rhs_val; break;
case RT_COMPARE_OP_MORE: cmp = lhs_val > rhs_val; break;
case RT_COMPARE_OP_LESS_EQUAL: cmp = lhs_val <= rhs_val; break;
case RT_COMPARE_OP_MORE_EQUAL: cmp = lhs_val >= rhs_val; break;
default: assert(0); cmp = 0;
}
if (cmp) {
return py_const_true;
} else {
return py_const_false;
}
}
#endif
// not implemented
assert(0);
return py_const_none;
@ -1482,7 +1588,11 @@ no_attr:
void rt_load_method(py_obj_t base, qstr attr, py_obj_t *dest) {
DEBUG_OP_printf("load method %s\n", qstr_str(attr));
if (IS_O(base, O_GEN_INSTANCE) && attr == q___next__) {
if (IS_O(base, O_STR) && attr == q_join) {
dest[1] = fun_str_join;
dest[0] = base;
return;
} else if (IS_O(base, O_GEN_INSTANCE) && attr == q___next__) {
dest[1] = fun_gen_instance_next;
dest[0] = base;
return;

View File

@ -97,10 +97,11 @@ 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 py_obj_print(py_obj_t o);
int rt_is_true(py_obj_t arg);
int py_get_int(py_obj_t arg);
machine_int_t py_get_int(py_obj_t arg);
machine_float_t py_obj_get_float(py_obj_t arg);
qstr py_get_qstr(py_obj_t arg);
py_obj_t *py_get_array_fixed_n(py_obj_t o, int n);
py_obj_t py_obj_new_int(int value);
py_obj_t *py_get_array_fixed_n(py_obj_t o, machine_int_t n);
py_obj_t py_obj_new_int(machine_int_t value);
py_obj_t rt_load_const_str(qstr qstr);
py_obj_t rt_load_name(qstr qstr);
py_obj_t rt_load_global(qstr qstr);

View File

@ -32,7 +32,8 @@ py_obj_t py_execute_byte_code(const byte *code, const py_obj_t *args, uint n_arg
// it shouldn't yield
assert(0);
}
assert(sp == &state[17]);
// TODO check fails if, eg, return from within for loop
//assert(sp == &state[17]);
return *sp;
}
@ -182,6 +183,12 @@ bool py_execute_byte_code_2(const byte *code, const byte **ip_in_out, py_obj_t *
++sp;
break;
case PYBC_ROT_TWO:
obj1 = sp[0];
sp[0] = sp[1];
sp[1] = obj1;
break;
case PYBC_ROT_THREE:
obj1 = sp[0];
sp[0] = sp[1];