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;
        }
Exemple #2
0
        public override AstNode Visit(ForEachStatement node)
        {
            // Create the foreach lexical scope.
            LexicalScope scope = CreateLexicalScope(node);
            node.SetScope(scope);

            // Push the lexical scope.
            PushScope(scope);

            // Get the element type expression.
            Expression typeExpr = node.GetTypeExpression();

            // Visit the container expression.
            Expression containerExpr = node.GetContainerExpression();
            containerExpr.Accept(this);

            // Get the container expression type.
            IChelaType containerType = containerExpr.GetNodeType();
            if(!containerType.IsReference())
                Error(containerExpr, "expected an object reference.");

            // Remove type references.
            containerType = DeReferenceType(containerType);
            if(containerType.IsReference())
                containerType = DeReferenceType(containerType);

            // Use primitives associated types.
            if(!containerType.IsStructure() && !containerType.IsClass() && !containerType.IsInterface())
            {
                IChelaType assoc = currentModule.GetAssociatedClass(containerType);
                if(assoc == null)
                    Error(containerExpr, "cannot iterate a container of type {0}", assoc.GetFullName());
                containerType = assoc;
            }

            // Get the GetEnumerator method group.
            Structure building = (Structure)containerType;
            FunctionGroup getEnumeratorGroup = building.FindMemberRecursive("GetEnumerator") as FunctionGroup;
            if(getEnumeratorGroup == null)
                Error(containerExpr, "cannot find GetEnumerator method in {0}", containerType.GetName());

            // Use the first no static member.
            Function getEnumeratorFunction = null;
            foreach(FunctionGroupName gname in getEnumeratorGroup.GetFunctions())
            {
                // Ignore static functions.
                if(gname.IsStatic())
                    continue;

                // Only one argument is supported.
                if(gname.GetFunctionType().GetArgumentCount() == 1)
                {
                    getEnumeratorFunction = gname.GetFunction();
                    break;
                }
            }

            // Make sure the function was found.
            if(getEnumeratorFunction == null)
                Error(containerExpr, "{0} doesn't have a no static GetEnumerator() method.", containerType.GetName());

            // Get the enumerator type.
            TokenPosition position = node.GetPosition();
            TypeNode enumeratorTypeNode = new TypeNode(TypeKind.Other, position);
            enumeratorTypeNode.SetOtherType(getEnumeratorFunction.GetFunctionType().GetReturnType());

            // Get the numerator.
            Expression enumeratorExpr = new CallExpression(
                new MemberAccess(node.GetContainerExpression(), "GetEnumerator", position),
                null, position);

            // Create a variable for the enumerator.
            string enumeratorName = GenSym();
            LocalVariablesDeclaration declEnum = new LocalVariablesDeclaration(enumeratorTypeNode,
                    new VariableDeclaration(enumeratorName, enumeratorExpr, position), position);

            // Create a variable for the current object.
            LocalVariablesDeclaration currentDecl =
                new LocalVariablesDeclaration(node.GetTypeExpression(),
                    new VariableDeclaration(node.GetName(), null, position), position);
            declEnum.SetNext(currentDecl);

            // Get the current member.
            Expression currentProp = new MemberAccess(new VariableReference(enumeratorName, position),
                    "Current", position);

            // Create the while job.
            AstNode whileJob = new ExpressionStatement(
                new AssignmentExpression(new VariableReference(node.GetName(), position),
                    new CastOperation(typeExpr, currentProp, position), position),
                position);
            whileJob.SetNext(node.GetChildren());

            // Create the loop with MoveNext condition.
            Expression moveNext = new CallExpression(
                new MemberAccess(new VariableReference(enumeratorName, position), "MoveNext", position),
                null, position);
            WhileStatement whileStmnt = new WhileStatement(moveNext, whileJob, position);
            currentDecl.SetNext(whileStmnt);

            // Change my children.
            node.SetChildren(declEnum);

            // Visit my children.
            VisitList(node.GetChildren());

            // Restore the scope.
            PopScope();

            return node;
        }
        public override AstNode Visit(EnumDefinition node)
        {
            // Push the scope.
            PushScope(node.GetScope());

            // Use a default type of const int.
            IChelaType baseType = ChelaType.GetIntType();
            IChelaType enumType = ConstantType.Create(baseType);

            // Declare the value field.
            Structure building = node.GetStructure();
            FieldVariable valueField =
                new FieldVariable("m_value", MemberFlags.Public, baseType, building);
            building.AddField(valueField);

            // Used for implicit prev + 1.
            IChelaType enumConst = ConstantType.Create(building);
            TypeNode enumIntExpr = new TypeNode(TypeKind.Other, node.GetPosition());
            enumIntExpr.SetOtherType(enumType);

            // Visit the constant defininitions.
            EnumConstantDefinition prev = null;
            AstNode child = node.GetChildren();
            while(child != null)
            {
                // Cast the child.
                EnumConstantDefinition constDef = (EnumConstantDefinition)child;

                // Set the child type.
                constDef.SetCoercionType(enumType);
                constDef.SetNodeType(enumConst);

                // If there isn't a constant expression, use previous + 1 or 0.
                if(constDef.GetValue() == null)
                {
                    TokenPosition constPos = constDef.GetPosition();
                    if(prev != null)
                    {
                        // Previous + 1
                        Expression prevExpr = new CastOperation(enumIntExpr,
                                                                new VariableReference(prev.GetName(), constPos),
                                                                constPos);
                        Expression implicitVal = new BinaryOperation(BinaryOperation.OpAdd,
                                                                     prevExpr,
                                                                     new ByteConstant(1, constPos),
                                                                     constPos);
                        constDef.SetValue(implicitVal);
                    }
                    else
                    {
                        // First element is 0
                        constDef.SetValue(new ByteConstant(0, constPos));
                    }
                }

                // Visit the constant definition.
                constDef.Accept(this);

                // Process the next constant.
                prev = constDef;
                child = child.GetNext();
            }

            // Restore the scope.
            PopScope();

            return node;
        }
