Esempio n. 1
0
        public override AstNode Visit(ReturnStatement node)
        {
            // Begin the node.
            builder.BeginNode(node);

            // Get the return value expression
            Expression expr = node.GetExpression();
            IChelaType coercionType = node.GetCoercionType();
            if(expr != null)
            {
                // Visit the expression.
                expr.Accept(this);

                // Get the expression type.
                object exprValue = expr.GetNodeValue();
                IChelaType exprType = expr.GetNodeType();

                // Perform coercion.
                if(exprType != coercionType)
                    Cast(node, exprValue, exprType, coercionType);
            }

            // Compute the return block.
            BasicBlock returnBlock = null;
            if(currentFunction.ReturnBlock != null)
            {
                ExceptionContext context = currentExceptionContext;
                while(context != null)
                {
                    returnBlock = context.GetCleanup();
                    if(returnBlock != null)
                        break;
                    context = context.GetParentContext();
                }

                if(returnBlock == null)
                    returnBlock = currentFunction.ReturnBlock;
            }

            // Perform yielding.
            if(node.IsYield)
            {
                // Get the generator data.
                FunctionDefinition defNode = currentFunction.DefinitionNode;

                // Store the yielded value.
                builder.CreateLoadArg(0);
                builder.CreatePush(1);
                builder.CreateStoreField(defNode.YieldedValue);
                builder.CreatePop();

                // Store the new state.
                builder.CreateLoadArg(0);
                builder.CreateLoadInt32(node.YieldState);
                builder.CreateStoreField(defNode.GeneratorState);

                // Return the yielded value.
                builder.CreateLoadBool(true);
                builder.CreateRet();

                // Create the merge block.
                BasicBlock mergeBlock = CreateBasicBlock();
                mergeBlock.SetName("merge");
                builder.SetBlock(mergeBlock);

                // Store the merge and dispose blocks.
                node.MergeBlock = mergeBlock;
                node.DisposeBlock = returnBlock;
                return builder.EndNode();
            }

            // Return the value.
            bool isVoid = coercionType == ChelaType.GetVoidType();
            if(currentFunction.ReturnBlock != null)
            {
                // Store the return value.
                if(!isVoid)
                    builder.CreateStoreLocal(currentFunction.ReturnValueVar);

                // Store the returning flag.
                builder.CreateLoadBool(true);
                builder.CreateStoreLocal(currentFunction.ReturningVar);

                // Perform delayed returning.
                builder.CreateJmp(returnBlock);
            }
            else
            {
                if(isVoid)
                    builder.CreateRetVoid();
                else
                    builder.CreateRet();
            }

            return builder.EndNode();
        }
Esempio n. 2
0
        public override AstNode Visit(ReturnStatement node)
        {
            Expression expr = node.GetExpression();

            // Visit the expression.
            if(expr != null)
                expr.Accept(this);

            // Get the expression type
            IChelaType exprType = expr != null ? expr.GetNodeType() : ChelaType.GetVoidType();

            // Get the function return type.
            FunctionType functionType = currentFunction.GetFunctionType();
            IChelaType returnType = functionType.GetReturnType();

            // Load the function definition node
            FunctionDefinition functionNode = currentFunction.DefinitionNode;

            // Use the yield type if writin a generator.
            if(node.IsYield)
            {
                // Make sure its a generateable function.
                if(functionNode == null)
                    Error(node, "only can create generators in function definitions.");

                // Don't allow yielding and returning and the same time.
                if(functionNode.HasReturns)
                    Error(node, "cannot mix return and generator style yield return in a same function.");

                // Convert the function into a generator.
                if(!functionNode.IsGenerator)
                    MakeCurrentGenerator(node);

                // Store myself in the interruption point table.
                functionNode.Yields.Add(node);

                // Use the yield type as return type.
                returnType = functionNode.YieldType;

            }
            else if(functionNode != null)
            {
                // Don't allow plain returning in not generators.
                if(functionNode.IsGenerator)
                    Error(node, "cannot perform plain return in a generator function.");

                // Prevent mixing a generator.
                functionNode.HasReturns = true;
            }

            // Check for coercion validity.
            if(exprType != returnType)
            {
                IChelaType coercionType = Coerce(node, returnType, exprType, expr.GetNodeValue());
                //System.Console.WriteLine("{0}->{1}={2}", exprType, coercionType, returnType);
                //System.Console.WriteLine("{0} == {1}", coercionType, returnType);
                if(coercionType != returnType)
                    Error(node, "cannot implicitly cast return type '{0}' into '{1}'",
                        exprType.GetDisplayName(), returnType.GetDisplayName());
            }

            // Set the coercion type.
            node.SetCoercionType(returnType);

            // Check for dead code.
            AstNode deadCode = node.GetNext();
            if(!node.IsYield && deadCode != null)
            {
                // Write a warning.
                Warning(node, "the code after a return is unreachable.");

                // Process the dead code for error.
                VisitList(deadCode);

                // Delete the dead code.
                node.SetNext(null);
            }

            return node;
        }