IEnumerable <LazyString> MethodHeaderActions(MethodInfo method) { var firstActions = new LazyString[] { () => $"Abort If (Not({FunctionCondition(method)()}));", () => "Wait(0, Abort When False);", SetGlobal(Variables.Temporary, JumpOffsetStack.GetLastElement(0)), }; LazyString actionCountStr = () => { var instruction = method.Instructions.First(); var nextInChain = FindNextSkipChain(method, instruction); var actionCount = nextInChain == null ? 99999999 : CalcNumActionsToSkip(method, nextInChain) - CalcNumActionsToSkip(method, instruction); return(actionCount.ToString()); }; var jumpToTarget = new[] { SetGlobal(Variables.Temporary2, GetGlobal(Variables.Temporary)), SetGlobal(Variables.Temporary, Subtract(GetGlobal(Variables.Temporary), Add(actionCountStr, () => "4"))), SkipIf( NotEqual(GetGlobal(Variables.Temporary2), () => "0"), Min(GetGlobal(Variables.Temporary2), Add(actionCountStr, () => "1"))), }; return(firstActions.Concat(JumpOffsetStack.Pop(1)).Concat(jumpToTarget)); }
void ConvertMethodToRule(StringWriter ruleWriter, MethodInfo method) { var writer = new StringWriter(); var writeLine = (Action <object>)(str => writer.WriteLine($" {str}")); writeLine("// Header"); foreach (var line in MethodHeaderActions(method)) { writeLine(line()); } writeLine(""); var actionCount = 0; writeLine("// Body"); foreach (var instr in method.Instructions) { var numActions = ToWorkshopActions(method, instr).Count(); writeLine($" // [{actionCount}] {instr}"); actionCount += numActions; foreach (var line in ToWorkshopActions(method, instr)) { writeLine(line()); } } var workshopEventAttr = GetCustomAttribute <WorkshopEventAttribute>(method); if (workshopEventAttr != null) { Debug.Assert(method.Definition.Parameters.Count == 3, $"Event function {method.Definition.Name} must have the following parameter list: (Player eventPlayer, float eventDamage, bool eventWasCriticalHit)"); ruleWriter.WriteLine(GenerateRule( $"Event Task for: {method.Definition.Name}", GetCodeName(typeof(Workshop.Event).GetMember(workshopEventAttr.m_event.ToString()).First()), $"", PushTaskForEventMethod(method)())); } ruleWriter.WriteLine(GenerateRule( method.Definition.Name, "Ongoing - Global;", $"{FunctionCondition(method)()} == True;", writer.ToString())); }
private bool CheckAddCondition(FunctionCondition condition) { if (condition is FunctionCondition) { if (condition is FreeCondition) { freeCondition = (FreeCondition)condition; return(true); } } return(true); }
IEnumerable <LazyString> TaskRunnerActions(MethodDefinition updateMethod) { yield return(() => $"Abort If (Not({FunctionCondition(0)()}));"); yield return(() => "Wait(0, Ignore Condition);"); foreach (var action in TaskQueue.PopTaskTo(Variables.Temporary)) { yield return(action); } var functionId = ArraySubscript(GetGlobal(Variables.Temporary), 0); // if there's no function, call Update (if it exists, otherwise just loop) var updateCallActions = updateMethod == null ? new LazyString[0] : Impl_Call_CustomMethod_Direct(updateMethod); yield return(SkipIf(NotEqual(functionId, () => "0"), () => (updateCallActions.Count() + 1).ToString())); foreach (var action in updateCallActions) { yield return(action); } yield return(() => "Loop;"); // push event params onto stack before calling foreach (var action in ParameterStack.Push(ArraySlice(GetGlobal(Variables.Temporary), () => "1", () => "3"))) { yield return(action); } foreach (var action in Impl_Call_CustomMethod_Direct(functionId, m_maxNumLocalVariables)) { yield return(action); } yield return(() => "Loop;"); }
public void BuiltinTest() { Production prod = new Production(); prod.Label = "find-stack-of-two-blocks-to-the-left-of-a-red-block"; Variable x = new Variable("x"); Variable y = new Variable("y"); Variable z = new Variable("z"); prod.AddConditionToLHS(new PositiveCondition("C1", x, "on", y)); prod.AddConditionToLHS(new PositiveCondition("C2", y, "left of", z)); prod.AddConditionToLHS(new PositiveCondition("C3", z, "color", "red")); FunctionCondition funCond = new FunctionCondition("F4", x, new FuncTerm("funcEquals", new funcEquals()), new StringTerm("B1")); funCond.ConditionType = ConditionType.Function; prod.AddConditionToLHS(funCond); prod.AddConditionToRHS(new AssertCondition("C4", x, "is", "on top")); Rete rete = new Rete(); rete.AddProduction(prod); NetworkPrinter printer = new NetworkPrinter(); rete.DummyTopNode.Accept(printer); using (StreamWriter writer = new StreamWriter(@"C:\Temp\TestBuiltin.log", false)) { writer.Write(printer.Output); writer.WriteLine(); writer.WriteLine(); writer.WriteLine(); writer.WriteLine(); writer.WriteLine("-----------------------------------------------"); writer.Flush(); } WME wme1 = new WME("W1"); wme1.Fields[0] = "B1"; wme1.Fields[1] = "on"; wme1.Fields[2] = "B2"; rete.AddWME(wme1); WME wme2 = new WME("W2"); wme2.Fields[0] = "B1"; wme2.Fields[1] = "on"; wme2.Fields[2] = "B3"; rete.AddWME(wme2); WME wme3 = new WME("W3"); wme3.Fields[0] = "B1"; wme3.Fields[1] = "color"; wme3.Fields[2] = "red"; rete.AddWME(wme3); WME wme4 = new WME("W4"); wme4.Fields[0] = "B2"; wme4.Fields[1] = "on"; wme4.Fields[2] = "table"; rete.AddWME(wme4); WME wme5 = new WME("W5"); wme5.Fields[0] = "B2"; wme5.Fields[1] = "left of"; wme5.Fields[2] = "B3"; rete.AddWME(wme5); WME wme6 = new WME("W6"); wme6.Fields[0] = "B2"; wme6.Fields[1] = "color"; wme6.Fields[2] = "blue"; rete.AddWME(wme6); WME wme7 = new WME("W7"); wme7.Fields[0] = "B3"; wme7.Fields[1] = "left of"; wme7.Fields[2] = "B4"; rete.AddWME(wme7); WME wme8 = new WME("W8"); wme8.Fields[0] = "B3"; wme8.Fields[1] = "on"; wme8.Fields[2] = "table"; rete.AddWME(wme8); WME wme9 = new WME("W9"); wme9.Fields[0] = "B3"; wme9.Fields[1] = "color"; wme9.Fields[2] = "red"; rete.AddWME(wme9); printer = new NetworkPrinter(); rete.DummyTopNode.Accept(printer); using (StreamWriter writer = new StreamWriter(@"C:\Temp\TestBuiltin.log", true)) { writer.WriteLine(); writer.WriteLine(); writer.WriteLine(); writer.WriteLine(); writer.Write(printer.Output); writer.Flush(); } Assert.IsTrue(prod.InferredFacts.Count == 1, "Wrong number of conclusions"); Assert.IsTrue(rete.WorkingMemory.Count == 9, "Bad"); }
public string TranspileToRules(string source) { var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(Path.Combine( Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll")), MetadataReference.CreateFromFile("C:\\projects\\IL2Workshop\\WorkshopStub\\bin\\Debug\\netcoreapp3.0\\WorkshopStub.dll"), }; var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release); var syntaxTree = SyntaxFactory.ParseSyntaxTree(source); var compilation = CSharpCompilation.Create( "AsmBuild", new[] { syntaxTree }, references, options); var semanticModel = compilation.GetSemanticModel(syntaxTree); var substituter = new MethodSubstituter(semanticModel, m_generatedMethodToWorkshopCode); var newRoot = substituter.Visit(syntaxTree.GetRoot()); var newTree = SyntaxFactory.SyntaxTree(newRoot); var generatedClassTree = substituter.GetGeneratedClass(); compilation = compilation.RemoveAllSyntaxTrees(); compilation = compilation.AddSyntaxTrees(newTree, generatedClassTree); Console.WriteLine(generatedClassTree.ToString()); var result = compilation.Emit("AsmBuild.dll"); if (!result.Success) { foreach (var diag in result.Diagnostics) { Console.WriteLine(diag); } throw new System.Exception("Fail!"); } var module = ModuleDefinition.ReadModule("AsmBuild.dll"); var mainClass = module.GetType("MainClass"); var methods = mainClass.Methods; GenerateFunctionIds(methods); m_maxNumLocalVariables = methods.Max(m => m.Body.Variables.Count); var ruleWriter = new StringWriter(); var staticConstructor = methods.SingleOrDefault(m => m.Name == ".cctor"); var mainMethod = methods.Single(m => m.Name == "Main"); var entryPointActionsText = EntryPointActions(staticConstructor, mainMethod).Select(a => $" {a()}").ListToString("\n"); ruleWriter.WriteLine(GenerateRule("EntryPoint", "Ongoing - Global;", "", entryPointActionsText)); var updateMethod = methods.SingleOrDefault(m => m.Name == "Update"); var taskRunnerActionsText = TaskRunnerActions(updateMethod).Select(a => $" {a()}").ListToString("\n"); ruleWriter.WriteLine(GenerateRule("TaskRunner", "Ongoing - Global;", $"{FunctionCondition(0)()} == True;", taskRunnerActionsText)); foreach (var method in methods) { var methodInfo = new MethodInfo { Definition = method, Instructions = method.Body.Instructions.ToList(), }; InsertSkipChainInstructions(methodInfo); // TODO: add analyzer to prevent storing un-storable variables on stack (Array, Player, etc) Console.WriteLine(method); foreach (var instr in methodInfo.Instructions) { Console.WriteLine(instr); } Console.WriteLine(); ConvertMethodToRule(ruleWriter, methodInfo); } return(ruleWriter.ToString()); }
public void BasicOverrideTest() { Agenda agenda = new Agenda(); agenda.ConflictResolutionStrategy = new SalienceResolver(); Production prod = new Production(); prod.Label = "Gold Customer"; Variable customer = new Variable("customer"); Variable purchases = new Variable("purchases"); prod.AddConditionToLHS(new PositiveCondition("C1", customer, "purchases", purchases)); FunctionCondition gt = new FunctionCondition("C2", purchases, new FuncTerm("funcGreaterThan", new funcGreaterThan()), 10); gt.ConditionType = ConditionType.Function; prod.AddConditionToLHS(gt); AssertCondition rhs = new AssertCondition("R1", customer, "is", "gold"); rhs.ConditionType = ConditionType.Assert; prod.AddConditionToRHS(rhs); agenda.AddProduction(prod); Production prod1 = new Production(); prod1.Label = "Platinum Customer"; prod1.AddConditionToLHS(new PositiveCondition("C1", customer, "purchases", purchases)); FunctionCondition gt1 = new FunctionCondition("C2", purchases, new FuncTerm("funcGreaterThan", new funcGreaterThan()), 20); gt1.ConditionType = ConditionType.Function; prod1.AddConditionToLHS(gt1); AssertCondition rhs1 = new AssertCondition("R1", customer, "is", "Platinum"); rhs.ConditionType = ConditionType.Assert; prod1.AddConditionToRHS(rhs1); agenda.AddProduction(prod1); Override me = new Override(); me.Winner = "Platinum Customer"; me.Loser = "Gold Customer"; agenda.AddOverride(me); WME wme1 = new WME("W1"); wme1.Fields[0] = "joe"; wme1.Fields[1] = "purchases"; wme1.Fields[2] = "1"; agenda.AddFact(wme1); WME wme2 = new WME("W2"); wme2.Fields[0] = "ted"; wme2.Fields[1] = "purchases"; wme2.Fields[2] = "10"; agenda.AddFact(wme2); WME wme3 = new WME("W3"); wme3.Fields[0] = "ed"; wme3.Fields[1] = "purchases"; wme3.Fields[2] = "11"; agenda.AddFact(wme3); WME wme4 = new WME("W4"); wme4.Fields[0] = "phil"; wme4.Fields[1] = "purchases"; wme4.Fields[2] = "18"; agenda.AddFact(wme4); WME wme5 = new WME("W5"); wme5.Fields[0] = "mary"; wme5.Fields[1] = "purchases"; wme5.Fields[2] = "22"; agenda.AddFact(wme5); WME wme6 = new WME("W6"); wme6.Fields[0] = "jane"; wme6.Fields[1] = "purchases"; wme6.Fields[2] = "25"; agenda.AddFact(wme6); WME wme7 = new WME("W7"); wme7.Fields[0] = "fred"; wme7.Fields[1] = "purchases"; wme7.Fields[2] = "50"; agenda.AddFact(wme7); WME wme8 = new WME("W8"); wme8.Fields[0] = "harry"; wme8.Fields[1] = "purchases"; wme8.Fields[2] = "55"; agenda.AddFact(wme8); WME wme9 = new WME("W9"); wme9.Fields[0] = "jon"; wme9.Fields[1] = "purchases"; wme9.Fields[2] = "99"; agenda.AddFact(wme9); agenda.Run(); agenda.VisualizeNetworkToFile(@"C:\Temp\BasicOverrideTest.log", false); Assert.IsTrue(agenda.ActivatedRuleCount == 1, "Rule did not fire."); Assert.IsTrue(agenda.InferredFacts.Count == 5, "Bad"); }