예제 #1
0
        /*public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
         * {
         *  TES5LocalScope localScope = codeScope.LocalScope;
         *  ITES5Referencer timerReference = this.referenceFactory.CreateTimerReadReference(globalScope, multipleScriptsScope, localScope);
         *  ITES5Referencer localTimeReference = this.referenceFactory.CreateGSPLocalTimerReadReference(globalScope, multipleScriptsScope, localScope);
         *  TES5ObjectCallArguments methodArguments = new TES5ObjectCallArguments() { calledOn };
         *  return this.objectCallFactory.CreateObjectCall(timerReference, "getSecondsPassed", multipleScriptsScope, methodArguments);
         * }*/
        public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            const string  newFunctionName = "GetSecondsPassed";
            TES5BasicType returnType      = TES5BasicType.T_FLOAT;

            /*globalScope.AddFunctionIfNotExists(newFunctionName, () =>
             * {
             *  const string getCurrentRealTime = "GetCurrentRealTime";
             *  TES5FunctionScope newFunctionScope = new TES5FunctionScope(newFunctionName);
             *  TES5LocalScope newLocalScope = TES5LocalScopeFactory.CreateRootScope(newFunctionScope);
             *  TES5CodeScope newCodeScope = TES5CodeScopeFactory.CreateCodeScope(newLocalScope);
             *  TES5GlobalVariable calledYet = new TES5GlobalVariable("GSPCalledYet");
             *  TES5GlobalVariable lastSeconds = new TES5GlobalVariable("GSPLastSeconds");
             *  TES5SubBranch ifNotCalledYet = TES5BranchFactory.CreateSubBranch(new TES5ComparisonExpression(calledYet, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(false)), newLocalScope);
             *  ifNotCalledYet.CodeScope.AddChunk(TES5VariableAssignationFactory.CreateAssignation(calledYet, new TES5Bool(true)));
             *  ifNotCalledYet.CodeScope.AddChunk(TES5VariableAssignationFactory.CreateAssignation(lastSeconds, this.objectCallFactory.CreateObjectCall(TES5StaticReference.Utility, getCurrentRealTime, multipleScriptsScope)));
             *  ifNotCalledYet.CodeScope.AddChunk(new TES5Return(new TES5Float(0)));
             *  TES5CodeScope ifCalledYetCodeScope = TES5CodeScopeFactory.CreateCodeScopeRoot(newFunctionScope);
             *  ifCalledYetCodeScope.AddChunk(new TES5Return(new TES5ArithmeticExpression(this.objectCallFactory.CreateObjectCall(TES5StaticReference.Utility, getCurrentRealTime, multipleScriptsScope), TES5ArithmeticExpressionOperator.OPERATOR_SUBSTRACT, lastSeconds)));
             *  TES5ElseSubBranch ifCalledYet = new TES5ElseSubBranch(ifCalledYetCodeScope);
             *  TES5Branch branch = new TES5Branch(ifNotCalledYet, elseBranch: ifCalledYet);
             *  TES5FunctionCodeBlock getSecondsPassedLocalFunction = new TES5FunctionCodeBlock(newFunctionScope, newCodeScope, returnType, true);
             *  getSecondsPassedLocalFunction.AddChunk(branch);
             *  return getSecondsPassedLocalFunction;
             * });*/
            return(this.objectCallFactory.CreateObjectCall(calledOn, newFunctionName, multipleScriptsScope));
        }
예제 #2
0
 public BuildScopeCommandQFOrTIF(TES5PropertyFactory propertyFactory, FragmentsReferencesBuilder fragmentsReferencesBuilder, TES5BasicType scriptType, string scriptNamePrefix, TES5FragmentType fragmentType)
 {
     this.propertyFactory            = propertyFactory;
     this.fragmentsReferencesBuilder = fragmentsReferencesBuilder;
     this.scriptType       = scriptType;
     this.scriptNamePrefix = scriptNamePrefix;
     this.fragmentType     = fragmentType;
 }
예제 #3
0
        public void AddPlayerRefPropertyIfNotExists()
        {
            const string  name       = TES5PlayerReference.PlayerRefName;
            TES5BasicType playerType = TES5PlayerReference.TES5TypeStatic;
            TES5Property  property   = TES5PropertyFactory.ConstructWithTES4FormID(name, playerType, name, TES5PlayerReference.FormID);

            AddPropertyIfNotExists(property);
        }
