Пример #1
0
 /// <summary>
 /// Parser to turn lg content into a <see cref="Templates"/>.
 /// </summary>
 /// <param name="resource">LG resource.</param>
 /// <param name="importResolver">Resolver to resolve LG import id to template text.</param>
 /// <param name="expressionParser">Expression parser for parsing expressions.</param>
 /// <returns>new <see cref="Templates"/> entity.</returns>
 public static Templates ParseResource(
     LGResource resource,
     ImportResolverDelegate importResolver = null,
     ExpressionParser expressionParser     = null)
 {
     return(InnerParseResource(resource, importResolver, expressionParser));
 }
Пример #2
0
        /// <summary>
        /// Parser to turn lg content into a <see cref="Templates"/>.
        /// </summary>
        /// <param name="resource">LG resource.</param>
        /// <param name="importResolver">Resolver to resolve LG import id to template text.</param>
        /// <param name="expressionParser">Expression parser for parsing expressions.</param>
        /// <param name="cachedTemplates">Give the file path and templates to avoid parsing and to improve performance.</param>
        /// <param name="parentTemplates">Parent visited Templates.</param>
        /// <returns>new <see cref="Templates"/> entity.</returns>
        private static Templates InnerParseResource(
            LGResource resource,
            ImportResolverDelegate importResolver          = null,
            ExpressionParser expressionParser              = null,
            Dictionary <string, Templates> cachedTemplates = null,
            Stack <Templates> parentTemplates              = null)
        {
            if (resource == null)
            {
                throw new ArgumentNullException(nameof(resource));
            }

            cachedTemplates = cachedTemplates ?? new Dictionary <string, Templates>();
            parentTemplates = parentTemplates ?? new Stack <Templates>();
            if (cachedTemplates.ContainsKey(resource.Id))
            {
                return(cachedTemplates[resource.Id]);
            }

            importResolver = importResolver ?? DefaultFileResolver;
            var lg = new Templates(content: resource.Content, id: resource.Id, source: resource.FullName, importResolver: importResolver, expressionParser: expressionParser);

            try
            {
                lg            = new TemplatesTransformer(lg).Transform(AntlrParseTemplates(resource));
                lg.References = GetReferences(lg, cachedTemplates, parentTemplates);
                new StaticChecker(lg).Check().ForEach(u => lg.Diagnostics.Add(u));
            }
            catch (TemplateException ex)
            {
                ex.Diagnostics.ToList().ForEach(u => lg.Diagnostics.Add(u));
            }

            return(lg);
        }
Пример #3
0
        /// <summary>
        /// Parser to turn lg content into a <see cref="Templates"/> based on the original LGFile.
        /// </summary>
        /// <param name="content">Text content contains lg templates.</param>
        /// <param name="lg">Original LGFile.</param>
        /// <returns>New <see cref="Templates"/> entity.</returns>
        public static Templates ParseTextWithRef(string content, Templates lg)
        {
            if (lg == null)
            {
                throw new ArgumentNullException(nameof(lg));
            }

            var newLG = new Templates(content: content, id: InlineContentId, source: InlineContentId, importResolver: lg.ImportResolver, options: lg.Options, namedReferences: lg.NamedReferences);

            try
            {
                var resource = new LGResource(InlineContentId, InlineContentId, content);
                newLG            = new TemplatesTransformer(newLG).Transform(AntlrParseTemplates(resource));
                newLG.References = GetReferences(newLG)
                                   .Union(lg.References)
                                   .Union(new List <Templates> {
                    lg
                })
                                   .ToList();

                new StaticChecker(newLG).Check().ForEach(u => newLG.Diagnostics.Add(u));
            }
            catch (TemplateException ex)
            {
                ex.Diagnostics.ToList().ForEach(u => newLG.Diagnostics.Add(u));
            }

            return(newLG);
        }
Пример #4
0
        public static Templates ParseText(
            string content,
            string id = "",
            ImportResolverDelegate importResolver = null,
            ExpressionParser expressionParser     = null)
        {
            var resource = new LGResource(id, id, content);

            return(ParseResource(resource, importResolver, expressionParser));
        }
