public static Lambda CompileFunction(FunctionDefinition function) { List <Variable> specialMappedTypes = GetSpecialMappedVariables(); IEnumerable <NameExpression> freeVars = function .Walk() .ToList() .MatchWith(specialMappedTypes); if (freeVars.Count() > 0) { // TODO throw new NotImplementedException("Compiling functions with free variables"); } // Binding is needed for the function to know what sort of a stack size // is needed by the body, but isn't needed for our purposes here function.Bind(new Binder()); GlobalContext context = new GlobalContext(); InternalLambda functionLambda = new InternalLambda { closures = new Closure[0], description = function.CompileInner(), context = context }; // TODO: does the context need the function itself? return(functionLambda); }
public int Execute(Frame frame) { InternalLambda[] lambdas = new InternalLambda[descriptions.Length]; for (int i = 0; i < lambdas.Length; i++) { lambdas[i] = new InternalLambda { closures = frame.closures, context = frame.global, description = descriptions[i] }; } frame.result = RuntimeUtil.CanonicalizeLambdas(lambdas); return 1; }
internal static object Run(InternalLambda lambda, GlobalContext context, object[] args) { Stack <Frame> frames = new Stack <Frame>(); Frame currentFrame = new Frame(context, lambda); frames.Push(currentFrame); // TODO: Are the args guaranteed to the be the // first variables on the stack? for (int i = 0; i < args.Length; i++) { currentFrame.stack[i] = args[i]; } while (frames.Count > 0) { // This returns the result of an InternalCallInstruction frames.Peek().result = currentFrame.result; currentFrame = frames.Pop(); // If returning from a function, we should continue from // where we last ran int i = currentFrame.returnAddress; while (!currentFrame.shouldExit) { i += currentFrame.instructions[i].Execute(currentFrame); if (currentFrame.shouldCall) { // Assume that the instruction correctly outputs a // frame into the result; we will overwrite it on // return frames.Push(currentFrame); currentFrame.returnAddress = i; currentFrame.shouldCall = false; i = 0; currentFrame = currentFrame.result as Frame; } } } return(lambda.ReturnType == RedwoodType.Void ? null : currentFrame.result); }
public static async Task <GlobalContext> CompileModule( TopLevel toplevel, IResourceProvider resources) { // We may have some Dictionary <string, TopLevel> modules = new Dictionary <string, TopLevel>(); modules[toplevel.ModuleName] = toplevel; List <Variable> specialMappedTypeVariables = GetSpecialMappedVariables(); // If it has a dotwalk, it must be an import prefix List <ImportDetails> imports = toplevel .Walk() .ToList() .MatchWith(specialMappedTypeVariables) .Select((NameExpression ne) => new ImportDetails(toplevel.ModuleName, ne)) .ToList(); for (int i = 0; i < imports.Count; i++) { // Allow people to compile modules standalone without a // compiler, but don't let them compile if there are // unresolved modules if (resources == null) { throw new NotImplementedException(); } // If we haven't already got the module, then we // will have to go parse it ourselves if (!modules.ContainsKey(imports[i].From)) { // TODO: Other ways of caching modules? if (!resources.TryGetResource(imports[i].From, out Stream stream)) { throw new NotImplementedException(); } StreamReader sr = new StreamReader(stream); TopLevel tl = await new Parser(sr).ParseModule(imports[i].From); imports.AddRange( tl.Walk() .ToList() .MatchWith(specialMappedTypeVariables) .Select((NameExpression ne) => new ImportDetails(imports[i].To, ne)) ); modules[imports[i].From] = tl; } Variable variable = modules[imports[i].From] .DeclaredVariables .FirstOrDefault(variable => variable.Name == imports[i].Name); if (variable == null) { throw new NotImplementedException(); } imports[i].Variable = variable; } // We need to bind twice in order to determine some of // the types, such as for a method in a class first, // then bind again for its usage foreach (TopLevel module in modules.Values) { module.Bind(new Binder()); } if (toplevel.ModuleName == null) { toplevel.Bind(new Binder()); } foreach (TopLevel module in modules.Values) { module.Bind(new Binder()); } if (toplevel.ModuleName == null) { toplevel.Bind(new Binder()); } Dictionary <string, GlobalContext> contexts = new Dictionary <string, GlobalContext>(); foreach (TopLevel module in modules.Values) { contexts[module.ModuleName] = BuildContext(module); } // TODO: what if someone tries to import an import? foreach (ImportDetails import in imports) { contexts[import.To].AssignVariable( import.NameExpression.Variable.Name, contexts[import.From].LookupVariable(import.Name) ); } return(contexts[toplevel.ModuleName]); GlobalContext BuildContext(TopLevel toplevel) { GlobalContext context = new GlobalContext(); InternalLambda initializationLambda = new InternalLambda { closures = new Closure[0], description = new InternalLambdaDescription { argTypes = new RedwoodType[0], // All fields should go the global definition, but some // temporary variables may be used to define constructors stackSize = toplevel.StackSize, closureSize = 0, instructions = toplevel.Compile().ToArray(), returnType = null }, context = context }; // Populate the global context initializationLambda.Run(); return(context); } }
internal static object Run(InternalLambda lambda) { return(Run(lambda, lambda.context)); }
internal static object Run(InternalLambda lambda, GlobalContext context) { return(Run(lambda, context, new object[0])); }
internal static object Run(InternalLambda lambda, object[] args) { return(Run(lambda, lambda.context, args)); }