public override AstNode Visit(FunctionDefinition node)
        {
            // Visit the prototype.
            node.GetPrototype().Accept(this);

            return node;
        }
Beispiel #2
0
        private void DefineGeneratorBody(FunctionDefinition node)
        {
            // Get entry function.
            Function entryFunction = node.GetFunction();

            // Rebase his locals.
            entryFunction.RebaseLocals();

            // Create the generator class.
            Scope spaceScope = entryFunction.GetParentScope();
            Class generatorClass =
                new Class(GenSym(), MemberFlags.Internal, spaceScope);
            node.GeneratorClass = generatorClass;

            // Use the same generic prototype as the entry point function.
            generatorClass.SetGenericPrototype(entryFunction.GetGenericPrototype());

            // Add the generator class to the same scope as the function.
            if(spaceScope.IsClass() || spaceScope.IsStructure())
            {
                Structure parentClass = (Structure)spaceScope;
                parentClass.AddType(generatorClass);
            }
            else if(spaceScope.IsNamespace())
            {
                Namespace parentSpace = (Namespace)spaceScope;
                parentSpace.AddMember(generatorClass);
            }
            else
            {
                Error(node, "Cannot create generator class in {0}", spaceScope.GetFullName());
            }

            // Add the enumerable interface.
            Structure enumerableIface = null;
            if(node.IsEnumerable)
            {
                enumerableIface = currentModule.GetEnumerableIface();
                if(node.IsGenericIterator)
                {
                    enumerableIface = currentModule.GetEnumerableGIface();
                    GenericInstance gargs = new GenericInstance(enumerableIface.GetGenericPrototype(),
                        new IChelaType[]{node.YieldType});
                    enumerableIface = (Structure)enumerableIface.InstanceGeneric(gargs, currentModule);
                }

                generatorClass.AddInterface(enumerableIface);
            }

            // Add the enumerator interface.
            Structure enumeratorIface = currentModule.GetEnumeratorIface();
            if(node.IsGenericIterator)
            {
                enumeratorIface = currentModule.GetEnumeratorGIface();
                GenericInstance gargs = new GenericInstance(enumeratorIface.GetGenericPrototype(),
                    new IChelaType[]{node.YieldType});
                enumeratorIface = (Structure)enumeratorIface.InstanceGeneric(gargs, currentModule);
            }
            generatorClass.AddInterface(enumeratorIface);

            // Create the yielded field.
            FieldVariable yieldedValue = new FieldVariable("yielded", MemberFlags.Private, node.YieldType, generatorClass);
            generatorClass.AddField(yieldedValue);
            node.YieldedValue = yieldedValue;

            // Create the generator state variable.
            FieldVariable generatorState = new FieldVariable("state", MemberFlags.Private, ChelaType.GetIntType(), generatorClass);
            generatorClass.AddField(generatorState);
            node.GeneratorState = generatorState;

            // Encapsulate the locals in fields.
            foreach(LocalVariable local in entryFunction.GetLocals())
            {
                if(!local.IsPseudoLocal)
                    continue;

                // Variables containing arguments must be public.
                MemberFlags access = MemberFlags.Private;
                if(local.ArgumentIndex >= 0)
                    access = MemberFlags.Public;

                // Create the field to hold the state.
                FieldVariable localField = new FieldVariable(GenSym(), access, local.GetVariableType(), generatorClass);
                generatorClass.AddField(localField);
                local.ActualVariable = localField;
            }

            // Create an instance of the generator class.
            Structure generatorClassInstance = generatorClass.GetClassInstance();
            if(generatorClass.GetGenericPrototype().GetPlaceHolderCount() != 0)
            {
                // Create an instance using the same placeholders.
                GenericPrototype proto = generatorClass.GetGenericPrototype();
                int numargs = proto.GetPlaceHolderCount();
                IChelaType[] protoInstance = new IChelaType[numargs];
                for(int i = 0; i < numargs; ++i)
                    protoInstance[i] = proto.GetPlaceHolder(i);

                // Instance the generic class.
                GenericInstance instance = new GenericInstance(proto, protoInstance);
                generatorClassInstance = (Structure)generatorClassInstance.InstanceGeneric(instance, currentModule);
            }
            node.GeneratorClassInstance = generatorClassInstance;

            // Create the trivial constructor.
            Function ctor = CreateTrivialConstructor(generatorClass, generatorClassInstance);
            if(generatorClass.IsGeneric())
                ctor = FindFirstConstructor(generatorClassInstance);

            // Create a local to hold the created closure.
            LexicalScope topScope = (LexicalScope)node.GetScope();
            LocalVariable closureLocal = new LocalVariable("closure", topScope, ReferenceType.Create(generatorClassInstance));

            // Create the entry point content.
            BasicBlock entryBlock = CreateBasicBlock();
            entryBlock.SetName("entry");
            builder.SetBlock(entryBlock);

            // Create the closure and store it in his local.
            builder.CreateNewObject(generatorClassInstance, ctor, 0);
            builder.CreateStoreLocal(closureLocal);

            // Load the closure.
            builder.CreateLoadLocal(closureLocal);

            // Store the arguments into the closure.
            FunctionPrototype prototype = node.GetPrototype();
            AstNode argument = prototype.GetArguments();
            byte index = 0;
            while(argument != null)
            {
                FunctionArgument argNode = (FunctionArgument) argument;

                // TODO: Forbid ref, out, stream arguments here.

                // Store the argument in the closure.
                LocalVariable argVar = argNode.GetVariable();
                if(argVar != null)
                {
                    // Load the closure
                    builder.CreateDup1();

                    // Load the argument.
                    builder.CreateLoadArg(index);

                    // Store it into the field.
                    builder.CreateStoreField((FieldVariable)argVar.ActualVariable);
                }

                // Process the next argument.
                argument = argument.GetNext();
                index++;
            }

            // Encapsulate the argument variables.
            foreach(ArgumentVariable argVar in node.ArgumentVariables)
            {
                if(!argVar.IsPseudoArgument)
                    continue;

                // Create the argument field.
                FieldVariable argField = new FieldVariable(GenSym(), MemberFlags.Public, argVar.GetVariableType(), generatorClass);
                generatorClass.AddField(argField);
                argVar.ActualVariable = argField;

                // Store the self field.
                if(!currentFunction.IsStatic() && argVar.GetArgumentIndex() == 0)
                    node.GeneratorSelf = argField;

                // Load the closure.
                builder.CreateDup1();

                // Load the argument.
                builder.CreateLoadArg((byte)argVar.GetArgumentIndex());

                // Store it into the closure.
                builder.CreateStoreField(argField);
            }

            // Return the generator.
            builder.CreateRet();

            // Notify the yields about their states.
            int stateIndex = 2;
            foreach(ReturnStatement yieldStmtn in node.Yields)
            {
                yieldStmtn.YieldState = stateIndex;
                stateIndex += 2;
            }

            // Implement IEnumerator.
            if(node.IsEnumerable)
            {
                // Create the object GetEnumerator method.
                CreateGenerator_GetEnumerator(node, currentModule.GetEnumeratorIface(), false);

                // Create the generic GetEnumerator method
                if(node.IsGenericIterator)
                    CreateGenerator_GetEnumerator(node, enumeratorIface, true);
            }

            // Create the Current property.
            CreateGenerator_Current(node, false);
            if(node.IsGenericIterator)
                CreateGenerator_Current(node, true);

            // Create the Reset method.
            CreateGenerator_Reset(node);

            // Create the MoveNext method.
            Function moveNext = CreateGenerator_MoveNext(node);

            // Create the Dispose method.
            CreateGenerator_Dispose(node, moveNext);

            // Fix the inheritance.
            generatorClass.FixInheritance();
        }
