/*
         *  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);
        }
Beispiel #2
0
        private IEnumerable <TES5CodeBlock> CombineRepeatedEventCodeBlockNames(List <ITES5CodeBlock> blocks, string blockType, bool isStandalone, TES5GlobalScope globalScope)
        {
            ITES5CodeBlock[] nonEvents = blocks.Where(b => !(b is TES5EventCodeBlock)).ToArray();
            if (nonEvents.Any())
            {
                throw new ConversionException("Some non-event code blocks were present in " + nameof(CombineRepeatedEventCodeBlockNames) + ":  " + string.Join("; ", nonEvents.Select(b => b.GetType().FullName)));
            }
            TES5EventCodeBlock[]         eventBlocks         = blocks.Cast <TES5EventCodeBlock>().ToArray();
            List <TES5FunctionCodeBlock> functions           = new List <TES5FunctionCodeBlock>();
            TES5ObjectCallArguments?     localScopeArguments = null;

            for (int i = 0; i < eventBlocks.Length; i++)
            {
                ITES5CodeBlock    block            = eventBlocks[i];
                TES5FunctionScope newFunctionScope = new TES5FunctionScope(blockType + "_" + (i + 1).ToString());
                foreach (var parameter in block.FunctionScope.GetParameters())
                {
                    newFunctionScope.AddParameter(parameter);
                }

                TES5FunctionCodeBlock function = new TES5FunctionCodeBlock(newFunctionScope, block.CodeScope, TES5VoidType.Instance, isStandalone, false);
                functions.Add(function);
                if (localScopeArguments == null)
                {
                    localScopeArguments = new TES5ObjectCallArguments();
                    foreach (var parameter in block.FunctionScope.GetParameters())
                    {
                        localScopeArguments.Add(TES5ReferenceFactory.CreateReferenceToVariableOrProperty(parameter));
                    }
                }
            }

            if (functions.Any())
            {
                //Create the proxy block.
                ITES5CodeBlock     lastBlock  = blocks.Last();
                TES5EventCodeBlock proxyBlock = TES5BlockFactory.CreateEventCodeBlock(
                    //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, globalScope);
                foreach (var function in functions)
                {
                    yield return(function);

                    TES5ObjectCall functionCall = this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), function.BlockName, localScopeArguments, false// hacky.
                                                                                          );
                    proxyBlock.AddChunk(functionCall);
                }

                yield return(proxyBlock);
            }

            /*
             * //This was not ultimately necessary.
             * IGrouping<string, TES5StateCodeBlock>[] states = blocks.OfType<TES5StateCodeBlock>().ToLookup(b => b.BlockName).ToArray();
             * List<TES5CodeBlock> consolidatedStateCodeBlocks = states.Where(b => b.Count() == 1).SelectMany(b => b.Select(b2 => (TES5CodeBlock)b2).ToArray()).ToList();
             * IGrouping<string, TES5StateCodeBlock>[] repeatedStateCodeBlocks = states.Where(b => b.Count() > 1).ToArray();
             * for (int i = 0; i < repeatedStateCodeBlocks.Length; i++)
             * {
             *  IGrouping<string, TES5StateCodeBlock> groupsWithSameName = repeatedStateCodeBlocks[i];
             *  TES5StateCodeBlock firstGroup = groupsWithSameName.First();
             *  foreach (var otherGroup in groupsWithSameName.Skip(1))
             *  {
             *      foreach (ITES5CodeChunk chunk in otherGroup.CodeScope.CodeChunks)
             *      {
             *          firstGroup.AddChunk(chunk);
             *      }
             *  }
             *  if (firstGroup.CodeBlocks.Blocks.Any())
             *  {
             *      TES5CodeBlock[] reducedBlocks = CombineRepeatedCodeBlockNames(firstGroup.CodeBlocks.Blocks, blockType, isStandalone, globalScope, multipleScriptsScope).ToArray();
             *      firstGroup.CodeBlocks.Blocks.Clear();
             *      firstGroup.CodeBlocks.Blocks.AddRange(reducedBlocks);
             *  }
             *  consolidatedStateCodeBlocks.Add(firstGroup);
             * }
             * foreach(TES5CodeBlock codeBlock in consolidatedStateCodeBlocks)
             * {
             *  yield return codeBlock;
             * }
             */
        }