public override List <string> CodeGen(TranslationContext context) { var csContext = (CSTranslationContext)context; var csClass = csContext.CurrentClass; var codeResult = new List <string>(); var operand = GetOperand <VMSetToNextOperand>(); if (operand.SearchType == VMSetToNextSearchType.ClosestHouse) { return(Line($"_bResult = false; //set to next closest house not yet impl")); } codeResult.Add($"{{ //set to next ({operand.SearchType.ToString()})"); codeResult.Add($"var targetValue = {CSScopeMemory.GetExpression(csContext, operand.TargetOwner, operand.TargetData, false)};"); //re-evaluation of what this actually does: //tries to find the next object id (from the previous) that meets a specific condition. //the previous object id is supplied via the target variable // //we should take the first result with object id > targetValue. if (operand.SearchType == VMSetToNextSearchType.PartOfAMultipartTile) { codeResult.Add($"var objPointer = context.VM.GetObjectById(targetValue);"); codeResult.Add($"var result = VMSetToNext.MultitilePart(context, objPointer, targetValue);"); codeResult.Add($"_bResult = result != 0;"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "result", false)}"); codeResult.Add($"}}"); } else if (operand.SearchType == VMSetToNextSearchType.ObjectAdjacentToObjectInLocal) { codeResult.Add($"var objPointer = context.VM.GetObjectById(targetValue);"); codeResult.Add($"var result = VMSetToNext.AdjToLocal(context, objPointer, {operand.Local});"); codeResult.Add($"_bResult = result != null;"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "result.ObjectID", false)}"); codeResult.Add($"}}"); } else if (operand.SearchType == VMSetToNextSearchType.Career) { codeResult.Add($"var result = Content.Content.Get().Jobs.SetToNext(targetValue);"); codeResult.Add($"_bResult = result >= 0;"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "result", false)}"); codeResult.Add($"}}"); } else if (operand.SearchType == VMSetToNextSearchType.NeighborId) { codeResult.Add($"var result = Content.Content.Get().Neighborhood.SetToNext(targetValue);"); codeResult.Add($"_bResult = result >= 0;"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "result", false)};"); codeResult.Add($"}}"); } else if (operand.SearchType == VMSetToNextSearchType.NeighborOfType) { codeResult.Add($"var result = Content.Content.Get().Neighborhood.SetToNext(targetValue, {operand.GUID});"); codeResult.Add($"_bResult = result >= 0;"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "result", false)};"); codeResult.Add($"}}"); } else { //if we've cached the search type, use that instead of all objects switch (operand.SearchType) { case VMSetToNextSearchType.ObjectOnSameTile: codeResult.Add($"var objPointer = context.VM.GetObjectById(targetValue) ?? context.Caller;"); codeResult.Add($"var entities = context.VM.Context.ObjectQueries.GetObjectsAt(objPointer.Position);"); break; case VMSetToNextSearchType.Person: case VMSetToNextSearchType.FamilyMember: codeResult.Add($"var entities = context.VM.Context.ObjectQueries.Avatars;"); break; case VMSetToNextSearchType.ObjectOfType: codeResult.Add($"var entities = context.VM.Context.ObjectQueries.GetObjectsByGUID({operand.GUID});"); break; case VMSetToNextSearchType.ObjectWithCategoryEqualToSP0: csClass.UseParams = true; codeResult.Add($"var entities = context.VM.Context.ObjectQueries.GetObjectsByCategory(args[0]);"); break; case VMSetToNextSearchType.FSOObjectOfSemiGlobal: codeResult.Add($"var semiglobal = FSO.Content.Content.Get().WorldObjects.Get(operand.GUID).Resource.SemiGlobal;"); codeResult.Add($"if (sg != null) {{ "); codeResult.Add($"string sg_name = sg.Iff.Filename;"); codeResult.Add($"if (obj.SemiGlobal.Iff.Filename != null) entities = context.VM.Context.ObjectQueries.GetObjectsBySemiGlobal(sg_name);"); codeResult.Add($"else entities = null; }}"); codeResult.Add($"else entities = null;"); break; default: codeResult.Add($"var entities = context.VM.Entities;"); break; } codeResult.Add($"_bResult = false;"); codeResult.Add($"if (entities != null) {{"); bool loop = (operand.SearchType == VMSetToNextSearchType.ObjectOnSameTile); codeResult.Add($"var ind = (entities.Count < 4)?0:VM.FindNextIndexInObjList(entities, targetValue);"); codeResult.Add($"for (int i = ind; i < entities.Count; i++) {{"); codeResult.Add($"var tempObj = entities[i];"); string found = null; switch (operand.SearchType) { //manual search types case VMSetToNextSearchType.NonPerson: found = "tempObj is VMGameObject"; break; case VMSetToNextSearchType.FamilyMember: found = "(context.VM.TS1State.CurrentFamily?.FamilyGUIDs?.Contains(((VMAvatar)tempObj).Object.OBJ.GUID) ?? false)"; break; default: //set to next object, or cached search. break; } if (found != null) { codeResult.Add($"if (tempObj.ObjectID > targetValue && {found}) {{"); } else { codeResult.Add($"if (tempObj.ObjectID > targetValue) {{"); } codeResult.Add($"{CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "tempObj.ObjectID", false)}"); codeResult.Add($"_bResult = true; break;"); codeResult.Add($"}}"); //end if codeResult.Add($"}}"); //end loop if (loop) { codeResult.Add($"if (!_bResult) {{"); codeResult.Add($"VMEntity first = entities.FirstOrDefault();"); codeResult.Add($"_bResult = first != null && entities.Contains(objPointer);"); codeResult.Add($"if (_bResult) {CSScopeMemory.SetStatement(csContext, operand.TargetOwner, operand.TargetData, "=", "first.ObjectID", false)}"); codeResult.Add($"}}"); //loop around } codeResult.Add($"}}"); //end "entities != null" codeResult.Add($"}} //end set to next"); //end primitive scope } return(codeResult); }
public override List <string> CodeGen(TranslationContext context) { var csContext = (CSTranslationContext)context; var csClass = csContext.CurrentClass; var operand = GetOperand <VMExpressionOperand>(); var big = CSScopeMemory.IsBig(operand.LhsOwner) || CSScopeMemory.IsBig(operand.RhsOwner); string basicOp = null; string basicExpressionOp = null; switch (operand.Operator) { case VMExpressionOperator.AndEquals: basicOp = "&="; break; case VMExpressionOperator.Assign: basicOp = "="; break; case VMExpressionOperator.DivEquals: basicOp = "/="; break; case VMExpressionOperator.MinusEquals: basicOp = "-="; break; case VMExpressionOperator.ModEquals: basicOp = "%="; break; case VMExpressionOperator.MulEquals: basicOp = "*="; break; case VMExpressionOperator.PlusEquals: basicOp = "+="; break; case VMExpressionOperator.TS1OrEquals: basicOp = "|="; break; case VMExpressionOperator.TS1XorEquals: basicOp = "^="; break; case VMExpressionOperator.TS1AssignSqrtRHS: return(Line(CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "&=", $"(short)Math.Sqrt({CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)})", big))); case VMExpressionOperator.ClearFlag: case VMExpressionOperator.SetFlag: string flag; if (operand.RhsOwner == VMVariableScope.Literal) { int intFlag = (1 << (operand.RhsData - 1)); if (operand.Operator == VMExpressionOperator.ClearFlag) { intFlag = ~intFlag; } if (big) { flag = intFlag.ToString(); } else { flag = ((short)intFlag).ToString(); } } else { if (operand.Operator == VMExpressionOperator.ClearFlag) { flag = $"~(1 << ({CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)} - 1))"; } else { flag = $"(1 << ({CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)} - 1))"; } if (!CSScopeMemory.IsBig(operand.LhsOwner)) { flag = $"(short)({flag})"; } } if (operand.Operator == VMExpressionOperator.ClearFlag) { return(Line(CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "&=", flag, big))); } else { return(Line(CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "|=", flag, big))); } case VMExpressionOperator.Equals: basicExpressionOp = "=="; break; case VMExpressionOperator.GreaterThan: basicExpressionOp = ">"; break; case VMExpressionOperator.GreaterThanOrEqualTo: basicExpressionOp = ">="; break; case VMExpressionOperator.LessThan: basicExpressionOp = "<"; break; case VMExpressionOperator.LessThanOrEqualTo: basicExpressionOp = "<="; break; case VMExpressionOperator.NotEqualTo: basicExpressionOp = "!="; break; case VMExpressionOperator.IsFlagSet: var lExp = CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big); var rExp = $"(1 << ({CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)} - 1))"; return(Line($"({lExp} & {rExp}) > 0")); case VMExpressionOperator.DecAndGreaterThan: if (CSScopeMemory.ScopeMutable(operand.LhsOwner)) { return(Line($"--{CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big)} > {CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)}")); } else { return(new List <string>() { CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "-=", "1", big), $"_bResult = {CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big)} > {CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)};" }); } case VMExpressionOperator.IncAndLessThan: if (CSScopeMemory.ScopeMutable(operand.LhsOwner)) { return(Line($"++{CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big)} < {CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)}")); } else { return(new List <string>() { CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "+=", "1", big), $"_bResult = {CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big)} < {CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big)};" }); } } if (!VM.GlobTS1) { if (operand.Operator == VMExpressionOperator.Push) { string list; switch (operand.LhsOwner) { case VMVariableScope.MyList: list = "context.Caller.MyList"; break; case VMVariableScope.StackObjectList: list = "context.StackObject.MyList"; break; default: throw new Exception($"Invalid scope for list operation push! LHS: {operand.LhsOwner}"); } var rhsValue = CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, false); switch (operand.LhsData) { case 0: //front return(Line($"{list}.AddFirst({rhsValue});")); case 1: //back return(Line($"{list}.AddLast({rhsValue});")); case 2: throw new Exception("Unknown list push destination: " + operand.LhsData); } } else if (operand.Operator == VMExpressionOperator.Pop) { string list; switch (operand.RhsOwner) { case VMVariableScope.MyList: list = "context.Caller.MyList"; break; case VMVariableScope.StackObjectList: list = "context.StackObject.MyList"; break; default: throw new Exception($"Invalid scope for list operation pop! RHS: {operand.RhsOwner}"); } switch (operand.RhsData) { case 0: //front return(new List <string>() { "{ //list pop", $"var list = {list};", "_bResult = list.Count > 0;", "if (_bResult) {", CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "=", $"list.First.Value", false), $"{list}.RemoveFirst();", "}", "} //end list pop" }); case 1: //back return(new List <string>() { "{ //list pop", $"var list = {list};", "_bResult = list.Count > 0;", "if (_bResult) {", CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, "=", $"list.Last.Value", false), $"{list}.RemoveLast();", "}", "} //end list pop" }); default: throw new Exception("Unknown list pop source: " + operand.LhsData); } } } if (basicOp != null) { return(Line(CSScopeMemory.SetStatement(csContext, operand.LhsOwner, operand.LhsData, basicOp, CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big), big))); } if (basicExpressionOp != null) { var lExp = CSScopeMemory.GetExpression(csContext, operand.LhsOwner, operand.LhsData, big); var rExp = CSScopeMemory.GetExpression(csContext, operand.RhsOwner, operand.RhsData, big); return(Line($"{lExp} {basicExpressionOp} {rExp}")); } return(Line($"//unknown expression type {operand.Operator}")); }
private void OutputBlock(SimanticsBlock block, CSTranslationClass cls) { for (int i = 0; i < block.IBody.Count - 1; i++) { var inst = block.IBody[i]; var body = cls.Instructions[inst.Index]; switch (body.ReturnType) { case PrimitiveReturnType.SimanticsTrue: case PrimitiveReturnType.SimanticsTrueFalse: //truefalse result discarded, same destination WriteLines(body.Body, true); break; case PrimitiveReturnType.NativeStatementTrue: case PrimitiveReturnType.NativeStatementTrueFalse: //truefalse result discarded, same destination WriteLines(body.Body, false); break; case PrimitiveReturnType.NativeExpressionTrueFalse: //we have a problem... the expression needs to evaluate, but we don't do anything with the result. //put it in the boolean temp and ignore it. if (body.Body.Count == 1) { WriteLine($"_bResult = {body.Body.First()};"); } else { WriteLines(body.Body, true); } break; case PrimitiveReturnType.SimanticsSubroutine: //a subroutine that yields but doesn't branch. default: throw new Exception("Non-statement in the middle of a sequence (detected areas with no branching)?"); } } var lastInst = block.IBody[block.IBody.Count - 1]; var lastBody = cls.Instructions[lastInst.Index]; LastInstruction = block.LastInstructionIndex; string caseConst = null; if (block.BlockType == SimanticsBlockType.Switch || block.BlockType == SimanticsBlockType.SwitchCase || block.BlockType == SimanticsBlockType.SwitchLast) { caseConst = CSScopeMemory.GetConstant(Context, block.SwitchOperand.RhsOwner, block.SwitchOperand.RhsData); } switch (block.BlockType) { case SimanticsBlockType.InstructionSequence: case SimanticsBlockType.IfElse: //just set the instruction based on the value and return back to the while loop if (lastBody.ReturnType == PrimitiveReturnType.SimanticsSubroutine || lastInst.Yields) { UpdateInstruction(); if (lastBody.Body.Count > 1) { WriteLines(lastBody.Body, false); WriteLine($"return _sResult;"); } else { WriteLine($"return {lastBody.Body.First()};"); } break; } switch (lastBody.ReturnType) { case PrimitiveReturnType.NativeStatementTrueFalse: if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer) { goto case PrimitiveReturnType.NativeStatementTrue; } WriteLines(lastBody.Body, false); WriteLine("if (_bResult) "); OutputBinaryBranch(lastInst.Instruction, cls); break; case PrimitiveReturnType.NativeExpressionTrueFalse: if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer) { WriteLine($"_bResult = {lastBody.Body.First()}; //true and false do the same thing"); OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); } else { WriteLine($"if ({lastBody.Body.First()}) "); OutputBinaryBranch(lastInst.Instruction, cls); } break; case PrimitiveReturnType.SimanticsTrueFalse: if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer) { goto case PrimitiveReturnType.SimanticsTrue; } WriteLine($"if ({lastBody.Body.First()} == VMPrimitiveExitCode.GOTO_TRUE) "); OutputBinaryBranch(lastInst.Instruction, cls); break; case PrimitiveReturnType.SimanticsStatement: if (lastInst.Instruction.TruePointer == lastInst.Instruction.FalsePointer) { WriteLines(lastBody.Body, false); OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); } else { WriteLines(lastBody.Body, false); WriteLine($"if (_sResult == VMPrimitiveExitCode.GOTO_TRUE) "); OutputBinaryBranch(lastInst.Instruction, cls); } break; case PrimitiveReturnType.NativeStatementTrue: WriteLines(lastBody.Body, false); OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); break; case PrimitiveReturnType.SimanticsTrue: WriteLines(lastBody.Body, true); OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); break; } if (block.Parent == cls.Structure.RootBlock && cls.HasGlobalSwitch) { WriteLine("break;"); } break; case SimanticsBlockType.Switch: string switchLhs = CSScopeMemory.GetExpression(Context, block.SwitchOperand.LhsOwner, block.SwitchOperand.LhsData, true); WriteLine($"switch ({switchLhs}) "); WriteLine("{"); IndentLevel++; WriteLine($"case {caseConst}:"); IndentLevel++; var set = new HashSet <string> { caseConst }; cls.SwitchPreviousCases[block] = set; OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); WriteLine($"break;"); IndentLevel--; OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls); break; case SimanticsBlockType.SwitchCase: var cset = cls.SwitchPreviousCases[FindSwitchBlockStart(block)]; if (cset.Contains(caseConst)) { WriteLine($"// case {caseConst} duplicated! skipped block at {lastInst.Instruction.FalsePointer}"); } else { cset.Add(caseConst); WriteLine($"case {caseConst}:"); IndentLevel++; OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); WriteLine($"break;"); IndentLevel--; } OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls); break; case SimanticsBlockType.SwitchLast: var lset = cls.SwitchPreviousCases[FindSwitchBlockStart(block)]; if (lset.Contains(caseConst)) { WriteLine($"// case {caseConst} duplicated! skipped block at {lastInst.Instruction.FalsePointer}"); } else { lset.Add(caseConst); WriteLine($"case {caseConst}:"); IndentLevel++; OutputReturnBlockOrJump(lastInst.Instruction.TruePointer, cls); WriteLine($"break;"); IndentLevel--; } WriteLine($"default:"); IndentLevel++; OutputReturnBlockOrJump(lastInst.Instruction.FalsePointer, cls); WriteLine($"break;"); IndentLevel--; IndentLevel--; WriteLine("}"); if (FindSwitchBlockStart(block).Parent == cls.Structure.RootBlock && cls.HasGlobalSwitch) { WriteLine("break;"); } break; default: throw new Exception($"Block type {block.BlockType.ToString()} not yet implemented."); } //our last instruction }