Beispiel #3
0
        private void DefineFunctionBody(FunctionDefinition node, Function function, LexicalScope topScope)
        {
            // Create the top basic block.
            BasicBlock topBlock = CreateBasicBlock();
            topBlock.SetName("top");
            builder.SetBlock(topBlock);

            // Prepare returning.
            PrepareReturning(node, function, topScope);

            // Store the arguments into local variables.
            FunctionPrototype prototype = node.GetPrototype();
            AstNode argument = prototype.GetArguments();
            byte index = 0;
            while(argument != null)
            {
                FunctionArgument argNode = (FunctionArgument) argument;
                LocalVariable argVar = argNode.GetVariable();
                if(argVar != null && !argVar.IsPseudoScope())
                {
                    // Load the argument.
                    builder.CreateLoadArg(index);

                    // Store it into the local.
                    builder.CreateStoreLocal(argVar);
                }

                // Process the next argument.
                argument = argument.GetNext();
                index++;
            }

            // Generate constructor initialization.
            if(function.IsConstructor())
            {
                Method ctor = (Method)function;
                ConstructorInitializer ctorInit = prototype.GetConstructorInitializer();
                if(ctorInit != null)
                    ctorInit.Accept(this);
                else
                    CreateImplicitBaseConstructor(node, ctor);

                // Initialize some field.
                if(ctor.IsCtorLeaf())
                {
                    Structure building = (Structure)ctor.GetParentScope();
                    GenerateFieldInitializations(node, building);
                }
            }
            else if(function.IsStaticConstructor())
            {
                // Generate static field initialization.
                Scope parent = function.GetParentScope();
                Structure pbuilding = parent as Structure;
                if(pbuilding != null)
                    GenerateStaticFieldInitializations(node, function, pbuilding);
            }

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

            // Finish return.
            FinishReturn(node, function);
        }
