Change object representation from 1 big union to individual structs.

A big change.  Micro Python objects are allocated as individual structs
with the first element being a pointer to the type information (which
is itself an object).  This scheme follows CPython.  Much more flexible,
not necessarily slower, uses same heap memory, and can allocate objects
statically.

Also change name prefix, from py_ to mp_ (mp for Micro Python).
diff --git a/unix/Makefile b/unix/Makefile
index 76cc0a3..463f6b1 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -31,6 +31,25 @@
 	runtime.o \
 	map.o \
 	obj.o \
+	objbool.o \
+	objboundmeth.o \
+	objcell.o \
+	objclass.o \
+	objclosure.o \
+	objcomplex.o \
+	objdict.o \
+	objexcept.o \
+	objfloat.o \
+	objfun.o \
+	objgenerator.o \
+	objinstance.o \
+	objlist.o \
+	objnone.o \
+	objrange.o \
+	objset.o \
+	objstr.o \
+	objtuple.o \
+	objtype.o \
 	builtin.o \
 	vm.o \
 	showbc.o \
@@ -42,6 +61,8 @@
 
 $(PROG): $(BUILD) $(OBJ)
 	$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
+	strip $(PROG)
+	size $(PROG)
 
 $(BUILD):
 	mkdir $@
@@ -52,7 +73,7 @@
 $(BUILD)/%.o: $(PYSRC)/%.s
 	$(AS) -o $@ $<
 
-$(BUILD)/%.o: $(PYSRC)/%.c mpyconfig.h
+$(BUILD)/%.o: $(PYSRC)/%.c mpconfig.h
 	$(CC) $(CFLAGS) -c -o $@ $<
 
 $(BUILD)/emitnx64.o: $(PYSRC)/emitnative.c $(PYSRC)/emit.h
@@ -65,7 +86,7 @@
 $(BUILD)/vm.o: $(PYSRC)/vm.c
 	$(CC) $(CFLAGS) -O3 -c -o $@ $<
 
-$(BUILD)/main.o: mpyconfig.h
+$(BUILD)/main.o: mpconfig.h
 $(BUILD)/parse.o: $(PYSRC)/grammar.h
 $(BUILD)/compile.o: $(PYSRC)/grammar.h
 $(BUILD)/emitcpy.o: $(PYSRC)/emit.h
diff --git a/unix/lexerunix.c b/unix/lexerunix.c
index e76d7f2..ac07781 100644
--- a/unix/lexerunix.c
+++ b/unix/lexerunix.c
@@ -17,7 +17,7 @@
     if (sb->src_cur < sb->src_end) {
         return *sb->src_cur++;
     } else {
-        return PY_LEXER_CHAR_EOF;
+        return MP_LEXER_CHAR_EOF;
     }
 }
 
@@ -30,16 +30,16 @@
     }
 }
 
-py_lexer_t *py_lexer_new_from_str_len(const char *src_name, const char *str, uint len, bool free_str) {
+mp_lexer_t *mp_lexer_new_from_str_len(const char *src_name, const char *str, uint len, bool free_str) {
     str_buf_t *sb = m_new(str_buf_t, 1);
     sb->free = free_str;
     sb->src_beg = str;
     sb->src_cur = str;
     sb->src_end = str + len;
-    return py_lexer_new(src_name, sb, (py_lexer_stream_next_char_t)str_buf_next_char, (py_lexer_stream_close_t)str_buf_free);
+    return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_char_t)str_buf_next_char, (mp_lexer_stream_close_t)str_buf_free);
 }
 