예제 #4
0
 public TES5LocalVariable(string nameWithSuffix, TES5BasicType type, TES5LocalVariableParameterMeaning[] meanings = null)
     : base(nameWithSuffix, type)
 {
     if (meanings == null)
     {
         meanings = new TES5LocalVariableParameterMeaning[] { };
     }
     this.Meanings = meanings;
 }
        private static ITES5Type?MemberByValue(string typeName)
        {
            if (typeName == TES5VoidType.OriginalNameConst)
            {
                return(TES5VoidType.Instance);
            }
            TES5BasicType?basicTypeFromName = TES5BasicType.GetFirstOrNullCaseInsensitive(typeName);

            return(basicTypeFromName);
        }
예제 #6
0
 public TES5SignatureParameter(string nameWithSuffix, TES5BasicType type, bool hasFixedDeclaration, TES5LocalVariableParameterMeaning[]?meanings = null)
 {
     Name                     = nameWithSuffix;
     TES5Type                 = type;
     declarationType          = type;
     this.hasFixedDeclaration = hasFixedDeclaration;
     if (meanings == null)
     {
         meanings = new TES5LocalVariableParameterMeaning[] { };
     }
     this.Meanings = meanings;
 }
        private static ITES5Type MemberByValue(string typeName, Func <TES5BasicType> basicTypeFunc)
        {
            ITES5Type?typeByName = MemberByValue(typeName);

            if (typeByName != null)
            {
                return(typeByName);
            }
            TES5BasicType customTypeBase = basicTypeFunc();

            return(new TES5CustomType(typeName, TES4Prefix, customTypeBase));
        }
        private static TES5BasicType?GetCommonBaseTES5Type(IReadOnlyList <TES4Record> tes4Records)
        {
            if (!tes4Records.Any())
            {
                return(null);
            }
            TES5BasicType[] tes5Types = tes4Records.Select(r =>
            {
                TES5BasicType basicType = TypeMapper.GetTES5BasicType(r.RecordType);
                return(basicType);
            }).ToArray();
            TES5BasicType commonBaseType = TES5InheritanceGraphAnalyzer.GetCommonBaseType(tes5Types);

            return(commonBaseType);
        }
예제 #9
0
        private void InferenceTypeOfMethodArgument(TES5ObjectCall objectCall, ITES5Value argument, int argumentIndex)
        {
            ITES5Type calledOnType = objectCall.AccessedObject.TES5Type.NativeType;

            /*
             * Get the argument type according to TES5Inheritance graph.
             */
            TES5BasicType argumentTargetType = TES5InheritanceGraphAnalyzer.FindTypeByMethodParameter(calledOnType.NativeType, objectCall.FunctionName, argumentIndex);

            if (argument.TES5Type != argumentTargetType)
            {
                /*
                 * 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? :)
                 */
                ITES5Referencer?referencerArgument = argument as ITES5Referencer;
                if (referencerArgument != null && TES5InheritanceGraphAnalyzer.IsExtending(argumentTargetType, argument.TES5Type.NativeType))
                { //HACKY!
                    if (referencerArgument.ReferencesTo == null)
                    {
                        throw new NullableException(nameof(referencerArgument.ReferencesTo));
                    }
                    this.InferenceType(referencerArgument.ReferencesTo, argumentTargetType);
                }
                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.TES5Type == TES5BasicType.T_FLOAT)
                    {
                        TES5Castable?argumentCastable = argument as TES5Castable;
                        if (argumentCastable != null)
                        { //HACKY! When we"ll clean up this interface, it will dissapear :)
                            argumentCastable.ManualCastTo = argumentTargetType;
                        }
                    }
                    else if (
                        !TES5InheritanceGraphAnalyzer.IsExtending(argument.TES5Type, argumentTargetType) &&
                        !TES5InheritanceGraphAnalyzer.IsNumberTypeOrBoolAndInt(argument.TES5Type, argumentTargetType) &&
                        !(argument is TES5None && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(argumentTargetType, TES5None.TES5TypeStatic)))
                    {
                        throw new ConversionTypeMismatchException("Argument type mismatch at " + objectCall.FunctionName + " index " + argumentIndex + ".  Expected " + argumentTargetType.Name + ".  Found " + argument.TES5Type.OriginalName + " : " + argument.TES5Type.NativeType.OriginalName + ".");
                    }
                }
            }
        }
예제 #10
0
        private void InferenceTypeOfCalledObject(TES5ObjectCall objectCall)
        {
            /*
             * Check if we have something to inference inside the code, not some static class or method call return
             */
            if (objectCall.AccessedObject.ReferencesTo == null)
            {
                return;
            }
            ITES5Type inferencableType = objectCall.AccessedObject.TES5Type.NativeType;
            //this is not "exactly" nice solution, but its enough. For now.
            TES5BasicType inferenceType = TES5InheritanceGraphAnalyzer.FindTypeByMethod(objectCall, esmAnalyzer);

            if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(inferencableType, inferenceType))
            {
                return; //We already have the good type.
            }
            this.InferenceType(objectCall.AccessedObject.ReferencesTo, inferenceType);
        }
예제 #11
0
 /*
  * Try to inference variable"s type with type.
  *
  *
  *  Needed for proxifying the properties to other scripts
  *  - Will return true if inferencing succeeded, false otherwise.
  * @throws ConversionTypeMismatchException
  */
 private void InferenceType(ITES5VariableOrProperty variable, TES5BasicType type)
 {
     if (!TES5InheritanceGraphAnalyzer.IsTypeOrExtendsTypeOrIsNumberType(type, variable.TES5Type.NativeType, false))
     {
         if (TES5InheritanceGraphAnalyzer.IsExtending(variable.TES5Type.NativeType, type))
         {
             return;
         }
         throw new ConversionTypeMismatchException("Could not extend " + variable.TES5Type.NativeType.Value + " to " + type.Value + ".");
     }
     if (variable.TES5Type.AllowInference)
     {
         variable.TES5Type = type;
     }
     else if (variable.TES5Type.AllowNativeTypeInference)
     {
         variable.TES5Type.NativeType = type;
     }
     else
     {
         throw new ConversionTypeMismatchException(variable.Name + " (" + variable.TES5DeclaredType.OriginalName + " : " + variable.TES5DeclaredType.NativeType.Name + ") could not be inferenced to a " + type.Name + " because inference was not allowed.");
     }
 }
        /*
         * @param memberByValue string Type to be created.
         * @param basicType TES5BasicType You might override the basic type for this custom type created.
         */
        public static ITES5Type MemberByValue(string memberByValue, ITES5Type basicType = null)
        {
            if (memberByValue == null)
            {
                throw new ArgumentNullException(nameof(memberByValue));
            }
            if (memberByValue == "void")
            {
                return(new TES5VoidType());
            }
            TES5BasicType tes5BasicType = TES5BasicType.GetFirstOrNull(PHPFunction.UCWords(memberByValue));

            if (tes5BasicType != null)
            {
                return(tes5BasicType);
            }
            //Ugly - todo: REFACTOR THIS TO NON-STATIC CLASS AND MOVE THIS TO DI
            if (basicType == null)
            {
                ESMAnalyzer analyzer = ESMAnalyzer._instance();
                basicType = analyzer.GetScriptType(memberByValue);
            }
            return(new TES5CustomType(memberByValue, TES4Prefix, basicType));
        }
예제 #13
0
        private static void InferEventBlockContainingType(string functionBlockName, TES5GlobalScope globalScope)
        {
            TES5BasicType[]? allowedTypes = eventNameToTypes[functionBlockName];//null indicates that any type is allowed
            if (allowedTypes == null || allowedTypes.Any(t => TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(globalScope.ScriptHeader.ScriptType, t)))
            {
                return;
            }
            if (allowedTypes.Length == 1)
            {
                TES5BasicType singleAllowedType = allowedTypes[0];
                if (globalScope.ScriptHeader.ScriptType.AllowNativeTypeInference && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(singleAllowedType, globalScope.ScriptHeader.ScriptType.NativeType))
                {
                    if (globalScope.ScriptHeader.ScriptType.NativeType != singleAllowedType)
                    {
                        globalScope.ScriptHeader.SetNativeType(singleAllowedType);
                    }
                    return;
                }
            }
            ITES5Type basicScriptType = globalScope.ScriptHeader.ScriptType.NativeType;
            bool      expected        = functionBlockName == "OnHit" && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(basicScriptType, TES5BasicType.T_ACTIVEMAGICEFFECT);

            throw new ConversionTypeMismatchException("Event " + functionBlockName + " is not allowed on " + globalScope.ScriptHeader.ScriptType.Value + " (" + basicScriptType.Value + ").", expected: expected);
        }
 public ITES5Referencer CreateReference(string referenceName, TES5BasicType typeForNewProperty, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope)
 {
     return(CreateReference(referenceName, typeForNewProperty, null, globalScope, multipleScriptsScope, localScope));
 }
예제 #15
0
        private ITES5Value ConvertComparisonExpression(ITES4BinaryExpression expression, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            Tuple <ITES4Value, ITES4Value>[] tes4ValueTuples = new Tuple <ITES4Value, ITES4Value>[]
            {
                new Tuple <ITES4Value, ITES4Value>(expression.LeftValue, expression.RightValue),
                new Tuple <ITES4Value, ITES4Value>(expression.RightValue, expression.LeftValue)
            };

            /*
             * Scenario 1 - Special functions converted on expression level
             */
            foreach (Tuple <ITES4Value, ITES4Value> tes4ValueTuple in tes4ValueTuples)
            {
                ITES4Callable?valueTupleItem1 = tes4ValueTuple.Item1 as ITES4Callable;
                if (valueTupleItem1 == null)
                {
                    continue;
                }

                TES4Function function = valueTupleItem1.Function;

                switch (function.FunctionCall.FunctionName.ToLower())
                {
                case "getweaponanimtype":
                {
                    ITES5Referencer calledOn = this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope);
                    TES5ObjectCall  equippedWeaponLeftValue = this.objectCallFactory.CreateObjectCall(this.objectCallFactory.CreateObjectCall(calledOn, "GetEquippedWeapon"), "GetWeaponType");

                    int[] targetedWeaponTypes;
                    switch ((int)tes4ValueTuple.Item2.Data)
                    {
                    case 0:
                    {
                        targetedWeaponTypes = new int[] { 0 };
                        break;
                    }

                    case 1:
                    {
                        targetedWeaponTypes = new int[] { 1, 2, 3, 4 };
                        break;
                    }

                    case 2:
                    {
                        targetedWeaponTypes = new int[] { 5, 6, 8 };
                        break;
                    }

                    case 3:
                    {
                        targetedWeaponTypes = new int[] { 7, 9 };
                        break;
                    }

                    default:
                    {
                        throw new ConversionException("GetWeaponAnimType() - Unknown weapon type in expression");
                    }
                    }

                    List <TES5ComparisonExpression> expressions = new List <TES5ComparisonExpression>();

                    foreach (var targetedWeaponType in targetedWeaponTypes)
                    {
                        expressions.Add(TES5ExpressionFactory.CreateComparisonExpression(equippedWeaponLeftValue, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(targetedWeaponType)));
                    }

                    ITES5Expression resultExpression = expressions[0];

                    expressions.RemoveAt(0);

                    while (expressions.Any())
                    {
                        resultExpression = TES5ExpressionFactory.CreateLogicalExpression(resultExpression, TES5LogicalExpressionOperator.OPERATOR_OR, expressions.Last());
                        expressions.RemoveAt(expressions.Count - 1);
                    }

                    return(resultExpression);
                }

                case "getdetected":
                {
                    TES5ObjectCallArguments inversedArgument = new TES5ObjectCallArguments()
                    {
                        this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope)
                    };
                    TES5ObjectCall getDetectedLeftValue  = this.objectCallFactory.CreateObjectCall(this.referenceFactory.CreateReadReference(function.Arguments[0].StringValue, globalScope, multipleScriptsScope, codeScope.LocalScope), "isDetectedBy", inversedArgument);
                    TES5Integer    getDetectedRightValue = new TES5Integer(((int)tes4ValueTuple.Item2.Data == 0) ? 0 : 1);
                    return(TES5ExpressionFactory.CreateComparisonExpression(getDetectedLeftValue, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, getDetectedRightValue));
                }

                case "getdetectionlevel":
                {
                    if (!tes4ValueTuple.Item2.HasFixedValue)
                    {
                        throw new ConversionException("Cannot convert getDetectionLevel calls with dynamic comparision");
                    }

                    TES5Bool tes5Bool = new TES5Bool(((int)tes4ValueTuple.Item2.Data) == 3);         //true only if the compared value was 3

                    TES5ObjectCallArguments inversedArgument = new TES5ObjectCallArguments()
                    {
                        this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope)
                    };

                    return(TES5ExpressionFactory.CreateComparisonExpression
                           (
                               this.objectCallFactory.CreateObjectCall(this.referenceFactory.CreateReadReference(function.Arguments[0].StringValue, globalScope, multipleScriptsScope, codeScope.LocalScope), "isDetectedBy", inversedArgument),
                               TES5ComparisonExpressionOperator.OPERATOR_EQUAL,
                               tes5Bool
                           ));
                }

                case "getcurrentaiprocedure":
                {
                    if (!tes4ValueTuple.Item2.HasFixedValue)
                    {
                        throw new ConversionException("Cannot convert getCurrentAIProcedure() calls with dynamic comparision");
                    }

                    switch ((int)tes4ValueTuple.Item2.Data)
                    {
                    case 4:
                    {
                        return(TES5ExpressionFactory.CreateComparisonExpression(
                                   this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "IsInDialogueWithPlayer"),
                                   TES5ComparisonExpressionOperator.OPERATOR_EQUAL,
                                   new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL)          //cast to true if the original op was ==, false otherwise.
                                   ));
                    }

                    case 8:
                    {
                        //ref.getSleepState() == 3
                        return(TES5ExpressionFactory.CreateComparisonExpression(
                                   this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "getSleepState"),
                                   TES5ComparisonExpressionOperator.OPERATOR_EQUAL,
                                   new TES5Integer(3)          //SLEEPSTATE_SLEEP
                                   ));
                    }

                    case 13:
                    {
                        return(TES5ExpressionFactory.CreateComparisonExpression(
                                   this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "IsInCombat"),
                                   TES5ComparisonExpressionOperator.OPERATOR_EQUAL,
                                   new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL)          //cast to true if the original op was ==, false otherwise.
                                   ));
                    }

                    case 0:            //Travel
                    case 7:            //Wander
                    case 15:           //Pursue
                    case 17:           //Done
                    {
                        //@INCONSISTENCE idk how to check it tbh. We return always true. Think about better representation
                        return(new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL));
                    }

                    default:
                    {
                        throw new ConversionException("Cannot convert GetCurrentAiProcedure - unknown TES4 procedure number arg " + ((int)tes4ValueTuple.Item2.Data).ToString());
                    }
                    }
                }

                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
                    int goTo;
                    switch ((int)tes4ValueTuple.Item2.Data)
                    {
                    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
                    return(TES5ExpressionFactory.CreateComparisonExpression
                           (
                               this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "GetSitState"),
                               TES5ComparisonExpressionOperator.GetFirst(expression.Operator.Name),
                               new TES5Integer(goTo)
                           ));
                }
                }
            }

            ITES5Value leftValue  = this.CreateValue(expression.LeftValue, codeScope, globalScope, multipleScriptsScope);
            ITES5Value rightValue = this.CreateValue(expression.RightValue, codeScope, globalScope, multipleScriptsScope);

            Tuple <ITES5Value, ITES5Value>[] tes5ValueTuples = new Tuple <ITES5Value, ITES5Value>[]
            {
                new Tuple <ITES5Value, ITES5Value>(leftValue, rightValue),
                new Tuple <ITES5Value, ITES5Value>(rightValue, leftValue)
            };

            TES5BasicType objectReferenceType   = TES5BasicType.T_FORM; //used just to make sure.
            TES5ComparisonExpressionOperator op = TES5ComparisonExpressionOperator.GetFirst(expression.Operator.Name);

            /*
             * Scenario 2: Comparision of ObjectReferences to integers ( quick formid check )
             */
            bool flipOperator = false;

            foreach (var valueTuple in tes5ValueTuples)
            {
                TES5ComparisonExpressionOperator newOp = !flipOperator ? op : op.Flip();
                if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type, objectReferenceType) || TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type.NativeType, objectReferenceType))
                {
                    if (valueTuple.Item2.TES5Type == TES5BasicType.T_INT)
                    {
                        //Perhaps we should allow to try to cast upwards for primitives, .asPrimitive() or similar
                        //In case we do know at compile time that we"re comparing against zero, then we can assume
                        //we can compare against None, which allows us not call GetFormID() on most probably None object
                        TES5Integer tes5SetItem2Integer = (TES5Integer)valueTuple.Item2;
                        if (tes5SetItem2Integer.IntValue == 0)
                        {
                            newOp = op == TES5ComparisonExpressionOperator.OPERATOR_EQUAL ? op : TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL;
                            return(TES5ExpressionFactory.CreateComparisonExpression(valueTuple.Item1, newOp, new TES5None()));
                        }
                        else
                        {
                            ITES5Referencer callable        = (ITES5Referencer)valueTuple.Item1;
                            TES5ObjectCall  tes5setNewItem1 = this.objectCallFactory.CreateObjectCall(callable, "GetFormID");
                            return(TES5ExpressionFactory.CreateComparisonExpression(tes5setNewItem1, newOp, valueTuple.Item2));
                        }
                    }
                }
                else if (valueTuple.Item1.TES5Type.OriginalName == TES5VoidType.OriginalNameConst)
                {
#if PHP_COMPAT
                    TES5IntegerOrFloat tes5SetItem2Number = tes5set.Item2 as TES5IntegerOrFloat;
                    if (tes5SetItem2Number != null && tes5SetItem2Number.ConvertedIntValue == 0)
                    {
                        return(TES5ExpressionFactory.createArithmeticExpression(tes5set.Item1, newOp, new TES5None()));
                    }
#else
                    throw new ConversionException("Type was void.");//This shouldn't happen anymore.
#endif
                }
                if (!TES5InheritanceGraphAnalyzer.IsTypeOrExtendsTypeOrIsNumberType(valueTuple.Item1.TES5Type, valueTuple.Item2.TES5Type, true))//WTM:  Change:  Added entire if branch
                {
                    if (valueTuple.Item1.TES5Type.NativeType == TES5BasicType.T_QUEST && valueTuple.Item2.TES5Type == TES5BasicType.T_INT)
                    {
                        TES5ObjectCall getStage = this.objectCallFactory.CreateObjectCall((ITES5Referencer)valueTuple.Item1, "GetStage");
                        return(TES5ExpressionFactory.CreateComparisonExpression(getStage, newOp, valueTuple.Item2));
                    }
                    if (valueTuple.Item1.TES5Type == TES5BasicType.T_BOOL && valueTuple.Item2.TES5Type == TES5BasicType.T_INT)
                    {
                        int item2Value = ((TES5Integer)valueTuple.Item2).IntValue;
                        if (item2Value != 0 && item2Value != 1)
                        {
                            throw new ConversionException("Unexpected Value:  " + item2Value.ToString());
                        }
                        ITES5Value newItem2 = new TES5Bool(item2Value == 1);
                        newOp = op == TES5ComparisonExpressionOperator.OPERATOR_EQUAL ? op : TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL;
                        return(TES5ExpressionFactory.CreateComparisonExpression(valueTuple.Item1, newOp, newItem2));
                    }
                    if (valueTuple.Item1.TES5Type == TES5BasicType.T_ACTOR && valueTuple.Item2.TES5Type == TES5BasicType.T_ACTORBASE)
                    {
                        return(TES5ExpressionFactory.CreateComparisonExpression(objectCallFactory.CreateGetActorBase((TES5ObjectCall)valueTuple.Item1), newOp, valueTuple.Item2));
                    }
                    //WTM:  Change:  Added for se08barriertriggerscript
                    if (newOp == TES5ComparisonExpressionOperator.OPERATOR_EQUAL && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type, TES5BasicType.T_FORM) && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item2.TES5Type, TES5BasicType.T_FORM))
                    {
                        TES5Reference reference1 = (TES5Reference)valueTuple.Item1;
                        TES5Reference reference2 = (TES5Reference)valueTuple.Item2;
                        reference1.ManualCastTo = TES5BasicType.T_FORM;
                        reference2.ManualCastTo = TES5BasicType.T_FORM;
                        return(TES5ExpressionFactory.CreateComparisonExpression(reference1, newOp, reference2));
                    }
                    throw new ConversionException("Type could not be converted.");
                }
                TES5ComparisonExpression?containsCall = ConvertGetItemCountCallToContainsItemCall(valueTuple.Item1, op, valueTuple.Item2); //WTM:  Change:  Added
                if (containsCall != null)
                {
                    return(containsCall);
                }
                flipOperator = true;
            }
            return(TES5ExpressionFactory.CreateComparisonExpression(leftValue, op, rightValue));
        }
 /*
  * @param memberByValue string Type to be created.
  * @param basicType TES5BasicType You might override the basic type for this custom type created.
  */
 public static ITES5Type MemberByValue(string typeName, TES5BasicType basicType)
 {
     return(MemberByValue(typeName, () => basicType));
 }
 public TES5LocalVariable(string nameWithSuffix, TES5BasicType type)
 {
     Name     = nameWithSuffix;
     TES5Type = type;
 }
 private TES5ArrayType(TES5BasicType elementType)
     : base(elementType.Name + "[]")
 {
 }