Пример #1
0
        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));
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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));
            }
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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;
        }
Пример #7
0
        /// <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);
        }