Exemplo n.º 1
0
 private Snapshot()
 {
     if (PerformanceProfiler.IsActive)
     {
         PerformanceProfiler.Begin();
     }
 }
Exemplo n.º 2
0
        public static void StartProfiler()
        {
#if PROFILE
            if (PerformanceProfiler.IsActive)
            {
                if (!profilerrunning)
                {
                    profilerrunning = true;
                    WriteLine(DebugMessageType.SPECIAL, "Starting the Profiler...");
                    PerformanceProfiler.Begin();
                    PerformanceProfiler.Start();
                }
                else
                {
                    WriteLine(DebugMessageType.SPECIAL, "Profiler is already running!");
                }
            }
            else
            {
                WriteLine(DebugMessageType.SPECIAL, "Unable to start the Profiler...");
            }
#else
            WriteLine(DebugMessageType.SPECIAL, "Unable to start the Profiler: incorrect build configuration selected!");
#endif
        }
Exemplo n.º 3
0
        public PerformanceProfile(string sdkPath, string resultsDirectory) : base(resultsDirectory)
        {
            var saveSnapshotProfilingConfig = new SaveSnapshotProfilingConfig
            {
                ProfilingControlKind = ProfilingControlKind.Api,
                TempDir        = Path.GetTempPath(),
                SaveDir        = resultsDirectory,
                RedistDir      = sdkPath,
                ProfilingType  = ProfilingType.Performance,
                ListFile       = this.ListFile,
                SnapshotFormat = SnapshotFormat.Uncompressed
            };

            while (SelfAttach.State != SelfApiState.None)
            {
                Thread.Sleep(250);
            }

            SelfAttach.Attach(saveSnapshotProfilingConfig);
            this.WaitForProfilerToAttachToProcess();

            if (PerformanceProfiler.IsActive)
            {
                PerformanceProfiler.Begin();
                PerformanceProfiler.Start();
            }
        }
Exemplo n.º 4
0
        public MorestachioDocumentInfo TokenizeAndParse(ParserOptions parsingOptions)
        {
            var errors   = new List <IMorestachioError>();
            var profiler = new PerformanceProfiler(parsingOptions.ProfileExecution);
            Queue <TokenPair> tokens;

            using (profiler.Begin("Tokenize"))
            {
                tokens = new Queue <TokenPair>(Tokenizer.Tokenize(parsingOptions, errors, profiler));
            }

            //if there are any errors do not parse the template
            MorestachioDocumentInfo documentInfo;

            if (errors.Any())
            {
                documentInfo = new MorestachioDocumentInfo(parsingOptions, null, errors);
            }
            else
            {
                documentInfo = Parse(parsingOptions, tokens);
            }
            documentInfo.Profiler = profiler;
            return(documentInfo);
        }
Exemplo n.º 5
0
 private static void InitJbProfilers()
 {
     if (PerformanceProfiler.IsActive)
     {
         PerformanceProfiler.Stop();
     }
     else
     {
         PerformanceProfiler.Begin();
     }
 }
 // ReSharper disable once UnusedParameter.Local
 private void ExecuteHandler(ClientSession session)
 {
     while (SelfAttach.State != SelfApiState.Active)
     {
         Thread.Sleep(250);  // wait until API starts
     }
     if (PerformanceProfiler.IsActive)
     {
         PerformanceProfiler.Begin();
         PerformanceProfiler.Start();
     }
 }