Пример #5
0
        /// <summary>
        /// Parser to turn lg content into a <see cref="Templates"/>.
        /// </summary>
        /// <param name="filePath">Absolut path of a LG file.</param>
        /// <param name="importResolver">Resolver to resolve LG import id to template text.</param>
        /// <param name="expressionParser">Expression parser for parsing expressions.</param>
        /// <returns>new <see cref="Templates"/> entity.</returns>
        public static Templates ParseFile(
            string filePath,
            ImportResolverDelegate importResolver = null,
            ExpressionParser expressionParser     = null)
        {
            var fullPath = Path.GetFullPath(filePath.NormalizePath());
            var content  = File.ReadAllText(fullPath);

            var resource = new LGResource(fullPath, fullPath, content);

            return(ParseResource(resource, importResolver, expressionParser));
        }
        private static void ResolveImportResources(Templates start, HashSet <Templates> resourcesFound, Dictionary <string, Templates> cachedTemplates, Stack <Templates> parentTemplates)
        {
            resourcesFound.Add(start);
            parentTemplates.Push(start);
            foreach (var import in start.Imports)
            {
                LGResource resource;
                try
                {
                    var originalResource = new LGResource(start.Id, start.Source, start.Content);
                    resource = start.ImportResolver(originalResource, import.Id);
                }
                catch (Exception e)
                {
                    var diagnostic = new Diagnostic(import.SourceRange.Range, e.Message, DiagnosticSeverity.Error, start.Source);
                    throw new TemplateException(e.Message, new List <Diagnostic>()
                    {
                        diagnostic
                    });
                }

                // Cycle reference would throw exception to avoid infinite Loop.
                // Import self is allowed, and would ignore it.
                if (parentTemplates.Peek().Id != resource.Id && parentTemplates.Any(u => u.Id == resource.Id))
                {
                    var errorMsg   = $"{TemplateErrors.LoopDetected} {resource.Id} => {start.Id}";
                    var diagnostic = new Diagnostic(import.SourceRange.Range, errorMsg, DiagnosticSeverity.Error, start.Source);
                    throw new TemplateException(errorMsg, new List <Diagnostic>()
                    {
                        diagnostic
                    });
                }

                if (resourcesFound.All(u => u.Id != resource.Id))
                {
                    Templates childResource;
                    if (cachedTemplates.ContainsKey(resource.Id))
                    {
                        childResource = cachedTemplates[resource.Id];
                    }
                    else
                    {
                        childResource = InnerParseResource(resource, start.ImportResolver, start.ExpressionParser, cachedTemplates, parentTemplates);
                        cachedTemplates.Add(resource.Id, childResource);
                    }

                    ResolveImportResources(childResource, resourcesFound, cachedTemplates, parentTemplates);
                }
            }

            parentTemplates.Pop();
        }
        /// <summary>
        /// Default import resolver, using relative/absolute file path to access the file content.
        /// </summary>
        /// <param name="resource">Original Resource.</param>
        /// <param name="resourceId">Import path.</param>
        /// <returns>Target content id.</returns>
        private static LGResource DefaultFileResolver(LGResource resource, string resourceId)
        {
            // import paths are in resource files which can be executed on multiple OS environments
            // normalize to map / & \ in importPath -> OSPath
            var importPath = resourceId.NormalizePath();

            if (!Path.IsPathRooted(importPath))
            {
                // get full path for importPath relative to path which is doing the import.
                importPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(resource.FullName), resourceId));
            }

            return(new LGResource(importPath, importPath, File.ReadAllText(importPath)));
        }
