public function createCodeChunk(TES4CodeChunk $chunk, TES5CodeScope $codeScope, \Ormin\OBSLexicalParser\TES5\AST\Scope\TES5GlobalScope $globalScope, \Ormin\OBSLexicalParser\TES5\AST\Scope\TES5MultipleScriptsScope $multipleScriptsScope)
 {
     switch (true) {
         case $chunk instanceof TES4Branch:
             $codeChunks = $this->branchFactory->createCodeChunk($chunk, $codeScope, $globalScope, $multipleScriptsScope);
             break;
         case $chunk instanceof TES4Return:
             $codeChunks = $this->returnFactory->createCodeChunk();
             break;
         case $chunk instanceof TES4Callable:
             $codeChunks = $this->objectCallFactory->createCodeChunk($chunk, $codeScope, $globalScope, $multipleScriptsScope);
             break;
         case $chunk instanceof TES4VariableAssignation:
             $codeChunks = $this->assignationFactory->createCodeChunk($chunk, $codeScope, $globalScope, $multipleScriptsScope);
             break;
         case $chunk instanceof TES4VariableDeclarationList:
             $codeChunks = $this->localVariableListFactory->createCodeChunk($chunk, $codeScope);
             break;
         default:
             throw new ConversionException("Cannot convert a chunk: " . get_class($chunk));
     }
     return $codeChunks;
 }
 /**
  * @param TES4SubBranch $branch
  * @param TES5CodeScope $outerCodeScope
  * @param TES5GlobalScope $globalScope
  * @return TES5SubBranch
  */
 private function convertSubBranch(TES4SubBranch $branch, TES5CodeScope $outerCodeScope, \Ormin\OBSLexicalParser\TES5\AST\Scope\TES5GlobalScope $globalScope, TES5MultipleScriptsScope $multipleScriptsScope)
 {
     $outerLocalScope = $outerCodeScope->getLocalScope();
     $expression = $this->valueFactory->createValue($branch->getExpression(), $outerCodeScope, $globalScope, $multipleScriptsScope);
     $newScope = $this->localScopeFactory->createRecursiveScope($outerLocalScope);
     $newCodeScope = $this->codeScopeFactory->createCodeScope($newScope);
     $branchChunks = $branch->getCodeChunks();
     if ($branchChunks !== null) {
         foreach ($branchChunks->getCodeChunks() as $codeChunk) {
             $codeChunks = $this->codeChunkFactory->createCodeChunk($codeChunk, $newCodeScope, $globalScope, $multipleScriptsScope);
             if ($codeChunks !== null) {
                 foreach ($codeChunks as $newCodeChunk) {
                     $newCodeScope->add($newCodeChunk);
                 }
             }
         }
     }
     return new TES5SubBranch($expression, $newCodeScope);
 }
 /**
  * @param TES4CodeBlock $block
  * @param TES5EventBlockList $blockList
  * @param TES5EventCodeBlock $newBlock
  * @param TES5MultipleScriptsScope $multipleScriptsScope
  * @param TES5GlobalScope $globalScope
  */
 public function modify(TES4CodeBlock $block, TES5EventBlockList $blockList, TES5EventCodeBlock $newBlock, TES5GlobalScope $globalScope, TES5MultipleScriptsScope $multipleScriptsScope)
 {
     $blockLocalScope = $newBlock->getLocalScope();
     switch (strtolower($block->getBlockType())) {
         case "gamemode":
         case 'scripteffectupdate':
             $onInitLocalScope = $this->blockLocalScopeFactory->createFromBlockType("OnInit", $globalScope);
             $newInitBlock = new TES5EventCodeBlock("OnInit", $onInitLocalScope, $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($onInitLocalScope)));
             $args = new TES5ObjectCallArguments();
             $args->add(new TES5Float(self::ON_UPDATE_TICK));
             $function = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "RegisterForUpdate", $multipleScriptsScope, $args);
             $newInitBlock->addChunk($function);
             $blockList->add($newInitBlock);
             break;
         case "onactivate":
             $onInitLocalScope = $this->blockLocalScopeFactory->createFromBlockType("OnInit", $globalScope);
             $newInitBlock = new TES5EventCodeBlock("OnInit", $onInitLocalScope, $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($onInitLocalScope)));
             $function = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "BlockActivation", $multipleScriptsScope);
             $newInitBlock->addChunk($function);
             $blockList->add($newInitBlock);
             break;
         case 'onactorequip':
             $parameterList = $block->getBlockParameterList();
             if ($parameterList == null) {
                 break;
             }
             $parameterList = $parameterList->getVariableList();
             $tesEquippedTarget = $parameterList[0];
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
             $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->findVariableWithMeaning(TES5LocalVariableParameterMeaning::CONTAINER())), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer);
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case "ontriggeractor":
             $parameterList = $block->getBlockParameterList();
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $activator = $localScope->findVariableWithMeaning(TES5LocalVariableParameterMeaning::ACTIVATOR());
             $castedToActor = new TES5LocalVariable("akAsActor", TES5BasicType::T_ACTOR());
             $referenceToCastedVariable = $this->referenceFactory->createReferenceToVariable($castedToActor);
             $referenceToNonCastedVariable = $this->referenceFactory->createReferenceToVariable($activator);
             $expression = $this->expressionFactory->createArithmeticExpression($referenceToCastedVariable, TES5ArithmeticExpressionOperator::OPERATOR_NOT_EQUAL(), new TES5None());
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $newCodeScope->getLocalScope()->addVariable($castedToActor);
             $newCodeScope->add($this->assignationFactory->createAssignation($referenceToCastedVariable, $referenceToNonCastedVariable));
             if ($parameterList !== null) {
                 //NOT TESTED
                 $parameterList = $parameterList->getVariableList();
                 $targetActor = $this->valueFactory->createReadReference($parameterList[0]->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
                 $interExpression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($activator), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $targetActor);
                 $interBranchCode = unserialize(serialize($newBlock->getCodeScope()));
                 $outerBranchCode = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($newCodeScope->getLocalScope()));
                 $interBranchCode->getLocalScope()->setParentScope($outerBranchCode->getLocalScope());
                 $outerBranchCode->add(new TES5Branch(new TES5SubBranch($interExpression, $interBranchCode)));
             } else {
                 $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
                 $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             }
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case 'onadd':
             $parameterList = $block->getBlockParameterList();
             if ($parameterList == null) {
                 break;
             }
             $parameterList = $parameterList->getVariableList();
             $tesEquippedTarget = $parameterList[0];
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
             $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akNewContainer")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer);
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case 'ondrop':
             $parameterList = $block->getBlockParameterList();
             if ($parameterList == null) {
                 break;
             }
             $parameterList = $parameterList->getVariableList();
             $tesEquippedTarget = $parameterList[0];
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
             $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akOldContainer")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer);
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case 'onpackagestart':
             $parameterList = $block->getBlockParameterList();
             if ($parameterList == null) {
                 break;
             }
             $parameterList = $parameterList->getVariableList();
             $tesEquippedTarget = $parameterList[0];
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
             $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akNewPackage")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer);
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case 'onpackagedone':
         case 'onpackagechange':
         case 'onpackageend':
             $parameterList = $block->getBlockParameterList()->getVariableList();
             $tesEquippedTarget = $parameterList[0];
             $localScope = $newBlock->getCodeScope()->getLocalScope();
             $newContainer = $this->valueFactory->createReadReference($tesEquippedTarget->getBlockParameter(), $globalScope, $multipleScriptsScope, $localScope);
             $expression = $this->expressionFactory->createArithmeticExpression($this->referenceFactory->createReferenceToVariable($localScope->getVariableByName("akOldPackage")), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $newContainer);
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
         case 'onalarm':
             //@INCONSISTENCE - We don't account for alarm type.
             $expression = $this->expressionFactory->createArithmeticExpression($this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), "IsAlarmed", $multipleScriptsScope), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Bool(true));
             $newCodeScope = $this->codeScopeFactory->createCodeScope($this->blockLocalScopeFactory->createRecursiveScope($blockLocalScope));
             $outerBranchCode = unserialize(serialize($newBlock->getCodeScope()));
             $outerBranchCode->getLocalScope()->setParentScope($newCodeScope->getLocalScope());
             $newCodeScope->add(new TES5Branch(new TES5SubBranch($expression, $outerBranchCode)));
             $newBlock->setCodeScope($newCodeScope);
             break;
             /**
             
                     case 'onalarm':
                     {
             
             $this->skyrimGroupEventName = 'onhit';
             
             if ($this->eventArgs[1] != 3) {
                 //Nothing eelse is supported really..
                 $this->omit = true;
                 break;
             }
             
             $branch = new TES4ConditionalBranch();
             $expression = new TES4Expression();
             $leftConstant = new TES4Constant("akAggressor", "ObjectReference");
             //                $actionConstant        = new TES4Constant($this->eventArgs[1],"Package");
             
             $actionConstant = TES4Factories::createReference($this->eventArgs[2], $this);
             
             $expression->left_side = $leftConstant;
             $expression->right_side = $actionConstant;
             $expression->comparision_operator = TES4Expression::COMPARISION_OPERATOR_EQUAL;
             
             $codeBlock = new TES4CodeBlock();
             $codeBlock->chunks = $this->chunks;
             
             $branch->ifs[] = array(
                 'rawExpression' => 'SCRIPT_GENERATED',
                 'expression' => $expression,
                 'codeBlock' => $codeBlock
             );
             $this->chunks = new TES4ChunkContainer();
             $this->chunks->parent = $this;
             $this->chunks->addChunk($branch);
             
             break;
                     }
             */
     }
 }
 /**
  * @param TES4ScriptCollection $scripts
  * @return TES5ScriptCollection
  * @throws ConversionException
  */
 public function convert(TES4ScriptCollection $scripts)
 {
     $transpiledCollection = new TES5ScriptCollection();
     $scriptHeaders = [];
     $globalScopes = [];
     /**
      * @var TES4Target $scriptTarget
      */
     foreach ($scripts->getIterator() as $k => $scriptTarget) {
         $script = $scriptTarget->getScript();
         //Create the header.
         $scriptHeader = $this->createHeader($script);
         $variableList = $script->getVariableDeclarationList();
         $globalScope = new TES5GlobalScope($scriptHeader);
         foreach ($this->esmAnalyzer->getGlobalVariables() as $globalVariable) {
             $globalScope->addGlobalVariable($globalVariable);
         }
         if ($variableList !== null) {
             $this->propertiesFactory->createProperties($variableList, $globalScope);
         }
         $scriptHeaders[$k] = $scriptHeader;
         $globalScopes[$k] = $globalScope;
     }
     //Add the static global scopes which are added by complimenting scripts..
     $staticGlobalScopes = $this->staticGlobalScopesFactory->createGlobalScopes();
     foreach ($staticGlobalScopes as $staticGlobalScope) {
         $globalScopes[] = $staticGlobalScope;
     }
     $multipleScriptsScope = new TES5MultipleScriptsScope($globalScopes);
     /**
      * @var TES4Target $scriptTarget
      */
     foreach ($scripts->getIterator() as $k => $scriptTarget) {
         $scriptHeader = $scriptHeaders[$k];
         $globalScope = $globalScopes[$k];
         $script = $scriptTarget->getScript();
         $blockList = new TES5BlockList();
         $parsedBlockList = $script->getBlockList();
         $createdBlocks = [];
         if ($parsedBlockList !== null) {
             foreach ($parsedBlockList->getBlocks() as $block) {
                 $newBlockList = $this->blockFactory->createBlock($multipleScriptsScope, $globalScope, $block);
                 foreach ($newBlockList->getBlocks() as $newBlock) {
                     if (!isset($createdBlocks[$newBlock->getBlockType()])) {
                         $createdBlocks[$newBlock->getBlockType()] = [];
                     }
                     $createdBlocks[$newBlock->getBlockType()][] = $newBlock;
                 }
             }
         }
         //todo encapsulate it to a different class.
         foreach ($createdBlocks as $blockType => $blocks) {
             if (count($blocks) > 1) {
                 /**
                  * @var TES5FunctionCodeBlock[] $functions
                  */
                 $functions = [];
                 $i = 1;
                 $localScopeArguments = null;
                 /**
                  * @var TES5EventCodeBlock $block
                  */
                 foreach ($blocks as $block) {
                     $function = new TES5FunctionCodeBlock($blockType . "_" . $i, null, $block->getLocalScope(), $block->getCodeScope());
                     $functions[] = $function;
                     if ($localScopeArguments === null) {
                         $localScopeArguments = new TES5ObjectCallArguments();
                         foreach ($block->getLocalScope()->getLocalVariables() as $localVariable) {
                             $localScopeArguments->add($this->referenceFactory->createReferenceToVariable($localVariable));
                         }
                     }
                     ++$i;
                 }
                 //Create the proxy block.
                 $proxyBlock = $this->blockFactory->createNewBlock($blockType, clone $block->getLocalScope());
                 foreach ($functions as $function) {
                     $blockList->add($function);
                     $functionCall = $this->valueFactory->createObjectCall($this->referenceFactory->createReferenceToSelf($globalScope), $function->getFunctionName(), $multipleScriptsScope, $localScopeArguments, false);
                     $proxyBlock->addChunk($functionCall);
                 }
                 $blockList->add($proxyBlock);
             } else {
                 $block = current($blocks);
                 $blockList->add($block);
             }
         }
         $tesScript = new TES5Script($scriptHeader, $globalScope, $blockList);
         $transpiledCollection->add($tesScript, $scriptTarget->getOutputPath());
     }
     return $transpiledCollection;
 }