Example #1
0
        public static List <PageFragment> ParseScript(this ScriptContext context, ReadOnlyMemory <char> text)
        {
            var                   to             = new List <PageFragment>();
            ScriptLanguage        scriptLanguage = null;
            ReadOnlyMemory <char> modifiers      = default;
            ReadOnlyMemory <char> prevBlock      = default;
            int                   startBlockPos  = -1;
            var                   cursorPos      = 0;
            var                   lastBlockPos   = 0;

            const int delim = 3; // '```'.length

            while (text.TryReadLine(out var line, ref cursorPos))
            {
                var lineLength = line.Length;
                line = line.AdvancePastWhitespace();

                if (line.StartsWith("```"))
                {
                    if (scriptLanguage != null && startBlockPos >= 0 && line.Slice(delim).AdvancePastWhitespace().IsEmpty) //is end block
                    {
                        var templateFragments = ScriptTemplate.Language.Parse(context, prevBlock);
                        to.AddRange(templateFragments);

                        var blockBody      = text.ToLineStart(cursorPos, lineLength, startBlockPos);
                        var blockFragments = scriptLanguage.Parse(context, blockBody, modifiers);
                        to.AddRange(blockFragments);

                        prevBlock      = default;
                        startBlockPos  = -1;
                        scriptLanguage = null;
                        modifiers      = null;
                        lastBlockPos   = cursorPos;
                        continue;
                    }

                    if (line.SafeGetChar(delim).IsValidVarNameChar())
                    {
                        line = line.Slice(delim).ParseVarName(out var blockNameSpan);

                        var blockName = blockNameSpan.ToString();
                        scriptLanguage = context.GetScriptLanguage(blockName);
                        if (scriptLanguage == null)
                        {
                            continue;
                        }

                        modifiers = line.AdvancePastChar('|');
                        var delimLen = text.Span.SafeCharEquals(cursorPos - 2, '\r') ? 2 : 1;
                        prevBlock     = text.Slice(lastBlockPos, cursorPos - lastBlockPos - lineLength - delimLen);
                        startBlockPos = cursorPos;
                    }
                }
            }

            var remainingBlock = text.Slice(lastBlockPos);

            if (!remainingBlock.IsEmpty)
            {
                var templateFragments = ScriptTemplate.Language.Parse(context, remainingBlock);
                to.AddRange(templateFragments);
            }

            return(to);
        }
        internal static JsStatement[] ParseCodeStatements(this ScriptContext context, ReadOnlyMemory <char> code)
        {
            var to = new List <JsStatement>();

            int startExpressionPos = -1;

            var cursorPos = 0;

            while (code.TryReadLine(out var line, ref cursorPos))
            {
                var lineLength = line.Length;
                line = line.TrimStart();
                var leftIndent = lineLength - line.Length;
                line = line.TrimEnd();
                var rightIndent = lineLength - leftIndent - line.Length;

                if (line.IsEmpty)
                {
                    continue;
                }

                var firstChar = line.Span[0];

                // comments
                if (firstChar == '*')
                {
                    if (line.EndsWith("*"))
                    {
                        continue;
                    }
                }

                // template block statement
                if (firstChar == '{' && line.Span.SafeCharEquals(1, '{') && line.Span.SafeCharEquals(2, '#'))
                {
                    var fromLineStart = code.ToLineStart(cursorPos, lineLength).AdvancePastWhitespace();
                    var literal       = fromLineStart.Slice(3);

                    literal = literal.ParseTemplateScriptBlock(context, out var blockFragment);
                    blockFragment.OriginalText = fromLineStart.Slice(0, fromLineStart.Length - literal.Length);
                    to.Add(new JsPageBlockFragmentStatement(blockFragment));

                    cursorPos = code.Length - literal.Length;
                    continue;
                }

                // code block statement
                if (firstChar == '#')
                {
                    var fromLineStart = code.ToLineStart(cursorPos, lineLength).AdvancePastWhitespace();
                    var literal       = fromLineStart.Slice(1);

                    literal = literal.ParseCodeScriptBlock(context, out var blockFragment);
                    to.Add(new JsPageBlockFragmentStatement(blockFragment));

                    blockFragment.OriginalText = fromLineStart.Slice(0, fromLineStart.Length - literal.Length);

                    cursorPos = code.Length - literal.Length;
                    continue;
                }

                const int delim = 2; // '}}'.length
                // multi-line expression
                if (startExpressionPos >= 0)
                {
                    // multi-line end
                    if (line.EndsWith("}}"))
                    {
                        if (code.Span.SafeCharEquals(startExpressionPos, '*'))
                        {
                            if (!line.EndsWith("*}}")) // not a closing block comment, continue
                            {
                                continue;
                            }

                            // ignore multi-line comment
                        }
                        else
                        {
                            var CRLF      = code.Span.SafeCharEquals(cursorPos - 2, '\r') ? 2 : 1;
                            var exprStr   = code.Slice(startExpressionPos, cursorPos - startExpressionPos - rightIndent - delim - CRLF).Trim();
                            var afterExpr = exprStr.Span.ParseExpression(out var expr, out var filters);

                            to.AddExpression(exprStr, expr, filters);
                        }

                        startExpressionPos = -1;
                    }
                    continue;
                }

                if (firstChar == '{' && line.Span.SafeCharEquals(1, '{'))
                {
                    // single-line {{ expr }}
                    if (line.EndsWith("}}"))
                    {
                        var exprStr   = code.Slice(cursorPos - lineLength + leftIndent + delim, lineLength - leftIndent - delim - delim).Trim();
                        var afterExpr = exprStr.Span.ParseExpression(out var expr, out var filters);

                        to.AddExpression(exprStr, expr, filters);
                        continue;
                    }

                    // multi-line start
                    var CRLF = code.Span.SafeCharEquals(cursorPos - 2, '\r') ? 2 : 1;
                    startExpressionPos = cursorPos - lineLength - CRLF + leftIndent + delim;
                    continue;
                }
                else
                {
                    // treat line as an expression statement
                    var afterExpr = line.Span.ParseExpression(out var expr, out var filters);
                    afterExpr = afterExpr.AdvancePastWhitespace();

                    if (!afterExpr.IsEmpty)
                    {
                        throw new SyntaxErrorException($"Unexpected syntax after expression: {afterExpr.ToString()}, near {line.DebugLiteral()}");
                    }

                    to.AddExpression(line, expr, filters);
                }
            }

            return(to.ToArray());
        }