public TES5CodeChunkCollection createCodeChunk(ITES4CodeChunk chunk, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4Branch branch = chunk as TES4Branch; if (branch != null) { return(TES5BranchFactory.CreateCodeChunk(branch, codeScope, globalScope, multipleScriptsScope, this, valueFactory)); } TES4Return returnChunk = chunk as TES4Return; if (returnChunk != null) { return(this.returnFactory.CreateCodeChunkCollection(codeScope.LocalScope.FunctionScope, globalScope, multipleScriptsScope)); } ITES4Callable callable = chunk as ITES4Callable; if (callable != null) { return(this.valueFactory.CreateCodeChunks(callable, codeScope, globalScope, multipleScriptsScope)); } TES4VariableAssignation assignation = chunk as TES4VariableAssignation; if (assignation != null) { return(this.variableAssignationConversionFactory.CreateCodeChunk(assignation, codeScope, globalScope, multipleScriptsScope)); } TES4VariableDeclarationList declarationList = chunk as TES4VariableDeclarationList; if (declarationList != null) { TES5LocalVariableListFactory.createCodeChunk(declarationList, codeScope); return(null); } throw new ConversionException("Cannot convert a chunk: " + chunk.GetType().FullName); }
/* * Add initial code to the blocks and return the scope in which conversion should occur * Sometimes, we want to add a bit of code before the converted code, or want to encapsulate whole converted code * with a branch or so - this is a place to do it. * * * * Scope in which we want for conversion to happen */ public TES5CodeScope AddInitialCode(TES5GlobalScope globalScope, TES5EventCodeBlock eventCodeBlock) { if (eventCodeBlock.BlockName == "OnUpdate") { if (globalScope.ScriptHeader.ScriptType.NativeType == TES5BasicType.T_QUEST) { //Even though we"d like this script to not do anything at this time, it seems like sometimes condition races, so we"re putting it into a loop anyways but with early return bailout TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "IsRunning", new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(false)), eventCodeBlock.CodeScope.LocalScope); if (!globalScope.QuestHasOnUpdateRegisterForSingleUpdate)//WTM: Change: Added { //If quest has RegisterForSingleUpdate already, preventing adding it again. //Previously, RegisterForSingleUpdate was being called multiple times in OnUpdate because of how CombineRepeatedEventCodeBlockNames splits multiple OnUpdate methods into separate functions. //See TES4tutorialscript.psc for an example. globalScope.QuestHasOnUpdateRegisterForSingleUpdate = true; branch.MainBranch.CodeScope.AddChunk(this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope)); } branch.MainBranch.CodeScope.AddChunk(new TES5Return()); eventCodeBlock.AddChunk(branch); return(eventCodeBlock.CodeScope); } /*else if (globalScope.ScriptHeader.BasicScriptType == TES5BasicType.T_OBJECTREFERENCE) * { * TES5LocalScope localScope = eventCodeBlock.CodeScope.LocalScope; * TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToPlayer(), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments())), localScope); * eventCodeBlock.AddChunk(branch); * return branch.MainBranch.CodeScope; * }*/ } return(eventCodeBlock.CodeScope); }
/* * Add initial code to the blocks and return the scope in which conversion should occur * Sometimes, we want to add a bit of code before the converted code, or want to encapsulate whole converted code * with a branch or so - this is a place to do it. * * * * Scope in which we want for conversion to happen */ public TES5CodeScope AddInitialCode(TES5MultipleScriptsScope multipleScriptsScope, TES5GlobalScope globalScope, TES5EventCodeBlock eventCodeBlock) { switch (eventCodeBlock.BlockName) { case "OnUpdate": { if (globalScope.ScriptHeader.BasicScriptType == TES5BasicType.T_QUEST) { TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "IsRunning", multipleScriptsScope, new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(false)), eventCodeBlock.CodeScope.LocalScope); //Even though we"d like this script to not do anything at this time, it seems like sometimes condition races, so we"re putting it into a loop anyways but with early return bailout branch.MainBranch.CodeScope.AddChunk(this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope, multipleScriptsScope)); branch.MainBranch.CodeScope.AddChunk(new TES5Return()); eventCodeBlock.AddChunk(branch); return(eventCodeBlock.CodeScope); } /*else if (globalScope.ScriptHeader.BasicScriptType== TES5BasicType.T_OBJECTREFERENCE) * { * TES5LocalScope localScope = eventCodeBlock.CodeScope.LocalScope; * TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToPlayer(), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments())), localScope); * eventCodeBlock.AddChunk(branch); * return branch.MainBranch.CodeScope; * }*/ else { return(eventCodeBlock.CodeScope); } } default: { return(eventCodeBlock.CodeScope); } } }
public TES5CodeChunkCollection CreateCodeChunk(ITES4CodeChunk chunk, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4Branch?branch = chunk as TES4Branch; if (branch != null) { return(TES5BranchFactory.CreateCodeChunk(branch, codeScope, globalScope, multipleScriptsScope, this, valueFactory)); } TES4Return?returnChunk = chunk as TES4Return; if (returnChunk != null) { return(this.returnFactory.CreateCodeChunkCollection(codeScope.LocalScope.FunctionScope, globalScope)); } ITES4Callable?callable = chunk as ITES4Callable; if (callable != null) { return(this.valueFactory.CreateCodeChunks(callable, codeScope, globalScope, multipleScriptsScope)); } TES4VariableAssignation?assignation = chunk as TES4VariableAssignation; if (assignation != null) { return(this.variableAssignationConversionFactory.CreateCodeChunk(assignation, codeScope, globalScope, multipleScriptsScope)); } //WTM: Change: The below code doesn't seem to be reached. It also returns null, and I don't want this method to return a nullable reference type if not necessary. //TES4VariableDeclarationList? declarationList = chunk as TES4VariableDeclarationList; //if (declarationList != null) { TES5LocalVariableListFactory.CreateCodeChunk(declarationList, codeScope); return null; } throw new ConversionException("Cannot convert a chunk: " + chunk.GetType().FullName); }
public TES5CodeChunkCollection CreateCodeChunk(TES4VariableAssignation chunk, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5CodeChunkCollection codeChunkCollection = new TES5CodeChunkCollection(); string referenceName = chunk.Reference.StringValue; ITES5Referencer reference = this.referenceFactory.CreateReference(referenceName, globalScope, multipleScriptsScope, codeScope.LocalScope); ITES5Value value = this.valueFactory.CreateValue(chunk.Value, codeScope, globalScope, multipleScriptsScope); if (reference.TES5Type == TES5BasicType.T_GLOBALVARIABLE) { //if the reference is in reality a global variable, we will need to convert it by creating a Reference.SetValue(value); call //Object call creation TES5ObjectCallArguments objectCallArguments = new TES5ObjectCallArguments() { value }; TES5ObjectCall objectCall = this.objectCallFactory.CreateObjectCall(reference, "SetValue", objectCallArguments); codeChunkCollection.Add(objectCall); } else { if (reference.ReferencesTo == null) { throw new NullableException(nameof(reference.ReferencesTo)); } if (!reference.ReferencesTo.TES5Type.IsPrimitive && value.TES5Type.IsPrimitive) { //Hacky! TES5IntegerOrFloat?valueNumber = value as TES5IntegerOrFloat; if (valueNumber != null && valueNumber.ConvertedIntValue == 0) { value = new TES5None(); } } TES5VariableAssignation assignation = TES5VariableAssignationFactory.CreateAssignation(reference, value); this.typeInferencer.InferenceObjectByAssignation(reference, value); codeChunkCollection.Add(assignation); //post analysis. //Todo - rethink the prefix here ITES5Referencer?referencerValue = value as ITES5Referencer; if (referencerValue != null && referencerValue.Name == TES5Property.AddPropertyNameSuffix(TES5ReferenceFactory.MESSAGEBOX_VARIABLE_CONST)) { /* * Create block: * variable = this.TES4_MESSAGEBOX_RESULT; ; assignation * if(variable != -1) ; branch, expression * this.TES4_MESSAGEBOX_RESULT = -1; ; reassignation * endIf */ TES5Integer negativeOne = new TES5Integer(-1); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(reference, TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL, negativeOne); TES5VariableAssignation reassignation = TES5VariableAssignationFactory.CreateAssignation(referencerValue, negativeOne); TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(expression, codeScope.LocalScope); branch.MainBranch.CodeScope.AddChunk(reassignation); codeChunkCollection.Add(branch); } } return(codeChunkCollection); }