Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
f0778a7c
Commit
f0778a7c
authored
Jun 07, 2014
by
Damien George
Browse files
py: Implement default keyword only args.
Should finish addressing issue #524.
parent
aabd83ea
Changes
6
Hide whitespace changes
Inline
Side-by-side
py/compile.c
View file @
f0778a7c
...
...
@@ -1035,7 +1035,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
if
(
comp
->
have_star
)
{
comp
->
num_dict_params
+=
1
;
#if !MICROPY_EMIT_CPYTHON
#if MICROPY_EMIT_CPYTHON
EMIT_ARG
(
load_const_str
,
MP_PARSE_NODE_LEAF_ARG
(
pn_id
),
false
);
compile_node
(
comp
,
pn_equal
);
#else
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
if
(
comp
->
num_dict_params
==
1
)
{
// in Micro Python we put the default positional parameters into a tuple using the bytecode
...
...
@@ -1048,11 +1051,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
// first default dict param, so make the map
EMIT_ARG
(
build_map
,
0
);
}
#endif
EMIT_ARG
(
load_const_str
,
MP_PARSE_NODE_LEAF_ARG
(
pn_id
),
false
);
// compile value then key, then store it to the dict
compile_node
(
comp
,
pn_equal
);
#if !MICROPY_EMIT_CPYTHON
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
EMIT_ARG
(
load_const_str
,
MP_PARSE_NODE_LEAF_ARG
(
pn_id
),
false
);
EMIT
(
store_map
);
#endif
}
else
{
...
...
py/emitglue.c
View file @
f0778a7c
...
...
@@ -119,14 +119,14 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
// def_args must be MP_OBJ_NULL or a tuple
assert
(
def_args
==
MP_OBJ_NULL
||
MP_OBJ_IS_TYPE
(
def_args
,
&
mp_type_tuple
));
//
TODO implement default kw args
assert
(
def_kw_args
==
MP_OBJ_NULL
);
//
def_kw_args must be MP_OBJ_NULL or a dict
assert
(
def_kw_args
==
MP_OBJ_NULL
||
MP_OBJ_IS_TYPE
(
def_kw_args
,
&
mp_type_dict
)
);
// make the function, depending on the raw code kind
mp_obj_t
fun
;
switch
(
rc
->
kind
)
{
case
MP_CODE_BYTECODE
:
fun
=
mp_obj_new_fun_bc
(
rc
->
scope_flags
,
rc
->
arg_names
,
rc
->
n_pos_args
,
rc
->
n_kwonly_args
,
def_args
,
rc
->
u_byte
.
code
);
fun
=
mp_obj_new_fun_bc
(
rc
->
scope_flags
,
rc
->
arg_names
,
rc
->
n_pos_args
,
rc
->
n_kwonly_args
,
def_args
,
def_kw_args
,
rc
->
u_byte
.
code
);
break
;
case
MP_CODE_NATIVE_PY
:
fun
=
mp_make_function_n
(
rc
->
n_pos_args
,
rc
->
u_native
.
fun
);
...
...
py/obj.h
View file @
f0778a7c
...
...
@@ -380,7 +380,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t
mp_obj_new_exception_args
(
const
mp_obj_type_t
*
exc_type
,
uint
n_args
,
const
mp_obj_t
*
args
);
mp_obj_t
mp_obj_new_exception_msg
(
const
mp_obj_type_t
*
exc_type
,
const
char
*
msg
);
mp_obj_t
mp_obj_new_exception_msg_varg
(
const
mp_obj_type_t
*
exc_type
,
const
char
*
fmt
,
...);
// counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
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
,
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
,
mp_obj_t
def_kw_args
,
const
byte
*
code
);
mp_obj_t
mp_obj_new_fun_asm
(
uint
n_args
,
void
*
fun
);
mp_obj_t
mp_obj_new_gen_wrap
(
mp_obj_t
fun
);
mp_obj_t
mp_obj_new_closure
(
mp_obj_t
fun
,
uint
n_closed
,
const
mp_obj_t
*
closed
);
...
...
py/objfun.c
View file @
f0778a7c
...
...
@@ -249,6 +249,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
// 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.
//
// TODO Now that we allocate the state for the bytecode execution, we probably don't
// need extra_args anymore, and definitely don't need flat_args.
//
// TODO The following comment is obsolete and probably wrong:
// 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
);
...
...
@@ -260,7 +264,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
DEBUG_printf
(
"Func n_def_args: %d
\n
"
,
self
->
n_def_args
);
const
mp_obj_t
*
kwargs
=
args
+
n_args
;
mp_obj_t
*
extra_args
=
self
->
extra_args
+
self
->
n_def_args
;
mp_obj_t
*
extra_args
=
self
->
extra_args
+
self
->
n_def_args
+
self
->
has_def_kw_args
;
uint
n_extra_args
=
0
;
// check positional arguments
...
...
@@ -295,7 +299,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
// check keyword arguments
if
(
n_kw
!=
0
)
{
if
(
n_kw
!=
0
||
self
->
has_def_kw_args
)
{
// We cannot use dynamically-sized array here, because GCC indeed
// deallocates it on leaving defining scope (unlike most static stack allocs).
// So, we have 2 choices: allocate it unconditionally at the top of function
...
...
@@ -355,10 +359,19 @@ continue2:;
}
// Check that all mandatory keyword args are specified
// Fill in default kw args if we have them
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
])));
mp_map_elem_t
*
elem
=
NULL
;
if
(
self
->
has_def_kw_args
)
{
elem
=
mp_map_lookup
(
&
((
mp_obj_dict_t
*
)
self
->
extra_args
[
self
->
n_def_args
])
->
map
,
MP_OBJ_NEW_QSTR
(
self
->
args
[
self
->
n_pos_args
+
i
]),
MP_MAP_LOOKUP
);
}
if
(
elem
!=
NULL
)
{
flat_args
[
self
->
n_pos_args
+
i
]
=
elem
->
value
;
}
else
{
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
])));
}
}
}
...
...
@@ -513,7 +526,7 @@ const mp_obj_type_t mp_type_fun_bc = {
.
binary_op
=
fun_binary_op
,
};
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
)
{
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
,
mp_obj_t
def_kw_args
,
const
byte
*
code
)
{
uint
n_def_args
=
0
;
uint
n_extra_args
=
0
;
mp_obj_tuple_t
*
def_args
=
def_args_in
;
...
...
@@ -522,6 +535,9 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
n_def_args
=
def_args
->
len
;
n_extra_args
=
def_args
->
len
;
}
if
(
def_kw_args
!=
MP_OBJ_NULL
)
{
n_extra_args
+=
1
;
}
if
((
scope_flags
&
MP_SCOPE_FLAG_VARARGS
)
!=
0
)
{
n_extra_args
+=
1
;
}
...
...
@@ -535,18 +551,24 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
o
->
n_pos_args
=
n_pos_args
;
o
->
n_kwonly_args
=
n_kwonly_args
;
o
->
n_def_args
=
n_def_args
;
o
->
has_def_kw_args
=
def_kw_args
!=
MP_OBJ_NULL
;
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
));
mp_obj_t
*
extra_args
=
o
->
extra_args
;
memset
(
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
));
memcpy
(
extra_args
,
def_args
->
items
,
n_def_args
*
sizeof
(
mp_obj_t
));
extra_args
+=
n_def_args
;
}
if
(
def_kw_args
!=
MP_OBJ_NULL
)
{
*
extra_args
++
=
def_kw_args
;
}
if
((
scope_flags
&
MP_SCOPE_FLAG_VARARGS
)
!=
0
)
{
o
->
extra_args
[
n_def_args
]
=
MP_OBJ_NULL
;
*
extra_args
++
=
MP_OBJ_NULL
;
}
if
((
scope_flags
&
MP_SCOPE_FLAG_VARARGS
)
!=
0
)
{
o
->
extra_args
[
n_
extra_args
-
1
]
=
MP_OBJ_NULL
;
*
extra_args
=
MP_OBJ_NULL
;
}
return
o
;
}
...
...
py/objfun.h
View file @
f0778a7c
...
...
@@ -30,10 +30,15 @@ typedef struct _mp_obj_fun_bc_t {
machine_uint_t
n_pos_args
:
16
;
// number of arguments this function takes
machine_uint_t
n_kwonly_args
:
16
;
// number of arguments this function takes
machine_uint_t
n_def_args
:
16
;
// number of default arguments
machine_uint_t
has_def_kw_args
:
1
;
// set if this function has default keyword args
machine_uint_t
takes_var_args
:
1
;
// set if this function takes variable args
machine_uint_t
takes_kw_args
:
1
;
// set if this function takes keyword args
const
byte
*
bytecode
;
// bytecode for the function
qstr
*
args
;
// argument names (needed to resolve positional args passed as keywords)
// values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
// the following extra_args array is allocated space to take (in order):
// - values of positional default args (if any)
// - a single slot for default kw args dict (if it has them)
// - a single slot for var args tuple (if it takes them)
// - a single slot for kw args dict (if it takes them)
mp_obj_t
extra_args
[];
}
mp_obj_fun_bc_t
;
tests/basics/fun-kwonly.py
View file @
f0778a7c
...
...
@@ -43,14 +43,14 @@ def f(a, *, b, **kw):
f
(
1
,
b
=
2
)
f
(
1
,
b
=
2
,
c
=
3
)
#
# with a default value
; not currently working
#
def g(a, *, b=2, c):
#
print(a, b, c)
#
#
g(1, c=3)
#
g(1, b=3, c=4)
#
g(1, **{'c':3})
#
g(1, **{'b':'3', 'c':4})
# with a default value
def
g
(
a
,
*
,
b
=
2
,
c
):
print
(
a
,
b
,
c
)
g
(
1
,
c
=
3
)
g
(
1
,
b
=
3
,
c
=
4
)
g
(
1
,
**
{
'c'
:
3
})
g
(
1
,
**
{
'b'
:
'3'
,
'c'
:
4
})
# with named star
def
f
(
*
a
,
b
,
c
):
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment