public function getData()
 {
     switch ($this->operator) {
         case TES4ArithmeticExpressionOperator::OPERATOR_EQUAL():
             return $this->leftValue->getData() == $this->rightValue->getData();
         case TES4ArithmeticExpressionOperator::OPERATOR_GREATER():
             return $this->leftValue->getData() > $this->rightValue->getData();
         case TES4ArithmeticExpressionOperator::OPERATOR_GREATER_OR_EQUAL():
             return $this->leftValue->getData() >= $this->rightValue->getData();
         case TES4ArithmeticExpressionOperator::OPERATOR_LESS():
             return $this->leftValue->getData() < $this->rightValue->getData();
         case TES4ArithmeticExpressionOperator::OPERATOR_LESS_OR_EQUAL():
             return $this->leftValue->getData() <= $this->rightValue->getData();
         case TES4ArithmeticExpressionOperator::OPERATOR_NOT_EQUAL():
             return $this->leftValue->getData() != $this->rightValue->getData();
     }
     throw new ConversionException("Unknown TES4ArithmeticExpressionOperator");
 }
 protected function createObscriptCodeParsingTree()
 {
     $this('Code+')->is('Code+', 'Code')->call(function (TES4CodeChunks $list, TES4CodeChunk $codeDeclaration) {
         $list->add($codeDeclaration);
         return $list;
     })->is('Code')->call(function (TES4CodeChunk $codeDeclaration) {
         $list = new TES4CodeChunks();
         $list->add($codeDeclaration);
         return $list;
     });
     $this('Code')->is('Branch')->is('SetValue', 'NWL')->is('Function', 'NWL')->is('ObjectCall', 'NWL')->is('LocalVariableDeclaration+')->is('Return');
     #todo - THIS should be fixed on lexer level, right now it ignores NWL after the return
     $this('LocalVariableDeclaration+')->is('LocalVariableDeclaration+', 'LocalVariableDeclaration')->call(function (TES4VariableDeclarationList $list, TES4VariableDeclaration $variableDeclaration) {
         $list->add($variableDeclaration);
         return $list;
     })->is('LocalVariableDeclaration')->call(function (TES4VariableDeclaration $variableDeclaration) {
         $list = new TES4VariableDeclarationList();
         $list->add($variableDeclaration);
         return $list;
     });
     $this('LocalVariableDeclaration')->is('LocalVariableDeclarationType', 'VariableName')->call(function (CommonToken $variableDeclarationType, CommonToken $variableName) {
         return new TES4VariableDeclaration($variableName->getValue(), TES4Type::memberByValue(strtolower($variableDeclarationType->getValue())));
     });
     $this('Branch')->is('BranchStart', 'BranchEndToken')->call(function (TES4SubBranch $branchStart, $end) {
         return new TES4Branch($branchStart, null, null);
     })->is('BranchStart', 'BranchSubBranch+', 'BranchEndToken')->call(function (TES4SubBranch $branchStart, TES4SubBranchList $subbranches, $end) {
         return new TES4Branch($branchStart, $subbranches, null);
     })->is('BranchStart', 'BranchElse', 'BranchEndToken')->call(function (TES4SubBranch $branchStart, TES4ElseSubBranch $branchElse, $end) {
         return new TES4Branch($branchStart, null, $branchElse);
     })->is('BranchStart', 'BranchSubBranch+', 'BranchElse', 'BranchEndToken')->call(function (TES4SubBranch $branchStart, TES4SubBranchList $subbranches, TES4ElseSubBranch $branchElse, $end) {
         return new TES4Branch($branchStart, $subbranches, $branchElse);
     });
     $this('BranchElse')->is('BranchElseToken', 'Code+')->call(function ($branchElseToken, TES4CodeChunks $code) {
         return new TES4ElseSubBranch($code);
     })->is('BranchElseToken')->call(function ($branchElseToken) {
         return new TES4ElseSubBranch(null);
     });
     $this('BranchStart')->is('BranchStartToken', 'Value', 'NWL', 'Code+')->call(function ($branchStart, TES4Value $expression, $newLine, TES4CodeChunks $code) {
         return new TES4SubBranch($expression, $code);
     })->is('BranchStartToken', 'Value', 'NWL')->call(function ($branchStart, TES4Value $expression, $newLine) {
         return new TES4SubBranch($expression, null);
     });
     $this('BranchSubBranch+')->is('BranchSubBranch+', 'BranchSubBranch')->call(function (TES4SubBranchList $list, TES4SubBranch $branchSubBranchDeclaration) {
         $list->add($branchSubBranchDeclaration);
         return $list;
     })->is('BranchSubBranch')->call(function (TES4SubBranch $branchSubBranchDeclaration) {
         $list = new TES4SubBranchList();
         $list->add($branchSubBranchDeclaration);
         return $list;
     });
     $this('BranchSubBranch')->is('BranchElseifToken', 'Value', 'NWL', 'Code+')->call(function ($branchElseif, TES4Value $expression, $nwl, TES4CodeChunks $codeChunks) {
         return new TES4SubBranch($expression, $codeChunks);
     })->is('BranchElseifToken', 'Value', 'NWL')->call(function ($branchElseif, TES4Value $expression, $nwl) {
         return new TES4SubBranch($expression, null);
     });
     $this('MathOperator')->is('==')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     })->is('!=')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     })->is('>')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     })->is('<')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     })->is('<=')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     })->is('>=')->call(function (CommonToken $operator) {
         return TES4ArithmeticExpressionOperator::memberByValue($operator->getValue());
     });
     $this('LogicalOperator')->is('||')->call(function (CommonToken $operator) {
         return TES4LogicalExpressionOperator::memberByValue($operator->getValue());
     })->is('&&')->call(function (CommonToken $operator) {
         return TES4LogicalExpressionOperator::memberByValue($operator->getValue());
     });
     $this('Value')->is('Value', 'LogicalOperator', 'NotLogicalValue')->call(function (TES4Value $left, TES4LogicalExpressionOperator $operator, TES4Value $right) {
         return new TES4LogicalExpression($left, $operator, $right);
     })->is('NotLogicalValue');
     $this('NotLogicalValue')->is('NotLogicalValue', 'MathOperator', 'NotLogicalAndBinaryValue')->call(function (TES4Value $left, TES4ArithmeticExpressionOperator $operator, TES4Value $right) {
         return new TES4ArithmeticExpression($left, $operator, $right);
     })->is('NotLogicalAndBinaryValue');
     $this('NotLogicalAndBinaryValue')->is('NotLogicalAndBinaryValue', 'BinaryOperator', 'NonExpressionValue')->call(function (TES4Value $left, TES4BinaryExpressionOperator $operator, TES4Value $right) {
         return new TES4BinaryExpression($left, $operator, $right);
     })->is('NonExpressionValue');
     $this('NonExpressionValue')->is('ObjectAccess')->is('Function')->is('APIToken')->is('Primitive');
     $this('BinaryOperator')->is('+')->call(function (CommonToken $operator) {
         return TES4BinaryExpressionOperator::memberByValue($operator->getValue());
     })->is('-')->call(function (CommonToken $operator) {
         return TES4BinaryExpressionOperator::memberByValue($operator->getValue());
     })->is('*')->call(function (CommonToken $operator) {
         return TES4BinaryExpressionOperator::memberByValue($operator->getValue());
     })->is('/')->call(function (CommonToken $operator) {
         return TES4BinaryExpressionOperator::memberByValue($operator->getValue());
     });
     $this('ObjectAccess')->is('ObjectCall')->is('ObjectProperty');
     $this('ObjectCall')->is('APIToken', 'TokenDelimiter', 'Function')->call(function (TES4ApiToken $apiToken, $delimiter, TES4Function $function) {
         return new TES4ObjectCall($apiToken, $function);
     });
     $this('ObjectProperty')->is('APIToken', 'TokenDelimiter', 'APIToken')->call(function (TES4ApiToken $apiToken, $delimiter, TES4ApiToken $nextApiToken) {
         return new TES4ObjectProperty($apiToken, $nextApiToken);
     });
     $this('SetValue')->is('SetInitialization', 'ObjectProperty', 'Value')->call(function ($setInitialization, TES4ObjectProperty $objectProperty, TES4Value $expression) {
         return new TES4VariableAssignation($objectProperty, $expression);
     })->is('SetInitialization', 'APIToken', 'Value')->call(function ($setInitialization, TES4ApiToken $apiToken, TES4Value $expression) {
         return new TES4VariableAssignation($apiToken, $expression);
     });
     $this('Function')->is('FunctionCall', 'FunctionArguments')->call(function ($functionCall, $functionArguments) {
         return new TES4Function($functionCall, $functionArguments);
     })->is('FunctionCall')->call(function ($functionCall) {
         return new TES4Function($functionCall, new TES4FunctionArguments());
     });
     $this('FunctionCall')->is('FunctionCallToken')->call(function (CommonToken $functionCall) {
         return new TES4FunctionCall($functionCall->getValue());
     });
     $this('APIToken')->is('ReferenceToken')->call(function (CommonToken $token) {
         return new TES4ApiToken($token->getValue());
     });
     $this('FunctionArguments')->is('FunctionArguments', 'FunctionParameter')->call(function (TES4FunctionArguments $list, TES4Value $value) {
         $list->add($value);
         return $list;
     })->is('FunctionParameter')->call(function (TES4Value $value) {
         $list = new TES4FunctionArguments();
         $list->add($value);
         return $list;
     });
     $this('FunctionParameter')->is('ObjectAccess')->is('Function')->is('APIToken')->is('Primitive');
     $this('Primitive')->is('Float')->call(function (CommonToken $float) {
         $floatValue = $float->getValue();
         if (substr((string) $floatValue, 0, 1) == ".") {
             $floatValue = "0" . $floatValue;
         }
         return new TES4Float((double) $floatValue);
     })->is('Integer')->call(function (CommonToken $integer) {
         return new TES4Integer($integer->getValue());
     })->is('Boolean')->call(function (CommonToken $integer) {
         if (strtolower($integer->getValue()) == "true") {
             return new TES4Integer(1);
         }
         return new TES4Integer(0);
     })->is('String')->call(function (CommonToken $string) {
         return new TES4String($string->getValue());
     });
     $this('Return')->is('ReturnToken', 'NWL')->call(function ($returnToken, $nwl) {
         return new TES4Return();
     })->is('ReturnToken')->call(function ($returnToken) {
         return new TES4Return();
     });
 }
 private function convertArithmeticExpression(TES4Expression $expression, TES5CodeScope $codeScope, TES5GlobalScope $globalScope, TES5MultipleScriptsScope $multipleScriptsScope)
 {
     $sets = [[$expression->getLeftValue(), $expression->getRightValue()], [$expression->getRightValue(), $expression->getLeftValue()]];
     /**
      * Scenario 1 - Special functions converted on expression level
      * @var TES4Value[] $set
      */
     foreach ($sets as $set) {
         if (!$set[0] instanceof TES4Callable) {
             continue;
         }
         $function = $set[0]->getFunction();
         switch (strtolower($function->getFunctionCall()->getFunctionName())) {
             case "getweaponanimtype":
                 $calledOn = $this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope);
                 $leftValue = $this->createObjectCall($this->createObjectCall($calledOn, "GetEquippedWeapon", $multipleScriptsScope), "GetWeaponType", $multipleScriptsScope);
                 switch ((int) $set[1]->getData()) {
                     case 0:
                         $targetedWeaponTypes = [0];
                         break;
                     case 1:
                         $targetedWeaponTypes = [1, 2, 3, 4];
                         break;
                     case 2:
                         $targetedWeaponTypes = [5, 6, 8];
                         break;
                     case 3:
                         $targetedWeaponTypes = [7, 9];
                         break;
                     default:
                         throw new ConversionException("GetWeaponAnimType() - Unknown weapon type in expression");
                 }
                 $expressions = [];
                 foreach ($targetedWeaponTypes as $targetedWeaponType) {
                     $expressions[] = $this->expressionFactory->createArithmeticExpression($leftValue, TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Integer($targetedWeaponType));
                 }
                 $resultExpression = $expressions[0];
                 unset($expressions[0]);
                 while (!empty($expressions)) {
                     $resultExpression = $this->expressionFactory->createLogicalExpression($resultExpression, TES5LogicalExpressionOperator::OPERATOR_OR(), array_pop($expressions));
                 }
                 return $resultExpression;
             case "getdetected":
                 $inversedArgument = new TES5ObjectCallArguments();
                 $inversedArgument->add($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope));
                 $leftValue = $this->createObjectCall($this->createReadReference($function->getArguments()->getValue(0)->getData(), $globalScope, $multipleScriptsScope, $codeScope->getLocalScope()), "isDetectedBy", $multipleScriptsScope, $inversedArgument);
                 $rightValue = new TES5Integer((int) $set[1]->getData() == 0 ? 0 : 1);
                 $expression = $this->expressionFactory->createArithmeticExpression($leftValue, TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $rightValue);
                 return $expression;
             case "getdetectionlevel":
                 if (!$set[1]->hasFixedValue()) {
                     throw new ConversionException("Cannot convert getDetectionLevel calls with dynamic comparision");
                 }
                 $boolean = new TES5Bool($set[1]->getData() == 3);
                 //true only if the compared value was 3
                 $inversedArgument = new TES5ObjectCallArguments();
                 $inversedArgument->add($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope));
                 $expression = $this->expressionFactory->createArithmeticExpression($this->createObjectCall($this->createReadReference($function->getArguments()->getValue(0)->getData(), $globalScope, $multipleScriptsScope, $codeScope->getLocalScope()), "isDetectedBy", $multipleScriptsScope, $inversedArgument), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), $boolean);
                 return $expression;
             case "getcurrentaiprocedure":
                 if (!$set[1]->hasFixedValue()) {
                     throw new ConversionException("Cannot convert getCurrentAIProcedure() calls with dynamic comparision");
                 }
                 switch ((int) $set[1]->getData()) {
                     case 4:
                         //ref.getSleepState() == 3
                         $expression = $this->expressionFactory->createArithmeticExpression($this->createObjectCall($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope), "IsInDialogueWithPlayer", $multipleScriptsScope), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Bool((bool) $expression->getOperator() == TES4ArithmeticExpressionOperator::OPERATOR_EQUAL()));
                         return $expression;
                     case 8:
                         //ref.getSleepState() == 3
                         $expression = $this->expressionFactory->createArithmeticExpression($this->createObjectCall($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope), "getSleepState", $multipleScriptsScope), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Integer(3));
                         return $expression;
                     case 13:
                         //ref.getSleepState() == 3
                         $expression = $this->expressionFactory->createArithmeticExpression($this->createObjectCall($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope), "IsInCombat", $multipleScriptsScope), TES5ArithmeticExpressionOperator::OPERATOR_EQUAL(), new TES5Bool((bool) $expression->getOperator() == TES4ArithmeticExpressionOperator::OPERATOR_EQUAL()));
                         return $expression;
                     case 0:
                     case 7:
                     case 15:
                     case 17:
                         //@INCONSISTENCE Wander.. idk how to check it tbh. We return always true. Think about better representation
                         return new TES5Bool((bool) $expression->getOperator() == TES4ArithmeticExpressionOperator::OPERATOR_EQUAL());
                     default:
                         throw new ConversionException("Cannot convert GetCurrentAiProcedure - unknown TES4 procedure number arg " . (int) $set[1]->getData());
                 }
                 break;
             case "isidleplaying":
             case "getknockedstate":
             case "gettalkedtopc":
                 return new TES5Bool(true);
                 //This is so unimportant that i think it's not worth to find a good alternative and waste time.
             case "getsitting":
                 //WARNING: Needs to implement Horse sittings, too.
                 //SEE: http://www.gameskyrim.com/papyrus-isridinghorse-function-t255012.html
                 switch ((int) $set[1]->getData()) {
                     case 0:
                         $goTo = 0;
                         break;
                     case 1:
                     case 2:
                     case 11:
                     case 12:
                         $goTo = 2;
                         break;
                     case 3:
                     case 13:
                         $goTo = 3;
                         break;
                     case 4:
                     case 14:
                         $goTo = 4;
                         break;
                     default:
                         throw new ConversionException("GetSitting - unknown state found");
                 }
                 //ref.getSleepState() == 3
                 $expression = $this->expressionFactory->createArithmeticExpression($this->createObjectCall($this->createCalledOnReferenceOfCalledFunction($set[0], $codeScope, $globalScope, $multipleScriptsScope), "GetSitState", $multipleScriptsScope), TES5ArithmeticExpressionOperator::memberByValue($expression->getOperator()->value()), new TES5Integer($goTo));
                 return $expression;
         }
     }
     $leftValue = $this->createValue($expression->getLeftValue(), $codeScope, $globalScope, $multipleScriptsScope);
     $rightValue = $this->createValue($expression->getRightValue(), $codeScope, $globalScope, $multipleScriptsScope);
     $tes5sets = [[$leftValue, $rightValue], [$rightValue, $leftValue]];
     $objectReferenceType = TES5BasicType::T_FORM();
     //used just to make sure.
     $operator = TES5ArithmeticExpressionOperator::memberByValueWithDefault($expression->getOperator()->value(), null);
     /**
      * @var TES5Value[] $tes5set
      * Scenario 2: Comparision of ObjectReferences to integers ( quick formid check )
      */
     foreach ($tes5sets as $tes5set) {
         if ($tes5set[0]->getType() == $objectReferenceType || TES5InheritanceGraphAnalyzer::isExtending($tes5set[0]->getType(), $objectReferenceType)) {
             if ($tes5set[1]->getType() == TES5BasicType::T_INT()) {
                 $tes5set[0] = $this->createObjectCall($tes5set[0], "GetFormID", $multipleScriptsScope);
                 return $this->expressionFactory->createArithmeticExpression($tes5set[0], $operator, $tes5set[1]);
             }
         } else {
             if ($tes5set[0]->getType() == TES5TypeFactory::void()) {
                 if ($tes5set[1] instanceof TES5Integer || $tes5set[1] instanceof TES5Float) {
                     if ($tes5set[1]->getValue() == 0) {
                         return $this->expressionFactory->createArithmeticExpression($tes5set[0], $operator, new TES5None());
                     }
                 }
             }
         }
     }
     return $this->expressionFactory->createArithmeticExpression($leftValue, $operator, $rightValue);
 }
 public function getOperator()
 {
     return TES4ArithmeticExpressionOperator::OPERATOR_EQUAL();
 }