public function createProperties(TES4VariableDeclarationList $variableList, TES5GlobalScope $globalScope) { /** * @var TES4VariableDeclaration[] $alreadyDefinedVariables */ $alreadyDefinedVariables = []; foreach ($variableList->getVariableList() as $variable) { $theVariableName = strtolower($variable->getVariableName()); if (isset($alreadyDefinedVariables[$theVariableName])) { if ($variable->getVariableType() == $alreadyDefinedVariables[$theVariableName]->getVariableType()) { continue; //Same variable defined twice, smack the original script developer and fallthrough silently. } throw new ConversionException("Double definition of variable named " . $variable->getVariableName() . " with different types ( " . $alreadyDefinedVariables[$theVariableName]->getVariableType()->value() . " and " . $variable->getVariableType()->value() . " )"); } switch ($variable->getVariableType()) { case TES4Type::T_FLOAT(): $property = new TES5Property($variable->getVariableName(), TES5BasicType::T_FLOAT(), null); break; case TES4Type::T_INT(): case TES4Type::T_SHORT(): case TES4Type::T_LONG(): $property = new TES5Property($variable->getVariableName(), TES5BasicType::T_INT(), null); break; case TES4Type::T_REF(): $property = $this->createPropertyFromReference($variable); break; default: throw new ConversionException("Unknown variable declaration type."); } $globalScope->add($property); $alreadyDefinedVariables[$theVariableName] = $variable; } }
public function output() { $output = []; $output = array_merge($output, $this->scriptHeader->output()); $output = array_merge($output, $this->propertyList->output()); $output = array_merge($output, $this->blockList->output()); return implode(PHP_EOL, $output); }
public function createGlobalScopes() { $globalScopes = []; $globalScope = new TES5GlobalScope(new TES5ScriptHeader("TES4TimerHelper", "TES4TimerHelper", TES5BasicType::T_QUEST(), "")); $globalScopes[] = $globalScope; $globalScope = new TES5GlobalScope(new TES5ScriptHeader("TES4Container", "TES4Container", TES5BasicType::T_QUEST(), "")); $globalScope->add(new TES5Property("isInJail", TES5BasicType::T_BOOL(), "isInJail")); $globalScope->add(new TES5Property("isMurderer", TES5BasicType::T_BOOL(), "isMurderer")); $globalScopes[] = $globalScope; return $globalScopes; }
/** * @param string $scriptName * @param TES4VariableDeclarationList $variableList * @param TES4CodeChunks $script * @return TES5Script * @throws ConversionException */ public function convert($scriptName, TES4VariableDeclarationList $variableList, TES4CodeChunks $script) { //Create the header. $scriptHeader = new TES5ScriptHeader($this->nameTransformer->transform($scriptName, ''), $scriptName, TES5BasicType::T_TOPICINFO(), '', true); $globalScope = new TES5GlobalScope($scriptHeader); foreach ($this->esmAnalyzer->getGlobalVariables() as $globalVariable) { $globalScope->addGlobalVariable($globalVariable); } if ($variableList !== null) { //Converting the variables to the properties. $this->propertiesFactory->createProperties($variableList, $globalScope); } $fragment = $this->fragmentFactory->createFragment(TES5FragmentType::T_TIF(), "Fragment_0", $globalScope, new TES5MultipleScriptsScope([$globalScope]), $script); $blockList = new TES5BlockList(); $blockList->add($fragment); return new TES5Script($scriptHeader, $globalScope, $blockList); }
public function createReferenceToSelf(TES5GlobalScope $globalScope) { //todo perhaps move tes5scriptAsVariable to a new factory return new TES5SelfReference(new TES5ScriptAsVariable($globalScope->getScriptHeader())); }
/** * Extracts implicit reference from calls. * Returns a reference from calls like: * Enable * Disable * Activate * GetInFaction whatsoever * @param TES5GlobalScope $globalScope * @param TES5MultipleScriptsScope $multipleScriptsScope * @param TES5LocalScope $localScope * @return TES5Referencer * @throws \Ormin\OBSLexicalParser\TES5\Exception\ConversionException */ private function extractImplicitReference(TES5GlobalScope $globalScope, TES5MultipleScriptsScope $multipleScriptsScope, TES5LocalScope $localScope) { switch ($globalScope->getScriptHeader()->getBasicScriptType()) { case TES5BasicType::T_OBJECTREFERENCE(): return $this->referenceFactory->createReferenceToSelf($globalScope); case TES5BasicType::T_ACTIVEMAGICEFFECT(): $self = $this->referenceFactory->createReferenceToSelf($globalScope); return $this->createObjectCall($self, "GetTargetActor", $multipleScriptsScope); case TES5BasicType::T_QUEST(): //todo - this should not be done like this //we should actually not try to extract the implicit reference on the non-reference oblivion functions like "stopQuest" //think of this line as a hacky way to just get code forward. return $this->referenceFactory->createReferenceToSelf($globalScope); /** * TIF Fragments */ /** * TIF Fragments */ case TES5BasicType::T_TOPICINFO(): return $this->createReadReference('akSpeakerRef', $globalScope, $multipleScriptsScope, $localScope); default: throw new ConversionException("Cannot extract implicit reference - unknown basic script type."); } }
/** * @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; }