-py_lexer_t *py_lexer_new_from_file(const char *filename) {
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
     int fd = open(filename, O_RDONLY);
     if (fd < 0) {
         printf("cannot open file %s\n", filename);
@@ -51,5 +51,5 @@
     read(fd, data, size);
     close(fd);
 
-    return py_lexer_new_from_str_len(filename, data, size, true);
+    return mp_lexer_new_from_str_len(filename, data, size, true);
 }
diff --git a/unix/lexerunix.h b/unix/lexerunix.h
index aa7631c..d86f202 100644
--- a/unix/lexerunix.h
+++ b/unix/lexerunix.h
@@ -1,2 +1,2 @@
-py_lexer_t *py_lexer_new_from_str_len(const char *src_name, const char *str, uint len, bool free_str);
-py_lexer_t *py_lexer_new_from_file(const char *filename);
+mp_lexer_t *mp_lexer_new_from_str_len(const char *src_name, const char *str, uint len, bool free_str);
+mp_lexer_t *mp_lexer_new_from_file(const char *filename);
diff --git a/unix/main.c b/unix/main.c
index e5aa9de..295e82d 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -4,18 +4,19 @@
 
 #include "nlr.h"
 #include "misc.h"
-#include "mpyconfig.h"
+#include "mpconfig.h"
 #include "lexer.h"
 #include "lexerunix.h"
 #include "parse.h"
 #include "compile.h"
-#include "runtime.h"
 #include "obj.h"
+#include "runtime0.h"
+#include "runtime.h"
 #include "repl.h"
 
 #include <readline/readline.h>
 
-char *str_join(const char *s1, int sep_char, const char *s2) {
+static char *str_join(const char *s1, int sep_char, const char *s2) {
     int l1 = strlen(s1);
     int l2 = strlen(s2);
     char *s = m_new(char, l1 + l2 + 2);
@@ -29,14 +30,14 @@
     return s;
 }
 
-void do_repl(void) {
+static void do_repl(void) {
     for (;;) {
         char *line = readline(">>> ");
         if (line == NULL) {
             // EOF
             return;
         }
-        if (py_repl_is_compound_stmt(line)) {
+        if (mp_repl_is_compound_stmt(line)) {
             for (;;) {
                 char *line2 = readline("... ");
                 if (line2 == NULL || strlen(line2) == 0) {
@@ -49,23 +50,23 @@
             }
         }
 
-        py_lexer_t *lex = py_lexer_new_from_str_len("<stdin>", line, strlen(line), false);
-        py_parse_node_t pn = py_parse(lex, PY_PARSE_SINGLE_INPUT);
-        py_lexer_free(lex);
+        mp_lexer_t *lex = mp_lexer_new_from_str_len("<stdin>", line, strlen(line), false);
+        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT);
+        mp_lexer_free(lex);
 
-        if (pn != PY_PARSE_NODE_NULL) {
-            //py_parse_node_show(pn, 0);
-            bool comp_ok = py_compile(pn, true);
+        if (pn != MP_PARSE_NODE_NULL) {
+            //mp_parse_node_show(pn, 0);
+            bool comp_ok = mp_compile(pn, true);
             if (comp_ok) {
-                py_obj_t module_fun = rt_make_function_from_id(1);
-                if (module_fun != py_const_none) {
+                mp_obj_t module_fun = rt_make_function_from_id(1);
+                if (module_fun != mp_const_none) {
                     nlr_buf_t nlr;
                     if (nlr_push(&nlr) == 0) {
                         rt_call_function_0(module_fun);
                         nlr_pop();
                     } else {
                         // uncaught exception
-                        py_obj_print((py_obj_t)nlr.ret_val);
+                        mp_obj_print((mp_obj_t)nlr.ret_val);
                         printf("\n");
                     }
                 }
@@ -75,32 +76,32 @@
 }
 
 void do_file(const char *file) {
-    py_lexer_t *lex = py_lexer_new_from_file(file);
+    mp_lexer_t *lex = mp_lexer_new_from_file(file);
     //const char *pysrc = "def f():\n  x=x+1\n  print(42)\n";
-    //py_lexer_t *lex = py_lexer_from_str_len("<>", pysrc, strlen(pysrc), false);
+    //mp_lexer_t *lex = mp_lexer_from_str_len("<>", pysrc, strlen(pysrc), false);
     if (lex == NULL) {
         return;
     }
 
     if (0) {
         // just tokenise
-        while (!py_lexer_is_kind(lex, PY_TOKEN_END)) {
-            py_token_show(py_lexer_cur(lex));
-            py_lexer_to_next(lex);
+        while (!mp_lexer_is_kind(lex, MP_TOKEN_END)) {
+            mp_token_show(mp_lexer_cur(lex));
+            mp_lexer_to_next(lex);
         }
-        py_lexer_free(lex);
+        mp_lexer_free(lex);
 
     } else {
         // compile
 
-        py_parse_node_t pn = py_parse(lex, PY_PARSE_FILE_INPUT);
-        py_lexer_free(lex);
+        mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT);
+        mp_lexer_free(lex);
 
-        if (pn != PY_PARSE_NODE_NULL) {
+        if (pn != MP_PARSE_NODE_NULL) {
             //printf("----------------\n");
             //parse_node_show(pn, 0);
             //printf("----------------\n");
-            bool comp_ok = py_compile(pn, false);
+            bool comp_ok = mp_compile(pn, false);
             //printf("----------------\n");
 
 #if MICROPY_EMIT_CPYTHON
@@ -110,19 +111,19 @@
 #else
             if (1 && comp_ok) {
                 // execute it
-                py_obj_t module_fun = rt_make_function_from_id(1);
-                if (module_fun != py_const_none) {
+                mp_obj_t module_fun = rt_make_function_from_id(1);
+                if (module_fun != mp_const_none) {
                     nlr_buf_t nlr;
                     if (nlr_push(&nlr) == 0) {
-                        py_obj_t ret = rt_call_function_0(module_fun);
+                        mp_obj_t ret = rt_call_function_0(module_fun);
                         printf("done! got: ");
-                        py_obj_print(ret);
+                        mp_obj_print(ret);
                         printf("\n");
                         nlr_pop();
                     } else {
                         // uncaught exception
                         printf("exception: ");
-                        py_obj_print((py_obj_t)nlr.ret_val);
+                        mp_obj_print((mp_obj_t)nlr.ret_val);
                         printf("\n");
                     }
                 }
@@ -132,37 +133,58 @@
     }
 }
 
-void test_print(py_obj_t o_in) {
-    printf("<test>");
+typedef struct _test_obj_t {
+    mp_obj_base_t base;
+    bool value;
+} test_obj_t;
+
+static void test_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+    test_obj_t *self = self_in;
+    print(env, "<test %d>", self->value);
 }
 
-py_obj_t test_get(py_obj_t o_in) {
-    py_obj_t d1;
-    py_obj_t d2;
-    py_user_get_data(o_in, (machine_uint_t*)&d1, (machine_uint_t*)&d2);
-    return d1;
+static mp_obj_t test_get(mp_obj_t self_in) {
+    test_obj_t *self = self_in;
+    return mp_obj_new_int(self->value);
 }
 
-py_obj_t test_set(py_obj_t o_in, py_obj_t arg) {
-    py_user_set_data(o_in, (machine_uint_t)arg, (machine_uint_t)arg);
-    return py_const_none;
+static mp_obj_t test_set(mp_obj_t self_in, mp_obj_t arg) {
+    test_obj_t *self = self_in;
+    self->value = mp_obj_get_int(arg);
+    return mp_const_none;
 }
 
-const py_user_info_t test_obj_info = {
+static MP_DEFINE_CONST_FUN_OBJ_1(test_get_obj, test_get);
+static MP_DEFINE_CONST_FUN_OBJ_2(test_set_obj, test_set);
+
+static const mp_obj_type_t test_type = {
+    { &mp_const_type },
     "Test",
-    test_print,
-    {
-        { "get", 0, test_get },
-        { "set", 1, test_set },
-        { NULL, 0, NULL },
+    test_print, // print
+    NULL, // call_n
+    NULL, // unary_op
+    NULL, // binary_op
+    NULL, // getiter
+    NULL, // iternext
+    { // method list
+        { "get", &test_get_obj },
+        { "set", &test_set_obj },
+        { NULL, NULL },
     }
 };
 
+mp_obj_t test_obj_new(int value) {
+    test_obj_t *o = m_new_obj(test_obj_t);
+    o->base.type = &test_type;
+    o->value = value;
+    return o;
+}
+
 int main(int argc, char **argv) {
     qstr_init();
     rt_init();
 
-    rt_store_name(qstr_from_str_static("test"), py_obj_new_user(&test_obj_info, (machine_uint_t)py_obj_new_int(42), 0));
+    rt_store_name(qstr_from_str_static("test"), test_obj_new(42));
 
     if (argc == 1) {
         do_repl();
diff --git a/unix/mpyconfig.h b/unix/mpconfig.h
similarity index 89%
rename from unix/mpyconfig.h
rename to unix/mpconfig.h
index f187cbb..a358d7d 100644
--- a/unix/mpyconfig.h
+++ b/unix/mpconfig.h
@@ -13,6 +13,7 @@
 typedef int64_t machine_int_t; // must be pointer size
 typedef uint64_t machine_uint_t; // must be pointer size
 typedef void *machine_ptr_t; // must be of pointer size
+typedef const void *machine_const_ptr_t; // must be of pointer size
 typedef double machine_float_t;
 
 machine_float_t machine_sqrt(machine_float_t x);