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(); }
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; }