private void PrepareReturning(AstNode where, Function function, LexicalScope scope) { // Get the definition node and check for generator. FunctionDefinition defNode = function.DefinitionNode; bool isGenerator = false; if(defNode != null) isGenerator = defNode.IsGenerator; // Use standard return. if(function.GetExceptionContext() == null && !isGenerator) return; // Create the return block. BasicBlock returnBlock = new BasicBlock(function); returnBlock.SetName("retBlock"); function.ReturnBlock = returnBlock; // Create the return value local. FunctionType functionType = function.GetFunctionType(); IChelaType retType = functionType.GetReturnType(); if(retType != ChelaType.GetVoidType() && !isGenerator) function.ReturnValueVar = new LocalVariable(GenSym() + "_retval", scope, retType); // Create the is returning flag. function.ReturningVar = new LocalVariable(GenSym() + "_isret", scope, ChelaType.GetBoolType(), isGenerator); function.ReturningVar.Type = LocalType.Return; // Create the field for generators. if(isGenerator) { FieldVariable returningField = new FieldVariable("returning", MemberFlags.Private, ChelaType.GetBoolType(), defNode.GeneratorClass); defNode.GeneratorClass.AddField(returningField); function.ReturningVar.ActualVariable = returningField; } // Initializer the returning flag to false. builder.CreateLoadBool(false); PerformAssignment(where, function.ReturningVar); }
private void CreateGenerator_GetEnumerator(FunctionDefinition node, Structure enumeratorType, bool generic) { // Get the generator class. Class genClass = node.GeneratorClass; // Use the GetEnumerator name for the most specific version. string name = "GetEnumerator"; Function contract = null; if(!generic && node.IsGenericIterator) { name = GenSym(); contract = FindFirstConstract(currentModule.GetEnumerableIface(), "GetEnumerator"); } // Create the function type. FunctionType functionType = FunctionType.Create(ReferenceType.Create(enumeratorType), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method(name, MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction(name, method); // Set the explicit contract. if(contract != null) method.SetExplicitContract(contract); // Create the method block. BasicBlock block = new BasicBlock(method); block.SetName("top"); // Return this. builder.SetBlock(block); builder.CreateLoadArg(0); builder.CreateRet(); }
private Method CreateTrivialConstructor(Structure building, Structure buildingInstance) { // Create the constructor function type. FunctionType type = FunctionType.Create(ChelaType.GetVoidType(), new IChelaType[]{ReferenceType.Create(buildingInstance)}, false); // Create the constructor. Method ctor = new Method(".ctor", MemberFlags.Public | MemberFlags.Constructor, building); ctor.SetFunctionType(type); building.AddFunction(".ctor", ctor); // Create the constructor block. BasicBlock top = new BasicBlock(ctor); top.SetName("top"); top.Append(new Instruction(OpCode.RetVoid, null)); return ctor; }
private void CreateGenerator_Current(FunctionDefinition node, bool generic) { // Get the generator class. Class genClass = node.GeneratorClass; // Use the get_Current name for the most specific version. string name = "get_Current"; Function contract = null; if(!generic && node.IsGenericIterator) { name = GenSym(); contract = FindFirstConstract(currentModule.GetEnumeratorIface(), "get_Current"); } // Select the current type. IChelaType currentType = node.YieldType; if(!generic) currentType = ReferenceType.Create(currentModule.GetObjectClass()); // Create the function type. FunctionType functionType = FunctionType.Create(currentType, new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method(name, MemberFlags.Public, genClass); method.SetFunctionType(functionType); genClass.AddFunction(name, method); // Set the explicit contract. if(contract != null) method.SetExplicitContract(contract); // Create the method block. BasicBlock block = new BasicBlock(method); block.SetName("top"); // Create the return and error blocks. BasicBlock retBlock = new BasicBlock(method); retBlock.SetName("ret"); BasicBlock errorBlock = new BasicBlock(method); errorBlock.SetName("error"); // Make sure reset was called before the first Current. builder.SetBlock(block); builder.CreateLoadArg(0); builder.CreateLoadField(node.GeneratorState); builder.CreateLoadInt32(0); builder.CreateCmpEQ(); builder.CreateBr(errorBlock, retBlock); // Raise an error if reset wasn't called. builder.SetBlock(errorBlock); Class excpt = (Class)ExtractClass(node, currentModule.GetLangMember("InvalidOperationException")); builder.CreateLoadString("IEnumerator.MoveNext must be called before than IEnumerator.Current."); builder.CreateNewObject(excpt, GetExceptionCtor(node, excpt), 1); builder.CreateThrow(); // Load the yielded value. builder.SetBlock(retBlock); builder.CreateLoadArg(0); builder.CreateLoadField(node.YieldedValue); // Cast the yielded value. Cast(node, null, node.YieldType, currentType); // Return. builder.CreateRet(); }