Beispiel #4
0
        public override AstNode Visit(FunctionDefinition node)
        {
            // Begin the node.
            builder.BeginNode(node);

            // Process attributes.
            ProcessAttributes(node);

            // Get the prototype.
            FunctionPrototype prototype = node.GetPrototype();

            // Get the function.
            Function function = prototype.GetFunction();

            // Ignore functions without a body.
            if(node.GetChildren() == null)
                return builder.EndNode();

            // Store the old function.
            // TODO: Add closures
            Function oldFunction = currentFunction;
            currentFunction = function;

            // Update the securiry.
            if(function.IsUnsafe())
                PushUnsafe();

            // Get the function lexical scope.
            LexicalScope topScope = (LexicalScope)node.GetScope();

            // Update the scope.
            PushScope(topScope);

            // Define the generator or function body
            if(node.IsGenerator)
                DefineGeneratorBody(node);
            else
                DefineFunctionBody(node, function, topScope);

            // Restore the scope.
            PopScope();

            // Restore the security.
            if(function.IsUnsafe())
                PopUnsafe();

            // Restore the current function.
            currentFunction = oldFunction;

            return builder.EndNode();
        }
        public override AstNode Visit(FunctionDefinition node)
        {
            // Get the prototype.
            FunctionPrototype prototype = node.GetPrototype();

            // Visit the prototype.
            prototype.Accept(this);

            // Set the node type.
            node.SetNodeType(prototype.GetNodeType());

            // Get and link the function with the definition.
            Function function = prototype.GetFunction();
            node.SetFunction(function);

            // Create finalizers as macros.
            AstNode children = node.GetChildren();
            if(prototype.GetDestructorName() != null && children != null)
            {
                TokenPosition position = node.GetPosition();
                // Get the base finalizer.
                Expression baseFinalizer = new MemberAccess(new BaseExpression(position), "Finalize", position);

                // Invoke it.
                AstNode baseInvoke = new CallExpression(baseFinalizer, null, position);
                FinallyStatement finalStmnt = new FinallyStatement(baseInvoke, position);

                // Try the finalizer, always invoke the parent finalizer.
                TryStatement tryStmnt = new TryStatement(children, null, finalStmnt, position);
                node.SetChildren(tryStmnt);
            }

            return node;
        }
