public override AstNode Visit(FunctionDefinition node) { // Process attributes. ProcessAttributes(node); // Ignore pure declarations. if(node.GetChildren() == null) return node; // Update the scope. PushScope(node.GetScope()); // Visit the children. VisitList(node.GetChildren()); // Restore the scope. PopScope(); return node; }
private Function CreateGenerator_MoveNext(FunctionDefinition node) { // Get the generator class. Class genClass = node.GeneratorClass; // Create the function type. FunctionType functionType = FunctionType.Create(ChelaType.GetBoolType(), new IChelaType[]{ReferenceType.Create(node.GeneratorClassInstance)}, false); // Create the method. Method method = new Method("MoveNext", MemberFlags.Public, genClass); method.SetFunctionType(functionType); method.DefinitionNode = node; genClass.AddFunction("MoveNext", method); // Swap the exception contexts. method.SwapExceptionContexts(currentFunction); // Store the old function. Function oldFunction = currentFunction; currentFunction = method; // Create the jump table block. BasicBlock jmpBlock = CreateBasicBlock(); jmpBlock.SetName("jmp"); // Generate the main code. BasicBlock topBlock = CreateBasicBlock(); topBlock.SetName("top"); builder.SetBlock(topBlock); // Prepare returning. LexicalScope topScope = (LexicalScope) node.GetScope(); PrepareReturning(node, currentFunction, topScope); // Create the function body. VisitList(node.GetChildren()); // Finish returning. FinishReturn(node, currentFunction); // Create the state jump table. builder.SetBlock(jmpBlock); // Load the current state. builder.CreateLoadArg(0); builder.CreateLoadField(node.GeneratorState); // Build the jump table. int numstates = node.Yields.Count*2+3; int[] stateConstants = new int[numstates]; BasicBlock[] stateEntries = new BasicBlock[numstates]; // The default case is return. stateConstants[0] = -1; stateEntries[0] = currentFunction.ReturnBlock; // The first state is the top block. stateConstants[1] = 0; stateEntries[1] = topBlock; // The second state is the return block. stateConstants[2] = 1; stateEntries[2] = currentFunction.ReturnBlock; // The next states are the yield merges followed by yield disposes. for(int i = 0; i < node.Yields.Count; ++i) { ReturnStatement yieldStmnt = node.Yields[i]; // Emit the merge state. int stateId = i*2+2; int entryIndex = stateId+1; stateConstants[entryIndex] = stateId; stateEntries[entryIndex] = yieldStmnt.MergeBlock; // Emit the dispose state. stateConstants[entryIndex+1] = stateId+1; stateEntries[entryIndex+1] = yieldStmnt.DisposeBlock; } builder.CreateSwitch(stateConstants, stateEntries); // Restore the old function. currentFunction = oldFunction; return method; }
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(); }
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(); }