Commit 34864b14 authored by Vitja Makarov's avatar Vitja Makarov

CyFunction's defaults getter for non-literal default arguments

parent fc581b12
...@@ -6162,6 +6162,22 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -6162,6 +6162,22 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
self.defaults_tuple = TupleNode(self.pos, args=[ self.defaults_tuple = TupleNode(self.pos, args=[
arg.default for arg in default_args]) arg.default for arg in default_args])
self.defaults_tuple.analyse_types(env) self.defaults_tuple.analyse_types(env)
else:
defaults_getter = Nodes.DefNode(
self.pos, args=[], star_arg=None, starstar_arg=None,
body=Nodes.ReturnStatNode(
self.pos, return_type=py_object_type,
value=DefaultsTupleNode(
self.pos, default_args,
self.defaults_struct)),
decorators=None, name="__defaults__")
defaults_getter.analyse_declarations(env)
defaults_getter.analyse_expressions(env)
defaults_getter.body.analyse_expressions(
defaults_getter.local_scope)
defaults_getter.py_wrapper_required = False
defaults_getter.pymethdef_required = False
self.def_node.defaults_getter = defaults_getter
def may_be_none(self): def may_be_none(self):
return False return False
...@@ -6258,6 +6274,9 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -6258,6 +6274,9 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if self.defaults_tuple: if self.defaults_tuple:
code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % ( code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % (
self.result(), self.defaults_tuple.py_result())) self.result(), self.defaults_tuple.py_result()))
if def_node.defaults_getter:
code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
self.result(), def_node.defaults_getter.entry.pyfunc_cname))
if self.specialized_cpdefs: if self.specialized_cpdefs:
self.generate_fused_cpdef(code, code_object_result, flags) self.generate_fused_cpdef(code, code_object_result, flags)
...@@ -6389,6 +6408,43 @@ class CodeObjectNode(ExprNode): ...@@ -6389,6 +6408,43 @@ class CodeObjectNode(ExprNode):
)) ))
class DefaultArgNode(ExprNode):
# CyFunction's non-literal argument default value
subexprs = []
def __init__(self, pos, arg, defaults_struct):
super(DefaultArgNode, self).__init__(pos)
self.arg = arg
self.defaults_struct = defaults_struct
def analyse_types(self, env):
self.type = self.arg.type
self.is_temp = False
def generate_result_code(self, code):
pass
def result(self):
return '__Pyx_CyFunction_Defaults(%s, %s)->%s' % (
self.defaults_struct.name, Naming.self_cname,
self.defaults_struct.lookup(self.arg.name).cname)
class DefaultsTupleNode(TupleNode):
# CyFunction's __defaults__ tuple
def __init__(self, pos, defaults, defaults_struct):
args = []
for arg in defaults:
if not arg.default.is_literal:
arg = DefaultArgNode(pos, arg, defaults_struct)
else:
arg = arg.default
args.append(arg)
super(DefaultsTupleNode, self).__init__(pos, args=args)
class LambdaNode(InnerFunctionNode): class LambdaNode(InnerFunctionNode):
# Lambda expression node (only used as a function reference) # Lambda expression node (only used as a function reference)
# #
......
...@@ -2704,6 +2704,8 @@ class DefNode(FuncDefNode): ...@@ -2704,6 +2704,8 @@ class DefNode(FuncDefNode):
py_wrapper_required = True py_wrapper_required = True
func_cname = None func_cname = None
defaults_getter = None
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds) FuncDefNode.__init__(self, pos, **kwds)
k = rk = r = 0 k = rk = r = 0
...@@ -3068,6 +3070,9 @@ class DefNode(FuncDefNode): ...@@ -3068,6 +3070,9 @@ class DefNode(FuncDefNode):
return 1 return 1
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
if self.defaults_getter:
self.defaults_getter.generate_function_definitions(env, code)
# Before closure cnames are mangled # Before closure cnames are mangled
if self.py_wrapper_required: if self.py_wrapper_required:
# func_cname might be modified by @cname # func_cname might be modified by @cname
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#define __Pyx_CyFunction_Defaults(type, f) \ #define __Pyx_CyFunction_Defaults(type, f) \
((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) ((type *)(((__pyx_CyFunctionObject *) (f))->defaults))
#define __Pyx_CyFunction_SetDefaultsGetter(f, g) \
((__pyx_CyFunctionObject *) (f))->defaults_getter = (g)
typedef struct { typedef struct {
...@@ -34,6 +36,7 @@ typedef struct { ...@@ -34,6 +36,7 @@ typedef struct {
/* Defaults info */ /* Defaults info */
PyObject *defaults_tuple; /* Const defaults tuple */ PyObject *defaults_tuple; /* Const defaults tuple */
PyObject *(*defaults_getter)(PyObject *);
} __pyx_CyFunctionObject; } __pyx_CyFunctionObject;
static PyTypeObject *__pyx_CyFunctionType = 0; static PyTypeObject *__pyx_CyFunctionType = 0;
...@@ -210,6 +213,17 @@ __Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op) ...@@ -210,6 +213,17 @@ __Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op)
return op->defaults_tuple; return op->defaults_tuple;
} }
if (op->defaults_getter) {
PyObject *res = op->defaults_getter((PyObject *) op);
/* Cache result */
if (res) {
Py_INCREF(res);
op->defaults_tuple = res;
}
return res;
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -281,6 +295,7 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f ...@@ -281,6 +295,7 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f
op->defaults_pyobjects = 0; op->defaults_pyobjects = 0;
op->defaults = NULL; op->defaults = NULL;
op->defaults_tuple = NULL; op->defaults_tuple = NULL;
op->defaults_getter = NULL;
PyObject_GC_Track(op); PyObject_GC_Track(op);
return (PyObject *) op; return (PyObject *) op;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment