public override AstNode Visit(FunctionPrototype node) { // Get the name expression. Expression nameExpression = node.GetNameExpression(); if(nameExpression == null) return node; // Visit the name expression. nameExpression.SetHints(Expression.MemberHint); nameExpression.Accept(this); // Get the function and his type. Function function = node.GetFunction(); FunctionType functionType = function.GetFunctionType(); if(!function.IsMethod()) Error(node, "expected a method prototype."); Method method = (Method)function; // It must be a function selector. IChelaType nameType = nameExpression.GetNodeType(); if(!nameType.IsFunctionGroup()) Error(nameExpression, "expected a function group."); FunctionGroupSelector selector = (FunctionGroupSelector)nameExpression.GetNodeValue(); FunctionGroup group = selector.GetFunctionGroup(); // Find a matching function in the group. Function match = null; foreach(FunctionGroupName gname in group.GetFunctions()) { // Ignore static functions. if(gname.IsStatic()) continue; // Check for match. FunctionType candidate = gname.GetFunctionType(); // Found a match?. if(MatchFunction(candidate, functionType, 1)) { match = (Function)gname.GetFunction(); break; } } // Raise an error. if(match == null) Error(nameExpression, "couldn't find matching interface member for {0}", functionType.GetName()); // TODO: Rename the method. // Bind the contract. method.SetExplicitContract(match); return node; }
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; }