public static bool ContainsMemoryAccessor(ExpressionBase expression) { var funcCall = expression as FunctionCallExpression; if (funcCall != null) { var func = AchievementScriptInterpreter.GetGlobalScope().GetFunction(funcCall.FunctionName.Name); if (func is MemoryAccessorFunction) { return(true); } foreach (var parameter in funcCall.Parameters) { if (ContainsMemoryAccessor(parameter)) { return(true); } } return(false); } var leftRightExpression = expression as LeftRightExpressionBase; if (leftRightExpression != null) { return(ContainsMemoryAccessor(leftRightExpression.Left) || ContainsMemoryAccessor(leftRightExpression.Right)); } return(false); }
public void TestGetConditionString(string input, string expected) { ExpressionBase error; InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.Context = new TriggerBuilderContext(); var expression = Parse(input); ExpressionBase processed; Assert.That(expression.ReplaceVariables(scope, out processed), Is.True); var result = TriggerBuilderContext.GetConditionString(processed, scope, out error); if (error != null) { Assert.That(((ParseErrorExpression)error).InnermostError.Message, Is.EqualTo(expected)); } else { Assert.That(error, Is.Null); Assert.That(result, Is.EqualTo(expected)); } }
private List <Requirement> Evaluate(string input, string expectedError = null) { var requirements = new List <Requirement>(); var funcDef = new RepeatedFunction(); var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); Assert.That(expression, Is.InstanceOf <FunctionCallExpression>()); var funcCall = (FunctionCallExpression)expression; ExpressionBase error; var scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error); var context = new TriggerBuilderContext { Trigger = requirements }; scope.Context = context; ExpressionBase evaluated; Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True); if (expectedError == null) { Assert.That(funcDef.BuildTrigger(context, scope, funcCall), Is.Null); } else { var parseError = funcDef.BuildTrigger(context, scope, funcCall); Assert.That(parseError, Is.Not.Null); Assert.That(parseError.Message, Is.EqualTo(expectedError)); } return(requirements); }
public void TestSizes() { var scope = AchievementScriptInterpreter.GetGlobalScope(); var sizes = new Dictionary <string, FieldSize> { { "byte(0x1234)", FieldSize.Byte }, { "bit0(0x1234)", FieldSize.Bit0 }, { "bit1(0x1234)", FieldSize.Bit1 }, { "bit2(0x1234)", FieldSize.Bit2 }, { "bit3(0x1234)", FieldSize.Bit3 }, { "bit4(0x1234)", FieldSize.Bit4 }, { "bit5(0x1234)", FieldSize.Bit5 }, { "bit6(0x1234)", FieldSize.Bit6 }, { "bit7(0x1234)", FieldSize.Bit7 }, { "low4(0x1234)", FieldSize.LowNibble }, { "high4(0x1234)", FieldSize.HighNibble }, { "word(0x1234)", FieldSize.Word }, { "dword(0x1234)", FieldSize.DWord }, { "bit(0,0x1234)", FieldSize.Bit0 }, { "bit(1,0x1234)", FieldSize.Bit1 }, { "bit(2,0x1234)", FieldSize.Bit2 }, { "bit(3,0x1234)", FieldSize.Bit3 }, { "bit(4,0x1234)", FieldSize.Bit4 }, { "bit(5,0x1234)", FieldSize.Bit5 }, { "bit(6,0x1234)", FieldSize.Bit6 }, { "bit(7,0x1234)", FieldSize.Bit7 }, }; foreach (var kvp in sizes) { var requirements = Evaluate(kvp.Key); Assert.That(requirements.Count, Is.EqualTo(1), kvp.Key); Assert.That(requirements[0].Left.Size, Is.EqualTo(kvp.Value), kvp.Key); } }
public void TestPopulateEditorOrder() { var vmGame = new GameViewModelHarness(1234, "Title"); var interpreter = new AchievementScriptInterpreter(); AddGeneratedLeaderboard(interpreter, 17, "Leaderboard1"); AddGeneratedAchievement(interpreter, 65, "Test1"); AddGeneratedAchievement(interpreter, 68, "A Test2"); AddGeneratedAchievement(interpreter, 61, "Test3"); AddGeneratedRichPresence(interpreter); // list is sorted by the order they were generated, not by id or title // rich presence always appears before achievements, leaderboards always appear after vmGame.PopulateEditorList(interpreter); Assert.That(vmGame.Editors.Count(), Is.EqualTo(6)); Assert.That(vmGame.Editors.ElementAt(0).Title, Is.EqualTo("Script")); Assert.That(vmGame.Editors.ElementAt(1).Title, Is.EqualTo("Rich Presence")); Assert.That(vmGame.Editors.ElementAt(2).Title, Is.EqualTo("Test1")); Assert.That(vmGame.Editors.ElementAt(3).Title, Is.EqualTo("A Test2")); Assert.That(vmGame.Editors.ElementAt(4).Title, Is.EqualTo("Test3")); Assert.That(vmGame.Editors.ElementAt(5).Title, Is.EqualTo("Leaderboard1")); // despite having ids, these don't get categorized as Core or Unofficial without reading from file Assert.That(vmGame.GeneratedAchievementCount, Is.EqualTo(3)); Assert.That(vmGame.CoreAchievementCount, Is.EqualTo(0)); Assert.That(vmGame.CoreAchievementPoints, Is.EqualTo(0)); Assert.That(vmGame.UnofficialAchievementCount, Is.EqualTo(0)); Assert.That(vmGame.UnofficialAchievementPoints, Is.EqualTo(0)); Assert.That(vmGame.LocalAchievementCount, Is.EqualTo(0)); Assert.That(vmGame.LocalAchievementPoints, Is.EqualTo(0)); }
public void TestFunctionReference() { string input = "once(f)"; var requirements = new List <Requirement>(); var funcDef = new OnceFunction(); var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); Assert.That(expression, Is.InstanceOf <FunctionCallExpression>()); var funcCall = (FunctionCallExpression)expression; var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.AssignVariable(new VariableExpression("f"), new FunctionReferenceExpression("f2")); ExpressionBase error; scope = funcCall.GetParameters(funcDef, scope, out error); var context = new TriggerBuilderContext { Trigger = requirements }; scope.Context = context; ExpressionBase evaluated; Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True); funcCall = evaluated as FunctionCallExpression; var parseError = funcDef.BuildTrigger(context, scope, funcCall); Assert.That(parseError, Is.Not.Null); Assert.That(parseError.InnermostError.Message, Is.EqualTo("Function used like a variable")); }
internal void PopulateEditorList(AchievementScriptInterpreter interpreter) { var editors = new List <ViewerViewModelBase>(); if (Script != null) { editors.Add(Script); } var selectedEditor = (SelectedEditor != null) ? SelectedEditor.Title : null; if (interpreter != null) { GeneratedAchievementCount = interpreter.Achievements.Count(); editors.Capacity += GeneratedAchievementCount; if (!String.IsNullOrEmpty(interpreter.RichPresence)) { var richPresenceViewModel = new RichPresenceViewModel(this, interpreter.RichPresence); if (richPresenceViewModel.Lines.Any()) { richPresenceViewModel.SourceLine = interpreter.RichPresenceLine; editors.Add(richPresenceViewModel); } } foreach (var achievement in interpreter.Achievements) { var achievementViewModel = new AchievementViewModel(this); achievementViewModel.Generated.Asset = achievement; editors.Add(achievementViewModel); } foreach (var leaderboard in interpreter.Leaderboards) { var leaderboardViewModel = new LeaderboardViewModel(this); leaderboardViewModel.Generated.Asset = leaderboard; editors.Add(leaderboardViewModel); } } else { GeneratedAchievementCount = 0; } if (_publishedAchievements.Count > 0 || _publishedLeaderboards.Count > 0) { MergePublished(editors); } if (_localAssets != null) { MergeLocal(editors); } UpdateTemporaryIds(editors); SelectedEditor = editors.FirstOrDefault(e => e.Title == selectedEditor); Editors = editors; }
public void TestTriggerWhenDefinition() { var funcDef = AchievementScriptInterpreter.GetGlobalScope().GetFunction("trigger_when"); Assert.That(funcDef, Is.Not.Null); Assert.That(funcDef.Name.Name, Is.EqualTo("trigger_when")); Assert.That(funcDef.Parameters.Count, Is.EqualTo(1)); Assert.That(funcDef.Parameters.ElementAt(0).Name, Is.EqualTo("comparison")); }
public void TestDefinition() { var def = AchievementScriptInterpreter.GetGlobalScope().GetFunction("disable_when"); Assert.That(def, Is.Not.Null); Assert.That(def.Name.Name, Is.EqualTo("disable_when")); Assert.That(def.Parameters.Count, Is.EqualTo(2)); Assert.That(def.Parameters.ElementAt(0).Name, Is.EqualTo("comparison")); Assert.That(def.Parameters.ElementAt(1).Name, Is.EqualTo("until")); }
public void TestIsTrueMemoryAccessorFunction() { var expr = new FunctionCallExpression("byte", new ExpressionBase[] { new IntegerConstantExpression(0x1234) }); var scope = AchievementScriptInterpreter.GetGlobalScope(); ParseErrorExpression error; Assert.That(expr.IsTrue(scope, out error), Is.Null); Assert.That(error, Is.Null); }
public void TestIsTrueAlwaysFalseFunction() { var expr = AlwaysFalseFunction.CreateAlwaysFalseFunctionCall(); var scope = AchievementScriptInterpreter.GetGlobalScope(); ParseErrorExpression error; Assert.That(expr.IsTrue(scope, out error), Is.False); Assert.That(error, Is.Null); }
private Achievement AddGeneratedAchievement(AchievementScriptInterpreter interpreter, int id, string name) { var achievement = new Achievement { Id = id, Title = name, Description = name }; ((List <Achievement>)interpreter.Achievements).Add(achievement); return(achievement); }
public void TestGetValueString(string input, string expected) { ExpressionBase error; InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.Context = new TriggerBuilderContext(); var expression = Parse(input); var result = TriggerBuilderContext.GetValueString(expression, scope, out error); Assert.That(error, Is.Null); Assert.That(result, Is.EqualTo(expected)); }
public void TestIsTrue(string input, bool?expected) { var tokenizer = Tokenizer.CreateTokenizer(input); var expr = ExpressionBase.Parse(new PositionalTokenizer(tokenizer)); var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.Context = new RATools.Parser.TriggerBuilderContext(); ParseErrorExpression error; Assert.That(expr.IsTrue(scope, out error), Is.EqualTo(expected)); Assert.That(error, Is.Null); }
public void TestIsTrueUserFunctionReturningBoolean() { var userFunc = Parse("function u() => always_true()"); var expr = new FunctionCallExpression("u", new ExpressionBase[0]); var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.AddFunction(userFunc); ParseErrorExpression error; Assert.That(expr.IsTrue(scope, out error), Is.True); Assert.That(error, Is.Null); }
public void TestIsTrue(string input, bool expected) { var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input)); var expression = ExpressionBase.Parse(tokenizer); Assert.That(expression, Is.InstanceOf <ConditionalExpression>()); ParseErrorExpression error; var scope = AchievementScriptInterpreter.GetGlobalScope(); var result = expression.IsTrue(scope, out error); Assert.That(error, Is.Null); Assert.That(result, Is.EqualTo(expected)); }
private static string Evaluate(string input) { var script = "achievement(\"title\", \"desc\", 5,\n" + input + "\n)"; var tokenizer = Tokenizer.CreateTokenizer(script); var parser = new AchievementScriptInterpreter(); if (parser.Run(tokenizer)) { var achievement = parser.Achievements.First(); var builder = new AchievementBuilder(achievement); return(builder.RequirementsDebugString); } return(parser.Error.InnermostError.Message); }
private Leaderboard AddGeneratedLeaderboard(AchievementScriptInterpreter interpreter, int id, string name) { var leaderboard = new Leaderboard { //Id = id, Title = name, Start = "1=1", Submit = "1=1", Cancel = "1=1", Value = "1" }; ((List <Leaderboard>)interpreter.Leaderboards).Add(leaderboard); return(leaderboard); }
private static string GetInnerErrorMessage(AchievementScriptInterpreter parser) { if (parser.Error == null) { return(null); } var err = parser.Error; while (err.InnerError != null) { err = err.InnerError; } return(string.Format("{0}:{1} {2}", err.Location.Start.Line, err.Location.Start.Column, err.Message)); }
/// <summary> /// Gets the return value from calling a function. /// </summary> /// <param name="scope">The scope object containing variable values and function parameters.</param> /// <param name="result">[out] The new expression containing the function result.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public virtual bool Evaluate(InterpreterScope scope, out ExpressionBase result) { var interpreter = new AchievementScriptInterpreter(); var interpreterScope = new InterpreterScope(scope) { Context = interpreter }; if (!interpreter.Evaluate(Expressions, interpreterScope)) { result = interpreter.Error; return(false); } result = interpreterScope.ReturnValue; return(true); }
"trigger_when(byte(1) == 56) && trigger_when(byte(2) == 3) && trigger_when(byte(1) == 55 || byte(2) == 4)")] // and can be separated, but not nested ors public void TestReplaceVariables(string input, string expected) { var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.Context = new TriggerBuilderContext(); var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); ExpressionBase evaluated; Assert.That(expression.ReplaceVariables(scope, out evaluated), Is.True); var builder = new StringBuilder(); evaluated.AppendString(builder); Assert.That(builder.ToString(), Is.EqualTo(expected)); }
public void TestPushMemoryComparison() { var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); var array = new ArrayExpression(); scope.DefineVariable(new VariableDefinitionExpression("arr"), array); AddHappyFunction(scope); Evaluate("array_push(arr, byte(1) == 2)", scope); var comparison = (ComparisonExpression)array.Entries[0]; Assert.That(comparison.Left, Is.InstanceOf <FunctionCallExpression>()); Assert.That(((FunctionCallExpression)comparison.Left).FunctionName.Name, Is.EqualTo("byte")); Assert.That(comparison.Right, Is.InstanceOf <IntegerConstantExpression>()); Assert.That(((IntegerConstantExpression)comparison.Right).Value, Is.EqualTo(2)); }
private RichPresenceBuilder Evaluate(string input, string expectedError = null) { var funcDef = new RichPresenceValueFunction(); var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); Assert.That(expression, Is.InstanceOf <FunctionCallExpression>()); var funcCall = (FunctionCallExpression)expression; ExpressionBase error; var scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error); var context = new RichPresenceDisplayFunction.RichPresenceDisplayContext { RichPresence = new RichPresenceBuilder() }; scope.Context = context; ExpressionBase evaluated; if (expectedError != null && expectedError.EndsWith(" format")) { Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.False); var parseError = evaluated as ParseErrorExpression; Assert.That(parseError, Is.Not.Null); Assert.That(parseError.Message, Is.EqualTo(expectedError)); return(context.RichPresence); } ExpressionBase result; Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True); if (expectedError == null) { Assert.That(funcDef.BuildMacro(context, scope, out result), Is.True); context.RichPresence.DisplayString = ((StringConstantExpression)result).Value; } else { Assert.That(funcDef.BuildMacro(context, scope, out result), Is.False); Assert.That(result, Is.InstanceOf <ParseErrorExpression>()); Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo(expectedError)); } return(context.RichPresence); }
public void TestExplicitCall() { // not providing a TriggerBuilderContext simulates calling the function at a global scope var funcDef = new MemoryAccessorFunction("byte", FieldSize.Byte); var input = "byte(0x1234)"; var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); Assert.That(expression, Is.InstanceOf <FunctionCallExpression>()); var funcCall = (FunctionCallExpression)expression; ExpressionBase error; var scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error); Assert.That(funcDef.Evaluate(scope, out error), Is.False); Assert.That(error, Is.InstanceOf <ParseErrorExpression>()); Assert.That(((ParseErrorExpression)error).Message, Is.EqualTo("byte has no meaning outside of a trigger clause")); }
public void TestExplicitCall() { // not providing a RichPresenceDisplayContext simulates calling the function at a global scope var funcDef = new RichPresenceValueFunction(); var input = "rich_presence_value(\"Name\", byte(0x1234))"; var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input))); Assert.That(expression, Is.InstanceOf <FunctionCallExpression>()); var funcCall = (FunctionCallExpression)expression; ExpressionBase error; var scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error); Assert.That(funcDef.Evaluate(scope, out error), Is.False); Assert.That(error, Is.InstanceOf <ParseErrorExpression>()); Assert.That(((ParseErrorExpression)error).Message, Is.EqualTo("rich_presence_value has no meaning outside of a rich_presence_display call")); }
public void TestScopedVariable() { var script = "function ItemInInventory(id) => any_of(range(0x1200, 0x1208, step=2), addr => word(addr) == id)\n" + "achievement(\"title\", \"desc\", 5, ItemInInventory(17))"; var tokenizer = Tokenizer.CreateTokenizer(script); var parser = new AchievementScriptInterpreter(); if (!parser.Run(tokenizer)) { Assert.Fail(parser.ErrorMessage); } var achievement = parser.Achievements.First(); var builder = new AchievementBuilder(achievement); Assert.That(builder.RequirementsDebugString, Is.EqualTo( "word(0x001200) == 17 || word(0x001202) == 17 || word(0x001204) == 17 || word(0x001206) == 17 || word(0x001208) == 17")); }
public void TestPredicateWithDefaultParameter() { var script = "function p(addr, id=17) => byte(addr) == id\n" + "achievement(\"title\", \"desc\", 5, any_of([1, 2, 3], p))"; var tokenizer = Tokenizer.CreateTokenizer(script); var parser = new AchievementScriptInterpreter(); if (!parser.Run(tokenizer)) { Assert.Fail(parser.ErrorMessage); } var achievement = parser.Achievements.First(); var builder = new AchievementBuilder(achievement); Assert.That(builder.RequirementsDebugString, Is.EqualTo( "byte(0x000001) == 17 || byte(0x000002) == 17 || byte(0x000003) == 17")); }
public void TestReplaceVariablesMemoryAccessor() { var value = new FunctionCallExpression("byte", new[] { new IntegerConstantExpression(1) }); var expr = new ArrayExpression(); expr.Entries.Add(value); var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); ExpressionBase result; Assert.That(expr.ReplaceVariables(scope, out result), Is.True); Assert.That(result, Is.InstanceOf <ArrayExpression>()); var arrayResult = (ArrayExpression)result; Assert.That(arrayResult.Entries.Count, Is.EqualTo(1)); Assert.That(arrayResult.Entries[0].ToString(), Is.EqualTo(value.ToString())); }
public void TestReplaceVariablesLogicalFunctionCall() { var functionDefinition = UserFunctionDefinitionExpression.ParseForTest("function func(i) => byte(i) == 1"); var functionCall = new FunctionCallExpression("func", new ExpressionBase[] { new IntegerConstantExpression(2) }); var value1 = new IntegerConstantExpression(98); var expr = new DictionaryExpression(); expr.Add(functionCall, value1); var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope()); scope.AddFunction(functionDefinition); ExpressionBase result; Assert.That(expr.ReplaceVariables(scope, out result), Is.False); Assert.That(result, Is.InstanceOf <ParseErrorExpression>()); Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo("Dictionary key must evaluate to a constant")); }
private AchievementScriptInterpreter Parse(string input, bool expectedSuccess = true) { var tokenizer = Tokenizer.CreateTokenizer(input); var parser = new AchievementScriptInterpreter(); if (expectedSuccess) { if (!parser.Run(tokenizer)) { Assert.That(parser.ErrorMessage, Is.Null); Assert.Fail("AchievementScriptInterpreter.Run failed with no error message"); } } else { Assert.That(parser.Run(tokenizer), Is.False); Assert.That(parser.ErrorMessage, Is.Not.Null); } return(parser); }