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()); }