コード例 #1
0
 private function inferenceTypeOfMethodArguments(TES5ObjectCall $objectCall, TES5MultipleScriptsScope $multipleScriptsScope)
 {
     /**
      * Inference the arguments
      */
     $arguments = $objectCall->getArguments();
     $argumentNumber = 0;
     $calledOnType = $objectCall->getAccessedObject()->getType()->getNativeType();
     foreach ($arguments->getArguments() as $argument) {
         /**
          * Get the argument type according to TES5Inheritance graph.
          */
         $argumentTargetType = TES5InheritanceGraphAnalyzer::findTypeByMethodParameter($calledOnType, $objectCall->getFunctionName(), $argumentNumber);
         if ($argument->getType() == $argumentTargetType) {
             ++$argumentNumber;
             continue;
             //Same type matched. We do not need to do anything :)
         }
         /**
          * todo - maybe we should move getReferencesTo() to TES5Value and make all of the rest TES5Values just have null references as they do not reference anything? :)
          */
         if (TES5InheritanceGraphAnalyzer::isExtending($argumentTargetType, $argument->getType()->getNativeType()) && $argument instanceof TES5Referencer) {
             //HACKY!
             $this->inferenceType($argument->getReferencesTo(), $argumentTargetType, $multipleScriptsScope);
         } else {
             //So there's one , one special case where we actually have to cast a var from one to another even though they are not ,,inheriting" from themselves, because they are primitives.
             //Scenario: there's an T_INT argument, and we feed it with a T_FLOAT variable reference. It won't work :(
             //We need to cast it on call level ( NOT inference it ) to make it work and not break other possible scenarios ( more specifically, when a float would be inferenced to int and there's a
             //float assigment somewhere in the code )
             if ($argumentTargetType == TES5BasicType::T_INT() && $argument->getType() == TES5BasicType::T_FLOAT()) {
                 if ($argument instanceof TES5Reference) {
                     //HACKY! When we'll clean up this interface, it will dissapear :)
                     $argument->setManualCastTo(TES5BasicType::T_INT());
                 }
             }
         }
         ++$argumentNumber;
     }
 }
 /**
  * @param TES5ObjectCall $objectCall
  * @return mixed|TES5Type
  * @throws \Ormin\OBSLexicalParser\TES5\Exception\ConversionException
  *
  */
 public static function findTypeByMethod(TES5ObjectCall $objectCall)
 {
     $methodName = $objectCall->getFunctionName();
     $possibleMatches = [];
     foreach (self::$callReturns as $type => $methods) {
         foreach ($methods as $method => $functionData) {
             if (strtolower($method) == strtolower($methodName)) {
                 $possibleMatches[] = TES5TypeFactory::memberByValue($type);
             }
         }
     }
     $calledOn = $objectCall->getAccessedObject()->getReferencesTo();
     $extendingMatches = [];
     $actualType = $calledOn->getPropertyType()->getNativeType();
     /**
      * @var TES5Type[] $possibleMatches
      */
     foreach ($possibleMatches as $possibleMatch) {
         if ($possibleMatch == $actualType) {
             return $possibleMatch;
             //if the possible match matches the actual basic type, it means that it surely IS one of those.
         }
         //Ok, so are those matches somehow connected at all?
         if (TES5InheritanceGraphAnalyzer::isExtending($possibleMatch, $actualType) || TES5InheritanceGraphAnalyzer::isExtending($actualType, $possibleMatch)) {
             $extendingMatches[] = $possibleMatch;
         }
     }
     switch (count($extendingMatches)) {
         case 0:
             $concatTypes = [];
             foreach ($possibleMatches as $possibleMatch) {
                 $concatTypes[] = $possibleMatch->value();
             }
             throw new ConversionException("Cannot find any possible type for method " . $methodName . ", trying to extend " . $actualType->value() . " with following types: " . implode(', ', $concatTypes));
         case 1:
             return current($extendingMatches);
         default:
             //We analyze the property name and check inside the ESM analyzer.
             $formType = ESMAnalyzer::instance()->getFormTypeByEDID($calledOn->getReferenceEdid());
             if (!in_array($formType, $extendingMatches)) {
                 throw new ConversionException("ESM <-> Inheritance Graph conflict, ESM returned " . $formType->value() . ", which is not present in possible matches from inheritance graph");
             }
             return $formType;
     }
 }