public ConstructorInitializer(bool baseCall, AstNode arguments, TokenPosition position) : base(position) { this.baseCall = baseCall; this.arguments = arguments; this.ctorGroup = null; }
/// <summary> /// Creates a merged group with a level of superior scope. /// </summary> public FunctionGroup CreateMerged(FunctionGroup firstLevel, bool isNamespace) { FunctionGroup ret = new FunctionGroupInstance(this); ret.mergedGroup = true; ret.AppendLevel(this, false); ret.AppendLevel(firstLevel, isNamespace); return ret; }
/// <summary> /// Appends a function group level, detecting ambiguity for namespace functions. /// </summary> public void AppendLevel(FunctionGroup level, bool isNamespaceLevel) { if (levels == null) { levels = new List <LevelData>(); } levels.Add(new LevelData(level, isNamespaceLevel)); }
/// <summary> /// Creates a merged group with a level of superior scope. /// </summary> public FunctionGroup CreateMerged(FunctionGroup firstLevel, bool isNamespace) { FunctionGroup ret = new FunctionGroupInstance(this); ret.mergedGroup = true; ret.AppendLevel(this, false); ret.AppendLevel(firstLevel, isNamespace); return(ret); }
internal static void PreloadMember(ChelaModule module, ModuleReader reader, MemberHeader header) { // Create the temporal event and register it. FunctionGroup fgroup = new FunctionGroup(module); module.RegisterMember(fgroup); // Read the name. fgroup.name = module.GetString(header.memberName); // Skip the structure elements. reader.Skip(header.memberSize); }
private void AppendLevelContent(FunctionGroup level, bool isNamespaceLevel) { level.MakeConcrete(); foreach (FunctionGroupName gname in level.functions) { // Check if the object belongs to the included namespace level bool isNamespace = gname.IsNamespaceLevel || isNamespaceLevel; // Read the name data. FunctionType type = gname.GetFunctionType(); bool isStatic = gname.IsStatic(); // Find a similar group. FunctionGroupName old = Find(gname); if (old == null) { FunctionGroupName newName = new FunctionGroupName(type, isStatic); newName.IsNamespaceLevel = isNamespace; newName.SetFunction(gname.GetFunction()); functions.Add(newName); continue; } // Ignore names of lower scopes. if (!isNamespace || !old.IsNamespaceLevel) { continue; } // Now the old name is a namespace level, and we are adding another // namespace level function, in other words, we have detected an ambiguity. Function oldFunction = old.GetFunction(); FunctionAmbiguity amb; if (!oldFunction.IsAmbiguity()) { amb = new FunctionAmbiguity(oldFunction.GetName(), oldFunction.GetFlags(), oldFunction.GetParentScope()); amb.AddCandidate(oldFunction); old.SetFunction(amb); } else { amb = (FunctionAmbiguity)oldFunction; } // Add the new function into the ambiguity list. amb.AddCandidate(gname.GetFunction()); } }
protected static bool RecursiveMerge(ref ScopeMember res, ScopeMember level) { if (level != null && res != null) { if (res.IsTypeGroup() && level.IsTypeGroup()) { // Merge type groups. TypeGroup lower = (TypeGroup)res; TypeGroup next = (TypeGroup)level; if (!lower.IsMergedGroup()) { res = lower.CreateMerged(next, false); } else { lower.AppendLevel(next, false); } } else if (res.IsFunctionGroup() && level.IsFunctionGroup()) { // Merge function groups. FunctionGroup lower = (FunctionGroup)res; FunctionGroup next = (FunctionGroup)level; if (!lower.IsMergedGroup()) { res = lower.CreateMerged(next, false); } else { lower.AppendLevel(next, false); } } } else if (res == null) { // Set the result to the next level. res = level; } return(IsRecursiveContinue(res)); }
public LevelData(FunctionGroup level, bool isNamespaceLevel) { this.data = level; this.isNamespaceLevel = isNamespaceLevel; }
private Function PickFunction(AstNode node, FunctionGroup fgroup, FunctionGroupType groupType, FunctionGroupSelector selector, Expression arguments) { if(groupType == ChelaType.GetAnyFunctionGroupType()) { Function ret = PickFunction(node, fgroup, false, selector, arguments, true); if(ret != null) return ret; return PickFunction(node, fgroup, true, selector, arguments, false); } else if(groupType == ChelaType.GetStaticFunctionGroupType()) { return PickFunction(node, fgroup, true, selector, arguments, false); } else { return PickFunction(node, fgroup, false, selector, arguments, false); } }
public void SetConstructorGroup(FunctionGroup ctorGroup) { this.ctorGroup = ctorGroup; }
private Function PickFunction(AstNode node, FunctionGroup fgroup, FunctionGroupType groupType, FunctionGroupSelector selector, List<object> arguments, bool forgive) { if(groupType == ChelaType.GetAnyFunctionGroupType()) { Function ret = PickFunction(node, fgroup, false, selector, arguments, true); if(ret != null) return ret; return PickFunction(node, fgroup, true, selector, arguments, false || forgive); } else if(groupType == ChelaType.GetStaticFunctionGroupType()) { return PickFunction(node, fgroup, true, selector, arguments, false || forgive); } else { return PickFunction(node, fgroup, false, selector, arguments, false || forgive); } }
private Function PickFunction(AstNode node, FunctionGroup fgroup, FunctionGroupType groupType, List<object> arguments) { return PickFunction(node, fgroup, groupType, null, arguments, false); }
private Function PickFunction(AstNode node, FunctionGroup fgroup, bool isStatic, FunctionGroupSelector selector, Expression arguments, bool forgive) { // Store the arguments in a vector. AstNode arg = arguments; List<object> argList = new List<object> (); while(arg != null) { argList.Add(arg); arg = arg.GetNext(); } return PickFunction(node, fgroup, isStatic, selector, argList, forgive); }
public override AstNode Visit(FunctionPrototype node) { MemberFlags callingConvention = node.GetFlags() & MemberFlags.LanguageMask; bool isCdecl = callingConvention == MemberFlags.Cdecl; bool isUnsafe = (node.GetFlags() & MemberFlags.SecurityMask) == MemberFlags.Unsafe; // Use the unsafe scope. if(isUnsafe) PushUnsafe(); // Generate a name for explicit contracts. if(node.GetNameExpression() != null) node.SetName(GenSym()); // Find an existing group. ScopeMember oldGroup = currentContainer.FindMember(node.GetName()); if(oldGroup != null && (oldGroup.IsType() || !oldGroup.IsFunctionGroup())) { if(oldGroup.IsFunction() && isCdecl) { // TODO: Add additional checks. Function oldDefinition = (Function)oldGroup; node.SetFunction(oldDefinition); node.SetNodeType(oldDefinition.GetFunctionType()); oldGroup = null; return node; } else Error(node, "cannot override something without a function group."); } FunctionGroup functionGroup = null; if(oldGroup != null) // Cast the group member. functionGroup = (FunctionGroup)oldGroup; // Make sure the destructor name is correct. if(node.GetDestructorName() != null) { // Get the building scope. Scope buildingScope = currentScope; while(buildingScope != null && (buildingScope.IsFunction() || buildingScope.IsPseudoScope() || buildingScope.IsLexicalScope())) buildingScope = buildingScope.GetParentScope(); // Make sure we are in a class. if(buildingScope == null || !buildingScope.IsClass()) Error(node, "only classes can have finalizers."); // Make sure the destructor and class name are the same. if(node.GetDestructorName() != buildingScope.GetName()) Error(node, "finalizers must have the same name as their class."); } // Read the instance flag. MemberFlags instanceFlags = node.GetFlags() & MemberFlags.InstanceMask; // Don't allow overloading with cdecl. if(isCdecl && functionGroup != null) Error(node, "overloading and cdecl are incompatible."); // Make sure static constructor doesn't have modifiers. if(instanceFlags == MemberFlags.StaticConstructor && node.GetFlags() != MemberFlags.StaticConstructor) Error(node, "static constructors cannot have modifiers."); // Static constructors cannot have paraemeters. if(instanceFlags == MemberFlags.StaticConstructor && node.GetArguments() != null) Error(node, "static constructors cannot have parameters."); // Add the this argument. if(currentContainer.IsStructure() || currentContainer.IsClass() || currentContainer.IsInterface()) { // Cast the scope. Structure building = (Structure)currentContainer; // Add the this argument. if(instanceFlags != MemberFlags.Static && instanceFlags != MemberFlags.StaticConstructor) { // Instance the building. building = building.GetSelfInstance(); // Use the structure type. TypeNode thisType = new TypeNode(TypeKind.Reference, node.GetPosition()); thisType.SetOtherType(building); // Create the this argument. FunctionArgument thisArg = new FunctionArgument(thisType, "this", node.GetPosition()); // Add to the begin of the argument list. thisArg.SetNext(node.GetArguments()); node.SetArguments(thisArg); } } // Parse the generic signature. GenericSignature genericSign = node.GetGenericSignature(); GenericPrototype genProto = null; PseudoScope protoScope = null; if(genericSign != null) { // Visit the generic signature. genericSign.Accept(this); // Create the placeholders scope. genProto = genericSign.GetPrototype(); protoScope = new PseudoScope(currentScope, genProto); node.SetScope(protoScope); } // Use the prototype scope. if(protoScope != null) PushScope(protoScope); // Visit the arguments. VisitList(node.GetArguments()); // Visit the return type. Expression returnTypeExpr = node.GetReturnType(); IChelaType returnType; if(returnTypeExpr != null) { // Don't allow the same name as the container. if((currentContainer.IsStructure() || currentContainer.IsClass() || currentContainer.IsInterface()) && node.GetName() == currentContainer.GetName()) Error(node, "constructors cannot have a return type."); returnTypeExpr.Accept(this); returnType = returnTypeExpr.GetNodeType(); returnType = ExtractActualType(returnTypeExpr, returnType); // Use references for class/interface. if(returnType.IsPassedByReference()) returnType = ReferenceType.Create(returnType); } else if(node.GetDestructorName() != null) { returnType = ChelaType.GetVoidType(); } else { returnType = ChelaType.GetVoidType(); if(!currentContainer.IsStructure() && !currentContainer.IsClass()) Error(node, "only classes and structures can have constructors."); if(node.GetName() != currentContainer.GetName()) Error(node, "constructors must have the same name as their parent."); } // Restore the prototype scope. if(protoScope != null) PopScope(); // Create his function type. List<IChelaType> arguments = new List<IChelaType> (); bool variableArgs = false; // Add the argument types. AstNode argNode = node.GetArguments(); while(argNode != null) { // Cast the argument node. FunctionArgument funArg = (FunctionArgument)argNode; // Store the argument type. arguments.Add(funArg.GetNodeType()); // Set the variable argument flags. variableArgs = funArg.IsParams(); // Check the next argument. argNode = argNode.GetNext(); } // Set the function type. FunctionType type = FunctionType.Create(returnType, arguments, variableArgs, callingConvention); node.SetNodeType(type); // Check the function safetyness. if(type.IsUnsafe()) UnsafeError(node, "safe function with unsafe type."); // Avoid collisions. if(functionGroup != null) { Function ambiguos = functionGroup.Find(type, instanceFlags == MemberFlags.Static); if(ambiguos != null) Error(node, "adding ambiguous overload for " + ambiguos.GetFullName()); } // Create and add the method into his scope. Function function = null; if(currentContainer.IsStructure() || currentContainer.IsClass() || currentContainer.IsInterface()) { // Cast the scope. Structure building = (Structure) currentContainer; // Create the function according to his instance type. if(instanceFlags == MemberFlags.Static || instanceFlags == MemberFlags.StaticConstructor) { function = new Function(node.GetName(), node.GetFlags(), currentContainer); } else { Method method = new Method(node.GetName(), node.GetFlags(), currentContainer); function = method; // Check the constructor initializer. ConstructorInitializer ctorInit = node.GetConstructorInitializer(); if(ctorInit == null || ctorInit.IsBaseCall()) method.SetCtorLeaf(true); } // Set the function position. function.Position = node.GetPosition(); // Set the function type. function.SetFunctionType(type); // Add the function. try { building.AddFunction(node.GetName(), function); } catch(ModuleException error) { Error(node, error.Message); } } else if(currentContainer.IsNamespace()) { // Create the function. function = new Function(node.GetName(), node.GetFlags(), currentContainer); function.SetFunctionType(type); // Set the function position. function.Position = node.GetPosition(); // Add the method into his namespace. Namespace space = (Namespace) currentContainer; // Create the function group. if(functionGroup == null && !isCdecl) { functionGroup = new FunctionGroup(node.GetName(), currentContainer); oldGroup = functionGroup; space.AddMember(functionGroup); } // Add the function into the function group or the namespace. if(!isCdecl) functionGroup.Insert(function); else space.AddMember(function); } else { Error(node, "a function cannot be added here."); } // Store the generic prototype. if(genProto != null) function.SetGenericPrototype(genProto); // Set the node function. node.SetFunction(function); // Check for main function. if(function.IsStatic() && function.GetName() == "Main") CheckMainCandidate(node, function); // Create kernel entry point. if(function.IsKernel()) CreateKernelEntryPoint(node, function); // Restore the safety scope. if(isUnsafe) PopUnsafe(); return node; }
private void AppendLevelContent(FunctionGroup level, bool isNamespaceLevel) { level.MakeConcrete(); foreach(FunctionGroupName gname in level.functions) { // Check if the object belongs to the included namespace level bool isNamespace = gname.IsNamespaceLevel || isNamespaceLevel; // Read the name data. FunctionType type = gname.GetFunctionType(); bool isStatic = gname.IsStatic(); // Find a similar group. FunctionGroupName old = Find(gname); if(old == null) { FunctionGroupName newName = new FunctionGroupName(type, isStatic); newName.IsNamespaceLevel = isNamespace; newName.SetFunction(gname.GetFunction()); functions.Add(newName); continue; } // Ignore names of lower scopes. if(!isNamespace || !old.IsNamespaceLevel) continue; // Now the old name is a namespace level, and we are adding another // namespace level function, in other words, we have detected an ambiguity. Function oldFunction = old.GetFunction(); FunctionAmbiguity amb; if(!oldFunction.IsAmbiguity()) { amb = new FunctionAmbiguity(oldFunction.GetName(), oldFunction.GetFlags(), oldFunction.GetParentScope()); amb.AddCandidate(oldFunction); old.SetFunction(amb); } else { amb = (FunctionAmbiguity)oldFunction; } // Add the new function into the ambiguity list. amb.AddCandidate(gname.GetFunction()); } }
/// <summary> /// Appends a function group level, detecting ambiguity for namespace functions. /// </summary> public void AppendLevel(FunctionGroup level, bool isNamespaceLevel) { if(levels == null) levels = new List<LevelData>(); levels.Add(new LevelData(level, isNamespaceLevel)); }
private Function PickFunction(AstNode node, FunctionGroup fgroup, bool isStatic, FunctionGroupSelector selector, List<object> arguments, bool forgive) { // Count the number of arguments. int startIndex = isStatic ? 0 : 1; int numargs = startIndex + arguments.Count; // Store the generic arguments. IChelaType[] genericArguments = null; if(selector != null) genericArguments = selector.GenericParameters; // Select a function in the group. List<Function> bestMatches = new List<Function> (); int bestCoercions = -1; int numfunctions = fgroup.GetFunctionCount(); bool nonKernelContext = !currentContainer.IsKernel(); foreach(FunctionGroupName groupName in fgroup.GetFunctions()) { // Only use the same static-ness. if(groupName.IsStatic() != isStatic) continue; // Get the candidate prototype. Function function = groupName.GetFunction(); FunctionType prototype = groupName.GetFunctionType(); // Use the kernel entry point when it exists, and calling a kernel from a non-kernel context. if(nonKernelContext && function.IsKernel() && function.EntryPoint != null) { function = function.EntryPoint; prototype = function.GetFunctionType(); } // Check for generics. IChelaType[] genericArgumentsMatched = null; GenericPrototype genProto = null; if(function != null) { genProto = function.GetGenericPrototype(); if(genProto.GetPlaceHolderCount() > 0 && genericArguments != null) { // Check if the generic function is matched. if(!CheckGenericArguments(fgroup.GetFunctionCount() == 1 ? node : null, genProto, genericArguments)) continue; // Matched function, store the arguments and substitute in the prototype genericArgumentsMatched = genericArguments; function = function.InstanceGeneric(new GenericInstance(genProto, genericArguments), currentModule); prototype = function.GetFunctionType(); } else if(genProto.GetPlaceHolderCount() > 0) { // Try replacing arguments. genericArgumentsMatched = new IChelaType[genProto.GetPlaceHolderCount()]; } } // TODO: Add variable arguments. if(numargs != prototype.GetArgumentCount()) continue; // Check the arguments. int index = startIndex; bool match = true; int coercions = 0; for(int i = 0; i < arguments.Count; ++i) { // Get the argument type. object argObject = arguments[i]; object argValue = null; AstNode arg = null; IChelaType argExprType = null; if(argObject is IChelaType) { argExprType = (IChelaType)argObject; } else { arg = (AstNode)argObject; argExprType = arg.GetNodeType(); argValue = arg.GetNodeValue(); } // Get the argument type. IChelaType argType = prototype.GetArgument(index); // Check for reference value. Variable argValueVar = argValue as Variable; bool refValue = argValueVar != null && argValueVar.IsTemporalReferencedSlot(); // Reference argument requires exact match. bool cantMatch = false; bool refArg = false; if(argType.IsReference()) { IChelaType referencedArg = DeReferenceType(argType); // Check for reference argument. if(!referencedArg.IsPassedByReference() || referencedArg.IsReference()) { refArg = true; if(!argExprType.IsReference() || argValueVar == null || !refValue) { cantMatch = true; } else if(argType != argExprType) { // Extract the expression base type. IChelaType exprValueType = DeReferenceType(argExprType); exprValueType = DeConstType(exprValueType); // Check for some type equivalences. IChelaType argValueType = referencedArg; // Check for out-ref differences. if(exprValueType == argValueType) { // Out-ref difference, so don't match. cantMatch = true; } else { // Check primitive-associated pairs. if(!exprValueType.IsFirstClass() || argValueType != currentModule.GetAssociatedClass(exprValueType)) { if(!argValueType.IsFirstClass() || exprValueType != currentModule.GetAssociatedClass(argValueType)) cantMatch = true; } } } } else if(refValue) { // Ignore not references candidates when the argument is a reference. cantMatch = true; } } else if(refValue) { // Ignore not references candidates when the argument is a reference. cantMatch = true; } // Check coercion. if(argExprType != argType || cantMatch) { int argCoercions = 0; IChelaType coercedArgument = null; // Perform coercion. if(!cantMatch) { if(argType.IsGenericType() && !argType.IsGenericImplicit() && genericArguments == null) { // Perform generic coercion. coercedArgument = GenericCoercion(arg, argType, argExprType, genProto, genericArgumentsMatched, out argCoercions); } else { // Perform ordinary coercion. if(refArg) coercedArgument = RefCoerceCounted(arg, argType, argExprType, argValue, out argCoercions); else coercedArgument = CoerceCounted(arg, argType, argExprType, argValue, out argCoercions); } } // Check for coercion success. if(cantMatch || coercedArgument != argType) { // Print early error message. if(numfunctions == 1 && !forgive) Error(node, "cannot implicitly cast argument {0} from {1} to {2}.{3}", i+1, argExprType.GetDisplayName(), argType.GetDisplayName(), cantMatch ? " Must use ref/out operator." : null); match = false; break; } else coercions += argCoercions; } // Check the next argument. index++; } // Ignore not matching candidates. if(!match) continue; // Has at least one match. if(bestMatches.Count == 0) { bestMatches.Add(function); bestCoercions = coercions; continue; } // Prefer the candidates with less coercions. if(coercions < bestCoercions || bestCoercions < 0) { bestMatches.Clear(); bestMatches.Add(function); bestCoercions = coercions; } else if(coercions == bestCoercions) { bestMatches.Add(function); } } // Only one function can be the match. if(bestMatches.Count == 0 && !forgive) { string error = "cannot find a matching function for '" + fgroup.GetName() + "'"; if(fgroup.GetFunctionCount() > 1) error += "\ncandidates are:"; else error += " the option is:"; foreach(FunctionGroupName gname in fgroup.GetFunctions()) { Function function = gname.GetFunction(); FunctionType functionType = function.GetFunctionType(); if(nonKernelContext && function.IsKernel() && function.EntryPoint != null) functionType = function.EntryPoint.GetFunctionType(); error += "\n\t" + functionType.GetDisplayName(); } Error(node, error); } else if(bestMatches.Count > 1) { string error = "ambiguous matches for '" + fgroup.GetName() + "'\n" + "candidates are:"; foreach(Function candidate in bestMatches) { error += "\n\t" + candidate.GetFunctionType().GetName(); } Error(node, error); } // Get the selected function. Function matched = null; if(bestMatches.Count != 0) { matched = (Function)bestMatches[0]; // Prevent ambiguity. matched.CheckAmbiguity(node.GetPosition()); // Perform coercion again, required by delegates. FunctionType prototype = matched.GetFunctionType(); int index = startIndex; for(int i = 0; i < arguments.Count; ++i) { // Get the argument type. object argObject = arguments[i]; if(argObject is IChelaType) continue; // Read the argument data. AstNode arg = (AstNode)argObject; IChelaType argExprType = arg.GetNodeType(); object argValue = arg.GetNodeValue(); // Perform the coercion again. IChelaType argType = prototype.GetArgument(index); if(argExprType != argType) { int argCoercions = 0; CoerceCounted(arg, argType, argExprType, argValue, out argCoercions); } // Coerce the next argument. index++; } } // Return the matched function. return matched; }