Пример #8
0
        /// <summary>
        /// Adds a new template and returns the updated Templates instance.
        /// </summary>
        /// <param name="templateName">New template name.</param>
        /// <param name="parameters">New params.</param>
        /// <param name="templateBody">New template body.</param>
        /// <returns>Updated LG file.</returns>
        public Templates AddTemplate(string templateName, List <string> parameters, string templateBody)
        {
            var template = this.FirstOrDefault(u => u.Name == templateName);

            if (template != null)
            {
                throw new ArgumentException(TemplateErrors.TemplateExist(templateName));
            }

            ClearDiagnostics();

            var templateNameLine = BuildTemplateNameLine(templateName, parameters);
            var newTemplateBody  = ConvertTemplateBody(templateBody);
            var content          = $"{templateNameLine}{_newLine}{newTemplateBody}";

            var originStartLine = GetLinesOfText(Content).Length;

            // update content
            Content = $"{Content}{_newLine}{templateNameLine}{_newLine}{newTemplateBody}";

            var newTemplates = new Templates(content: string.Empty, id: Id, importResolver: ImportResolver, expressionParser: ExpressionParser, namedReferences: NamedReferences);
            var resource     = new LGResource(Id, Id, content);

            newTemplates = new TemplatesTransformer(newTemplates).Transform(AntlrParseTemplates(resource));

            AppendDiagnosticsWithOffset(newTemplates.Diagnostics, originStartLine);

            var newTemplate = newTemplates.FirstOrDefault();

            if (newTemplate != null)
            {
                AdjustRangeForAddTemplate(newTemplate, originStartLine);
                Add(newTemplate);
                new StaticChecker(this).Check().ForEach(u => Diagnostics.Add(u));
            }

            return(this);
        }
