py: Implement keyword-only args.

Implements 'def f(*, a)' and 'def f(*a, b)', but not default
keyword-only args, eg 'def f(*, a=1)'.

Partially addresses issue #524.
diff --git a/py/objfun.c b/py/objfun.c
index 940b64a..a5266eb 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -152,17 +152,18 @@
     mp_obj_fun_bc_t *self = self_in;
 
     assert(n_kw == 0);
+    assert(self->n_kwonly_args == 0);
     assert(self->takes_var_args == 0);
     assert(self->takes_kw_args == 0);
 
     mp_obj_t *extra_args = self->extra_args + self->n_def_args;
     uint n_extra_args = 0;
 
-    if (n_args > self->n_args) {
-            goto arg_error;
+    if (n_args > self->n_pos_args) {
+        goto arg_error;
     } else {
-        extra_args -= self->n_args - n_args;
-        n_extra_args += self->n_args - n_args;
+        extra_args -= self->n_pos_args - n_args;
+        n_extra_args += self->n_pos_args - n_args;
     }
     *out_args1 = args;
     *out_args1_len = n_args;
@@ -171,10 +172,15 @@
     return true;
 
 arg_error:
-    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
+    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_pos_args, n_args));
 }
 
 STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    // This function is pretty complicated.  It's main aim is to be efficient in speed and RAM
+    // usage for the common case of positional only args.
+    //
+    // extra_args layout: def_args, var_arg tuple, kwonly args, var_kw dict
+
     DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
     DEBUG_printf("Input pos args: ");
     dump_args(args, n_args);
@@ -187,19 +193,18 @@
     mp_obj_t *extra_args = self->extra_args + self->n_def_args;
     uint n_extra_args = 0;
 
-
     // check positional arguments
 
-    if (n_args > self->n_args) {
+    if (n_args > self->n_pos_args) {
         // given more than enough arguments
         if (!self->takes_var_args) {
             nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "function takes %d positional arguments but %d were given", self->n_args, n_args));
+                "function takes %d positional arguments but %d were given", self->n_pos_args, n_args));
         }
         // put extra arguments in varargs tuple
-        *extra_args = mp_obj_new_tuple(n_args - self->n_args, args + self->n_args);
+        *extra_args = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
         n_extra_args = 1;
-        n_args = self->n_args;
+        n_args = self->n_pos_args;
     } else {
         if (self->takes_var_args) {
             DEBUG_printf("passing empty tuple as *args\n");
@@ -209,14 +214,14 @@
         // Apply processing and check below only if we don't have kwargs,
         // otherwise, kw handling code below has own extensive checks.
         if (n_kw == 0) {
-            if (n_args >= self->n_args - self->n_def_args) {
+            if (n_args >= self->n_pos_args - self->n_def_args) {
                 // given enough arguments, but may need to use some default arguments
-                extra_args -= self->n_args - n_args;
-                n_extra_args += self->n_args - n_args;
+                extra_args -= self->n_pos_args - n_args;
+                n_extra_args += self->n_pos_args - n_args;
             } else {
                 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
                     "function takes at least %d positional arguments but %d were given",
-                    self->n_args - self->n_def_args, n_args));
+                    self->n_pos_args - self->n_def_args, n_args));
             }
         }
     }
@@ -229,13 +234,13 @@
         // So, we have 2 choices: allocate it unconditionally at the top of function
         // (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
         //mp_obj_t flat_args[self->n_args];
-        mp_obj_t *flat_args = alloca(self->n_args * sizeof(mp_obj_t));
-        for (int i = self->n_args - 1; i >= 0; i--) {
+        mp_obj_t *flat_args = alloca((self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t));
+        for (int i = self->n_pos_args + self->n_kwonly_args - 1; i >= 0; i--) {
             flat_args[i] = MP_OBJ_NULL;
         }
         memcpy(flat_args, args, sizeof(*args) * n_args);
         DEBUG_printf("Initial args: ");
-        dump_args(flat_args, self->n_args);
+        dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
 
         mp_obj_t dict = MP_OBJ_NULL;
         if (self->takes_kw_args) {
@@ -243,7 +248,7 @@
         }
         for (uint i = 0; i < n_kw; i++) {
             qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
-            for (uint j = 0; j < self->n_args; j++) {
+            for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
                 if (arg_name == self->args[j]) {
                     if (flat_args[j] != MP_OBJ_NULL) {
                         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
@@ -261,10 +266,10 @@
 continue2:;
         }
         DEBUG_printf("Args with kws flattened: ");
-        dump_args(flat_args, self->n_args);
+        dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
 
-        // Now fill in defaults
-        mp_obj_t *d = &flat_args[self->n_args - 1];
+        // Now fill in defaults for positional args
+        mp_obj_t *d = &flat_args[self->n_pos_args - 1];
         mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
         for (int i = self->n_def_args; i > 0; i--, d--, s--) {
             if (*d == MP_OBJ_NULL) {
@@ -272,9 +277,9 @@
             }
         }
         DEBUG_printf("Args after filling defaults: ");
-        dump_args(flat_args, self->n_args);
+        dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
 
-        // Now check that all mandatory args specified
+        // Check that all mandatory positional args are specified
         while (d >= flat_args) {
             if (*d-- == MP_OBJ_NULL) {
                 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
@@ -282,8 +287,16 @@
             }
         }
 
+        // Check that all mandatory keyword args are specified
+        for (int i = 0; i < self->n_kwonly_args; i++) {
+            if (flat_args[self->n_pos_args + i] == MP_OBJ_NULL) {
+                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
+                    "function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
+            }
+        }
+
         args = flat_args;
-        n_args = self->n_args;
+        n_args = self->n_pos_args + self->n_kwonly_args;
 
         if (self->takes_kw_args) {
             extra_args[n_extra_args] = dict;
@@ -291,6 +304,10 @@
         }
     } else {
         // no keyword arguments given
+        if (self->n_kwonly_args != 0) {
+            nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
+                "function missing keyword-only argument"));
+        }
         if (self->takes_kw_args) {
             extra_args[n_extra_args] = mp_obj_new_dict(0);
             n_extra_args += 1;
@@ -320,7 +337,7 @@
     .binary_op = fun_binary_op,
 };
 
-mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args_in, const byte *code) {
+mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, const byte *code) {
     uint n_def_args = 0;
     uint n_extra_args = 0;
     mp_obj_tuple_t *def_args = def_args_in;
@@ -339,14 +356,22 @@
     o->base.type = &mp_type_fun_bc;
     o->globals = mp_globals_get();
     o->args = args;
-    o->n_args = n_args;
+    o->n_pos_args = n_pos_args;
+    o->n_kwonly_args = n_kwonly_args;
     o->n_def_args = n_def_args;
     o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
     o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
     o->bytecode = code;
+    memset(o->extra_args, 0, n_extra_args * sizeof(mp_obj_t));
     if (def_args != MP_OBJ_NULL) {
         memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
     }
+    if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
+        o->extra_args[n_def_args] = MP_OBJ_NULL;
+    }
+    if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
+        o->extra_args[n_extra_args - 1] = MP_OBJ_NULL;
+    }
     return o;
 }