Commit 36780b2a authored by Stefan Behnel's avatar Stefan Behnel

implement cyfunction.__code__ (with empty byte code), including argument related co_* fields

parent 500f9a40
...@@ -5189,8 +5189,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5189,8 +5189,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
# self_object ExprNode or None # self_object ExprNode or None
# binding bool # binding bool
# module_name EncodedString Name of defining module # module_name EncodedString Name of defining module
# code_object CodeObjectNode the PyCodeObject creator node
subexprs = ['code_object']
subexprs = []
self_object = None self_object = None
binding = False binding = False
...@@ -5219,16 +5221,22 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5219,16 +5221,22 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
def generate_result_code(self, code): def generate_result_code(self, code):
if self.binding: if self.binding:
constructor = "__Pyx_CyFunction_NewEx" constructor = "__Pyx_CyFunction_NewEx"
if self.code_object:
code_object_result = ', ' + self.code_object.py_result()
else:
code_object_result = ', NULL'
else: else:
constructor = "PyCFunction_NewEx" constructor = "PyCFunction_NewEx"
code_object_result = ''
py_mod_name = self.get_py_mod_name(code) py_mod_name = self.get_py_mod_name(code)
code.putln( code.putln(
'%s = %s(&%s, %s, %s); %s' % ( '%s = %s(&%s, %s, %s%s); %s' % (
self.result(), self.result(),
constructor, constructor,
self.pymethdef_cname, self.pymethdef_cname,
self.self_result_code(), self.self_result_code(),
py_mod_name, py_mod_name,
code_object_result,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
...@@ -5244,6 +5252,65 @@ class InnerFunctionNode(PyCFunctionNode): ...@@ -5244,6 +5252,65 @@ class InnerFunctionNode(PyCFunctionNode):
return "((PyObject*)%s)" % (Naming.cur_scope_cname) return "((PyObject*)%s)" % (Naming.cur_scope_cname)
return "NULL" return "NULL"
class CodeObjectNode(ExprNode):
# Create a PyCodeObject for a CyFunction instance.
#
# def_node DefNode the Python function node
# varnames TupleNode a tuple with all variable names
subexprs = ['varnames']
is_temp = False
def __init__(self, def_node):
ExprNode.__init__(self, def_node.pos, def_node=def_node)
args = list(def_node.args)
if def_node.star_arg:
args.append(def_node.star_arg)
if def_node.starstar_arg:
args.append(def_node.starstar_arg)
# FIXME: lacks non-args !
self.varnames = TupleNode(
def_node.pos,
args = [ IdentifierStringNode(arg.pos, unicode_value=arg.name,
value=StringEncoding.BytesLiteral(arg.name.utf8encode()))
for arg in args ],
is_temp = 0,
is_literal = 1)
def calculate_result_code(self):
return self.result_code
def generate_result_code(self, code):
self.result_code = code.get_py_const(py_object_type, 'codeobj_', cleanup_level=2)
code = code.get_cached_constants_writer()
code.mark_pos(self.pos)
func = self.def_node
func_name = code.get_py_string_const(
func.name, identifier=True, is_str=False, unicode_value=func.name)
# FIXME: better way to get the module file path at module init time? Encoding to use?
file_path = StringEncoding.BytesLiteral(func.pos[0].get_filenametable_entry().encode('utf8'))
file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True)
code.putln("%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, 0, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s); %s" % (
self.result_code,
len(func.args), # argcount
func.num_kwonly_args, # kwonlyargcount (Py3 only)
len(self.varnames.args), # nlocals
Naming.empty_bytes, # code
Naming.empty_tuple, # consts
Naming.empty_tuple, # names (FIXME: all local non-args!)
self.varnames.result(), # varnames
Naming.empty_tuple, # freevars (FIXME)
Naming.empty_tuple, # cellvars (FIXME)
file_path_const, # filename
func_name, # name
self.pos[1], # firstlineno
Naming.empty_bytes, # lnotab
code.error_goto_if_null(self.result_code, self.pos),
))
class LambdaNode(InnerFunctionNode): class LambdaNode(InnerFunctionNode):
# Lambda expression node (only used as a function reference) # Lambda expression node (only used as a function reference)
# #
...@@ -8806,11 +8873,12 @@ typedef struct { ...@@ -8806,11 +8873,12 @@ typedef struct {
PyObject *func_weakreflist; PyObject *func_weakreflist;
PyObject *func_name; PyObject *func_name;
PyObject *func_doc; PyObject *func_doc;
PyObject *func_code;
} __pyx_CyFunctionObject; } __pyx_CyFunctionObject;
static PyTypeObject *__pyx_CyFunctionType = 0; static PyTypeObject *__pyx_CyFunctionType = 0;
static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module, PyObject* code);
static int __Pyx_CyFunction_init(void); static int __Pyx_CyFunction_init(void);
""" % Naming.__dict__, """ % Naming.__dict__,
...@@ -8949,6 +9017,14 @@ __Pyx_CyFunction_get_closure(CYTHON_UNUSED __pyx_CyFunctionObject *op) ...@@ -8949,6 +9017,14 @@ __Pyx_CyFunction_get_closure(CYTHON_UNUSED __pyx_CyFunctionObject *op)
return Py_None; return Py_None;
} }
static PyObject *
__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op)
{
PyObject* result = (op->func_code) ? op->func_code : Py_None;
Py_INCREF(result);
return result;
}
static PyGetSetDef __pyx_CyFunction_getsets[] = { static PyGetSetDef __pyx_CyFunction_getsets[] = {
{(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, {(char *) "func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0},
{(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, {(char *) "__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0},
...@@ -8961,6 +9037,8 @@ static PyGetSetDef __pyx_CyFunction_getsets[] = { ...@@ -8961,6 +9037,8 @@ static PyGetSetDef __pyx_CyFunction_getsets[] = {
{(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, {(char *) "__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0},
{(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, {(char *) "func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0},
{(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, {(char *) "__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0},
{(char *) "func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0},
{(char *) "__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0},
{0, 0, 0, 0, 0} {0, 0, 0, 0, 0}
}; };
...@@ -8989,7 +9067,7 @@ static PyMethodDef __pyx_CyFunction_methods[] = { ...@@ -8989,7 +9067,7 @@ static PyMethodDef __pyx_CyFunction_methods[] = {
}; };
static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) { static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module, PyObject* code) {
__pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType); __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType);
if (op == NULL) if (op == NULL)
return NULL; return NULL;
...@@ -9002,6 +9080,8 @@ static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObjec ...@@ -9002,6 +9080,8 @@ static PyObject *__Pyx_CyFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObjec
op->func_dict = NULL; op->func_dict = NULL;
op->func_name = NULL; op->func_name = NULL;
op->func_doc = NULL; op->func_doc = NULL;
Py_XINCREF(code);
op->func_code = code;
PyObject_GC_Track(op); PyObject_GC_Track(op);
return (PyObject *)op; return (PyObject *)op;
} }
...@@ -9016,6 +9096,7 @@ static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) ...@@ -9016,6 +9096,7 @@ static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m)
Py_XDECREF(m->func_dict); Py_XDECREF(m->func_dict);
Py_XDECREF(m->func_name); Py_XDECREF(m->func_name);
Py_XDECREF(m->func_doc); Py_XDECREF(m->func_doc);
Py_XDECREF(m->func_code);
PyObject_GC_Del(m); PyObject_GC_Del(m);
} }
...@@ -9026,6 +9107,7 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, ...@@ -9026,6 +9107,7 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit,
Py_VISIT(m->func_dict); Py_VISIT(m->func_dict);
Py_VISIT(m->func_name); Py_VISIT(m->func_name);
Py_VISIT(m->func_doc); Py_VISIT(m->func_doc);
Py_VISIT(m->func_code);
return 0; return 0;
} }
......
...@@ -567,9 +567,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -567,9 +567,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__" #define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#define __Pyx_PyIdentifier_FromString(s) PyString_FromString(s) #define __Pyx_PyIdentifier_FromString(s) PyString_FromString(s)
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \\
PyCode_New(a, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#else #else
#define __Pyx_BUILTIN_MODULE_NAME "builtins" #define __Pyx_BUILTIN_MODULE_NAME "builtins"
#define __Pyx_PyIdentifier_FromString(s) PyUnicode_FromString(s) #define __Pyx_PyIdentifier_FromString(s) PyUnicode_FromString(s)
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \\
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#endif #endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
......
...@@ -2339,10 +2339,13 @@ class DefNode(FuncDefNode): ...@@ -2339,10 +2339,13 @@ class DefNode(FuncDefNode):
if genv.is_closure_scope: if genv.is_closure_scope:
rhs = self.py_cfunc_node = ExprNodes.InnerFunctionNode( rhs = self.py_cfunc_node = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname) self.pos, pymethdef_cname = self.entry.pymethdef_cname,
code_object = ExprNodes.CodeObjectNode(self))
else: else:
rhs = self.py_cfunc_node = ExprNodes.PyCFunctionNode( rhs = self.py_cfunc_node = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding']) self.pos, pymethdef_cname = self.entry.pymethdef_cname,
binding = env.directives['binding'],
code_object = ExprNodes.CodeObjectNode(self))
if env.is_py_class_scope: if env.is_py_class_scope:
if not self.is_staticmethod and not self.is_classmethod: if not self.is_staticmethod and not self.is_classmethod:
...@@ -7806,11 +7809,9 @@ static void __Pyx_AddTraceback(const char *funcname, int %(CLINENO)s, ...@@ -7806,11 +7809,9 @@ static void __Pyx_AddTraceback(const char *funcname, int %(CLINENO)s,
if (!py_funcname) goto bad; if (!py_funcname) goto bad;
py_globals = PyModule_GetDict(%(GLOBALS)s); py_globals = PyModule_GetDict(%(GLOBALS)s);
if (!py_globals) goto bad; if (!py_globals) goto bad;
py_code = PyCode_New( py_code = __Pyx_PyCode_New(
0, /*int argcount,*/ 0, /*int argcount,*/
#if PY_MAJOR_VERSION >= 3
0, /*int kwonlyargcount,*/ 0, /*int kwonlyargcount,*/
#endif
0, /*int nlocals,*/ 0, /*int nlocals,*/
0, /*int stacksize,*/ 0, /*int stacksize,*/
0, /*int flags,*/ 0, /*int flags,*/
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
# mode: run # mode: run
# tag: cyfunction # tag: cyfunction
import sys
IS_PY3 = sys.version_info[0] >= 3
def test_dict(): def test_dict():
""" """
>>> test_dict.foo = 123 >>> test_dict.foo = 123
...@@ -82,3 +85,67 @@ class BindingTest: ...@@ -82,3 +85,67 @@ class BindingTest:
""" """
def __repr__(self): def __repr__(self):
return '<BindingTest instance>' return '<BindingTest instance>'
def codeof(func):
if IS_PY3:
return func.__code__
else:
return func.func_code
def cy_no_arg(): pass
def cy_one_arg(a): pass
def cy_two_args(x, b): pass
def cy_default_args(x=1, b=2): pass
def test_code():
"""
>>> def no_arg(): pass
>>> def one_arg(a): pass
>>> def two_args(x, b): pass
>>> def default_args(x=1, b=2): pass
>>> codeof(no_arg).co_argcount
0
>>> codeof(cy_no_arg).co_argcount
0
>>> print(codeof(no_arg).co_name)
no_arg
>>> print(codeof(cy_no_arg).co_name)
cy_no_arg
>>> codeof(no_arg).co_varnames
()
>>> codeof(cy_no_arg).co_varnames
()
>>> codeof(one_arg).co_argcount
1
>>> codeof(cy_one_arg).co_argcount
1
>>> print(codeof(one_arg).co_name)
one_arg
>>> print(codeof(cy_one_arg).co_name)
cy_one_arg
>>> codeof(one_arg).co_varnames
('a',)
>>> codeof(cy_one_arg).co_varnames
('a',)
>>> codeof(two_args).co_argcount
2
>>> codeof(cy_two_args).co_argcount
2
>>> codeof(two_args).co_varnames
('x', 'b')
>>> codeof(cy_two_args).co_varnames
('x', 'b')
>>> codeof(default_args).co_argcount
2
>>> codeof(cy_default_args).co_argcount
2
>>> codeof(default_args).co_varnames
('x', 'b')
>>> codeof(cy_default_args).co_varnames
('x', 'b')
"""
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