Exemple #4
0
        public override AstNode Visit(LockStatement node)
        {
            // Create the block lexical scope.
            LexicalScope blockScope = CreateLexicalScope(node);
            node.SetScope(blockScope);

            // Push the scope.
            PushScope(blockScope);

            // Visit the mutex expression.
            Expression mutexExpr = node.GetMutexExpression();
            mutexExpr.Accept(this);

            // Make sure its a reference object
            IChelaType mutexType = mutexExpr.GetNodeType();
            if(!mutexType.IsReference())
                Error(mutexExpr, "expected an object expression.");
            mutexType = DeReferenceType(mutexType);

            // Remove the variable layer.
            if(mutexType.IsReference())
                mutexType = DeReferenceType(mutexType);

            // Must be a class or an interface.
            if(!mutexType.IsClass() && !mutexType.IsInterface())
                Error(mutexExpr, "expected a class/interface instance.");

            // Create the mutex local.
            TokenPosition position = node.GetPosition();
            string mutexName = GenSym();
            AstNode decl = new LocalVariablesDeclaration(new TypeNode(TypeKind.Object, position),
                    new VariableDeclaration(mutexName, node.GetMutexExpression(), position),
                        position);

            // Chela.Threading.Monitor variable.
            TypeNode monitor = new TypeNode(TypeKind.Other, position);
            Structure threadingMonitor = (Structure)currentModule.GetThreadingMember("Monitor", true);
            if(threadingMonitor == null)
                Error(node, "couldn't use lock when the runtime doesn't define Chela.Threading.Monitor" );
            monitor.SetOtherType(threadingMonitor);

            // Enter into the mutex.
            AstNode enterMutex = new CallExpression(new MemberAccess(monitor, "Enter", position),
                                    new VariableReference(mutexName, position), position);
            decl.SetNext(enterMutex);

            // Try finally
            AstNode exitMutex = new CallExpression(new MemberAccess(monitor, "Exit", position),
                                    new VariableReference(mutexName, position), position);
            FinallyStatement finallyStmnt = new FinallyStatement(exitMutex, position);

            // Try statement.
            TryStatement tryStmnt = new TryStatement(node.GetChildren(), null, finallyStmnt, position);
            enterMutex.SetNext(tryStmnt);

            // Replace my children.
            node.SetChildren(decl);

            // Visit the block children.
            VisitList(node.GetChildren());

            // Restore the scope.
            PopScope();

            return node;
        }