public void TestMemoryScope() { var engine = new TemplateEngine().AddFile(GetExampleFilePath("MemoryScope.lg")); var evaled = engine.EvaluateTemplate("T1", new { turn = new { name = "Dong", count = 3 } }); Assert.AreEqual(evaled, "Hi Dong, welcome to Seattle, Seattle is a beautiful place, how many burgers do you want, 3?"); var scope = new SimpleObjectMemory(new { schema = new Dictionary <string, object>() { { "Bread", new Dictionary <string, object>() { { "enum", new List <string>() { "A", "B" } } } } } }); evaled = engine.EvaluateTemplate("AskBread", scope); Assert.AreEqual(evaled, "Which Bread, A or B do you want?"); }
/// <summary> /// Expand the results of a template with given name and scope. /// </summary> /// <param name="templateName">Given template name.</param> /// <param name="scope">Given scope.</param> /// <returns>All possiable results.</returns> public List <string> ExpandTemplate(string templateName, object scope) { if (!(scope is CustomizedMemory)) { scope = new CustomizedMemory(SimpleObjectMemory.Wrap(scope)); } if (!TemplateMap.ContainsKey(templateName)) { throw new Exception(LGErrors.TemplateNotExist(templateName)); } if (evaluationTargetStack.Any(e => e.TemplateName == templateName)) { throw new Exception($"{LGErrors.LoopDetected} {string.Join(" => ", evaluationTargetStack.Reverse().Select(e => e.TemplateName))} => {templateName}"); } // Using a stack to track the evaluation trace evaluationTargetStack.Push(new EvaluationTarget(templateName, scope)); var result = Visit(TemplateMap[templateName].ParseTree); evaluationTargetStack.Pop(); return(result); }
public void TestAccumulatePath() { var memory = new SimpleObjectMemory(new { f = "foo", b = "bar", z = new { z = "zar" }, n = 2 }); // normal case, note, we doesn't append a " yet var exp = Expression.Parse("a[f].b[n].z"); var(path, left, err) = ExpressionFunctions.TryAccumulatePath(exp, memory); Assert.AreEqual(path, "a['foo'].b[2].z"); // normal case exp = Expression.Parse("a[z.z][z.z].y"); (path, left, err) = ExpressionFunctions.TryAccumulatePath(exp, memory); Assert.AreEqual(path, "a['zar']['zar'].y"); // normal case exp = Expression.Parse("a.b[z.z]"); (path, left, err) = ExpressionFunctions.TryAccumulatePath(exp, memory); Assert.AreEqual(path, "a.b['zar']"); // stop evaluate at middle exp = Expression.Parse("json(x).b"); (path, left, err) = ExpressionFunctions.TryAccumulatePath(exp, memory); Assert.AreEqual(path, "b"); }
/// <summary> /// Evaluate a template with given name and scope. /// </summary> /// <param name="templateName">Template name to be evaluated.</param> /// <param name="scope">The state visible in the evaluation.</param> /// <returns>Evaluate result.</returns> public object EvaluateTemplate(string templateName, object scope = null) { CheckErrors(); var memory = SimpleObjectMemory.Wrap(scope); var evaluator = new Evaluator(AllTemplates.ToList(), ExpressionEngine); return(evaluator.EvaluateTemplate(templateName, new CustomizedMemory(memory))); }
/// <summary> /// Expands template expression using Adaptive Expression Library (AEL) /// </summary> /// <param name="unboundString"></param> /// <param name="data"></param> /// <param name="isTemplatedString"></param> /// <returns><c>string</c></returns> public static string Expand(string unboundString, SimpleObjectMemory data, bool isTemplatedString = false) { if (unboundString == null) { return(""); } Expression exp; try { exp = Expression.Parse(unboundString.Substring(2, unboundString.Length - 3)); } // AEL can throw any errors, for example, System.Data.Syntax error will be thrown from AEL's ANTLR // when AEL encounters unknown functions. // We can't possibly know all errors and we simply want to leave the expression as it is when there are any exceptions #pragma warning disable CA1031 // Do not catch general exception types catch (Exception) #pragma warning restore CA1031 // Do not catch general exception types { return(unboundString); } var options = new Options { NullSubstitution = (path) => $"${{{path}}}" }; StringBuilder result = new StringBuilder(); var(value, error) = exp.TryEvaluate(data, options); if (error == null) { if (value is string && isTemplatedString) { result.Append("\""); } result.Append(value.ToString()); if (value is string && isTemplatedString) { result.Append("\""); } } else { result.Append("${" + unboundString + "}"); } return(result.ToString()); }
/// <summary> /// constructs a data context of which current data is jtoken /// </summary> /// <param name="jtoken">new data to kept as data context</param> /// <param name="rootDataContext">root data context</param> public DataContext(JToken jtoken, JToken rootDataContext) { AELMemory = (jtoken is JObject) ? new SimpleObjectMemory(jtoken) : new SimpleObjectMemory(new JObject()); token = jtoken; RootDataContext = rootDataContext; if (jtoken is JArray) { IsArrayType = true; } AELMemory.SetValue(dataKeyword, token); AELMemory.SetValue(rootKeyword, rootDataContext); }
/// <summary> /// Evaluate a template with given name and scope. /// </summary> /// <param name="inputTemplateName">template name.</param> /// <param name="scope">scope.</param> /// <returns>Evaluate result.</returns> public object EvaluateTemplate(string inputTemplateName, object scope) { if (!(scope is CustomizedMemory)) { scope = new CustomizedMemory(SimpleObjectMemory.Wrap(scope)); } (var reExecute, var templateName) = ParseTemplateName(inputTemplateName); if (!TemplateMap.ContainsKey(templateName)) { throw new Exception(LGErrors.TemplateNotExist(templateName)); } if (evaluationTargetStack.Any(e => e.TemplateName == templateName)) { throw new Exception($"{LGErrors.LoopDetected} {string.Join(" => ", evaluationTargetStack.Reverse().Select(e => e.TemplateName))} => {templateName}"); } var templateTarget = new EvaluationTarget(templateName, scope); var currentEvaluateId = templateTarget.GetId(); EvaluationTarget previousEvaluateTarget = null; if (evaluationTargetStack.Count != 0) { previousEvaluateTarget = evaluationTargetStack.Peek(); if (!reExecute && previousEvaluateTarget.EvaluatedChildren.ContainsKey(currentEvaluateId)) { return(previousEvaluateTarget.EvaluatedChildren[currentEvaluateId]); } } // Using a stack to track the evaluation trace evaluationTargetStack.Push(templateTarget); var result = Visit(TemplateMap[templateName].ParseTree); if (previousEvaluateTarget != null) { previousEvaluateTarget.EvaluatedChildren[currentEvaluateId] = result; } evaluationTargetStack.Pop(); return(result); }
public CustomizedMemory(object scope) { this.GlobalMemory = scope == null ? null : SimpleObjectMemory.Wrap(scope); this.LocalMemory = null; }
/// <summary> /// Evaluate a template with given name and scope. /// </summary> /// <param name="templateName">Template name to be evaluated.</param> /// <param name="scope">The state visible in the evaluation.</param> /// <returns>Evaluate result.</returns> public object EvaluateTemplate(string templateName, object scope = null) { return(this.EvaluateTemplate(templateName, SimpleObjectMemory.Wrap(scope))); }