public override TES5Target Transpile(string sourcePath, string outputPath, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
 {
     TES4CodeChunks ast = ParseOrGetFromCache(sourcePath);
     TES4FragmentTarget fragmentTarget = new TES4FragmentTarget(ast, outputPath);
     TES5Target convertedScript = this.converter.Convert(fragmentTarget, globalScope, multipleScriptsScope);
     return convertedScript;
 }
Exemplo n.º 2
0
        public override TES5Target Transpile(string sourcePath, string outputPath, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4Script script     = ParseOrGetFromCache(sourcePath);
            TES4Target tes4Target = new TES4Target(script, outputPath);
            TES5Target target     = this.converter.Convert(tes4Target, globalScope, multipleScriptsScope);

            return(target);
        }
        public static void GenerateINFOAddTopicScripts(ESMAnalyzer esmAnalyzer, BuildTracker buildTracker, IBuildTarget tifBuildTarget)
        {
            TES5TypeInferencer    typeInferencer    = new TES5TypeInferencer(esmAnalyzer);
            TES5ObjectCallFactory objectCallFactory = new TES5ObjectCallFactory(typeInferencer);
            TES4TopicsToTES5GlobalVariableFinder globalVariableFinder = new TES4TopicsToTES5GlobalVariableFinder();
            TES5GlobalVariables globalVariables = esmAnalyzer.GlobalVariables;
            var builtTIFs = buildTracker.GetBuiltScripts(BuildTargetFactory.TIFName);

            foreach (TES4Record infoRecord in esmAnalyzer.GetRecords().Where(r => r.RecordType == TES4RecordType.INFO))
            {
                TES4SubrecordData[] names = infoRecord.GetSubrecords("NAME").ToArray();
                if (names.Any())
                {
                    string                fragment0Name     = TES5FragmentFactory.GetFragmentName(0);
                    string                nameTES5FormIDHex = (infoRecord.FormID + 0x01000000).ToString("x8");
                    string                scriptName        = TES5ReferenceFactory.tif_Prefix + "_" + nameTES5FormIDHex;
                    TES5Script?           infoTIF           = builtTIFs.Where(s => s.Key == scriptName).Select(s => s.Value.Script).FirstOrDefault();
                    TES5FunctionCodeBlock fragment0;
                    if (infoTIF != null)
                    {
                        fragment0 = infoTIF.BlockList.Blocks.OfType <TES5FunctionCodeBlock>().Where(b => b.BlockName == fragment0Name).First();
                    }
                    else
                    {
                        TES5ScriptHeader  scriptHeader  = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(scriptName, TES5BasicType.T_TOPICINFO, TES5TypeFactory.TES4_Prefix, true);
                        TES5GlobalScope   globalScope   = new TES5GlobalScope(scriptHeader);
                        TES5FunctionScope functionScope = new TES5FunctionScope(fragment0Name);
                        functionScope.AddParameter(new TES5SignatureParameter("akSpeakerRef", TES5BasicType.T_OBJECTREFERENCE, true));
                        TES5LocalScope localScope = new TES5LocalScope(functionScope);
                        TES5CodeScope  codeScope  = TES5CodeScopeFactory.CreateCodeScope(localScope);
                        fragment0 = new TES5FunctionCodeBlock(functionScope, codeScope, TES5VoidType.Instance, false, true);
                        TES5BlockList blockList = new TES5BlockList()
                        {
                            fragment0
                        };
                        infoTIF = new TES5Script(globalScope, blockList, true);
                        string     outputPath = tifBuildTarget.GetTranspileToPath(scriptName);
                        TES5Target target     = new TES5Target(infoTIF, outputPath);
                        buildTracker.RegisterBuiltScript(tifBuildTarget, target);
                    }
                    foreach (TES4SubrecordData name in names)
                    {
                        int                 formID                   = infoRecord.ExpandBytesIntoFormID(name);
                        TES4Record          addedTopic               = esmAnalyzer.GetRecordByFormID(formID);
                        Tuple <int, string>?globalVariable           = globalVariableFinder.GetGlobalVariableNullable(addedTopic.FormID);
                        string              globalVariableEditorID   = globalVariable != null ? globalVariable.Item2 : globalVariableFinder.GetGlobalVariableEditorID(addedTopic.GetEditorID());
                        Nullable <int>      globalVariableTES5FormID = globalVariable != null ? globalVariable.Item1 : (Nullable <int>)null;
                        TES5Property        topicAddedProperty       = TES5PropertyFactory.ConstructWithTES5FormID(globalVariableEditorID, TES5BasicType.T_GLOBALVARIABLE, globalVariableEditorID, globalVariableTES5FormID);
                        infoTIF.GlobalScope.AddPropertyIfNotExists(topicAddedProperty);
                        TES5Reference topicAddedReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(topicAddedProperty);
                        fragment0.AddChunk(objectCallFactory.CreateObjectCall(topicAddedReference, "SetValueInt", new TES5ObjectCallArguments()
                        {
                            new TES5Integer(1)
                        }));
                    }
                }
            }
        }
Exemplo n.º 4
0
        public void Write(IBuildTarget target, BuildTracker buildTracker, ProgressWriter progressWriter)
        {
            var scripts = buildTracker.GetBuiltScripts(target.Name).Values;
            List <TES5Target> connectedQuestFragments = new List <TES5Target>();
            Dictionary <string, List <QuestStageScript> > jointScripts = new Dictionary <string, List <QuestStageScript> >();

            /*
             * Scan manually for .map files in the QF scripts folder
             * Reason is that in case we"ve got a quest with no fragments to anything whatsoever, we"ll have to go
             * through it too ( just with empty subfragments trees ), to generate the objective handlings
             */
            string sourcePath = target.GetSourcePath();

            foreach (var mapFilePath in
                     Directory.EnumerateFiles(sourcePath, "*.map")
                     .Concat(Directory.EnumerateFiles(sourcePath, "*.map2")))
            {
                string mapFileName = Path.GetFileNameWithoutExtension(mapFilePath);
                jointScripts.AddNewListIfNotContainsKey(mapFileName);
            }

            /*
             * Group the fragments together
             */
            foreach (var script in scripts)
            {
                string[] parts = script.Script.ScriptHeader.OriginalScriptName.Split('_');
                if (parts.Length < 3)
                {
                    //Not able to categorize, probably wrong name of the fragment.
                    continue;
                }

                string baseName = parts[0] + "_" + parts[1] + "_" + parts[2];
                jointScripts.AddNewListIfNotContainsKeyAndAddValueToList(baseName, new QuestStageScript(script, int.Parse(parts[3], CultureInfo.InvariantCulture), int.Parse(parts[4], CultureInfo.InvariantCulture)));
            }

            const string joiningQFFragments = "Joining QF Fragments...";

            progressWriter.Write(joiningQFFragments);
            foreach (var kvp in jointScripts)
            {
                var        resultingFragmentName = kvp.Key;
                var        subfragmentsTrees     = kvp.Value;
                TES5Target joinedQF = this.QFFragmentFactory.JoinQFFragments(target, resultingFragmentName, subfragmentsTrees);
                connectedQuestFragments.Add(joinedQF);
            }
            progressWriter.ClearByPreviousProgress(joiningQFFragments);
            //WTM:  Note:  Subtract total scripts and add back connected quest fragments.
            int totalAddend = -scripts.Count + connectedQuestFragments.Count;

            progressWriter.ModifyTotalAndWrite(totalAddend);

            Write(connectedQuestFragments, progressWriter);
        }
        public TES5Target Convert(TES5FragmentType fragmentType, TES4FragmentTarget fragmentTarget, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES5FunctionCodeBlock fragment  = CreateFragment(fragmentType, 0, globalScope, multipleScriptsScope, fragmentTarget.CodeChunks);
            TES5BlockList         blockList = new TES5BlockList()
            {
                fragment
            };
            TES5Script script = new TES5Script(globalScope, blockList, true);
            TES5Target target = new TES5Target(script, fragmentTarget.OutputPath);

            return(target);
        }
Exemplo n.º 6
0
        /*
         *  The script to be converted
         *  The script"s global scope
         *  The scope under which we"re converting
         *
         * @throws ConversionException
         */
        public TES5Target Convert(TES4Target target, bool isStandalone, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4Script    script          = target.Script;
            TES4BlockList?parsedBlockList = script.BlockList;
            Dictionary <string, List <ITES5CodeBlock> > createdBlocks = new Dictionary <string, List <ITES5CodeBlock> >();

            if (parsedBlockList != null)
            {
                TES5EventCodeBlock?onUpdateBlockOfNonQuestOrAME = null;
                foreach (TES4CodeBlock block in parsedBlockList.Blocks)
                {
                    TES5BlockList newBlockList = this.blockFactory.CreateBlock(block, globalScope, multipleScriptsScope, ref onUpdateBlockOfNonQuestOrAME);
                    foreach (ITES5CodeBlock newBlock in newBlockList.Blocks)
                    {
                        createdBlocks.AddNewListIfNotContainsKeyAndAddValueToList(newBlock.BlockName, newBlock);
                    }
                }
            }

            TES5BlockList blockList = new TES5BlockList();

            foreach (var createdBlock in createdBlocks)
            {
                var blockType = createdBlock.Key;
                var blocks    = createdBlock.Value;
                if (blocks.Count > 1)
                {
                    foreach (TES5CodeBlock block in CombineRepeatedEventCodeBlockNames(blocks, blockType, isStandalone, globalScope))
                    {
                        blockList.Add(block);
                    }
                }
                else
                {
                    ITES5CodeBlock block = blocks[0];
                    blockList.Add(block);
                }
            }

            TES5Target result = new TES5Target(new TES5Script(globalScope, blockList, false), target.OutputPath);

            return(result);
        }
        public void execute(string buildPath = Build.DEFAULT_BUILD_PATH, bool skipParsing = false, string mode = "strict")
        {
            set_time_limit(10800); // 3 hours is the maximum for this command. Need more? You really screwed something, full suite for all Oblivion vanilla data takes 20 minutes. :)
            float threshold;

            switch (mode)
            {
            case "sloppy":
            {
                threshold = 0.5f;
                break;
            }

            case "normal":
            {
                threshold = 0.85f;
                break;
            }

            case "strict":
            default:
            {
                threshold = 0.95f;
                break;
            }

            case "perfect":
            {
                threshold = 1;
                break;
            }
            }

            if (!skipParsing)
            {
                SyntaxErrorCleanParser parser = new SyntaxErrorCleanParser(new TES4ObscriptCodeGrammar());
                //parser = new Parser(new TES4OBScriptGrammar());
                TES4ToTES5ASTTIFFragmentConverter converter = TES4ToTES5ASTTIFFragmentConverterFactory.GetConverter(new Build(buildPath));
                string   inputFolder = "./Fragments/TIF/fragments/";
                string   outputFolder = "./Fragments/TIF/PapyrusFragments/";
                string[] scandir = Directory.GetFiles(inputFolder);
                int      success = 0, total = 0;
                Dictionary <string, TES5MultipleScriptsScope> ASTTable = new Dictionary <string, TES5MultipleScriptsScope>();
                Console.WriteLine("Lexing and parsing..");
                int totalNumber = scandir.Length;
                foreach (var scriptPath in scandir)
                {
                    if (!scriptPath.EndsWith(".txt"))
                    {
                        continue;
                    }

                    if ((total % 10) == 0)
                    {
                        Console.WriteLine(total + "/" + totalNumber + "...");
                    }

                    string scriptFileName   = scriptPath.Substring(0, scriptPath.Length - 4);
                    string outputScriptPath = scriptFileName + ".psc";
                    total++;
                    try
                    {
                        Console.WriteLine(scriptFileName + "...");
                        FragmentLexer               lexer        = new FragmentLexer();
                        ArrayTokenStream            tokens       = lexer.lex(File.ReadAllText(path));
                        TES4VariableDeclarationList variableList = this.fragmentsReferencesBuilder.buildVariableDeclarationList(inputFolder + scriptFileName + ".references");
                        TES5MultipleScriptsScope    AST          = (TES5MultipleScriptsScope)parser.ParseWithFixLogic(tokens);
                        ASTTable[scriptPath] = AST;
                        TES5Target TES5AST      = converter.convert(scriptFileName, variableList, AST);
                        string     outputScript = TES5AST.output();
                        File.WriteAllText(outputFolder + outputScriptPath, outputScript);
                        Process.Start("lua", "\"Utilities/beautifier.lua\" \"" + outputFolder + outputScriptPath + "\"");
                        success++;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(scriptPath + "\r\n" + e.GetType().FullName + ":  " + e.Message + "\r\n");
                        continue;
                    }
                }

                float successRate = (float)success / total;
                if (successRate < threshold)
                {
                    float percent = (float)Math.Round(successRate * 100);
                    Console.WriteLine("ERROR: Build failed on parsing step in " + mode + " mode. The rate is " + success + "/" + total + " (" + percent + " %)");
                    return;
                }

                Console.WriteLine("Parsing in " + mode + " mode succedeed (rate " + success + "/" + total + ").  Copying Skyrim scripts and parsed papyrus fragments to build folder...");
            }

            Console.WriteLine("Build in " + mode + " mode succeeded!");
        }
        /*
         *  The script to be converted
         *  The script"s global scope
         *  The scope under which we"re converting
         *
         * @throws ConversionException
         */
        public TES5Target Convert(TES4Target target, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4Script    script          = target.Script;
            TES5BlockList blockList       = new TES5BlockList();
            TES4BlockList parsedBlockList = script.BlockList;
            Dictionary <string, List <ITES5CodeBlock> > createdBlocks = new Dictionary <string, List <ITES5CodeBlock> >();

            if (parsedBlockList != null)
            {
                foreach (TES4CodeBlock block in parsedBlockList.Blocks)
                {
                    TES5BlockList newBlockList = this.blockFactory.CreateBlock(block, globalScope, multipleScriptsScope);
                    foreach (ITES5CodeBlock newBlock in newBlockList.Blocks)
                    {
                        createdBlocks.AddNewListIfNotContainsKeyAndAddValueToList(newBlock.BlockName, newBlock);
                    }
                }
            }

            //todo encapsulate it to a different class.
            bool isStandalone = target.OutputPath.Contains(Path.DirectorySeparatorChar + "Standalone" + Path.DirectorySeparatorChar);

            foreach (var createdBlock in createdBlocks)
            {
                var blockType = createdBlock.Key;
                var blocks    = createdBlock.Value;
                if (blocks.Count > 1)
                {
                    List <TES5FunctionCodeBlock> functions = new List <TES5FunctionCodeBlock>();
                    int i = 1;
                    TES5ObjectCallArguments localScopeArguments = null;
                    foreach (TES5CodeBlock block in blocks)
                    {
                        TES5FunctionScope newFunctionScope = new TES5FunctionScope(blockType + "_" + i.ToString());
                        foreach (var variable in block.FunctionScope.Variables.Values)
                        {
                            newFunctionScope.AddVariable(variable);
                        }

                        TES5FunctionCodeBlock function = new TES5FunctionCodeBlock(newFunctionScope, block.CodeScope, new TES5VoidType(), isStandalone);
                        functions.Add(function);
                        if (localScopeArguments == null)
                        {
                            localScopeArguments = new TES5ObjectCallArguments();
                            foreach (var variable in block.FunctionScope.Variables.Values)
                            {
                                localScopeArguments.Add(TES5ReferenceFactory.CreateReferenceToVariable(variable));
                            }
                        }

                        ++i;
                    }

                    //Create the proxy block.
                    ITES5CodeBlock     lastBlock  = blocks.Last();
                    TES5EventCodeBlock proxyBlock = TES5BlockFactory.CreateEventCodeBlock(blockType,

                                                                                          /*
                                                                                           * //WTM:  Change:  block was used below, but block is out of scope.  The PHP must have been using the last defined block from above.
                                                                                           * //WTM:  Change:  PHP called "clone" below, but I'm not sure if this is necessary or would even operate the same in C#.
                                                                                           */
                                                                                          lastBlock.FunctionScope);
                    foreach (var function in functions)
                    {
                        blockList.Add(function);
                        TES5ObjectCall functionCall = this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), function.BlockName, multipleScriptsScope, localScopeArguments, false // hacky.
                                                                                              );
                        proxyBlock.AddChunk(functionCall);
                    }

                    blockList.Add(proxyBlock);
                }
                else
                {
                    ITES5CodeBlock block = blocks[0];
                    blockList.Add(block);
                }
            }

            TES5Target result = new TES5Target(new TES5Script(globalScope, blockList), target.OutputPath);

            return(result);
        }