Beispiel #6
0
        public override AstNode Visit(FunctionDefinition node)
        {
            // Process attributes.
            ProcessAttributes(node);

            // Get the prototype.
            FunctionPrototype prototype = node.GetPrototype();

            // Get the function.
            Function function = prototype.GetFunction();

            // Store the definition node in the function.
            if(function.DefinitionNode != null)
                Error(node, "multiples definition of a function.");
            function.DefinitionNode = node;

            // Check for declarations, interfaces.
            MemberFlags instanceFlags = function.GetFlags() & MemberFlags.InstanceMask;
            if(instanceFlags == MemberFlags.Abstract || instanceFlags == MemberFlags.Contract
               || function.IsExternal())
            {
                if(node.GetChildren() != null)
                    Error(node, "abstract/extern functions cannot have a definition body.");
                return node;
            }
            else
            {
                if(node.GetChildren() == null)
                    Error(node, "functions must have a definition.");
            }

            // Store the old function.
            // TODO: Add closures
            Function oldFunction = currentFunction;
            currentFunction = function;

            // Create the function lexical scope.
            LexicalScope topScope = CreateLexicalScope(node);
            node.SetScope(topScope);

            // Use the prototype scope.
            Scope protoScope = prototype.GetScope();
            if(protoScope != null)
                PushScope(protoScope);

            // Update the scope.
            PushScope(topScope);

            // Push the security.
            if(function.IsUnsafe())
                PushUnsafe();

            // Declare the argument variables.
            AstNode argument = prototype.GetArguments();
            int index = 0;
            while(argument != null)
            {
                // Cast the argument node.
                FunctionArgument argNode = (FunctionArgument)argument;

                // Set the argument name.
                string name = argument.GetName();
                ArgumentData argData = function.GetArguments()[index++];
                argData.Name = name;

                // Create the argument variable.
                if(name != null && name != "" && name != "this")
                {
                    // Create the argument local variable
                    LocalVariable argLocal = new LocalVariable(name, topScope, argNode.GetNodeType());
                    argLocal.Type = LocalType.Argument;
                    argLocal.ArgumentIndex = index;

                    // Store it in the argument node.
                    argNode.SetVariable(argLocal);
                }
                else if(name == "this")
                {
                    // Create the this argument.
                    node.ArgumentVariables.Add(
                        new ArgumentVariable(0, "this", topScope, argument.GetNodeType())
                    );
                }

                argument = argument.GetNext();
            }

            // Check the constructor initializer.
            if(function.IsConstructor())
                CheckConstructorInit(node);

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

            // Restore the security.
            if(function.IsUnsafe())
                PopUnsafe();

            // Restore the scope.
            PopScope();

            // Restore the prototype scope.
            if(protoScope != null)
                PopScope();

            // Restore the current function.
            currentFunction = oldFunction;

            return node;
        }
Beispiel #7
0
        private void CheckConstructorInit(FunctionDefinition node)
        {
            // Get the prototype.
            FunctionPrototype prototype = node.GetPrototype();

            // Get the constructor initializer.
            ConstructorInitializer ctorInit = prototype.GetConstructorInitializer();

            // Get the function.
            Method function = (Method)prototype.GetFunction();

            // Special check for the implicit constructor.
            if(ctorInit == null)
            {
                CheckDefaultConstructorInit(node, function);
                return;
            }

            // Get the base constructor.
            Structure building = (Structure)function.GetParentScope();
            FunctionGroup ctorGroup;
            if(ctorInit.IsBaseCall())
            {
                Structure baseBuilding = building.GetBase();
                if(baseBuilding == null)
                    Error(node, "cannot invoke base constructor in Object definition.");

                ctorGroup = baseBuilding.GetConstructor();
            }
            else
            {
                ctorGroup = building.GetConstructor();
            }

            // Store the constructor group.
            ctorInit.SetConstructorGroup(ctorGroup);

            // Visit the constructor initializer
            ctorInit.Accept(this);

            // Set the parent constructor.
            function.SetCtorParent((Method)ctorInit.GetConstructor());

            // Make sure the construction invocation is acyclic.
            if(!function.IsCtorLeaf())
                CheckConstructorCycles(node, function);
        }