Пример #1
0
        /// <summary>
        /// Search for function blocks and split them out into their own McFunctions.
        /// </summary>
        public void SplitFunctionBlocks(BuildEnvironment env)
        {
            // Iterate over commands, finding function blocks in the *root level*
            // We then make take those commands into their own McFunction and run this function again on the sub McFunction.
            var functionBlocks = new Dictionary <Argument, Range>();
            int nesting        = 0;
            int i = 0;

            foreach (Command.Command command in Commands)
            {
                Argument arg = command.Arguments.LastOrDefault();
                if (arg == null)
                {
                    continue;
                }

                if (arg.Tokens.FirstOrDefault() is OpenFunctionBlockToken)
                {
                    nesting++;

                    if (nesting > FunctionBlockNestingLimit)
                    {
                        throw new Exception($"Exceeded function block nesting limit of {FunctionBlockNestingLimit}!");
                    }

                    if (nesting == 1)
                    {
                        // Root level function block.
                        functionBlocks.Add(arg, new Range(i, -1));
                    }
                }

                if (arg.Tokens.FirstOrDefault() is CloseFunctionBlockToken)
                {
                    nesting--;

                    if (nesting < 0)
                    {
                        throw new Exception("Unexpected additional function block bracket!");
                    }

                    if (nesting == 0)
                    {
                        // Back to root nesting, close this function block
                        functionBlocks.Last().Value.Maximum = i;
                    }
                }

                i++;
            }

            if (nesting > 0)
            {
                throw new Exception("Unclosed function block!");
            }

            // Move commands into child McFunctions
            int functionId = 0;

            foreach (KeyValuePair <Argument, Range> range in functionBlocks)
            {
                string parent = Id.Substring(0, Math.Max(Id.LastIndexOf("/"), Id.LastIndexOf(":")) + 1);
                string name   = Id.Substring(Math.Max(Id.LastIndexOf("/"), Id.LastIndexOf(":")) + 1);

                if (!parent.EndsWith("_subs/"))
                {
                    parent += "_subs/";
                }

                var mcFunction = new McFunction(parent + name + "_" + functionId++);
                ChildFunctions.Add(mcFunction);

                // Move commands
                mcFunction.Commands.AddRange(Commands.GetRange(range.Value.Minimum + 1, range.Value.Length - 1));
                Commands.RemoveRange(range.Value.Minimum + 1, range.Value.Length);

                // Replace argument with function call
                range.Key.Tokens.Clear();
                range.Key.Tokens.Add(new TextToken("function " + mcFunction.Id));

                Logger.Debug($"Function block \"{mcFunction.Id}\" created from commands {functionBlocks.Last().Value} in {Id}!");

                // Run split function blocks on child so they can do their own function blocks.
                mcFunction.SplitFunctionBlocks(env);
            }
        }
Пример #2
0
        public static void Compile(Options.CompileDatapack options)
        {
            Logger.Info($"Compile datapack\n\t{options.SourceDirectory} -> {options.OutputDirectory}");

            var env = new BuildEnvironment(options.SourceDirectory);

            env.OutputPath = options.OutputDirectory;

            // Try to add custom constants into build environment
            var constants = options.ToConstantsDictonary();

            if (constants != null)
            {
                foreach (var constant in constants)
                {
                    env.Constants.Add(constant.Key, constant.Value);
                }
                Logger.Info($"{constants.Count} command line constant{(constants.Count == 1 ? "" : "s")} provided.");
            }

            // Get file list
            List <string> files = GetFiles(env);

            Logger.Info($"{files.Count} files found to be compiled.");

            // Start parse & compile
            Logger.Info("Starting parse & compile...");
            var parser = new Parser.Parser(env);

            Timer.Start("parse_and_compile");

            var totalParseTime   = new TimeSpan();
            var totalCompileTime = new TimeSpan();

            foreach (string file in files)
            {
                // Parse
                Logger.Info($"Parsing {file}...");
                Timer.Start("parse");
                McFunction mcFunction = parser.Parse(file);
                totalParseTime = totalParseTime.Add(Timer.End("parse"));

                Logger.Debug($"Parsed {file}. {mcFunction.Commands.Count} commands found.");

                // Compile
                Logger.Info($"Compiling {file}...");
                Timer.Start("compile");
                mcFunction.Compile(env);
                totalCompileTime = totalCompileTime.Add(Timer.End("compile"));
                Logger.Debug($"Compiled {file}.");

                // Save
                mcFunction.Save(env);
            }

            TimeSpan parseAndCompileTime = Timer.End("parse_and_compile");

            Logger.Info($"Datapack compile finished. Took {Math.Round(parseAndCompileTime.TotalSeconds, 3)}s");
            Logger.Debug($"Total parse time: {Math.Round(totalParseTime.TotalSeconds, 3)}s");
            Logger.Debug($"Total compile time: {Math.Round(totalCompileTime.TotalSeconds, 3)}s");
        }