self.result_code = "<error>"
return
# Check no. of args
- expected_nargs = len(func_type.args)
+ max_nargs = len(func_type.args)
+ expected_nargs = max_nargs - func_type.optional_arg_count
actual_nargs = len(self.args)
if actual_nargs < expected_nargs \
- or (not func_type.has_varargs and actual_nargs > expected_nargs):
+ or (not func_type.has_varargs and actual_nargs > max_nargs):
expected_str = str(expected_nargs)
if func_type.has_varargs:
expected_str = "at least " + expected_str
+ elif func_type.optional_arg_count:
+ if actual_nargs > max_nargs:
+ expected_str = "at least " + expected_str
+ else:
+ expected_str = "at most " + str(max_nargs)
error(self.pos,
"Call with wrong number of arguments (expected %s, got %s)"
% (expected_str, actual_nargs))
self.result_code = "<error>"
return
# Coerce arguments
- for i in range(expected_nargs):
+ for i in range(min(max_nargs, actual_nargs)):
formal_type = func_type.args[i].type
self.args[i] = self.args[i].coerce_to(formal_type, env)
- for i in range(expected_nargs, actual_nargs):
+ for i in range(max_nargs, actual_nargs):
if self.args[i].type.is_pyobject:
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
zip(formal_args, self.args):
arg_code = actual_arg.result_as(formal_arg.type)
arg_list_code.append(arg_code)
+ if func_type.optional_arg_count:
+ for formal_arg in formal_args[len(self.args):]:
+ arg_list_code.append(formal_arg.type.cast_code('0'))
+ arg_list_code.append(str(max(0, len(formal_args) - len(self.args))))
for actual_arg in self.args[len(formal_args):]:
arg_list_code.append(actual_arg.result_code)
result = "%s(%s)" % (self.function.result_code,
- join(arg_list_code, ","))
+ join(arg_list_code, ", "))
if self.wrapper_call or \
self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
self.result_ctype = arg.ctype()
env.use_utility_code(type_test_utility_code)
+ def analyse_types(self, env):
+ pass
+
def result_in_temp(self):
return self.arg.result_in_temp()
if self.type.typeobj_is_available():
code.putln(
"if (!__Pyx_TypeTest(%s, %s)) %s" % (
- self.arg.py_result(),
+ self.arg.py_result(),
self.type.typeptr_cname,
code.error_goto(self.pos)))
else:
skip_dispatch_cname = pyrex_prefix + "skip_dispatch"
empty_tuple = pyrex_prefix + "empty_tuple"
cleanup_cname = pyrex_prefix + "module_cleanup"
+optional_count_cname = pyrex_prefix + "optional_arg_count"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
# with_gil boolean Acquire gil around function body
overridable = 0
+ optional_arg_count = 0
def analyse(self, return_type, env):
func_type_args = []
func_type_args.append(
PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
if arg_node.default:
- error(arg_node.pos, "C function argument cannot have default value")
+ self.optional_arg_count += 1
exc_val = None
exc_check = 0
if return_type.is_pyobject \
"Function cannot return a function")
func_type = PyrexTypes.CFuncType(
return_type, func_type_args, self.has_varargs,
+ optional_arg_count = self.optional_arg_count,
exception_value = exc_val, exception_check = exc_check,
calling_convention = self.base.calling_convention,
nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
# entry Symtab.Entry
py_func = None
+ assmt = None
+
+ def analyse_default_values(self, env):
+ genv = env.global_scope()
+ for arg in self.args:
+ if arg.default:
+ if arg.is_generic:
+ if not hasattr(arg, 'default_entry'):
+ arg.default.analyse_types(genv)
+ arg.default = arg.default.coerce_to(arg.type, genv)
+ arg.default.allocate_temps(genv)
+ arg.default_entry = genv.add_default_value(arg.type)
+ arg.default_entry.used = 1
+ else:
+ error(arg.pos,
+ "This argument cannot have a default value")
+ arg.default = None
- def analyse_expressions(self, env):
- pass
-
def need_gil_acquisition(self, lenv):
return 0
code.put_var_incref(entry)
def generate_execution_code(self, code):
- pass
+ # Evaluate and store argument default values
+ for arg in self.args:
+ default = arg.default
+ if default:
+ default.generate_evaluation_code(code)
+ default.make_owned_reference(code)
+ code.putln(
+ "%s = %s;" % (
+ arg.default_entry.cname,
+ default.result_as(arg.default_entry.type)))
+ if default.is_temp and default.type.is_pyobject:
+ code.putln(
+ "%s = 0;" %
+ default.result_code)
+ # For Python class methods, create and store function object
+ if self.assmt:
+ self.assmt.generate_execution_code(code)
+
class CFuncDefNode(FuncDefNode):
error(self.pos, "Function declared nogil has Python locals or temporaries")
return with_gil
+ def analyse_expressions(self, env):
+ self.args = self.declarator.args
+ self.analyse_default_values(env)
+ if self.overridable:
+ self.py_func.analyse_expressions(env)
+
def generate_function_header(self, code, with_pymethdef):
arg_decls = []
type = self.type
visibility = self.entry.visibility
for arg in type.args:
arg_decls.append(arg.declaration_code())
+ if type.optional_arg_count:
+ arg_decls.append("int %s" % Naming.optional_count_cname)
if type.has_varargs:
arg_decls.append("...")
if not arg_decls:
pass
def generate_argument_parsing_code(self, code):
- pass
+ rev_args = zip(self.declarator.args, self.type.args)
+ rev_args.reverse()
+ i = 0
+ for darg, targ in rev_args:
+ if darg.default:
+ code.putln('if (%s > %s) {' % (Naming.optional_count_cname, i))
+ code.putln('%s = %s;' % (targ.cname, darg.default_entry.cname))
+ i += 1
+ for _ in range(i):
+ code.putln('}')
+ code.putln('/* defaults */')
def generate_argument_conversion_code(self, code):
pass
if env.is_py_class_scope:
self.synthesize_assignment_node(env)
- def analyse_default_values(self, env):
- genv = env.global_scope()
- for arg in self.args:
- if arg.default:
- if arg.is_generic:
- arg.default.analyse_types(genv)
- arg.default = arg.default.coerce_to(arg.type, genv)
- arg.default.allocate_temps(genv)
- arg.default_entry = genv.add_default_value(arg.type)
- arg.default_entry.used = 1
- else:
- error(arg.pos,
- "This argument cannot have a default value")
- arg.default = None
-
def synthesize_assignment_node(self, env):
import ExprNodes
self.assmt = SingleAssignmentNode(self.pos,
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
- def generate_execution_code(self, code):
- # Evaluate and store argument default values
- for arg in self.args:
- default = arg.default
- if default:
- default.generate_evaluation_code(code)
- default.make_owned_reference(code)
- code.putln(
- "%s = %s;" % (
- arg.default_entry.cname,
- default.result_as(arg.default_entry.type)))
- if default.is_temp and default.type.is_pyobject:
- code.putln(
- "%s = 0;" %
- default.result_code)
- # For Python class methods, create and store function object
- if self.assmt:
- self.assmt.generate_execution_code(code)
-
def error_value(self):
return self.entry.signature.error_value
def p_cdef_statement(s, level, visibility = 'private', api = 0,
overridable = False):
pos = s.position()
- if overridable and level not in ('c_class', 'c_class_pxd'):
- error(pos, "Overridable cdef function not allowed here")
+# if overridable and level not in ('c_class', 'c_class_pxd'):
+# error(pos, "Overridable cdef function not allowed here")
visibility = p_visibility(s, visibility)
api = api or p_api(s)
if api:
def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "",
- nogil = 0, with_gil = 0, is_overridable = 0):
+ nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0):
self.return_type = return_type
self.args = args
self.has_varargs = has_varargs
+ self.optional_arg_count = optional_arg_count
self.exception_value = exception_value
self.exception_check = exception_check
self.calling_convention = calling_convention
return 0
if self.has_varargs <> other_type.has_varargs:
return 0
+ if self.optional_arg_count <> other_type.optional_arg_count:
+ return 0
if not self.return_type.same_as(other_type.return_type):
return 0
if not self.same_calling_convention_as(other_type):
or not self.args[i].type.same_as(other_type.args[i].type)
if self.has_varargs <> other_type.has_varargs:
return 0
+ if self.optional_arg_count <> other_type.optional_arg_count:
+ return 0
if not self.return_type.subtype_of_resolved_type(other_type.return_type):
return 0
return 1
for arg in self.args:
arg_decl_list.append(
arg.type.declaration_code("", for_display, pyrex = pyrex))
+ if self.optional_arg_count:
+ arg_decl_list.append("int %s" % Naming.optional_count_cname)
if self.has_varargs:
arg_decl_list.append("...")
arg_decl_code = string.join(arg_decl_list, ",")