def _getCallCodePosConstantKeywordConstArgs( to_name, called_name, expression, call_args, call_kw, emit, context ): kw_items = tuple(call_kw.getCompileTimeConstant().items()) args = call_args.getCompileTimeConstant() values = args + tuple(item[1] for item in kw_items) kw_names = tuple(item[0] for item in kw_items) arg_size = len(args) quick_mixed_calls_used.add((arg_size, False, False)) if isMutable(values): args_values_name = context.allocateTempName("call_args_values") args_values_name.getCType().emitAssignmentCodeFromConstant( to_name=args_values_name, constant=values, may_escape=True, emit=emit, context=context, ) vector_name = args_values_name else: args_values_name = context.getConstantCode(values) vector_name = None emitLineNumberUpdateCode(expression, emit, context) emit( """%s = CALL_FUNCTION_WITH_ARGS%d_VECTORCALL(%s, &PyTuple_GET_ITEM(%s, 0), %s);""" % ( to_name, arg_size, called_name, args_values_name, context.getConstantCode(kw_names), ) ) getErrorExitCode( check_name=to_name, release_names=(called_name, vector_name), emit=emit, context=context, ) context.addCleanupTempName(to_name)
def _generateCallCodeKwSplitFromConstant( to_name, expression, call_kw, called_name, called_attribute_name, emit, context ): assert called_name is not None # TODO: Not yet specialized for method calls. assert called_attribute_name is None kw_items = tuple(call_kw.getCompileTimeConstant().items()) values = tuple(item[1] for item in kw_items) kw_names = tuple(item[0] for item in kw_items) if isMutable(values): args_kwsplit_name = context.allocateTempName("call_args_kwsplit") args_kwsplit_name.getCType().emitAssignmentCodeFromConstant( to_name=args_kwsplit_name, constant=values, may_escape=True, emit=emit, context=context, ) split_name = args_kwsplit_name else: args_kwsplit_name = context.getConstantCode(values) split_name = None emitLineNumberUpdateCode(expression, emit, context) emit( """%s = CALL_FUNCTION_WITH_NO_ARGS_KWSPLIT(%s, &PyTuple_GET_ITEM(%s, 0), %s);""" % ( to_name, called_name, args_kwsplit_name, context.getConstantCode(kw_names), ) ) getErrorExitCode( check_name=to_name, release_names=(called_name, split_name), emit=emit, context=context, ) context.addCleanupTempName(to_name)
def _getCallCodeFromTuple( to_name, called_name, expression, args_value, needs_check, emit, context ): arg_size = len(args_value) # For 0 arguments, NOARGS is supposed to be used. assert arg_size > 0 emitLineNumberUpdateCode(expression, emit, context) # We create a tuple for the call, as this can be prepared and might have to be # recreated for cases, e.g. when calling C functions, so this is a good way of # having them. if isMutable(args_value): arg_tuple_name = context.allocateTempName("call_args_kwsplit") arg_tuple_name.getCType().emitAssignmentCodeFromConstant( to_name=arg_tuple_name, constant=args_value, may_escape=True, emit=emit, context=context, ) args_name = arg_tuple_name else: arg_tuple_name = context.getConstantCode(constant=args_value) args_name = None quick_tuple_calls_used.add(arg_size) emit( """\ %s = CALL_FUNCTION_WITH_POSARGS%d(%s, %s); """ % (to_name, arg_size, called_name, arg_tuple_name) ) getErrorExitCode( check_name=to_name, release_names=(called_name, args_name), needs_check=needs_check, emit=emit, context=context, ) context.addCleanupTempName(to_name)
def getConstantReturnValue(self): """Special function that checks if code generation allows to use common C code.""" body = self.subnode_body if body is None: return True, None first_statement = body.subnode_statements[0] if first_statement.isStatementReturnConstant(): constant_value = first_statement.getConstant() # TODO: For mutable constants, we could also have something, but it would require an indicator # flag to make a deep copy. if not isMutable(constant_value): return True, constant_value else: return False, False else: return False, False
def getConstantAccess(to_name, constant, emit, context): # Many cases, because for each type, we may copy or optimize by creating # empty. pylint: disable=R0912,R0915 if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode(constant=constant, context=context) else: code = "PyDict_Copy( %s )" % getConstantCode(constant=constant, context=context) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New( %s )" % getConstantCode(constant=constant, context=context) else: code = "PySet_New( NULL )" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode(constant=constant, context=context) else: code = "LIST_COPY( %s )" % getConstantCode(constant=constant, context=context) else: code = "PyList_New( 0 )" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode(constant=constant, context=context) ref_count = 1 else: code = getConstantCode(context=context, constant=constant) ref_count = 0 else: code = getConstantCode(context=context, constant=constant) ref_count = 0 emit("%s = %s;" % ( to_name, code, )) if ref_count: context.addCleanupTempName(to_name)
def getConstantAccess(to_name, constant, emit, context): # Many cases, because for each type, we may copy or optimize by creating # empty. pylint: disable=too-many-branches,too-many-statements if to_name.c_type == "nuitka_bool" and Options.isDebug(): info("Missing optimization for constant to C bool.") if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "PyDict_Copy( %s )" % context.getConstantCode(constant) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New( %s )" % context.getConstantCode(constant) else: code = "PySet_New( NULL )" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "LIST_COPY( %s )" % context.getConstantCode(constant) else: code = "PyList_New( 0 )" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant) ref_count = 0 elif type(constant) is bytearray: code = "BYTEARRAY_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant=constant) ref_count = 0 if to_name.c_type == "PyObject *": value_name = to_name else: value_name = context.allocateTempName("constant_value") emit("%s = %s;" % (value_name, code)) if to_name is not value_name: to_name.getCType().emitAssignConversionCode( to_name=to_name, value_name=value_name, needs_check=False, emit=emit, context=context, ) # Above is supposed to transfer ownership. if ref_count: getReleaseCode(value_name, emit, context) else: if ref_count: context.addCleanupTempName(value_name)
def isMutable(self): return isMutable(self.constant)
def isMutable(self): return isMutable( self.constant )
def getConstantAccess(to_name, constant, emit, context): # Many cases, because for each type, we may copy or optimize by creating # empty. pylint: disable=R0912,R0915 if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode( constant = constant, context = context ) else: code = "PyDict_Copy( %s )" % getConstantCode( constant = constant, context = context ) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New( %s )" % getConstantCode( constant = constant, context = context ) else: code = "PySet_New( NULL )" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode( constant = constant, context = context ) else: code = "LIST_COPY( %s )" % getConstantCode( constant = constant, context = context ) else: code = "PyList_New( 0 )" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % getConstantCode( constant = constant, context = context ) ref_count = 1 else: code = getConstantCode( context = context, constant = constant ) ref_count = 0 else: code = getConstantCode( context = context, constant = constant ) ref_count = 0 emit( "%s = %s;" % ( to_name, code, ) ) if ref_count: context.addCleanupTempName(to_name)
def makeConstantRefNode(constant, source_ref, user_provided=False): # This is dispatching per constant value and types, every case # to be a return statement, pylint: disable=too-many-branches,too-many-return-statements,too-many-statements # Dispatch based on constants first. if constant is None: return ExpressionConstantNoneRef(source_ref=source_ref) elif constant is True: return ExpressionConstantTrueRef(source_ref=source_ref) elif constant is False: return ExpressionConstantFalseRef(source_ref=source_ref) elif constant is Ellipsis: return ExpressionConstantEllipsisRef(source_ref=source_ref) else: # Next, dispatch based on type. constant_type = type(constant) if constant_type is int: return ExpressionConstantIntRef(constant=constant, source_ref=source_ref) elif constant_type is str: return ExpressionConstantStrRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) elif constant_type is float: return ExpressionConstantFloatRef(constant=constant, source_ref=source_ref) elif constant_type is long: return ExpressionConstantLongRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) elif constant_type is unicode: return ExpressionConstantUnicodeRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) elif constant_type is bytes: return ExpressionConstantBytesRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) elif constant_type is dict: if constant: assert isConstant(constant), repr(constant) return ExpressionConstantDictRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantDictEmptyRef( user_provided=user_provided, source_ref=source_ref, ) elif constant_type is tuple: if constant: assert isConstant(constant), repr(constant) if isMutable(constant): return ExpressionConstantTupleMutableRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantTupleRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantTupleEmptyRef( user_provided=user_provided, source_ref=source_ref, ) elif constant_type is list: if constant: assert isConstant(constant), repr(constant) return ExpressionConstantListRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantListEmptyRef( user_provided=user_provided, source_ref=source_ref, ) elif constant_type is set: if constant: assert isConstant(constant), repr(constant) return ExpressionConstantSetRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantSetEmptyRef( user_provided=user_provided, source_ref=source_ref, ) elif constant_type is frozenset: if constant: assert isConstant(constant), repr(constant) return ExpressionConstantFrozensetRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) else: return ExpressionConstantFrozensetEmptyRef( user_provided=user_provided, source_ref=source_ref, ) elif constant_type is complex: return ExpressionConstantComplexRef( constant=constant, source_ref=source_ref, ) elif constant_type is slice: return ExpressionConstantSliceRef( constant=constant, source_ref=source_ref, ) elif constant_type is type: return ExpressionConstantTypeRef(constant=constant, source_ref=source_ref) elif constant_type is xrange: return ExpressionConstantXrangeRef( constant=constant, source_ref=source_ref, ) elif constant_type is bytearray: return ExpressionConstantBytearrayRef( constant=constant, user_provided=user_provided, source_ref=source_ref, ) elif constant in builtin_anon_values: from .BuiltinRefNodes import ExpressionBuiltinAnonymousRef return ExpressionBuiltinAnonymousRef( builtin_name=builtin_anon_values[constant], source_ref=source_ref, ) elif constant in builtin_named_values: from .BuiltinRefNodes import ExpressionBuiltinRef return ExpressionBuiltinRef( builtin_name=builtin_named_values[constant], source_ref=source_ref) elif constant in builtin_exception_values_list: from .BuiltinRefNodes import ExpressionBuiltinExceptionRef if constant is NotImplemented: exception_name = "NotImplemented" else: exception_name = constant.__name__ return ExpressionBuiltinExceptionRef(exception_name=exception_name, source_ref=source_ref) else: # Missing constant type, ought to not happen, please report. assert False, (constant, constant_type)
def emitAssignmentCodeFromConstant(cls, to_name, constant, emit, context): # Many cases to deal with, pylint: disable=too-many-branches,too-many-statements if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY(%s)" % context.getConstantCode(constant) else: code = "PyDict_Copy(%s)" % context.getConstantCode( constant) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New(%s)" % context.getConstantCode(constant) else: code = "PySet_New(NULL)" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY(%s)" % context.getConstantCode(constant) else: code = "LIST_COPY(%s)" % context.getConstantCode(constant) else: code = "PyList_New(0)" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY(%s)" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant) ref_count = 0 elif type(constant) is bytearray: code = "BYTEARRAY_COPY(%s)" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant=constant) ref_count = 0 if to_name.c_type == "PyObject *": value_name = to_name else: value_name = context.allocateTempName("constant_value") emit("%s = %s;" % (value_name, code)) if to_name is not value_name: cls.emitAssignConversionCode( to_name=to_name, value_name=value_name, needs_check=False, emit=emit, context=context, ) # Above is supposed to transfer ownership. if ref_count: getReleaseCode(value_name, emit, context) else: if ref_count: context.addCleanupTempName(value_name)
def getConstantAccess(to_name, constant, emit, context): # Many cases, because for each type, we may copy or optimize by creating # empty. pylint: disable=too-many-branches,too-many-statements if to_name.c_type == "nuitka_bool" and Options.isDebug(): assert False, constant if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "PyDict_Copy( %s )" % context.getConstantCode(constant) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New( %s )" % context.getConstantCode(constant) else: code = "PySet_New( NULL )" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "LIST_COPY( %s )" % context.getConstantCode(constant) else: code = "PyList_New( 0 )" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant) ref_count = 0 elif type(constant) is bytearray: code = "BYTEARRAY_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant=constant) ref_count = 0 emit("%s = %s;" % ( to_name, code, )) if ref_count: context.addCleanupTempName(to_name)
def getConstantCode(self, constant, deep_check=False): if deep_check and Options.is_debug: assert not isMutable(constant) return self.constant_accessor.getConstantCode(constant)
def _getCallCodePosConstKeywordVariableArgs( to_name, called_name, expression, call_args, call_kw, emit, context ): # More details, pylint: disable=too-many-locals args = call_args.getCompileTimeConstant() kw_names = [] dict_value_names = [] for count, pair in enumerate(call_kw.subnode_pairs): kw_names.append(pair.subnode_key.getCompileTimeConstant()) dict_value_name = context.allocateTempName("kw_call_value_%d" % count) generateExpressionCode( to_name=dict_value_name, expression=pair.subnode_value, emit=emit, context=context, allow_none=False, ) dict_value_names.append(dict_value_name) args_count = len(args) quick_mixed_calls_used.add((args_count, True, True)) if isMutable(args): args_value_name = context.allocateTempName("call_posargs_values") args_value_name.getCType().emitAssignmentCodeFromConstant( to_name=args_value_name, constant=args, may_escape=True, emit=emit, context=context, ) args_name = args_value_name else: args_value_name = context.getConstantCode(args) args_name = None emitLineNumberUpdateCode(expression, emit, context) emit( """\ { PyObject *kw_values[%(kw_size)d] = {%(kw_values)s}; %(to_name)s = CALL_FUNCTION_WITH_POSARGS%(args_count)d_KWSPLIT(%(called_name)s, %(pos_args)s, kw_values, %(kw_names)s); } """ % { "to_name": to_name, "kw_values": ", ".join( str(dict_value_name) for dict_value_name in dict_value_names ), "kw_size": len(call_kw.subnode_pairs), "pos_args": args_value_name, "args_count": args_count, "called_name": called_name, "kw_names": context.getConstantCode(tuple(kw_names)), } ) getErrorExitCode( check_name=to_name, release_names=(called_name, args_name) + tuple(dict_value_names), emit=emit, context=context, ) context.addCleanupTempName(to_name)
def getConstantAccess(to_name, constant, emit, context): # Many cases, because for each type, we may copy or optimize by creating # empty. pylint: disable=too-many-branches,too-many-statements if to_name.c_type == "nuitka_bool" and Options.isDebug(): info("Missing optimization for constant to C bool.") if type(constant) is dict: if constant: for key, value in iterItems(constant): # key cannot be mutable. assert not isMutable(key) if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "PyDict_Copy( %s )" % context.getConstantCode(constant) else: code = "PyDict_New()" ref_count = 1 elif type(constant) is set: if constant: code = "PySet_New( %s )" % context.getConstantCode(constant) else: code = "PySet_New( NULL )" ref_count = 1 elif type(constant) is list: if constant: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) else: code = "LIST_COPY( %s )" % context.getConstantCode(constant) else: code = "PyList_New( 0 )" ref_count = 1 elif type(constant) is tuple: for value in constant: if isMutable(value): needs_deep = True break else: needs_deep = False if needs_deep: code = "DEEP_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant) ref_count = 0 elif type(constant) is bytearray: code = "BYTEARRAY_COPY( %s )" % context.getConstantCode(constant) ref_count = 1 else: code = context.getConstantCode(constant=constant) ref_count = 0 if to_name.c_type == "PyObject *": value_name = to_name else: value_name = context.allocateTempName("constant_value") emit("%s = %s;" % (value_name, code)) if ref_count: context.addCleanupTempName(value_name) if to_name is not value_name: to_name.getCType().emitAssignConversionCode( to_name=to_name, value_name=value_name, needs_check=False, emit=emit, context=context, )