Exemplo n.º 7
0
        internal static IEnumerable <TokenPair> Tokenize(ParserOptions parserOptions,
                                                         PerformanceProfiler profiler,
                                                         out TokenzierContext tokenzierContext)
        {
            var             templateString = parserOptions.Template;
            MatchCollection matches;

            using (profiler.Begin("Find Tokens"))
            {
                matches = TokenFinder.Matches(templateString);
            }

            var scopestack    = new Stack <Tuple <string, int> >();
            var partialsNames = new List <string>(parserOptions.PartialsStore?.GetNames() ?? new string[0]);
            var context       = new TokenzierContext(NewlineFinder.Matches(templateString).OfType <Match>().Select(k => k.Index).ToArray());

            tokenzierContext = context;
            context.SetLocation(0);
            var tokens = new List <TokenPair>();

            void BeginElse(Match match)
            {
                var firstNonContentToken = tokens
                                           .AsReadOnly()
                                           .Reverse()
                                           .FirstOrDefault(e => !e.Type.Equals(TokenType.Content));

                if (firstNonContentToken == null || !firstNonContentToken.Type.Equals(TokenType.IfClose))
                {
                    context.Errors
                    .Add(new MorestachioSyntaxError(
                             context.CurrentLocation
                             .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "find if block for else",
                             firstNonContentToken?.Value, "{{/if}}", "Could not find an /if block for this else"));
                }
                else
                {
                    scopestack.Push(Tuple.Create($"#else_{firstNonContentToken.Value}", match.Index));
                    tokens.Add(new TokenPair(TokenType.Else, firstNonContentToken.Value,
                                             context.CurrentLocation));
                }
            }

            void EndIf(Match match, string expected)
            {
                if (!string.Equals(match.Value, "{{" + expected + "}}", StringComparison.InvariantCultureIgnoreCase))
                {
                    context.Errors
                    .Add(new MorestachioSyntaxError(context.CurrentLocation
                                                    .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)),
                                                    "close",
                                                    expected,
                                                    "{{" + expected + "}}"));
                }
                else
                {
                    if (!scopestack.Any())
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)),
                                                                            "if",
                                                                            "{{#if name}}"));
                    }
                    else
                    {
                        var item1 = scopestack.Peek().Item1;
                        if (item1.StartsWith("#if") || item1.StartsWith("^if"))
                        {
                            var token = scopestack.Pop().Item1;
                            tokens.Add(new TokenPair(TokenType.IfClose, token,
                                                     context.CurrentLocation));
                        }
                        else
                        {
                            context.Errors.Add(new MorestachioUnopendScopeError(
                                                   context.CurrentLocation
                                                   .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)),
                                                   "if",
                                                   "{{#if name}}"));
                        }
                    }
                }
            }

            foreach (Match match in matches)
            {
                //yield front content.
                if (match.Index > context.Character)
                {
                    tokens.Add(new TokenPair(TokenType.Content, templateString.Substring(context.Character, match.Index - context.Character),
                                             context.CurrentLocation));
                }
                context.SetLocation(match.Index + 2);

                var tokenValue   = match.Value;
                var trimmedToken = tokenValue.TrimStart('{').TrimEnd('}');
                if (tokenValue.StartsWith("{{#declare ", true, CultureInfo.InvariantCulture))
                {
                    scopestack.Push(Tuple.Create(tokenValue, match.Index));
                    var token = trimmedToken.TrimStart('#').Trim()
                                .Substring("declare ".Length).Trim();
                    if (string.IsNullOrWhiteSpace(token))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "open", "declare",
                                                                      "{{#declare name}}", " Missing the Name."));
                    }
                    else
                    {
                        partialsNames.Add(token);
                        tokens.Add(new TokenPair(TokenType.PartialDeclarationOpen, token,
                                                 context.CurrentLocation));
                    }
                }
                else if (tokenValue.StartsWith("{{/declare", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(tokenValue, "{{/declare}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "close", "declare",
                                                                      "{{/declare}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("{{#declare", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var token = scopestack.Pop().Item1.TrimStart('{').TrimEnd('}').TrimStart('#').Trim()
                                    .Substring("declare".Length);
                        tokens.Add(new TokenPair(TokenType.PartialDeclarationClose, token,
                                                 context.CurrentLocation));
                    }
                    else
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "declare",
                                                                            "{{#declare name}}"));
                    }
                }
                else if (tokenValue.StartsWith("{{#include ", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('#').Trim()
                                .Substring("include ".Length).Trim();
                    if (string.IsNullOrWhiteSpace(token) || !partialsNames.Contains(token))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(
                                               context.CurrentLocation
                                               .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)),
                                               "use",
                                               "include",
                                               "{{#include name}}",
                                               $" There is no Partial declared '{token}'. Partial names are case sensitive and must be declared before an include."));
                    }
                    else
                    {
                        tokens.Add(new TokenPair(TokenType.RenderPartial, token,
                                                 context.CurrentLocation));
                    }
                }
                else if (tokenValue.StartsWith("{{#each", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('#').Trim().Substring("each".Length);
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;

                    scopestack.Push(Tuple.Create($"#each{alias ?? token}", match.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        tokens.Add(new TokenPair(TokenType.CollectionOpen, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                    else
                    {
                        context.Errors.Add(new InvalidPathSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), ""));
                    }

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        context.AdvanceLocation("each ".Length + alias.Length);
                        tokens.Add(new TokenPair(TokenType.Alias, alias,
                                                 context.CurrentLocation));
                    }
                }
                else if (tokenValue.StartsWith("{{/each", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(tokenValue, "{{/each}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "close", "each", "{{/each}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#each"))
                    {
                        var token = scopestack.Pop().Item1;
                        tokens.Add(new TokenPair(TokenType.CollectionClose, token,
                                                 context.CurrentLocation));
                    }
                    else
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "each", "{{#each name}}"));
                    }
                }
                else if (tokenValue.StartsWith("{{#while", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('#')
                                .Trim()
                                .Substring("while".Length);
                    scopestack.Push(Tuple.Create($"#while{token}", match.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        tokens.Add(new TokenPair(TokenType.WhileLoopOpen, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                    else
                    {
                        context.Errors.Add(new InvalidPathSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), ""));
                    }
                }
                else if (tokenValue.StartsWith("{{/while", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(tokenValue, "{{/while}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "close", "while", "{{/while}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#while"))
                    {
                        var token = scopestack.Pop().Item1;
                        tokens.Add(new TokenPair(TokenType.WhileLoopClose, token,
                                                 context.CurrentLocation));
                    }
                    else
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "while", "{{#while Expression}}"));
                    }
                }
                else if (tokenValue.StartsWith("{{#do", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('#')
                                .Trim()
                                .Substring("do".Length);
                    scopestack.Push(Tuple.Create($"#do{token}", match.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        tokens.Add(new TokenPair(TokenType.DoLoopOpen, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                    else
                    {
                        context.Errors.Add(new InvalidPathSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), ""));
                    }
                }
                else if (tokenValue.StartsWith("{{/do", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(tokenValue, "{{/do}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "close", "do", "{{/do}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#do"))
                    {
                        var token = scopestack.Pop().Item1;
                        tokens.Add(new TokenPair(TokenType.DoLoopClose, token,
                                                 context.CurrentLocation));
                    }
                    else
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "do", "{{#do Expression}}"));
                    }
                }
                else if (tokenValue.StartsWith("{{#if ", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('#').Trim().Substring("if".Length);
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    if (eval.Item2 != null)
                    {
                        context.Errors.Add(new MorestachioSyntaxError(
                                               context.CurrentLocation
                                               .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "^if", "AS", "No Alias"));
                    }

                    scopestack.Push(Tuple.Create($"#if{token}", match.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        tokens.Add(new TokenPair(TokenType.If, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                    else
                    {
                        context.Errors.Add(new InvalidPathSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), ""));
                    }
                }
                else if (tokenValue.StartsWith("{{^if ", true, CultureInfo.InvariantCulture))
                {
                    var token = trimmedToken.TrimStart('^').Trim().Substring("if".Length);
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    if (eval.Item2 != null)
                    {
                        context.Errors.Add(new MorestachioSyntaxError(
                                               context.CurrentLocation
                                               .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "^if", "AS", "No Alias"));
                    }

                    scopestack.Push(Tuple.Create($"^if{token}", match.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        tokens.Add(new TokenPair(TokenType.IfNot, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                    else
                    {
                        context.Errors.Add(new InvalidPathSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), ""));
                    }
                }
                else if (tokenValue.StartsWith("{{/if", true, CultureInfo.InvariantCulture))
                {
                    EndIf(match, "/If");
                }
                else if (tokenValue.StartsWith("{{#ifelse", true, CultureInfo.InvariantCulture))
                {
                    EndIf(match, "#ifelse");
                    BeginElse(match);
                }
                else if (tokenValue.Equals("{{#else}}", StringComparison.InvariantCultureIgnoreCase))
                {
                    BeginElse(match);
                }
                else if (tokenValue.Equals("{{/else}}", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (!string.Equals(tokenValue, "{{/else}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                      .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "close", "else", "{{/else}}"));
                    }
                    else
                    {
                        if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#else_"))
                        {
                            var token = scopestack.Pop().Item1;
                            tokens.Add(new TokenPair(TokenType.ElseClose, token,
                                                     context.CurrentLocation));
                        }
                        else
                        {
                            context.Errors.Add(new MorestachioUnopendScopeError(
                                                   context.CurrentLocation
                                                   .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "else",
                                                   "{{#else name}}"));
                        }
                    }
                }
                else if (tokenValue.StartsWith("{{#var ", true, CultureInfo.InvariantCulture))
                {
                    tokens.AddRange(ExpressionTokenizer.TokenizeVariableAssignment(tokenValue.Trim('{', '}'),
                                                                                   context));
                }
                else if (tokenValue.StartsWith("{{#"))
                {
                    //open group
                    var token = trimmedToken.TrimStart('#').Trim();

                    var eval = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;
                    scopestack.Push(Tuple.Create(alias ?? token, match.Index));

                    //if (scopestack.Any() && scopestack.Peek().Item1 == token)
                    //{
                    //	tokens.Add(new TokenPair(TokenType.ElementClose,
                    //		Validated(token, match.Index, lines, context.Errors), context.CurrentLocation));
                    //}
                    //else
                    //{
                    //	scopestack.Push(Tuple.Create(alias ?? token, match.Index));
                    //}
                    tokens.Add(new TokenPair(TokenType.ElementOpen, token, context.CurrentLocation)
                    {
                        MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                    });

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        context.AdvanceLocation(3 + alias.Length);
                        tokens.Add(new TokenPair(TokenType.Alias, alias,
                                                 context.CurrentLocation));
                    }
                }
                else if (tokenValue.StartsWith("{{^"))
                {
                    //open inverted group
                    var token = trimmedToken.TrimStart('^').Trim();
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;
                    scopestack.Push(Tuple.Create(alias ?? token, match.Index));
                    tokens.Add(new TokenPair(TokenType.InvertedElementOpen, token, context.CurrentLocation)
                    {
                        MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                    });

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        context.AdvanceLocation(1 + alias.Length);
                        tokens.Add(new TokenPair(TokenType.Alias, alias,
                                                 context.CurrentLocation));
                    }
                }
                else if (tokenValue.StartsWith("{{/"))
                {
                    var token = trimmedToken.TrimStart('/').Trim();
                    //close group
                    if (scopestack.Any() && scopestack.Peek().Item1 == token)
                    {
                        scopestack.Pop();
                        tokens.Add(new TokenPair(TokenType.ElementClose, token,
                                                 context.CurrentLocation));
                    }
                    else
                    {
                        context.Errors.Add(new MorestachioUnopendScopeError(context.CurrentLocation
                                                                            .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)), "/", "{{#path}}",
                                                                            " There are more closing elements then open."));
                    }
                }
                else if (tokenValue.StartsWith("{{{") || tokenValue.StartsWith("{{&"))
                {
                    //escaped single element
                    var token = trimmedToken.TrimStart('&').Trim();
                    tokens.Add(new TokenPair(TokenType.UnescapedSingleValue, token, context.CurrentLocation)
                    {
                        MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                    });
                }
                else if (tokenValue.StartsWith("{{!"))
                {
                    //it's a comment drop this on the floor, no need to even yield it.
                }
                else if (tokenValue.StartsWith("#") || tokenValue.StartsWith("/"))
                {
                    //catch expression handler
                    context.Errors.Add(new MorestachioSyntaxError(context.CurrentLocation
                                                                  .AddWindow(new CharacterSnippedLocation(1, 1, match.Value)),
                                                                  $"Unexpected token. Expected an valid Expression but got '{tokenValue}'", tokenValue, ""));
                }
                else
                {
                    //check for custom DocumentItem provider

                    var customDocumentProvider =
                        parserOptions.CustomDocumentItemProviders.FirstOrDefault(e => e.ShouldTokenize(tokenValue));

                    if (customDocumentProvider != null)
                    {
                        var tokenInfo  = new CustomDocumentItemProvider.TokenInfo(tokenValue, context, scopestack);
                        var tokenPairs = customDocumentProvider.Tokenize(tokenInfo, parserOptions);
                        tokens.AddRange(tokenPairs);
                    }
                    else
                    {
                        //unsingle value.
                        var token = trimmedToken.Trim();
                        tokens.Add(new TokenPair(TokenType.EscapedSingleValue, token, context.CurrentLocation)
                        {
                            MorestachioExpression = ExpressionTokenizer.ParseExpressionOrString(token, context)
                        });
                    }
                }

                //move forward in the string.
                if (context.Character > match.Index + match.Length)
                {
                    throw new InvalidOperationException("Internal index location error");
                }

                context.SetLocation(match.Index + match.Length);
            }

            if (context.Character < templateString.Length)
            {
                tokens.Add(new TokenPair(TokenType.Content, templateString.Substring(context.Character),
                                         context.CurrentLocation));
            }

            if (scopestack.Any() || parserOptions.CustomDocumentItemProviders.Any(f => f.ScopeStack.Any()))
            {
                foreach (var unclosedScope in scopestack
                         .Concat(parserOptions.CustomDocumentItemProviders.SelectMany(f => f.ScopeStack))
                         .Select(k =>
                {
                    var value = k.Item1.Trim('{', '#', '}');
                    if (value.StartsWith("each "))
                    {
                        value = value.Substring(5);
                    }

                    return(new
                    {
                        scope = value,
                        location = HumanizeCharacterLocation(k.Item2, context.Lines)
                    });
                }).Reverse())
                {
                    context.Errors.Add(new MorestachioUnopendScopeError(unclosedScope.location
                                                                        .AddWindow(new CharacterSnippedLocation(1, -1, "")), unclosedScope.scope, ""));
                }
            }

            return(tokens);
        }
Exemplo n.º 8
0
        internal static IEnumerable <TokenPair> TokenizeString(string partial,
                                                               ICollection <IMorestachioError> parseErrors,
                                                               PerformanceProfiler profiler)
        {
            var             templateString = partial;
            MatchCollection matches;

            using (profiler.Begin("Find Tokens"))
            {
                matches = TokenFinder.Matches(templateString);
            }

            var scopestack = new Stack <Tuple <string, int> >();

            var idx = 0;

            var lines = new List <int>();

            lines.AddRange(NewlineFinder.Matches(templateString).OfType <Match>().Select(k => k.Index));

            var partialsNames = new List <string>();

            var tokens = new List <TokenPair>();

            foreach (Match m in matches)
            {
                int tokenIndex = m.Index;
                //yield front content.
                if (m.Index > idx)
                {
                    tokens.Add(new TokenPair(TokenType.Content, templateString.Substring(idx, m.Index - idx), HumanizeCharacterLocation(tokenIndex, lines)));
                }

                if (m.Value.StartsWith("{{#declare", true, CultureInfo.InvariantCulture))
                {
                    scopestack.Push(Tuple.Create(m.Value, m.Index));
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('#').Trim().Substring("declare".Length);
                    if (string.IsNullOrWhiteSpace(token))
                    {
                        parseErrors.Add(new MorestachioSyntaxError(HumanizeCharacterLocation(m.Index, lines), "open", "declare", "{{#declare name}}", " Missing the Name."));
                    }
                    else
                    {
                        partialsNames.Add(token);
                        tokens.Add(new TokenPair(TokenType.PartialDeclarationOpen, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{/declare", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(m.Value, "{{/declare}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        parseErrors.Add(new MorestachioSyntaxError(HumanizeCharacterLocation(m.Index, lines), "close", "declare", "{{/declare}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("{{#declare"))
                    {
                        var token = scopestack.Pop().Item1.TrimStart('{').TrimEnd('}').TrimStart('#').Trim()
                                    .Substring("declare".Length);
                        tokens.Add(new TokenPair(TokenType.PartialDeclarationClose, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        parseErrors.Add(new MorestachioUnopendScopeError(HumanizeCharacterLocation(m.Index, lines), "declare", "{{#declare name}}"));
                    }
                }
                else if (m.Value.StartsWith("{{#include", true, CultureInfo.InvariantCulture))
                {
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('#').Trim().Substring("include".Length);
                    if (string.IsNullOrWhiteSpace(token) || !partialsNames.Contains(token))
                    {
                        parseErrors.Add(new MorestachioSyntaxError(
                                            HumanizeCharacterLocation(m.Index, lines),
                                            "use",
                                            "include",
                                            "{{#include name}}",
                                            $" There is no Partial declared '{token}'. Partial names are case sensitive and must be declared before an include."));
                    }
                    else
                    {
                        tokens.Add(new TokenPair(TokenType.RenderPartial, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{#each", true, CultureInfo.InvariantCulture))
                {
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('#').Trim().Substring("each".Length);
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;

                    scopestack.Push(Tuple.Create($"#each{alias}", m.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        if (FormatInExpressionFinder.IsMatch(token))
                        {
                            tokens.AddRange(TokenizeFormattables(token, templateString, lines,
                                                                 tokenIndex, parseErrors));

                            tokens.Add(new TokenPair(TokenType.CollectionOpen, ".", HumanizeCharacterLocation(tokenIndex, lines)));
                        }
                        else
                        {
                            tokens.Add(new TokenPair(TokenType.CollectionOpen,
                                                     Validated(token, templateString, m.Index, lines, parseErrors).Trim(), HumanizeCharacterLocation(tokenIndex, lines)));
                        }
                    }
                    else
                    {
                        parseErrors.Add(new InvalidPathSyntaxError(HumanizeCharacterLocation(m.Index, lines), ""));
                    }

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        tokens.Add(new TokenPair(TokenType.Alias, alias, HumanizeCharacterLocation(m.Index + $"#each{alias}".Length, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{#if", true, CultureInfo.InvariantCulture))
                {
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('#').Trim().Substring("if".Length);
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;

                    scopestack.Push(Tuple.Create($"#if{alias}", m.Index));

                    if (token.StartsWith(" ") && token.Trim() != "")
                    {
                        token = token.Trim();
                        if (FormatInExpressionFinder.IsMatch(token))
                        {
                            tokens.AddRange(TokenizeFormattables(token, templateString, lines,
                                                                 tokenIndex, parseErrors));

                            tokens.Add(new TokenPair(TokenType.If, ".", HumanizeCharacterLocation(tokenIndex, lines)));
                        }
                        else
                        {
                            tokens.Add(new TokenPair(TokenType.If,
                                                     Validated(token, templateString, m.Index, lines, parseErrors).Trim(), HumanizeCharacterLocation(tokenIndex, lines)));
                        }
                    }
                    else
                    {
                        parseErrors.Add(new InvalidPathSyntaxError(HumanizeCharacterLocation(m.Index, lines), ""));
                    }

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        tokens.Add(new TokenPair(TokenType.Alias, alias, HumanizeCharacterLocation(m.Index + $"#if{alias}".Length, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{/if", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(m.Value, "{{/if}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        parseErrors.Add(new MorestachioSyntaxError(HumanizeCharacterLocation(m.Index, lines), "close", "if", "{{/if}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#if"))
                    {
                        var token = scopestack.Pop().Item1;
                        tokens.Add(new TokenPair(TokenType.IfClose, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        parseErrors.Add(new MorestachioUnopendScopeError(HumanizeCharacterLocation(m.Index, lines), "if", "{{#if name}}"));
                    }
                }
                else if (m.Value.StartsWith("{{/each", true, CultureInfo.InvariantCulture))
                {
                    if (!string.Equals(m.Value, "{{/each}}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        parseErrors.Add(new MorestachioSyntaxError(HumanizeCharacterLocation(m.Index, lines), "close", "each", "{{/each}}"));
                    }
                    else if (scopestack.Any() && scopestack.Peek().Item1.StartsWith("#each"))
                    {
                        var token = scopestack.Pop().Item1;
                        tokens.Add(new TokenPair(TokenType.CollectionClose, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        parseErrors.Add(new MorestachioUnopendScopeError(HumanizeCharacterLocation(m.Index, lines), "each", "{{#each name}}"));
                    }
                }
                else if (m.Value.StartsWith("{{#"))
                {
                    //open group
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('#').Trim();

                    var eval = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;

                    if (scopestack.Any() && scopestack.Peek().Item1 == token)
                    {
                        tokens.Add(new TokenPair(TokenType.ElementClose,
                                                 Validated(token, templateString, m.Index, lines, parseErrors), HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        scopestack.Push(Tuple.Create(alias, m.Index));
                    }

                    if (FormatInExpressionFinder.IsMatch(token))
                    {
                        tokens.AddRange(TokenizeFormattables(token, templateString, lines, tokenIndex,
                                                             parseErrors));

                        tokens.Add(new TokenPair(TokenType.ElementOpen, ".", HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        tokens.Add(new TokenPair(TokenType.ElementOpen,
                                                 Validated(token, templateString, m.Index, lines, parseErrors), HumanizeCharacterLocation(tokenIndex, lines)));
                    }

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        tokens.Add(new TokenPair(TokenType.Alias, alias, HumanizeCharacterLocation(m.Index + token.Length, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{^"))
                {
                    //open inverted group
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('^').Trim();
                    var eval  = EvaluateNameFromToken(token);
                    token = eval.Item1;
                    var alias = eval.Item2;

                    if (scopestack.Any() && scopestack.Peek().Item1 == token)
                    {
                        tokens.Add(new TokenPair(TokenType.ElementClose,
                                                 Validated(token, templateString, m.Index, lines, parseErrors), HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        scopestack.Push(Tuple.Create(alias, m.Index));
                    }

                    if (FormatInExpressionFinder.IsMatch(token))
                    {
                        tokens.AddRange(TokenizeFormattables(token, templateString, lines, tokenIndex,
                                                             parseErrors));

                        tokens.Add(new TokenPair(TokenType.InvertedElementOpen, ".", HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        tokens.Add(new TokenPair(TokenType.InvertedElementOpen,
                                                 Validated(token, templateString, m.Index, lines, parseErrors), HumanizeCharacterLocation(tokenIndex, lines)));
                    }

                    if (!string.IsNullOrWhiteSpace(alias))
                    {
                        tokens.Add(new TokenPair(TokenType.Alias, alias,
                                                 HumanizeCharacterLocation(m.Index + $"#each{alias}".Length, lines)));
                    }
                }
                else if (m.Value.StartsWith("{{/"))
                {
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('/').Trim();
                    //close group
                    if (scopestack.Any() && scopestack.Peek().Item1 == token)
                    {
                        scopestack.Pop();
                        tokens.Add(new TokenPair(TokenType.ElementClose, token, HumanizeCharacterLocation(tokenIndex, lines)));
                    }
                    else
                    {
                        parseErrors.Add(new MorestachioUnopendScopeError(HumanizeCharacterLocation(m.Index, lines), "/", "{{#path}}", " There are more closing elements then open."));
                    }
                }
                else if (m.Value.StartsWith("{{{") | m.Value.StartsWith("{{&"))
                {
                    //escaped single element
                    var token = m.Value.TrimStart('{').TrimEnd('}').TrimStart('&').Trim();
                    tokens.Add(new TokenPair(TokenType.UnescapedSingleValue,
                                             Validated(token, templateString, m.Index, lines, parseErrors), HumanizeCharacterLocation(tokenIndex, lines)));
                }
                else if (m.Value.StartsWith("{{!"))
                {
                    //it's a comment drop this on the floor, no need to even yield it.
                }
                else
                {
                    tokens.AddRange(TokenizePath(parseErrors, m.Value, templateString, lines, tokenIndex));
                }

                //move forward in the string.
                idx = m.Index + m.Length;
            }

            if (idx < templateString.Length)
            {
                tokens.Add(new TokenPair(TokenType.Content, templateString.Substring(idx), HumanizeCharacterLocation(idx, lines)));
            }

            #region Assert that any scopes opened must be closed.

            if (scopestack.Any())
            {
                foreach (var unclosedScope in scopestack.Select(k =>
                {
                    var value = k.Item1.Trim('{', '#', '}');
                    if (value.StartsWith("each "))
                    {
                        value = value.Substring(5);
                    }

                    return(new
                    {
                        scope = value,
                        location = HumanizeCharacterLocation(k.Item2, lines)
                    });
                }).Reverse())
                {
                    parseErrors.Add(new MorestachioUnopendScopeError(unclosedScope.location, unclosedScope.scope, ""));
                }
            }

            return(tokens);

            #endregion

            ////We want to throw an aggregate template exception, but in due time.
            //if (!parseErrors.Any())
            //{
            //	yield break;
            //}

            //var innerExceptions = parseErrors.OrderBy(k => k.LineNumber).ThenBy(k => k.CharacterOnLine).ToArray();
            //throw new AggregateException(innerExceptions);
        }