Пример #9
0
        private static void ResolveImportResources(Templates start, HashSet <Templates> resourcesFound, Dictionary <string, Templates> cachedTemplates)
        {
            resourcesFound.Add(start);

            foreach (var import in start.Imports)
            {
                LGResource resource;
                try
                {
                    var originalResource = new LGResource(start.Id, start.Source, start.Content);
                    resource = start.ImportResolver(originalResource, import.Id);
                }
                catch (Exception e)
                {
                    var diagnostic = new Diagnostic(import.SourceRange.Range, e.Message, DiagnosticSeverity.Error, start.Source);
                    throw new TemplateException(e.Message, new List <Diagnostic>()
                    {
                        diagnostic
                    });
                }

                if (resourcesFound.All(u => u.Id != resource.Id))
                {
                    Templates childResource;
                    if (cachedTemplates.ContainsKey(resource.Id))
                    {
                        childResource = cachedTemplates[resource.Id];
                    }
                    else
                    {
                        childResource = ParseResource(resource, start.ImportResolver, start.ExpressionParser, cachedTemplates);
                        cachedTemplates.Add(resource.Id, childResource);
                    }

                    ResolveImportResources(childResource, resourcesFound, cachedTemplates);
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Parse LG content and achieve the AST.
        /// </summary>
        /// <param name="resource">LG resource.</param>
        /// <returns>The abstract syntax tree of lg file.</returns>
        public static IParseTree AntlrParseTemplates(LGResource resource)
        {
            if (string.IsNullOrEmpty(resource.Content))
            {
                return(null);
            }

            var input = new AntlrInputStream(resource.Content);
            var lexer = new LGFileLexer(input);

            lexer.RemoveErrorListeners();

            var tokens = new CommonTokenStream(lexer);
            var parser = new LGFileParser(tokens);

            parser.RemoveErrorListeners();
            var listener = new ErrorListener(resource.FullName);

            parser.AddErrorListener(listener);
            parser.BuildParseTree = true;

            return(parser.file());
        }
Пример #11
0
        /// <summary>
        /// Resolve imported LG resources from a start resource.
        /// All the imports will be visited and resolved to LGResouce list.
        /// </summary>
        /// <param name="start">The lg resource from which to start resolving imported resources.</param>
        /// <param name="importResolver">resolver to resolve LG import id to template text.</param>
        /// <param name="resourcesFound">Resources that have been found.</param>
        private void ResolveImportResources(LGResource start, ImportResolverDelegate importResolver, HashSet <LGResource> resourcesFound)
        {
            var resourceIds = start.Imports.Select(lg => lg.Id).ToList();

            resourcesFound.Add(start);

            foreach (var id in resourceIds)
            {
                try
                {
                    var(content, path) = importResolver(start.Id, id);
                    var childResource = LGParser.Parse(content, path);
                    if (!resourcesFound.Contains(childResource))
                    {
                        ResolveImportResources(childResource, importResolver, resourcesFound);
                    }
                }
                catch (Exception err)
                {
                    throw new Exception($"[Error]{id}:{err.Message}", err);
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Default import resolver, using relative/absolute file path to access the file content.
        /// </summary>
        /// <param name="resource">Original Resource.</param>
        /// <param name="resourceId">Import path.</param>
        /// <returns>Target content id.</returns>
        private static LGResource DefaultFileResolver(LGResource resource, string resourceId)
        {
            // import paths are in resource files which can be executed on multiple OS environments
            // normalize to map / & \ in importPath -> OSPath

            // If the import id contains "#", we would cut it to use the left path.
            // for example: [import](a.b.c#d.lg), after convertion, id would be d.lg
            var hashIndex = resourceId.IndexOf('#');

            if (hashIndex > 0)
            {
                resourceId = resourceId.Substring(hashIndex + 1);
            }

            var importPath = resourceId.NormalizePath();

            if (!Path.IsPathRooted(importPath))
            {
                // get full path for importPath relative to path which is doing the import.
                importPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(resource.FullName), resourceId));
            }

            return(new LGResource(importPath, importPath, File.ReadAllText(importPath)));
        }
Пример #13
0
        /// <summary>
        /// Updates an existing template in current Templates instance.
        /// </summary>
        /// <param name="templateName">Original template name. The only id of a template.</param>
        /// <param name="newTemplateName">New template Name.</param>
        /// <param name="parameters">New params.</param>
        /// <param name="templateBody">New template body.</param>
        /// <returns>Updated LG file.</returns>
        public Templates UpdateTemplate(string templateName, string newTemplateName, List <string> parameters, string templateBody)
        {
            var template = this.FirstOrDefault(u => u.Name == templateName);

            if (template != null)
            {
                ClearDiagnostics();

                var templateNameLine = BuildTemplateNameLine(newTemplateName, parameters);
                var newTemplateBody  = ConvertTemplateBody(templateBody);
                var content          = $"{templateNameLine}{_newLine}{newTemplateBody}";

                // update content
                Content = ReplaceRangeContent(
                    Content,
                    template.SourceRange.Range.Start.Line - 1,
                    template.SourceRange.Range.End.Line - 1,
                    content);

                var updatedTemplates = new Templates(content: string.Empty, id: Id, importResolver: ImportResolver, expressionParser: ExpressionParser, namedReferences: NamedReferences);
                var resource         = new LGResource(Id, Id, content);
                updatedTemplates = new TemplatesTransformer(updatedTemplates).Transform(AntlrParseTemplates(resource));

                var originStartLine = template.SourceRange.Range.Start.Line - 1;
                AppendDiagnosticsWithOffset(updatedTemplates.Diagnostics, originStartLine);

                var newTemplate = updatedTemplates.FirstOrDefault();
                if (newTemplate != null)
                {
                    AdjustRangeForUpdateTemplate(template, newTemplate);
                    new StaticChecker(this).Check().ForEach(u => Diagnostics.Add(u));
                }
            }

            return(this);
        }
Пример #14
0
 /// <summary>
 /// Parser to turn lg content into a <see cref="LanguageGeneration.Templates"/>.
 /// </summary>
 /// <param name="resource">LG resource.</param>
 /// <param name="importResolver">Resolver to resolve LG import id to template text.</param>
 /// <param name="expressionParser">Expression parser engine for parsing expressions.</param>
 /// <returns>new <see cref="Templates"/> entity.</returns>
 public static Templates ParseResource(
     LGResource resource,
     ImportResolverDelegate importResolver = null,
     ExpressionParser expressionParser     = null) => TemplatesParser.ParseResource(resource, importResolver, expressionParser).InjectToExpressionFunction();