Exemplo n.º 9
0
        /*
         * Joins N QF subfragments into one QF fragment that can be properly binded into Skyrim VM
         * @throws ConversionException
         */
        public TES5Target JoinQFFragments(IBuildTarget target, string resultingFragmentName, List <QuestStageScript> subfragmentsTrees)
        {
            int      tes4FormID = GetTES4FormID(resultingFragmentName);
            StageMap stageMap   = StageMapBuilder.Build(target, resultingFragmentName, esmAnalyzer, tes4FormID);

            /*
             * We need script fragment for objective handling for each stage, so when parsing the script fragments,
             * we"ll be marking them there, and intersecting this with stage.
             * This will give us an array of stages which don"t have script fragment, but will need it anyways
             * for objective handling.
             */
            TES5ScriptHeader resultingScriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(resultingFragmentName, TES5BasicType.T_QUEST, TES5TypeFactory.TES4_Prefix, true);
            TES5GlobalScope  resultingGlobalScope  = new TES5GlobalScope(resultingScriptHeader);

            string[] referenceAliases = ReferenceAliasBuilder.Build(target, resultingFragmentName, esmAnalyzer, tes4FormID).ToArray();
            foreach (string propertyName in referenceAliases)
            {
                resultingGlobalScope.AddProperty(TES5PropertyFactory.ConstructWithoutFormID(propertyName, TES5BasicType.T_REFERENCEALIAS, propertyName));
            }

            List <QuestStageBlock> questStageBlocks        = new List <QuestStageBlock>();
            HashSet <int>          implementedStages       = new HashSet <int>();
            HashSet <string>       propertiesNamesDeclared = new HashSet <string>();

            foreach (var subfragment in subfragmentsTrees)
            {
                TES5Target      subfragmentsTree       = subfragment.Script;
                TES5Script      subfragmentScript      = subfragmentsTree.Script;
                TES5GlobalScope subfragmentGlobalScope = subfragmentScript.GlobalScope;
                foreach (TES5Property subfragmentProperty in subfragmentGlobalScope.Properties)
                {
                    /*
                     * Move over the properties to the new global scope
                     */
                    if (propertiesNamesDeclared.Add(subfragmentProperty.Name))
                    {
                        resultingGlobalScope.AddProperty(subfragmentProperty);
                    }
                    else
                    {
                        if (subfragmentProperty.IsPlayerRef)
                        {
                            continue;
                        }
                        //WTM:  Change:  I don't think renaming these properties actually helps anything.

                        /*
                         * string propertyName = GeneratePropertyName(subfragmentScript.ScriptHeader, subfragmentProperty);
                         * subfragmentProperty.Rename(propertyName);
                         * if (!propertiesNamesDeclared.Add(subfragmentProperty.Name))
                         * {
                         *  throw new ConversionException(nameof(propertiesNamesDeclared) + " already contained property " + subfragmentProperty.Name + ".");
                         * }
                         */
                        //WTM:  Change:  I'm trying to unify properties and include extended type declarations.
                        TES5Property existingProperty = resultingGlobalScope.GetPropertyByName(subfragmentProperty.Name);
                        if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(existingProperty.TES5Type, subfragmentProperty.TES5Type))
                        {
                            continue;
                        }
                        if (TES5InheritanceGraphAnalyzer.IsExtending(subfragmentProperty.TES5Type, existingProperty.TES5Type))
                        {
                            existingProperty.TES5Type = subfragmentProperty.TES5Type;
                            continue;
                        }
                        if (TES5InheritanceGraphAnalyzer.IsExtending(existingProperty.TES5Type, subfragmentProperty.TES5Type.NativeType))
                        {
                            subfragmentProperty.TES5Type.NativeType = existingProperty.TES5Type.NativeType;
                            existingProperty.TES5Type = subfragmentProperty.TES5Type;
                            continue;
                        }
                        throw new ConversionException("Types were not compatible for property " + subfragmentProperty.Name + ":  " + subfragmentProperty.TES5Type.Value + " should extend " + existingProperty.TES5Type.Value + " (" + existingProperty.TES5Type.NativeType.Value + ").");
                    }
                }

                List <ITES5CodeBlock> subfragmentBlocks = subfragmentScript.BlockList.Blocks;
                if (subfragmentBlocks.Count != 1)
                {
                    throw new ConversionException("Wrong QF fragment, actual function count: " + subfragmentBlocks.Count + "..");
                }

                ITES5CodeBlock subfragmentBlock = subfragmentBlocks[0];
                if (subfragmentBlock.FunctionScope.BlockName != TES5FragmentFactory.GetFragmentName(0))
                {
                    throw new ConversionException("Wrong QF fragment funcname, actual function name: " + subfragmentBlock.FunctionScope.BlockName + ".");
                }

                string newFragmentFunctionName = TES5FragmentFactory.GetFragmentName(subfragment.Stage, subfragment.LogIndex);

                subfragmentBlock.FunctionScope.Rename(newFragmentFunctionName);
                List <int>?stageMapOfStage = stageMap.TryGetStageTargetsMap(subfragment.Stage);
                if (stageMapOfStage != null)
                {
                    var objectiveCodeChunks = objectiveHandlingFactory.GenerateObjectiveHandling(subfragmentBlock, resultingGlobalScope, stageMapOfStage);
                    foreach (var newCodeChunk in objectiveCodeChunks)
                    {
                        subfragmentBlock.AddChunk(newCodeChunk);
                    }
                }

                questStageBlocks.Add(new QuestStageBlock(subfragment.Stage, subfragment.LogIndex, subfragmentBlock));
                implementedStages.Add(subfragment.Stage);
            }

            /*
             * Diff to find stages which we still need to mark
             */
            int[] nonDoneStages = stageMap.StageIDs.Where(stageID => !implementedStages.Contains(stageID)).ToArray();
            foreach (int nonDoneStage in nonDoneStages)
            {
                TES5FunctionCodeBlock fragment = objectiveHandlingFactory.CreateEnclosedFragment(resultingGlobalScope, nonDoneStage, stageMap.GetStageTargetsMap(nonDoneStage));
                questStageBlocks.Add(new QuestStageBlock(nonDoneStage, 0, fragment));
            }

            this.mappedTargetsLogService.WriteScriptName(resultingFragmentName);
            foreach (var kvp in stageMap.MappedTargetsIndex)
            {
                var originalTargetIndex = kvp.Key;
                var mappedTargetIndexes = kvp.Value;
                this.mappedTargetsLogService.WriteLine(originalTargetIndex, mappedTargetIndexes);
            }

            TES5BlockList resultingBlockList = new TES5BlockList(questStageBlocks.OrderBy(b => b.StageID).ThenBy(b => b.LogIndex).Select(b => b.CodeBlock));
            TES5Script    resultingTree      = new TES5Script(resultingGlobalScope, resultingBlockList, true);
            string        outputPath         = target.GetTranspileToPath(resultingFragmentName);

            return(new TES5Target(resultingTree, outputPath));
        }
        /*
         * Joins N QF subfragments into one QF fragment that can be properly binded into Skyrim VM
         * @throws ConversionException
         */
        public TES5Target JoinQFFragments(BuildTarget target, string resultingFragmentName, List <QuestStageScript> subfragmentsTrees)
        {
            StageMap stageMap = BuildStageMap(target, resultingFragmentName);

            /*
             * We need script fragment for objective handling for each stage, so when parsing the script fragments,
             * we"ll be marking them there, and intersecting this with stage.
             * This will give us an array of stages which don"t have script fragment, but will need it anyways
             * for objective handling.
             */
            TES5ScriptHeader resultingScriptHeader = new TES5ScriptHeader(resultingFragmentName, TES5BasicType.T_QUEST, "", true);
            TES5BlockList    resultingBlockList    = new TES5BlockList();
            TES5GlobalScope  resultingGlobalScope  = new TES5GlobalScope(resultingScriptHeader);

            /*
             * Add ReferenceAlias"es
             * At some point, we might port the conversion so it doesn"t use the directly injected property,
             * but instead has a map to aliases and we"ll map accordingly and have references point to aliases instead
             */
            string sourcePath  = target.GetSourceFromPath(resultingFragmentName);
            string scriptName  = Path.GetFileNameWithoutExtension(sourcePath);
            string aliasesFile = Path.Combine(Path.GetDirectoryName(sourcePath), scriptName + ".aliases");

            string[] aliasesLines = File.ReadAllLines(aliasesFile);
            Dictionary <string, bool> aliasesDeclared = new Dictionary <string, bool>();

            foreach (var alias in aliasesLines)
            {
                string trimmedAlias = alias.Trim();
                if (trimmedAlias == "")
                {
                    continue;
                }
                try
                {
                    aliasesDeclared.Add(trimmedAlias, true);
                }
                catch (ArgumentException) { continue; }
                resultingGlobalScope.AddProperty(new TES5Property(trimmedAlias, TES5BasicType.T_REFERENCEALIAS, trimmedAlias));
            }

            Dictionary <int, bool>    implementedStages       = new Dictionary <int, bool>();
            Dictionary <string, bool> propertiesNamesDeclared = new Dictionary <string, bool>();

            foreach (var subfragment in subfragmentsTrees)
            {
                TES5Target      subfragmentsTree       = subfragment.Script;
                TES5Script      subfragmentScript      = subfragmentsTree.Script;
                TES5GlobalScope subfragmentGlobalScope = subfragmentScript.GlobalScope;
                foreach (TES5Property subfragmentProperty in subfragmentGlobalScope.Properties)
                {
                    /*
                     * Move over the properties to the new global scope
                     */
                    string propertyName;
                    if (propertiesNamesDeclared.ContainsKey(subfragmentProperty.Name))
                    {
                        propertyName = GeneratePropertyName(subfragmentScript.ScriptHeader, subfragmentProperty);
                        subfragmentProperty.Rename(propertyName);
                    }
                    else
                    {
                        propertyName = subfragmentProperty.Name;
                    }

                    propertiesNamesDeclared.Add(propertyName, true);
                    resultingGlobalScope.AddProperty(subfragmentProperty);
                    //WTM:  Note:  See QF_FGD03Viranus_0102d154.  Since ViranusDontonREF is present in multiple of the original fragments,
                    //ViranusDontonREF gets renamed by the above.  So multiple ViranusDontonREF variables are output.
                    //Below I tried not renaming, assuming instead that variables with matching names and types within a set of fragments were intended to be the same variable.
                    //It had OK results, but I'm leaving it commented for now.

                    /*string propertyNameWithSuffix = subfragmentProperty.PropertyNameWithSuffix;
                     * TES5Property existingProperty = resultingGlobalScope.Properties.Where(p => p.PropertyNameWithSuffix == propertyNameWithSuffix).FirstOrDefault();
                     * if (existingProperty != null && TES5InheritanceGraphAnalyzer.isExtending(subfragmentProperty.PropertyType, existingProperty.PropertyType))
                     * {
                     *  existingProperty.PropertyType = subfragmentProperty.PropertyType;
                     * }
                     * else
                     * {
                     *  bool add = true;
                     *  if (existingProperty != null)
                     *  {
                     *      if (TES5InheritanceGraphAnalyzer.isExtending(existingProperty.PropertyType, subfragmentProperty.PropertyType))
                     *      {
                     *          add = false;
                     *      }
                     *      else
                     *      {
                     *          string generatedPropertyName = generatePropertyName(subfragmentScript.ScriptHeader, subfragmentProperty, i);
                     *          subfragmentProperty.Rename(generatedPropertyName);
                     *      }
                     *  }
                     *  if (add)
                     *  {
                     *      resultingGlobalScope.Add(subfragmentProperty);
                     *  }
                     * }*/
                }

                List <ITES5CodeBlock> subfragmentBlocks = subfragmentScript.BlockList.Blocks;
                if (subfragmentBlocks.Count != 1)
                {
                    throw new ConversionException("Wrong QF fragment, actual function count: " + subfragmentBlocks.Count + "..");
                }

                ITES5CodeBlock subfragmentBlock = subfragmentBlocks[0];
                if (subfragmentBlock.FunctionScope.BlockName != "Fragment_0")
                {
                    throw new ConversionException("Wrong QF fragment funcname, actual function name: " + subfragmentBlock.FunctionScope.BlockName + "..");
                }

                string newFragmentFunctionName = "Fragment_" + subfragment.Stage.ToString();
                if (subfragment.LogIndex != 0)
                {
                    newFragmentFunctionName += "_" + subfragment.LogIndex;
                }

                subfragmentBlock.FunctionScope.Rename(newFragmentFunctionName);
                var objectiveCodeChunks = this.objectiveHandlingFactory.GenerateObjectiveHandling(subfragmentBlock, resultingGlobalScope, stageMap.GetStageTargetsMap(subfragment.Stage));
                foreach (var newCodeChunk in objectiveCodeChunks)
                {
                    subfragmentBlock.AddChunk(newCodeChunk);
                }

                resultingBlockList.Add(subfragmentBlock);
                implementedStages[subfragment.Stage] = true;
            }

            /*
             * Diff to find stages which we still need to mark
             */
            int[] nonDoneStages = stageMap.StageIDs.Where(stageID => !implementedStages.ContainsKey(stageID)).ToArray();
            foreach (int nonDoneStage in nonDoneStages)
            {
                TES5FunctionCodeBlock fragment = this.objectiveHandlingFactory.CreateEnclosedFragment(resultingGlobalScope, nonDoneStage, stageMap.GetStageTargetsMap(nonDoneStage));
                resultingBlockList.Add(fragment);
            }

            this.mappedTargetsLogService.WriteScriptName(resultingFragmentName);
            foreach (var kvp in stageMap.MappedTargetsIndex)
            {
                var originalTargetIndex = kvp.Key;
                var mappedTargetIndexes = kvp.Value;
                this.mappedTargetsLogService.WriteLine(originalTargetIndex, mappedTargetIndexes);
            }

            TES5Script resultingTree = new TES5Script(resultingGlobalScope, resultingBlockList);
            string     outputPath    = target.GetTranspileToPath(resultingFragmentName);

            return(new TES5Target(resultingTree, outputPath));
        }
Exemplo n.º 11
0
 public QuestStageScript(TES5Target script, int stage, int logIndex)
 {
     this.Script   = script;
     this.Stage    = stage;
     this.LogIndex = logIndex;
 }
 public void RegisterBuiltScript(BuildTarget buildTarget, TES5Target script)
 {
     this.builtScripts[buildTarget.GetTargetName()][script.Script.ScriptHeader.OriginalScriptName] = script;
 }