Add framework to support alternative implementations of long int Python type.
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 6deb442..ada4aa2 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -62,6 +62,18 @@
 #define MICROPY_ENABLE_LEXER_UNIX (0)
 #endif
 
+// Long int implementation
+#define MICROPY_LONGINT_IMPL_NONE (0)
+#define MICROPY_LONGINT_IMPL_LONGLONG (1)
+
+#ifndef MICROPY_LONGINT_IMPL
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
+#endif
+
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+typedef long long mp_longint_impl_t;
+#endif
+
 // Whether to support float and complex types
 #ifndef MICROPY_ENABLE_FLOAT
 #define MICROPY_ENABLE_FLOAT (0)
diff --git a/py/obj.h b/py/obj.h
index 5a104d7..a9a5827 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -198,6 +198,8 @@
 mp_obj_t mp_obj_new_bool(bool value);
 mp_obj_t mp_obj_new_cell(mp_obj_t obj);
 mp_obj_t mp_obj_new_int(machine_int_t value);
+mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
+mp_obj_t mp_obj_new_int_from_long_str(const char *s);
 mp_obj_t mp_obj_new_str(qstr qstr);
 #if MICROPY_ENABLE_FLOAT
 mp_obj_t mp_obj_new_float(mp_float_t val);
diff --git a/py/objint.c b/py/objint.c
index 9cd5eba..26d3c0e 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -11,8 +11,16 @@
 
 typedef struct _mp_obj_int_t {
     mp_obj_base_t base;
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+    mp_longint_impl_t val;
+#endif
 } mp_obj_int_t;
 
+void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in);
+mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
+
+// This dispatcher function is expected to be independent of the implementation
+// of long int
 static mp_obj_t int_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
     switch (n_args) {
         case 0:
@@ -20,7 +28,7 @@
 
         case 1:
             // TODO allow string as arg and parse it
-            return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
+            return mp_obj_new_int(mp_obj_get_int(args[0]));
 
         //case 2:
             // TODO, parse with given base
@@ -33,9 +41,41 @@
 const mp_obj_type_t int_type = {
     { &mp_const_type },
     "int",
+    .print = int_print,
     .make_new = int_make_new,
+    .binary_op = int_binary_op,
 };
 
-mp_obj_t mp_obj_new_int(machine_int_t value) {
-    return MP_OBJ_NEW_SMALL_INT(value);
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+// This is called only for non-SMALL_INT
+void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
 }
+
+// This is called only for non-SMALL_INT
+mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+    assert(0);
+}
+
+// This is called only with strings whose value doesn't fit in SMALL_INT
+mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
+    assert(0);
+}
+
+mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
+    // SMALL_INT accepts only signed numbers, of one bit less size
+    // then word size, which totals 2 bits less for unsigned numbers.
+    if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
+        return MP_OBJ_NEW_SMALL_INT(value);
+    }
+    // TODO: Raise exception
+    assert(0);
+}
+
+mp_obj_t mp_obj_new_int(machine_int_t value) {
+    if (MP_OBJ_FITS_SMALL_INT(value)) {
+        return MP_OBJ_NEW_SMALL_INT(value);
+    }
+    // TODO: Raise exception
+    assert(0);
+}
+#endif