private void CheckTemplateReference(string templateName, IEnumerable <Expression> children) { if (!this.TemplateMap.ContainsKey(templateName)) { throw new Exception(TemplateErrors.TemplateNotExist(templateName)); } var expectedArgsCount = this.TemplateMap[templateName].Parameters.Count(); var actualArgsCount = children.Count(); if (actualArgsCount != 0 && expectedArgsCount != actualArgsCount) { throw new Exception(TemplateErrors.ArgumentMismatch(templateName, expectedArgsCount, actualArgsCount)); } }
/// <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(TemplateErrors.TemplateNotExist(templateName)); } if (evaluationTargetStack.Any(e => e.TemplateName == templateName)) { throw new Exception($"{TemplateErrors.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); }
private void ValidTemplateReference(Expression expression) { var templateName = expression.Type; if (!this.TemplateMap.ContainsKey(templateName)) { throw new Exception(TemplateErrors.TemplateNotExist(templateName)); } var expectedArgsCount = this.TemplateMap[templateName].Parameters.Count(); var actualArgsCount = expression.Children.Length; if (expectedArgsCount != actualArgsCount) { throw new Exception(TemplateErrors.ArgumentMismatch(templateName, expectedArgsCount, actualArgsCount)); } }
/// <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 <object> ExpandTemplate(string templateName, object scope) { if (!(scope is CustomizedMemory)) { scope = new CustomizedMemory(scope); } if (!TemplateMap.ContainsKey(templateName)) { throw new Exception(TemplateErrors.TemplateNotExist(templateName)); } if (evaluationTargetStack.Any(e => e.TemplateName == templateName)) { throw new Exception($"{TemplateErrors.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 expanderResult = Visit(TemplateMap[templateName].TemplateBodyParseTree); evaluationTargetStack.Pop(); var result = new List <object>(); expanderResult.ForEach(u => { if (lgOptions.LineBreakStyle == LGLineBreakStyle.Markdown && u is string str) { result.Add(Evaluator.NewLineRegex.Replace(str, "$1$1")); } else { result.Add(u); } }); return(result); }
/// <summary> /// Analyzes a template to get the static analyzer results. /// </summary> /// <param name="templateName">Template name.</param> /// <returns>Analyze result including variables and template references.</returns> public AnalyzerResult AnalyzeTemplate(string templateName) { var missingName = !_templateMap.ContainsKey(templateName); var stackHasName = _evaluationTargetStack.Any(e => e.TemplateName == templateName); if (_analyzerOptions?.ThrowOnRecursive == true) { if (missingName) { throw new ArgumentException(TemplateErrors.TemplateNotExist(templateName)); } if (stackHasName) { throw new InvalidOperationException($"{TemplateErrors.LoopDetected} {string.Join(" => ", _evaluationTargetStack.Reverse().Select(e => e.TemplateName))} => {templateName}"); } } if (missingName || stackHasName) { return(new AnalyzerResult()); } // Using a stack to track the evaluation trace _evaluationTargetStack.Push(new EvaluationTarget(templateName, null)); // we don't exclude parameters any more // because given we don't track down for templates have parameters // the only scenario that we are still analyzing an parameterized template is // this template is root template to analyze, in this we also don't have exclude parameters var dependencies = Visit(_templateMap[templateName].TemplateBodyParseTree); _evaluationTargetStack.Pop(); return(dependencies); }
/// <summary> /// Analyzer a template to get the static analyzer results. /// </summary> /// <param name="templateName">Template name.</param> /// <returns>Analyze result including variables and template references.</returns> public AnalyzerResult AnalyzeTemplate(string templateName) { if (!templateMap.ContainsKey(templateName)) { throw new Exception(TemplateErrors.TemplateNotExist(templateName)); } if (evaluationTargetStack.Any(e => e.TemplateName == templateName)) { throw new Exception($"{TemplateErrors.LoopDetected} {string.Join(" => ", evaluationTargetStack.Reverse().Select(e => e.TemplateName))} => {templateName}"); } // Using a stack to track the evaluation trace evaluationTargetStack.Push(new EvaluationTarget(templateName, null)); // we don't exclude parameters any more // because given we don't track down for templates have parameters // the only scenario that we are still analyzing an parameterized template is // this template is root template to analyze, in this we also don't have exclude parameters var dependencies = Visit(templateMap[templateName].TemplateBodyParseTree); evaluationTargetStack.Pop(); return dependencies; }
/// <summary> /// Evaluate a template with given name and scope. /// Throws errors if certain errors detected <see cref="TemplateErrors"/>. /// </summary> /// <param name="inputTemplateName">Template name.</param> /// <param name="scope">Scope.</param> /// <returns>Evaluate result.</returns> public object EvaluateTemplate(string inputTemplateName, object scope) { var memory = scope is CustomizedMemory scopeMemory ? scopeMemory : new CustomizedMemory(scope); (var reExecute, var templateName) = ParseTemplateName(inputTemplateName); if (!TemplateMap.ContainsKey(templateName)) { throw new ArgumentException(TemplateErrors.TemplateNotExist(templateName)); } var templateTarget = new EvaluationTarget(templateName, memory); var currentEvaluateId = templateTarget.GetId(); if (_evaluationTargetStack.Any(e => e.GetId() == currentEvaluateId)) { throw new InvalidOperationException($"{TemplateErrors.LoopDetected} {string.Join(" => ", _evaluationTargetStack.Reverse().Select(e => e.TemplateName))} => {templateName}"); } object result = null; var hasResult = false; if (!reExecute) { if (_lgOptions.CacheScope == LGCacheScope.Global) { if (_cachedResult.ContainsKey(currentEvaluateId)) { result = _cachedResult[currentEvaluateId]; hasResult = true; } } else if (_lgOptions.CacheScope == null || _lgOptions.CacheScope == LGCacheScope.Local) { EvaluationTarget previousEvaluateTarget = null; if (CurrentTemplate() != null) { previousEvaluateTarget = CurrentTarget(); if (previousEvaluateTarget.CachedEvaluatedChildren.ContainsKey(currentEvaluateId)) { result = previousEvaluateTarget.CachedEvaluatedChildren[currentEvaluateId]; hasResult = true; } } } } if (!hasResult) { _evaluationTargetStack.Push(templateTarget); var currentTemplate = CurrentTemplate(); _lgOptions.OnEvent?.Invoke(currentTemplate, new BeginTemplateEvaluationArgs { Source = currentTemplate.SourceRange.Source, TemplateName = templateName }); result = Visit(TemplateMap[templateName].TemplateBodyParseTree); if (_lgOptions.OnEvent != null) { var text = $"Evaluate template [{templateName}] get result: {result}"; _lgOptions.OnEvent(currentTemplate, new MessageArgs { Source = currentTemplate.SourceRange.Source, Text = text }); } _evaluationTargetStack.Pop(); if (!reExecute) { if (_lgOptions.CacheScope == LGCacheScope.Global) { _cachedResult[currentEvaluateId] = result; } else if (_lgOptions.CacheScope == null || _lgOptions.CacheScope == LGCacheScope.Local) { if (_evaluationTargetStack.Count > 0) { _evaluationTargetStack.Peek().CachedEvaluatedChildren[currentEvaluateId] = result; } } } } return(result); }