summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--examples/unix/ffi_example.py38
-rw-r--r--py/compile.c19
-rw-r--r--py/emit.h2
-rw-r--r--py/emitbc.c10
-rw-r--r--py/emitcpy.c4
-rw-r--r--py/emitnative.c2
-rw-r--r--py/malloc.c10
-rw-r--r--py/mpconfig.h6
-rw-r--r--py/obj.c4
-rw-r--r--py/obj.h4
-rw-r--r--py/objarray.c55
-rw-r--r--py/objcomplex.c4
-rw-r--r--py/objdict.c9
-rw-r--r--py/objexcept.c18
-rw-r--r--py/objfloat.c2
-rw-r--r--py/objgenerator.c7
-rw-r--r--py/objlist.c9
-rw-r--r--py/objnone.c11
-rw-r--r--py/objstr.c66
-rw-r--r--py/objtuple.c9
-rw-r--r--py/parse.c6
-rw-r--r--py/qstr.c16
-rw-r--r--py/qstr.h2
-rw-r--r--py/runtime.c77
-rw-r--r--py/runtime0.h10
-rw-r--r--py/showbc.c8
-rw-r--r--py/vm.c45
-rw-r--r--stm/file.c1
-rw-r--r--stm/gccollect.c6
-rw-r--r--stm/gccollect.h5
-rw-r--r--stm/lcd.c10
-rw-r--r--stm/main.c41
-rw-r--r--stm/printf.c2
-rw-r--r--stm/rtc.c30
-rw-r--r--stm/stm32f405.ld4
-rw-r--r--tests/basics/array1.py13
-rw-r--r--tests/basics/bytearray1.py1
-rw-r--r--tests/basics/unary_op.py12
-rw-r--r--unix/Makefile4
-rw-r--r--unix/ffi.c330
-rw-r--r--unix/main.c16
-rw-r--r--unix/mpconfigport.h1
42 files changed, 731 insertions, 198 deletions
diff --git a/examples/unix/ffi_example.py b/examples/unix/ffi_example.py
new file mode 100644
index 0000000000..0ac12203e6
--- /dev/null
+++ b/examples/unix/ffi_example.py
@@ -0,0 +1,38 @@
+import ffi
+
+libc = ffi.open("libc.so.6")
+print("libc:", libc)
+print()
+
+# Declare few functions
+perror = libc.func("v", "perror", ["s"])
+time = libc.func("i", "time", "p")
+open = libc.func("i", "open", ["s", "i"])
+qsort = libc.func("v", "qsort", "piip")
+# And one variable
+errno = libc.var("i", "errno")
+
+print("time:", time)
+print("UNIX time is:", time(None))
+print()
+
+perror("ffi before error")
+open("somethingnonexistent__", 0)
+print(errno)
+perror("ffi after error")
+print()
+
+def cmp(pa, pb):
+ a = ffi.as_bytearray(pa, 1)
+ b = ffi.as_bytearray(pb, 1)
+ print("cmp:", a, b)
+ return a[0] - b[0]
+
+cmp_c = ffi.callback("i", cmp, "pp")
+print("callback:", cmp_c)
+
+# TODO: violates Py semantics, pass bytearray
+s = "foobar"
+print("org string:", s)
+qsort(s, len(s), 1, cmp_c)
+print("qsort'ed:", s)
diff --git a/py/compile.c b/py/compile.c
index e1b62a11bf..c1a7955dcd 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1912,7 +1912,21 @@ void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_node(comp, pns->nodes[0]);
+#if MICROPY_EMIT_CPYTHON
EMIT_ARG(unary_op, RT_UNARY_OP_NOT);
+#else
+ // eliminate use of NOT byte code
+ int l_load_false = comp_next_label(comp);
+ int l_done = comp_next_label(comp);
+ int stack_size = EMIT(get_stack_size);
+ EMIT_ARG(pop_jump_if_true, l_load_false);
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_TRUE);
+ EMIT_ARG(jump, l_done);
+ EMIT_ARG(label_assign, l_load_false);
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_FALSE);
+ EMIT_ARG(label_assign, l_done);
+ EMIT_ARG(set_stack_size, stack_size); // force stack size since it counts 1 pop and 2 pushes statically, but really it's 1 pop and 1 push dynamically
+#endif
}
void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -2487,7 +2501,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_NULL(pn)) {
// pass
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
- int arg = MP_PARSE_NODE_LEAF_ARG(pn);
+ machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
case MP_PARSE_NODE_SMALL_INT: EMIT_ARG(load_const_small_int, arg); break;
@@ -3016,7 +3030,8 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
scope->flags |= SCOPE_FLAG_OPTIMISED;
// TODO possibly other ways it can be nested
- if (scope->parent->kind == SCOPE_FUNCTION || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) {
+ // Note that we don't actually use this information at the moment (for CPython compat only)
+ if ((SCOPE_FUNCTION <= scope->parent->kind && scope->parent->kind <= SCOPE_SET_COMP) || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) {
scope->flags |= SCOPE_FLAG_NESTED;
}
}
diff --git a/py/emit.h b/py/emit.h
index fc5538f586..ff33a8f6d3 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -34,7 +34,7 @@ typedef struct _emit_method_table_t {
void (*import_from)(emit_t *emit, qstr qstr);
void (*import_star)(emit_t *emit);
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
- void (*load_const_small_int)(emit_t *emit, int arg);
+ void (*load_const_small_int)(emit_t *emit, machine_int_t arg);
void (*load_const_int)(emit_t *emit, qstr qstr);
void (*load_const_dec)(emit_t *emit, qstr qstr);
void (*load_const_id)(emit_t *emit, qstr qstr);
diff --git a/py/emitbc.c b/py/emitbc.c
index 9fa2880ecb..d74b065253 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -108,7 +108,7 @@ static void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) {
}
// integers (for small ints) are stored as 24 bits, in excess
-static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, int num) {
+static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) {
num += 0x800000;
assert(0 <= num && num <= 0xffffff);
byte* c = emit_get_cur_to_write_byte_code(emit, 4);
@@ -249,6 +249,7 @@ static void emit_bc_set_stack_size(emit_t *emit, int size) {
static void emit_bc_set_source_line(emit_t *emit, int source_line) {
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->byte_code_offset);
+#if MICROPY_ENABLE_SOURCE_LINE
if (source_line > emit->last_source_line) {
uint bytes_to_skip = emit->byte_code_offset - emit->last_source_line_offset;
uint lines_to_skip = source_line - emit->last_source_line;
@@ -257,6 +258,7 @@ static void emit_bc_set_source_line(emit_t *emit, int source_line) {
emit->last_source_line_offset = emit->byte_code_offset;
emit->last_source_line = source_line;
}
+#endif
}
static void emit_bc_load_id(emit_t *emit, qstr qstr) {
@@ -319,7 +321,7 @@ static void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
}
}
-static void emit_bc_load_const_small_int(emit_t *emit, int arg) {
+static void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) {
emit_pre(emit, 1);
emit_write_byte_code_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
}
@@ -390,7 +392,7 @@ static void emit_bc_load_attr(emit_t *emit, qstr qstr) {
}
static void emit_bc_load_method(emit_t *emit, qstr qstr) {
- emit_pre(emit, 0);
+ emit_pre(emit, 1);
emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr);
}
@@ -707,7 +709,7 @@ static void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, b
if (have_dbl_star_arg) {
s += 1;
}
- emit_pre(emit, -n_positional - 2 * n_keyword - s);
+ emit_pre(emit, -1 - n_positional - 2 * n_keyword - s);
int op;
if (have_star_arg) {
if (have_dbl_star_arg) {
diff --git a/py/emitcpy.c b/py/emitcpy.c
index 71861c918d..2e5c34cb2b 100644
--- a/py/emitcpy.c
+++ b/py/emitcpy.c
@@ -149,10 +149,10 @@ static void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
}
}
-static void emit_cpy_load_const_small_int(emit_t *emit, int arg) {
+static void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) {
emit_pre(emit, 1, 3);
if (emit->pass == PASS_3) {
- printf("LOAD_CONST %d\n", arg);
+ printf("LOAD_CONST " INT_FMT "\n", arg);
}
}
diff --git a/py/emitnative.c b/py/emitnative.c
index 258aa9fce5..1e5ea1fa9b 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -599,7 +599,7 @@ static void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
emit_post_push_imm(emit, vtype, val);
}
-static void emit_native_load_const_small_int(emit_t *emit, int arg) {
+static void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) {
emit_pre(emit);
if (emit->do_viper_types) {
emit_post_push_imm(emit, VTYPE_INT, arg);
diff --git a/py/malloc.c b/py/malloc.c
index 4f01dc63f5..a2c55eb06b 100644
--- a/py/malloc.c
+++ b/py/malloc.c
@@ -4,6 +4,12 @@
#include "misc.h"
#include "mpconfig.h"
+#if 0 // print debugging info
+#define DEBUG_printf(args...) printf(args)
+#else // don't print debugging info
+#define DEBUG_printf(args...) (void)0
+#endif
+
#if MICROPY_MEM_STATS
static int total_bytes_allocated = 0;
static int current_bytes_allocated = 0;
@@ -26,6 +32,7 @@ void *m_malloc(int num_bytes) {
current_bytes_allocated += num_bytes;
UPDATE_PEAK();
#endif
+ DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
return ptr;
}
@@ -43,6 +50,7 @@ void *m_malloc0(int num_bytes) {
current_bytes_allocated += num_bytes;
UPDATE_PEAK();
#endif
+ DEBUG_printf("malloc0 %d : %p\n", num_bytes, ptr);
return ptr;
}
@@ -67,6 +75,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
current_bytes_allocated += diff;
UPDATE_PEAK();
#endif
+ DEBUG_printf("realloc %d, %d : %p\n", old_num_bytes, new_num_bytes, ptr);
return ptr;
}
@@ -77,6 +86,7 @@ void m_free(void *ptr, int num_bytes) {
#if MICROPY_MEM_STATS
current_bytes_allocated -= num_bytes;
#endif
+ DEBUG_printf("free %p, %d\n", ptr, num_bytes);
}
int m_get_total_bytes_allocated(void) {
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 97e4b13875..38b74b733a 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -76,6 +76,12 @@
typedef long long mp_longint_impl_t;
#endif
+// Whether to include information in the byte code to determine source
+// line number (increases RAM usage, but doesn't slow byte code execution)
+#ifndef MICROPY_ENABLE_SOURCE_LINE
+#define MICROPY_ENABLE_SOURCE_LINE (0)
+#endif
+
// Whether to support float and complex types
#ifndef MICROPY_ENABLE_FLOAT
#define MICROPY_ENABLE_FLOAT (0)
diff --git a/py/obj.c b/py/obj.c
index 76a4d8f9b2..ce555efa6d 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -57,7 +57,11 @@ void mp_obj_print_exception(mp_obj_t exc) {
if (n > 0) {
printf("Traceback (most recent call last):\n");
for (int i = n - 3; i >= 0; i -= 3) {
+#if MICROPY_ENABLE_SOURCE_LINE
printf(" File \"%s\", line %d, in %s\n", qstr_str(values[i]), (int)values[i + 1], qstr_str(values[i + 2]));
+#else
+ printf(" File \"%s\", in %s\n", qstr_str(values[i]), qstr_str(values[i + 2]));
+#endif
}
}
}
diff --git a/py/obj.h b/py/obj.h
index 9c6a354220..56e4d96df6 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -223,7 +223,7 @@ mp_obj_t mp_obj_new_range(int start, int stop, int step);
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code);
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
-mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun);
+mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple);
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
@@ -291,6 +291,7 @@ uint mp_obj_str_get_len(mp_obj_t self_in);
qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
const byte *mp_obj_str_get_data(mp_obj_t self_in, uint *len);
+void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len);
// bytes
extern const mp_obj_type_t bytes_type;
@@ -348,6 +349,7 @@ extern const mp_obj_type_t zip_type;
// array
extern const mp_obj_type_t array_type;
uint mp_obj_array_len(mp_obj_t self_in);
+mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items);
// functions
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
diff --git a/py/objarray.c b/py/objarray.c
index 4f36561153..42dbfcda05 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -124,17 +124,22 @@ static void array_set_el(mp_obj_array_t *o, int index, mp_obj_t val_in) {
static void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_array_t *o = o_in;
if (o->typecode == BYTEARRAY_TYPECODE) {
- print(env, "bytearray([", o->typecode);
+ print(env, "bytearray(b", o->typecode);
+ mp_str_print_quoted(print, env, o->items, o->len);
} else {
- print(env, "array('%c', [", o->typecode);
- }
- for (int i = 0; i < o->len; i++) {
- if (i > 0) {
- print(env, ", ");
+ print(env, "array('%c'", o->typecode);
+ if (o->len > 0) {
+ print(env, ", [", o->typecode);
+ for (int i = 0; i < o->len; i++) {
+ if (i > 0) {
+ print(env, ", ");
+ }
+ print(env, "%d", array_get_el(o, i));
+ }
+ print(env, "]");
}
- print(env, "%d", array_get_el(o, i));
}
- print(env, "])");
+ print(env, ")");
}
static mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
@@ -164,20 +169,17 @@ static mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
}
static mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
- switch (n_args) {
- case 2:
- {
- // TODO check args
- uint l;
- const byte *s = mp_obj_str_get_data(args[0], &l);
- mp_obj_t initializer = args[1];
- return array_construct(*s, initializer);
- }
-
- default:
- nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args));
+ if (n_args < 1 || n_args > 2) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args));
+ }
+ // TODO check args
+ uint l;
+ const byte *typecode = mp_obj_str_get_data(args[0], &l);
+ if (n_args == 1) {
+ return array_new(*typecode, 0);
}
- return NULL;
+
+ return array_construct(*typecode, args[1]);
}
// This is top-level factory function, not virtual method
@@ -269,6 +271,17 @@ mp_obj_t mp_obj_new_bytearray(uint n, void *items) {
return o;
}
+// Create bytearray which references specified memory area
+mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
+ mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
+ o->base.type = &array_type;
+ o->typecode = BYTEARRAY_TYPECODE;
+ o->free = 0;
+ o->len = n;
+ o->items = items;
+ return o;
+}
+
/******************************************************************************/
/* array iterator */
diff --git a/py/objcomplex.c b/py/objcomplex.c
index af148a2786..24762e8b11 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -24,9 +24,9 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_complex_t *o = o_in;
if (o->real == 0) {
- print(env, "%.8gj", o->imag);
+ print(env, "%.8gj", (double) o->imag);
} else {
- print(env, "(%.8g+%.8gj)", o->real, o->imag);
+ print(env, "(%.8g+%.8gj)", (double) o->real, (double) o->imag);
}
}
diff --git a/py/objdict.c b/py/objdict.c
index 55a612913d..93ff1af90a 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -43,6 +43,14 @@ static mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
return rt_build_map(0);
}
+static mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
+ mp_obj_dict_t *self = self_in;
+ switch (op) {
+ case RT_UNARY_OP_NOT: if (self->map.used == 0) { return mp_const_true; } else { return mp_const_false; }
+ default: return MP_OBJ_NULL; // op not supported for None
+ }
+}
+
static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_dict_t *o = lhs_in;
switch (op) {
@@ -436,6 +444,7 @@ const mp_obj_type_t dict_type = {
"dict",
.print = dict_print,
.make_new = dict_make_new,
+ .unary_op = dict_unary_op,
.binary_op = dict_binary_op,
.getiter = dict_getiter,
.methods = dict_type_methods,
diff --git a/py/objexcept.c b/py/objexcept.c
index c91b71dd9e..8eb4e966e9 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -13,20 +13,19 @@
// This is unified class for C-level and Python-level exceptions
// Python-level exception have empty ->msg and all arguments are in
-// args tuple. C-level excepttion likely have ->msg, and may as well
-// have args tuple (or otherwise have it as NULL).
+// args tuple. C-level excepttion likely have ->msg and args is empty.
typedef struct mp_obj_exception_t {
mp_obj_base_t base;
mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now
qstr id;
- qstr msg;
+ vstr_t *msg;
mp_obj_tuple_t args;
} mp_obj_exception_t;
void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = o_in;
- if (o->msg != 0) {
- print(env, "%s: %s", qstr_str(o->id), qstr_str(o->msg));
+ if (o->msg != NULL) {
+ print(env, "%s: %s", qstr_str(o->id), vstr_str(o->msg));
} else {
// Yes, that's how CPython has it
if (kind == PRINT_REPR) {
@@ -55,7 +54,7 @@ static mp_obj_t exception_call(mp_obj_t self_in, uint n_args, uint n_kw, const m
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args);
o->base.type = &exception_type;
o->id = base->id;
- o->msg = 0;
+ o->msg = NULL;
o->args.len = n_args;
memcpy(o->args.items, args, n_args * sizeof(mp_obj_t));
return o;
@@ -92,15 +91,14 @@ mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) {
o->id = id;
o->args.len = 0;
if (fmt == NULL) {
- o->msg = 0;
+ o->msg = NULL;
} else {
// render exception message
- vstr_t *vstr = vstr_new();
+ o->msg = vstr_new();
va_list ap;
va_start(ap, fmt);
- vstr_vprintf(vstr, fmt, ap);
+ vstr_vprintf(o->msg, fmt, ap);
va_end(ap);
- o->msg = qstr_from_strn_take(vstr->buf, vstr->alloc, vstr->len);
}
return o;
diff --git a/py/objfloat.c b/py/objfloat.c
index 9f1f478cab..69fd65e199 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -21,7 +21,7 @@ mp_obj_t mp_obj_new_float(mp_float_t value);
static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_float_t *o = o_in;
- print(env, "%.8g", o->value);
+ print(env, "%.8g", (double) o->value);
}
static mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 91bbbceb2f..67f8eed59c 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -16,7 +16,6 @@
typedef struct _mp_obj_gen_wrap_t {
mp_obj_base_t base;
- uint n_state;
mp_obj_t *fun;
} mp_obj_gen_wrap_t;
@@ -35,7 +34,7 @@ mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
}
- return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args);
+ return mp_obj_new_gen_instance(bc_code, bc_n_state, n_args, args);
}
const mp_obj_type_t gen_wrap_type = {
@@ -44,11 +43,9 @@ const mp_obj_type_t gen_wrap_type = {
.call = gen_wrap_call,
};
-mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) {
+mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) {
mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t);
o->base.type = &gen_wrap_type;
- // we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done
- o->n_state = (n_locals < 3 ? 3 : n_locals) + n_stack;
o->fun = fun;
return o;
}
diff --git a/py/objlist.c b/py/objlist.c
index d21e16000d..fb68e2c566 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -122,6 +122,14 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) {
return true;
}
+static mp_obj_t list_unary_op(int op, mp_obj_t self_in) {
+ mp_obj_list_t *self = self_in;
+ switch (op) {
+ case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; }
+ default: return MP_OBJ_NULL; // op not supported for None
+ }
+}
+
static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_list_t *o = lhs;
switch (op) {
@@ -399,6 +407,7 @@ const mp_obj_type_t list_type = {
"list",
.print = list_print,
.make_new = list_make_new,
+ .unary_op = list_unary_op,
.binary_op = list_binary_op,
.getiter = list_getiter,
.methods = list_type_methods,
diff --git a/py/objnone.c b/py/objnone.c
index ecc7c4b4e7..4151403b21 100644
--- a/py/objnone.c
+++ b/py/objnone.c
@@ -6,19 +6,28 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
+#include "runtime0.h"
typedef struct _mp_obj_none_t {
mp_obj_base_t base;
} mp_obj_none_t;
-void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+static void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "None");
}
+static mp_obj_t none_unary_op(int op, mp_obj_t o_in) {
+ switch (op) {
+ case RT_UNARY_OP_NOT: return mp_const_true;
+ default: return MP_OBJ_NULL; // op not supported for None
+ }
+}
+
const mp_obj_type_t none_type = {
{ &mp_const_type },
"NoneType",
.print = none_print,
+ .unary_op = none_unary_op,
};
static const mp_obj_none_t none_obj = {{&none_type}};
diff --git a/py/objstr.c b/py/objstr.c
index 84ac74bab9..c30da00d71 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -34,45 +34,49 @@ static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
/******************************************************************************/
/* str */
-void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
+ // this escapes characters, but it will be very slow to print (calling print many times)
+ bool has_single_quote = false;
+ bool has_double_quote = false;
+ for (const byte *s = str_data, *top = str_data + str_len; (!has_single_quote || !has_double_quote) && s < top; s++) {
+ if (*s == '\'') {
+ has_single_quote = true;
+ } else if (*s == '"') {
+ has_double_quote = true;
+ }
+ }
+ int quote_char = '\'';
+ if (has_single_quote && !has_double_quote) {
+ quote_char = '"';
+ }
+ print(env, "%c", quote_char);
+ for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
+ if (*s == quote_char) {
+ print(env, "\\%c", quote_char);
+ } else if (*s == '\\') {
+ print(env, "\\\\");
+ } else if (32 <= *s && *s <= 126) {
+ print(env, "%c", *s);
+ } else if (*s == '\n') {
+ print(env, "\\n");
+ // TODO add more escape codes here if we want to match CPython
+ } else {
+ print(env, "\\x%02x", *s);
+ }
+ }
+ print(env, "%c", quote_char);
+}
+
+static void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &bytes_type);
if (kind == PRINT_STR && !is_bytes) {
print(env, "%.*s", str_len, str_data);
} else {
- // this escapes characters, but it will be very slow to print (calling print many times)
- bool has_single_quote = false;
- bool has_double_quote = false;
- for (const byte *s = str_data, *top = str_data + str_len; (!has_single_quote || !has_double_quote) && s < top; s++) {
- if (*s == '\'') {
- has_single_quote = true;
- } else if (*s == '"') {
- has_double_quote = true;
- }
- }
if (is_bytes) {
print(env, "b");
}
- int quote_char = '\'';
- if (has_single_quote && !has_double_quote) {
- quote_char = '"';
- }
- print(env, "%c", quote_char);
- for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
- if (*s == quote_char) {
- print(env, "\\%c", quote_char);
- } else if (*s == '\\') {
- print(env, "\\\\");
- } else if (32 <= *s && *s <= 126) {
- print(env, "%c", *s);
- } else if (*s == '\n') {
- print(env, "\\n");
- // TODO add more escape codes here if we want to match CPython
- } else {
- print(env, "\\x%02x", *s);
- }
- }
- print(env, "%c", quote_char);
+ mp_str_print_quoted(print, env, str_data, str_len);
}
}
diff --git a/py/objtuple.c b/py/objtuple.c
index ec35ef8550..754fe4b662 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -73,6 +73,14 @@ static mp_obj_t tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
}
}
+static mp_obj_t tuple_unary_op(int op, mp_obj_t self_in) {
+ mp_obj_tuple_t *self = self_in;
+ switch (op) {
+ case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; }
+ default: return MP_OBJ_NULL; // op not supported for None
+ }
+}
+
static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_tuple_t *o = lhs;
switch (op) {
@@ -97,6 +105,7 @@ const mp_obj_type_t tuple_type = {
"tuple",
.print = tuple_print,
.make_new = tuple_make_new,
+ .unary_op = tuple_unary_op,
.binary_op = tuple_binary_op,
.getiter = tuple_getiter,
};
diff --git a/py/parse.c b/py/parse.c
index d9969d6785..d0776cefba 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -172,15 +172,15 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
if (MP_PARSE_NODE_IS_NULL(pn)) {
printf("NULL\n");
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
- int arg = MP_PARSE_NODE_LEAF_ARG(pn);
+ machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break;
- case MP_PARSE_NODE_SMALL_INT: printf("int(%d)\n", arg); break;
+ case MP_PARSE_NODE_SMALL_INT: printf("int(" INT_FMT ")\n", arg); break;
case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break;
case MP_PARSE_NODE_DECIMAL: printf("dec(%s)\n", qstr_str(arg)); break;
case MP_PARSE_NODE_STRING: printf("str(%s)\n", qstr_str(arg)); break;
case MP_PARSE_NODE_BYTES: printf("bytes(%s)\n", qstr_str(arg)); break;
- case MP_PARSE_NODE_TOKEN: printf("tok(%d)\n", arg); break;
+ case MP_PARSE_NODE_TOKEN: printf("tok(" INT_FMT ")\n", arg); break;
default: assert(0);
}
} else {
diff --git a/py/qstr.c b/py/qstr.c
index f12cbceff6..f9f927f583 100644
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -185,3 +185,19 @@ const byte *qstr_data(qstr q, uint *len) {
*len = Q_GET_LENGTH(qd);
return Q_GET_DATA(qd);
}
+
+void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes) {
+ *n_pool = 0;
+ *n_qstr = 0;
+ *n_str_data_bytes = 0;
+ *n_total_bytes = 0;
+ for (qstr_pool_t *pool = last_pool; pool != NULL && pool != &const_pool; pool = pool->prev) {
+ *n_pool += 1;
+ *n_qstr += pool->len;
+ for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
+ *n_str_data_bytes += Q_GET_ALLOC(*q);
+ }
+ *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc;
+ }
+ *n_total_bytes += *n_str_data_bytes;
+}
diff --git a/py/qstr.h b/py/qstr.h
index 9224d48a19..779ebcb4a9 100644
--- a/py/qstr.h
+++ b/py/qstr.h
@@ -36,3 +36,5 @@ machine_uint_t qstr_hash(qstr q);
const char* qstr_str(qstr q);
uint qstr_len(qstr q);
const byte* qstr_data(qstr q, uint *len);
+
+void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes);
diff --git a/py/runtime.c b/py/runtime.c
index 8ad98d5f12..6dd6921599 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -44,11 +44,14 @@ typedef enum {
} mp_code_kind_t;
typedef struct _mp_code_t {
- mp_code_kind_t kind;
- int n_args;
- int n_locals;
- int n_stack;
- bool is_generator;
+ struct {
+ mp_code_kind_t kind : 8;
+ bool is_generator : 1;
+ };
+ struct {
+ uint n_args : 16;
+ uint n_state : 16;
+ };
union {
struct {
byte *code;
@@ -63,7 +66,7 @@ typedef struct _mp_code_t {
};
} mp_code_t;
-static int next_unique_code_id;
+static uint next_unique_code_id;
static machine_uint_t unique_codes_alloc = 0;
static mp_code_t *unique_codes = NULL;
@@ -130,7 +133,6 @@ void rt_init(void) {
mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array);
rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type);
- rt_store_name(MP_QSTR_array, m_array);
// built-in user functions
mp_map_add_qstr(&map_builtins, MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj);
@@ -188,37 +190,37 @@ void rt_deinit(void) {
#endif
}
-int rt_get_unique_code_id(void) {
+uint rt_get_unique_code_id(void) {
return next_unique_code_id++;
}
static void alloc_unique_codes(void) {
if (next_unique_code_id > unique_codes_alloc) {
+ DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
// increase size of unique_codes table
unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id);
- for (int i = unique_codes_alloc; i < next_unique_code_id; i++) {
+ for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
unique_codes[i].kind = MP_CODE_NONE;
}
unique_codes_alloc = next_unique_code_id;
}
}
-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(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) {
alloc_unique_codes();
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
- unique_codes[unique_code_id].n_args = n_args;
- 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;
+ unique_codes[unique_code_id].n_args = n_args;
+ unique_codes[unique_code_id].n_state = n_locals + n_stack;
unique_codes[unique_code_id].u_byte.code = code;
unique_codes[unique_code_id].u_byte.len = len;
//printf("byte code: %d bytes\n", len);
#ifdef DEBUG_PRINT
- DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args);
+ DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d n_locals=%d n_stack=%d\n", unique_code_id, code, len, n_args, n_locals, n_stack);
for (int i = 0; i < 128 && i < len; i++) {
if (i > 0 && i % 16 == 0) {
DEBUG_printf("\n");
@@ -239,15 +241,14 @@ void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, i
#endif
}
-void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) {
+void rt_assign_native_code(uint unique_code_id, void *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 == MP_CODE_NONE);
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
- unique_codes[unique_code_id].n_args = n_args;
- unique_codes[unique_code_id].n_locals = 0;
- unique_codes[unique_code_id].n_stack = 0;
unique_codes[unique_code_id].is_generator = false;
+ unique_codes[unique_code_id].n_args = n_args;
+ unique_codes[unique_code_id].n_state = 0;
unique_codes[unique_code_id].u_native.fun = fun;
//printf("native code: %d bytes\n", len);
@@ -272,15 +273,14 @@ void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args)
#endif
}
-void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_args) {
+void rt_assign_inline_asm_code(uint unique_code_id, void *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 == MP_CODE_NONE);
unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
- unique_codes[unique_code_id].n_args = n_args;
- unique_codes[unique_code_id].n_locals = 0;
- unique_codes[unique_code_id].n_stack = 0;
unique_codes[unique_code_id].is_generator = false;
+ unique_codes[unique_code_id].n_args = n_args;
+ unique_codes[unique_code_id].n_state = 0;
unique_codes[unique_code_id].u_inline_asm.fun = fun;
#ifdef DEBUG_PRINT
@@ -316,23 +316,18 @@ int rt_is_true(mp_obj_t arg) {
return 0;
} else if (arg == mp_const_true) {
return 1;
- } else if (MP_OBJ_IS_STR(arg)) {
- return mp_obj_str_get_len(arg) != 0;
- } else if (MP_OBJ_IS_TYPE(arg, &list_type)) {
- uint len;
- mp_obj_t *dummy;
- mp_obj_list_get(arg, &len, &dummy);
- return len != 0;
- } else if (MP_OBJ_IS_TYPE(arg, &tuple_type)) {
- uint len;
- mp_obj_t *dummy;
- mp_obj_tuple_get(arg, &len, &dummy);
- return len != 0;
- } else if (MP_OBJ_IS_TYPE(arg, &dict_type)) {
- return mp_obj_dict_len(arg) != 0;
} else {
- assert(0);
- return 0;
+ mp_obj_t len = mp_obj_len_maybe(arg);
+ if (len != MP_OBJ_NULL) {
+ // obj has a length, truth determined if len != 0
+ return len != MP_OBJ_NEW_SMALL_INT(0);
+ } else {
+ // TODO check for __bool__ method
+ // TODO check floats and complex numbers
+
+ // any other obj is true (TODO is that correct?)
+ return 1;
+ }
}
}
@@ -481,7 +476,7 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) {
if (MP_OBJ_IS_SMALL_INT(arg)) {
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);
switch (op) {
- case RT_UNARY_OP_NOT: if (val != 0) { return mp_const_true;} else { return mp_const_false; }
+ case RT_UNARY_OP_NOT: if (val == 0) { return mp_const_true;} else { return mp_const_false; }
case RT_UNARY_OP_POSITIVE: break;
case RT_UNARY_OP_NEGATIVE: val = -val; break;
case RT_UNARY_OP_INVERT: val = ~val; break;
@@ -684,7 +679,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
mp_obj_t fun;
switch (c->kind) {
case MP_CODE_BYTE:
- fun = mp_obj_new_fun_bc(c->n_args, c->n_locals + c->n_stack, c->u_byte.code);
+ fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code);
break;
case MP_CODE_NATIVE:
fun = rt_make_function_n(c->n_args, c->u_native.fun);
@@ -699,7 +694,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
// check for generator functions and if so wrap in generator object
if (c->is_generator) {
- fun = mp_obj_new_gen_wrap(c->n_locals, c->n_stack, fun);
+ fun = mp_obj_new_gen_wrap(fun);
}
return fun;
diff --git a/py/runtime0.h b/py/runtime0.h
index 4fdcdc3cc9..cd82b1412b 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -1,5 +1,5 @@
typedef enum {
- RT_UNARY_OP_NOT,
+ RT_UNARY_OP_NOT, // TODO remove this op since it's no longer needed
RT_UNARY_OP_POSITIVE,
RT_UNARY_OP_NEGATIVE,
RT_UNARY_OP_INVERT,
@@ -78,7 +78,7 @@ extern void *const rt_fun_table[RT_F_NUMBER_OF];
void rt_init(void);
void rt_deinit(void);
-int rt_get_unique_code_id(void);
-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, void *f, uint len, int n_args);
-void rt_assign_inline_asm_code(int unique_code_id, void *f, uint len, int n_args);
+uint rt_get_unique_code_id(void);
+void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator);
+void rt_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
+void rt_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);
diff --git a/py/showbc.c b/py/showbc.c
index f914223933..d7ae17c2e3 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -68,12 +68,10 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("LOAD_CONST_INT %s", qstr_str(qstr));
break;
- /*
case MP_BC_LOAD_CONST_DEC:
DECODE_QSTR;
- PUSH(rt_load_const_dec(qstr));
+ printf("LOAD_CONST_DEC %s", qstr_str(qstr));
break;
- */
case MP_BC_LOAD_CONST_ID:
DECODE_QSTR;
@@ -351,12 +349,12 @@ void mp_byte_code_print(const byte *ip, int len) {
case MP_BC_IMPORT_NAME:
DECODE_QSTR;
- printf("IMPORT NAME %s", qstr_str(qstr));
+ printf("IMPORT_NAME %s", qstr_str(qstr));
break;
case MP_BC_IMPORT_FROM:
DECODE_QSTR;
- printf("IMPORT NAME %s", qstr_str(qstr));
+ printf("IMPORT_FROM %s", qstr_str(qstr));
break;
default:
diff --git a/py/vm.c b/py/vm.c
index 0cc26021e8..8f5bb1ee57 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -26,8 +26,6 @@
#define SET_TOP(val) *sp = (val)
mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state) {
- n_state += 1; // XXX there is a bug somewhere which doesn't count enough state... (conwaylife and mandel have the bug)
-
// allocate state for locals and stack
mp_obj_t temp_state[10];
mp_obj_t *state = &temp_state[0];
@@ -82,7 +80,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
machine_uint_t unum;
qstr qst;
mp_obj_t obj1, obj2;
- mp_obj_t fast0 = fastn[0], fast1 = fastn[-1], fast2 = fastn[-2];
nlr_buf_t nlr;
volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions
@@ -90,8 +87,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack
const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
- // TODO if an exception occurs, do fast[0,1,2] become invalid??
-
// outer exception handling loop
for (;;) {
if (nlr_push(&nlr) == 0) {
@@ -148,15 +143,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
break;
case MP_BC_LOAD_FAST_0:
- PUSH(fast0);
+ PUSH(fastn[0]);
break;
case MP_BC_LOAD_FAST_1:
- PUSH(fast1);
+ PUSH(fastn[-1]);
break;
case MP_BC_LOAD_FAST_2:
- PUSH(fast2);
+ PUSH(fastn[-2]);
break;
case MP_BC_LOAD_FAST_N:
@@ -166,16 +161,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
case MP_BC_LOAD_DEREF:
DECODE_UINT;
- if (unum == 0) {
- obj1 = fast0;
- } else if (unum == 1) {
- obj1 = fast1;
- } else if (unum == 2) {
- obj1 = fast2;
- } else {
- obj1 = fastn[-unum];
- }
- PUSH(rt_get_cell(obj1));
+ PUSH(rt_get_cell(fastn[-unum]));
break;
case MP_BC_LOAD_NAME:
@@ -204,15 +190,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
break;
case MP_BC_STORE_FAST_0:
- fast0 = POP();
+ fastn[0] = POP();
break;
case MP_BC_STORE_FAST_1:
- fast1 = POP();
+ fastn[-1] = POP();
break;
case MP_BC_STORE_FAST_2:
- fast2 = POP();
+ fastn[-2] = POP();
break;
case MP_BC_STORE_FAST_N:
@@ -222,16 +208,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
case MP_BC_STORE_DEREF:
DECODE_UINT;
- if (unum == 0) {
- obj1 = fast0;
- } else if (unum == 1) {
- obj1 = fast1;
- } else if (unum == 2) {
- obj1 = fast2;
- } else {
- obj1 = fastn[-unum];
- }
- rt_set_cell(obj1, POP());
+ rt_set_cell(fastn[-unum], POP());
break;
case MP_BC_STORE_NAME:
@@ -479,8 +456,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
case MP_BC_MAKE_CLOSURE:
DECODE_UINT;
- obj1 = POP();
- PUSH(rt_make_closure_from_id(unum, obj1));
+ SET_TOP(rt_make_closure_from_id(unum, TOP()));
break;
case MP_BC_CALL_FUNCTION:
@@ -514,9 +490,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
case MP_BC_YIELD_VALUE:
nlr_pop();
*ip_in_out = ip;
- fastn[0] = fast0;
- fastn[-1] = fast1;
- fastn[-2] = fast2;
*sp_in_out = sp;
return true;
diff --git a/stm/file.c b/stm/file.c
index 35bfca16a5..84f7251fec 100644
--- a/stm/file.c
+++ b/stm/file.c
@@ -3,7 +3,6 @@
#include "misc.h"
#include "mpconfig.h"
-#include "mpconfigport.h"
#include "qstr.h"
#include "obj.h"
#include "file.h"
diff --git a/stm/gccollect.c b/stm/gccollect.c
index c0f67ac0d5..ada5493a23 100644
--- a/stm/gccollect.c
+++ b/stm/gccollect.c
@@ -13,10 +13,10 @@ void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t hea
void gc_collect(void) {
uint32_t start = sys_tick_counter;
gc_collect_start();
- gc_collect_root((void**)&_ram_start, ((uint32_t)&_heap_start - (uint32_t)&_ram_start) / 4);
+ gc_collect_root((void**)&_ram_start, ((uint32_t)&_heap_start - (uint32_t)&_ram_start) / sizeof(uint32_t));
machine_uint_t regs[10];
- gc_helper_get_regs_and_clean_stack(regs, HEAP_END);
- gc_collect_root((void**)HEAP_END, (RAM_END - HEAP_END) / 4); // will trace regs since they now live in this function on the stack
+ gc_helper_get_regs_and_clean_stack(regs, (machine_uint_t)&_heap_end);
+ gc_collect_root((void**)&_heap_end, ((uint32_t)&_ram_end - (uint32_t)&_heap_end) / sizeof(uint32_t)); // will trace regs since they now live in this function on the stack
gc_collect_end();
uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
diff --git a/stm/gccollect.h b/stm/gccollect.h
index 6467ec7d21..9187f0e9df 100644
--- a/stm/gccollect.h
+++ b/stm/gccollect.h
@@ -1,8 +1,7 @@
-#define HEAP_END (0x2001c000) // tunable
-#define RAM_END (0x20020000) // fixed for chip
-
extern uint32_t _ram_start;
extern uint32_t _heap_start;
+extern uint32_t _ram_end;
+extern uint32_t _heap_end;
void gc_collect(void);
diff --git a/stm/lcd.c b/stm/lcd.c
index dae4157a46..6f5019db1b 100644
--- a/stm/lcd.c
+++ b/stm/lcd.c
@@ -41,6 +41,16 @@
#define PYB_LCD_BL_PORT (GPIOB)
#define PYB_LCD_BL_PIN (GPIO_Pin_1) // Y12 = PB1
*/
+#elif defined(STM32F4DISC)
+/* Configure if needed */
+#define PYB_LCD_PORT (GPIOA)
+#define PYB_LCD_CS1_PIN (GPIO_Pin_2) // X3
+#define PYB_LCD_RST_PIN (GPIO_Pin_3) // X4
+#define PYB_LCD_A0_PIN (GPIO_Pin_4) // X5
+#define PYB_LCD_SCL_PIN (GPIO_Pin_5) // X6
+#define PYB_LCD_SI_PIN (GPIO_Pin_7) // X8
+#define PYB_LCD_BL_PORT (GPIOC)
+#define PYB_LCD_BL_PIN (GPIO_Pin_5) // X12
#endif
#define LCD_INSTR (0)
diff --git a/stm/main.c b/stm/main.c
index 90fdab3d22..313a868c41 100644
--- a/stm/main.c
+++ b/stm/main.c
@@ -129,6 +129,7 @@ static const char *help_text =
"Specific commands for the board:\n"
" pyb.info() -- print some general information\n"
" pyb.gc() -- run the garbage collector\n"
+" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n"
" pyb.delay(<n>) -- wait for n milliseconds\n"
" pyb.Led(<n>) -- create Led object for LED n (n=1,2)\n"
" Led methods: on(), off()\n"
@@ -174,15 +175,24 @@ static mp_obj_t pyb_info(void) {
extern void *_ebss;
extern void *_estack;
extern void *_etext;
+ printf("_etext=%p\n", &_etext);
printf("_sidata=%p\n", &_sidata);
printf("_sdata=%p\n", &_sdata);
printf("_edata=%p\n", &_edata);
printf("_sbss=%p\n", &_sbss);
printf("_ebss=%p\n", &_ebss);
printf("_estack=%p\n", &_estack);
- printf("_etext=%p\n", &_etext);
printf("_ram_start=%p\n", &_ram_start);
printf("_heap_start=%p\n", &_heap_start);
+ printf("_heap_end=%p\n", &_heap_end);
+ printf("_ram_end=%p\n", &_ram_end);
+ }
+
+ // qstr info
+ {
+ uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+ qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+ printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
}
// GC info
@@ -206,12 +216,21 @@ static mp_obj_t pyb_info(void) {
return mp_const_none;
}
+static bool repl_display_debugging_info = 0;
+
+static mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
+ repl_display_debugging_info = mp_obj_get_int(o_value);
+ return mp_const_none;
+}
+
+#if MICROPY_HW_HAS_SDCARD
// SD card test
static mp_obj_t pyb_sd_test(void) {
extern void sdio_init(void);
sdio_init();
return mp_const_none;
}
+#endif
static void SYSCLKConfig_STOP(void) {
/* After wake-up from STOP reconfigure the system clock */
@@ -418,15 +437,18 @@ void do_repl(void) {
if (nlr_push(&nlr) == 0) {
rt_call_function_0(module_fun);
nlr_pop();
- // optional timing
- if (0) {
- uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
- printf("(took %lu ms)\n", ticks);
- }
} else {
// uncaught exception
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
}
+
+ // display debugging info if wanted
+ if (repl_display_debugging_info) {
+ uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
+ printf("took %lu ms\n", ticks);
+ gc_collect();
+ pyb_info();
+ }
}
}
}
@@ -594,7 +616,7 @@ int main(void) {
soft_reset:
// GC init
- gc_init(&_heap_start, (void*)HEAP_END);
+ gc_init(&_heap_start, &_heap_end);
// Micro Python init
qstr_init();
@@ -632,6 +654,8 @@ soft_reset:
mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb);
rt_store_attr(m, MP_QSTR_info, rt_make_function_n(0, pyb_info));
+ rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj);
+ rt_store_attr(m, qstr_from_str("repl_info"), rt_make_function_n(1, pyb_set_repl_info));
#if MICROPY_HW_HAS_SDCARD
rt_store_attr(m, MP_QSTR_sd_test, rt_make_function_n(0, pyb_sd_test));
#endif
@@ -640,7 +664,6 @@ soft_reset:
rt_store_attr(m, MP_QSTR_source_dir, rt_make_function_n(1, pyb_source_dir));
rt_store_attr(m, MP_QSTR_main, rt_make_function_n(1, pyb_main));
rt_store_attr(m, MP_QSTR_sync, rt_make_function_n(0, pyb_sync));
- rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj);
rt_store_attr(m, MP_QSTR_delay, rt_make_function_n(1, pyb_delay));
#if MICROPY_HW_HAS_SWITCH
rt_store_attr(m, MP_QSTR_switch, (mp_obj_t)&pyb_switch_obj);
@@ -655,7 +678,7 @@ soft_reset:
rt_store_attr(m, MP_QSTR_mma_mode, (mp_obj_t)&pyb_mma_write_mode_obj);
#endif
rt_store_attr(m, MP_QSTR_hid, rt_make_function_n(1, pyb_hid_send_report));
-#if MICROPY_HW_HAS_RTC
+#if MICROPY_HW_ENABLE_RTC
rt_store_attr(m, MP_QSTR_time, rt_make_function_n(0, pyb_rtc_read));
#endif
#if MICROPY_HW_ENABLE_RNG
diff --git a/stm/printf.c b/stm/printf.c
index 82b168d1c4..a0620018cc 100644
--- a/stm/printf.c
+++ b/stm/printf.c
@@ -247,7 +247,9 @@ void stdout_print_strn(void *data, const char *str, unsigned int len) {
any = true;
}
if (!any) {
+#if MICROPY_HW_HAS_LCD
lcd_print_strn(str, len);
+#endif
}
}
diff --git a/stm/rtc.c b/stm/rtc.c
index 2dbb2c0aa1..e5e11c6222 100644
--- a/stm/rtc.c
+++ b/stm/rtc.c
@@ -8,8 +8,20 @@
#include "rtc.h"
void rtc_init(void) {
- uint32_t rtc_clksrc;
- uint32_t timeout = 1000000;
+ /* Enable the PWR clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
+
+ /* Allow access to RTC */
+ PWR_BackupAccessCmd(ENABLE);
+
+ if (RTC_ReadBackupRegister(RTC_BKP_DR0) == 0x32F2) {
+ // RTC still alive, so don't re-init it
+ // wait for RTC APB register synchronisation
+ RTC_WaitForSynchro();
+ return;
+ }
+
+ uint32_t timeout = 10000000;
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
@@ -26,7 +38,10 @@ void rtc_init(void) {
/* If LSE timed out, use LSI instead */
if (timeout == 0) {
- /* Enable the LSI OSC */
+ // Disable the LSE OSC
+ RCC_LSEConfig(RCC_LSE_OFF);
+
+ // Enable the LSI OSC
RCC_LSICmd(ENABLE);
/* Wait till LSI is ready */
@@ -34,15 +49,12 @@ void rtc_init(void) {
}
/* Use LSI as the RTC Clock Source */
- rtc_clksrc = RCC_RTCCLKSource_LSI;
+ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
} else {
/* Use LSE as the RTC Clock Source */
- rtc_clksrc = RCC_RTCCLKSource_LSE;
+ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
}
- /* Select the RTC Clock Source */
- RCC_RTCCLKConfig(rtc_clksrc);
-
/* Note: LSI is around (32KHz), these dividers should work either way */
/* ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
uint32_t uwSynchPrediv = 0xFF;
@@ -78,7 +90,7 @@ void rtc_init(void) {
RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);
// Indicator for the RTC configuration
- //RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
+ RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}
/******************************************************************************/
diff --git a/stm/stm32f405.ld b/stm/stm32f405.ld
index fbfc584f9d..6c29a681ce 100644
--- a/stm/stm32f405.ld
+++ b/stm/stm32f405.ld
@@ -19,6 +19,10 @@ _minimum_heap_size = 16K;
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
+/* RAM extents for the garbage collector */
+_ram_end = ORIGIN(RAM) + LENGTH(RAM);
+_heap_end = 0x2001c000; /* tunable */
+
/* define output sections */
SECTIONS
{
diff --git a/tests/basics/array1.py b/tests/basics/array1.py
new file mode 100644
index 0000000000..6f70fdb911
--- /dev/null
+++ b/tests/basics/array1.py
@@ -0,0 +1,13 @@
+import array
+
+a = array.array('B', [1, 2, 3])
+print(a, len(a))
+i = array.array('I', [1, 2, 3])
+print(i, len(i))
+print(a[0])
+print(i[-1])
+
+# Empty arrays
+print(len(array.array('h')))
+print(array.array('i'))
+
diff --git a/tests/basics/bytearray1.py b/tests/basics/bytearray1.py
index 3658713fa8..3111832f6c 100644
--- a/tests/basics/bytearray1.py
+++ b/tests/basics/bytearray1.py
@@ -1,6 +1,7 @@
a = bytearray([1, 2, 200])
print(a[0], a[2])
print(a[-1])
+print(a)
a[2] = 255
print(a[-1])
a.append(10)
diff --git a/tests/basics/unary_op.py b/tests/basics/unary_op.py
new file mode 100644
index 0000000000..9846285d55
--- /dev/null
+++ b/tests/basics/unary_op.py
@@ -0,0 +1,12 @@
+print(not None)
+print(not False)
+print(not True)
+print(not 0)
+print(not 1)
+print(not -1)
+print(not ())
+print(not (1,))
+print(not [])
+print(not [1,])
+print(not {})
+print(not {1:1})
diff --git a/unix/Makefile b/unix/Makefile
index 75825b7c4c..db01ccf9af 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -11,7 +11,8 @@ include ../py/py.mk
# compiler settings
CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -DUNIX
-LDFLAGS = -lm
+CFLAGS += -I/usr/lib/libffi-3.0.13/include
+LDFLAGS = -lm -ldl -lffi
# Debugging/Optimization
ifdef DEBUG
@@ -25,6 +26,7 @@ SRC_C = \
main.c \
file.c \
socket.c \
+ ffi.c \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
LIB = -lreadline
diff --git a/unix/ffi.c b/unix/ffi.c
new file mode 100644
index 0000000000..b40e9a4ee6
--- /dev/null
+++ b/unix/ffi.c
@@ -0,0 +1,330 @@
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <ffi.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "runtime.h"
+
+typedef struct _mp_obj_opaque_t {
+ mp_obj_base_t base;
+ void *val;
+} mp_obj_opaque_t;
+
+typedef struct _mp_obj_ffimod_t {
+ mp_obj_base_t base;
+ void *handle;
+} mp_obj_ffimod_t;
+
+typedef struct _mp_obj_ffivar_t {
+ mp_obj_base_t base;
+ void *var;
+ char type;
+// ffi_type *type;
+} mp_obj_ffivar_t;
+
+typedef struct _mp_obj_ffifunc_t {
+ mp_obj_base_t base;
+ void *func;
+ char rettype;
+ ffi_cif cif;
+ ffi_type *params[];
+} mp_obj_ffifunc_t;
+
+typedef struct _mp_obj_fficallback_t {
+ mp_obj_base_t base;
+ void *func;
+ ffi_closure *clo;
+ char rettype;
+ ffi_cif cif;
+ ffi_type *params[];
+} mp_obj_fficallback_t;
+
+static const mp_obj_type_t opaque_type;
+static const mp_obj_type_t ffimod_type;
+static const mp_obj_type_t ffifunc_type;
+static const mp_obj_type_t fficallback_type;
+static const mp_obj_type_t ffivar_type;
+
+static ffi_type *char2ffi_type(char c)
+{
+ switch (c) {
+ case 'b': return &ffi_type_schar;
+ case 'B': return &ffi_type_uchar;
+ case 'i': return &ffi_type_sint;
+ case 'I': return &ffi_type_uint;
+ case 'l': return &ffi_type_slong;
+ case 'L': return &ffi_type_ulong;
+ case 'p':
+ case 's': return &ffi_type_pointer;
+ case 'v': return &ffi_type_void;
+ default: return NULL;
+ }
+}
+
+static ffi_type *get_ffi_type(mp_obj_t o_in)
+{
+ if (MP_OBJ_IS_STR(o_in)) {
+ uint len;
+ const byte *s = mp_obj_str_get_data(o_in, &len);
+ ffi_type *t = char2ffi_type(*s);
+ if (t != NULL) {
+ return t;
+ }
+ }
+ // TODO: Support actual libffi type objects
+
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Unknown type"));
+}
+
+static mp_obj_t return_ffi_value(ffi_arg val, char type)
+{
+ switch (type) {
+ case 's': {
+ const char *s = (const char *)val;
+ return mp_obj_new_str((const byte *)s, strlen(s), false);
+ }
+ case 'v':
+ return mp_const_none;
+ default:
+ return mp_obj_new_int(val);
+ }
+}
+
+// FFI module
+
+static void ffimod_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_obj_ffimod_t *self = self_in;
+ print(env, "<ffimod %p>", self->handle);
+}
+
+static mp_obj_t ffimod_close(mp_obj_t self_in) {
+ mp_obj_ffimod_t *self = self_in;
+ dlclose(self->handle);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close);
+
+static mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) {
+ mp_obj_ffimod_t *self = args[0];
+ const char *rettype = mp_obj_str_get_str(args[1]);
+ const char *symname = mp_obj_str_get_str(args[2]);
+
+ void *sym = dlsym(self->handle, symname);
+ if (sym == NULL) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno));
+ }
+ int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(args[3]));
+ mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type*, nparams);
+ o->base.type = &ffifunc_type;
+
+ o->func = sym;
+ o->rettype = *rettype;
+
+ mp_obj_t iterable = rt_getiter(args[3]);
+ mp_obj_t item;
+ int i = 0;
+ while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ o->params[i++] = get_ffi_type(item);
+ }
+
+ int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
+ if (res != FFI_OK) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Error in ffi_prep_cif"));
+ }
+
+ return o;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func);
+
+static void call_py_func(ffi_cif *cif, void *ret, void** args, mp_obj_t func) {
+ mp_obj_t pyargs[cif->nargs];
+ for (int i = 0; i < cif->nargs; i++) {
+ pyargs[i] = mp_obj_new_int(*(int*)args[i]);
+ }
+ mp_obj_t res = rt_call_function_n_kw(func, cif->nargs, 0, pyargs);
+
+ *(ffi_arg*)ret = mp_obj_int_get(res);
+}
+
+static mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t paramtypes_in) {
+ const char *rettype = mp_obj_str_get_str(rettype_in);
+
+ int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in));
+ mp_obj_fficallback_t *o = m_new_obj_var(mp_obj_fficallback_t, ffi_type*, nparams);
+ o->base.type = &fficallback_type;
+
+ o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func);
+
+ o->rettype = *rettype;
+
+ mp_obj_t iterable = rt_getiter(paramtypes_in);
+ mp_obj_t item;
+ int i = 0;
+ while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+ o->params[i++] = get_ffi_type(item);
+ }
+
+ int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params);
+ if (res != FFI_OK) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Error in ffi_prep_cif"));
+ }
+
+ res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, func_in, o->func);
+ if (res != FFI_OK) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "ffi_prep_closure_loc"));
+ }
+
+ return o;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_callback_obj, mod_ffi_callback);
+
+static mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) {
+ mp_obj_ffimod_t *self = self_in;
+ const char *rettype = mp_obj_str_get_str(vartype_in);
+ const char *symname = mp_obj_str_get_str(symname_in);
+
+ void *sym = dlsym(self->handle, symname);
+ if (sym == NULL) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno));
+ }
+ mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t);
+ o->base.type = &ffivar_type;
+
+ o->var = sym;
+ o->type = *rettype;
+ return o;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var);
+
+static mp_obj_t ffimod_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+ const char *fname = mp_obj_str_get_str(args[0]);
+ void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
+
+ if (mod == NULL) {
+ nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno));
+ }
+ mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t);
+ o->base.type = type_in;
+ o->handle = mod;
+ return o;
+}
+
+static const mp_method_t ffimod_type_methods[] = {
+ { "func", &ffimod_func_obj },
+ { "var", &ffimod_var_obj },
+ { "close", &ffimod_close_obj },
+ { NULL, NULL },
+};
+
+static const mp_obj_type_t ffimod_type = {
+ { &mp_const_type },
+ "ffimod",
+ .print = ffimod_print,
+ .make_new = ffimod_make_new,
+ .methods = ffimod_type_methods,
+};
+
+// FFI function
+
+static void ffifunc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_obj_ffifunc_t *self = self_in;
+ print(env, "<ffifunc %p>", self->func);
+}
+
+mp_obj_t ffifunc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+ mp_obj_ffifunc_t *self = self_in;
+ assert(n_kw == 0);
+ assert(n_args == self->cif.nargs);
+
+ ffi_arg values[n_args];
+ void *valueptrs[n_args];
+ int i;
+ for (i = 0; i < n_args; i++) {
+ mp_obj_t a = args[i];
+ if (a == mp_const_none) {
+ values[i] = 0;
+ } else if (MP_OBJ_IS_INT(a)) {
+ values[i] = mp_obj_int_get(a);
+ } else if (MP_OBJ_IS_STR(a) || MP_OBJ_IS_TYPE(a, &bytes_type)) {
+ const char *s = mp_obj_str_get_str(a);
+ values[i] = (ffi_arg)s;
+ } else if (MP_OBJ_IS_TYPE(a, &fficallback_type)) {
+ mp_obj_fficallback_t *p = a;
+ values[i] = (ffi_arg)p->func;
+ } else {
+ assert(0);
+ }
+ valueptrs[i] = &values[i];
+ }
+
+ ffi_arg retval;
+ ffi_call(&self->cif, self->func, &retval, valueptrs);
+ return return_ffi_value(retval, self->rettype);
+}
+
+static const mp_obj_type_t ffifunc_type = {
+ { &mp_const_type },
+ "ffifunc",
+ .print = ffifunc_print,
+ .call = ffifunc_call,
+};
+
+// FFI callback for Python function
+
+static void fficallback_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_obj_fficallback_t *self = self_in;
+ print(env, "<fficallback %p>", self->func);
+}
+
+static const mp_obj_type_t fficallback_type = {
+ { &mp_const_type },
+ "fficallback",
+ .print = fficallback_print,
+};
+
+// FFI variable
+
+static void ffivar_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_obj_ffivar_t *self = self_in;
+ print(env, "<ffivar @%p: 0x%x>", self->var, *(int*)self->var);
+}
+
+static const mp_obj_type_t ffivar_type = {
+ { &mp_const_type },
+ "ffivar",
+ .print = ffivar_print,
+};
+
+// Generic opaque storage object
+
+static const mp_obj_type_t opaque_type = {
+ { &mp_const_type },
+ "opaqueval",
+// .print = opaque_print,
+};
+
+
+mp_obj_t mod_ffi_open(uint n_args, const mp_obj_t *args) {
+ return ffimod_make_new((mp_obj_t)&ffimod_type, n_args, 0, args);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open);
+
+mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) {
+ return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray);
+
+
+void ffi_init() {
+ mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("ffi"));
+ rt_store_attr(m, MP_QSTR_open, (mp_obj_t)&mod_ffi_open_obj);
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("callback"), (mp_obj_t)&mod_ffi_callback_obj);
+ // there would be as_bytes, but bytes currently is value, not reference type!
+ rt_store_attr(m, QSTR_FROM_STR_STATIC("as_bytearray"), (mp_obj_t)&mod_ffi_as_bytearray_obj);
+}
diff --git a/unix/main.c b/unix/main.c
index 212bbe877e..cd45e3be86 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -24,6 +24,7 @@
extern const mp_obj_fun_native_t mp_builtin_open_obj;
void file_init();
void rawsocket_init();
+void ffi_init();
static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
if (lex == NULL) {
@@ -215,6 +216,18 @@ int usage(void) {
return 1;
}
+mp_obj_t mem_info(void) {
+ printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
+ return mp_const_none;
+}
+
+mp_obj_t qstr_info(void) {
+ uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+ qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+ printf("qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
+ return mp_const_none;
+}
+
int main(int argc, char **argv) {
qstr_init();
rt_init();
@@ -224,9 +237,12 @@ int main(int argc, char **argv) {
rt_store_attr(m_sys, MP_QSTR_argv, py_argv);
rt_store_name(qstr_from_str("test"), test_obj_new(42));
+ rt_store_name(qstr_from_str("mem_info"), rt_make_function_n(0, mem_info));
+ rt_store_name(qstr_from_str("qstr_info"), rt_make_function_n(0, qstr_info));
file_init();
rawsocket_init();
+ ffi_init();
// Here is some example code to create a class and instance of that class.
// First is the Python, then the C code.
diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h
index 10abb8ce75..5eba0df613 100644
--- a/unix/mpconfigport.h
+++ b/unix/mpconfigport.h
@@ -12,6 +12,7 @@
#define MICROPY_DEBUG_PRINTERS (1)
#define MICROPY_ENABLE_REPL_HELPERS (1)
#define MICROPY_ENABLE_LEXER_UNIX (1)
+#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_ENABLE_FLOAT (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)