示例#1
0
        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);
            }
        }