public JsFilterExpressionStatement(string originalText, JsToken expr, params JsCallExpression[] filters) { FilterExpression = new PageVariableFragment(originalText.AsMemory(), expr, new List <JsCallExpression>(filters)); }
public JsFilterExpressionStatement(ReadOnlyMemory <char> originalText, JsToken expr, List <JsCallExpression> filters) { FilterExpression = new PageVariableFragment(originalText, expr, filters); }
protected bool Equals(PageVariableFragment other) { return(OriginalText.Span.SequenceEqual(other.OriginalText.Span) && Equals(Expression, other.Expression) && FilterExpressions.EquivalentTo(other.FilterExpressions)); }
public static List <PageFragment> ParseTemplate(this ScriptContext context, ReadOnlyMemory <char> text) { var to = new List <PageFragment>(); if (text.IsNullOrWhiteSpace()) { return(to); } int pos; var lastPos = 0; int nextPos() { var c1 = text.IndexOf("{{", lastPos); var c2 = text.IndexOf("{|", lastPos); if (c2 == -1) { return(c1); } return(c1 == -1 ? c2 : c1 < c2 ? c1 : c2); } while ((pos = nextPos()) != -1) { var block = text.Slice(lastPos, pos - lastPos); if (!block.IsNullOrEmpty()) { to.Add(new PageStringFragment(block)); } var varStartPos = pos + 2; if (varStartPos >= text.Span.Length) { throw new SyntaxErrorException($"Unterminated '{{{{' expression, near '{text.Slice(lastPos).DebugLiteral()}'"); } if (text.Span.SafeCharEquals(varStartPos - 1, '|')) // lang expression syntax {|lang ... |} https://flow.org/en/docs/types/objects/#toc-exact-object-types { var literal = text.Slice(varStartPos); ScriptLanguage lang = null; if (literal.SafeGetChar(0).IsValidVarNameChar()) { literal = literal.ParseVarName(out var langSpan); lang = context.GetScriptLanguage(langSpan.ToString()); if (lang != null) { var endPos = literal.IndexOf("|}"); if (endPos == -1) { throw new SyntaxErrorException($"Unterminated '|}}' expression, near '{text.Slice(varStartPos).DebugLiteral()}'"); } var exprStr = literal.Slice(0, endPos); var langExprFragment = lang.Parse(context, exprStr); to.AddRange(langExprFragment); } } if (lang == null) { var nextLastPos = text.IndexOf("|}", varStartPos) + 2; block = text.Slice(pos, nextLastPos - pos); if (!block.IsNullOrEmpty()) { to.Add(new PageStringFragment(block)); } } lastPos = text.IndexOf("|}", varStartPos) + 2; continue; } var firstChar = text.Span[varStartPos]; if (firstChar == '*') //comment { lastPos = text.IndexOf("*}}", varStartPos) + 3; if (text.Span.SafeCharEquals(lastPos, '\r')) { lastPos++; } if (text.Span.SafeCharEquals(lastPos, '\n')) { lastPos++; } } else if (firstChar == '#') //block statement { var literal = text.Slice(varStartPos + 1); literal = literal.ParseTemplateScriptBlock(context, out var blockFragment); var length = text.Length - pos - literal.Length; blockFragment.OriginalText = text.Slice(pos, length); lastPos = pos + length; to.Add(blockFragment); } else { var literal = text.Slice(varStartPos).Span; literal = literal.ParseJsExpression(out var expr, filterExpression: true); var filters = new List <JsCallExpression>(); if (!literal.StartsWith("}}")) { literal = literal.AdvancePastWhitespace(); if (literal.FirstCharEquals(FilterSep)) { literal = literal.AdvancePastPipeOperator(); while (true) { literal = literal.ParseJsCallExpression(out var filter, filterExpression: true); filters.Add(filter); literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty()) { throw new SyntaxErrorException("Unterminated filter expression"); } if (literal.StartsWith("}}")) { literal = literal.Advance(2); break; } if (!literal.FirstCharEquals(FilterSep)) { throw new SyntaxErrorException( $"Expected pipeline operator '|>' but was {literal.DebugFirstChar()}"); } literal = literal.AdvancePastPipeOperator(); } } else if (!literal.AdvancePastWhitespace().IsNullOrEmpty()) { throw new SyntaxErrorException($"Unexpected syntax '{literal.ToString()}', Expected pipeline operator '|>'"); } } else { literal = literal.Advance(2); } var length = text.Length - pos - literal.Length; var originalText = text.Slice(pos, length); lastPos = pos + length; var varFragment = new PageVariableFragment(originalText, expr, filters); to.Add(varFragment); var newLineLen = literal.StartsWith("\n") ? 1 : literal.StartsWith("\r\n") ? 2 : 0; if (newLineLen > 0) { var lastExpr = varFragment.FilterExpressions?.LastOrDefault(); var filterName = lastExpr?.Name ?? varFragment?.InitialExpression?.Name ?? varFragment.Binding; if ((filterName != null && context.RemoveNewLineAfterFiltersNamed.Contains(filterName)) || expr is JsVariableDeclaration) { lastPos += newLineLen; } } } } if (lastPos != text.Length) { var lastBlock = lastPos == 0 ? text : text.Slice(lastPos); to.Add(new PageStringFragment(lastBlock)); } return(to); }
public static List <PageFragment> ParseTemplate(this ScriptContext context, ReadOnlyMemory <char> text) { var to = new List <PageFragment>(); if (text.IsNullOrWhiteSpace()) { return(to); } int pos; var lastPos = 0; while ((pos = text.IndexOf("{{", lastPos)) != -1) { var block = text.Slice(lastPos, pos - lastPos); if (!block.IsNullOrEmpty()) { to.Add(new PageStringFragment(block)); } var varStartPos = pos + 2; if (varStartPos >= text.Span.Length) { throw new SyntaxErrorException($"Unterminated '{{{{' expression, near '{text.Slice(lastPos).DebugLiteral()}'"); } var firstChar = text.Span[varStartPos]; if (firstChar == '*') //comment { lastPos = text.IndexOf("*}}", varStartPos) + 3; if (text.Span.SafeCharEquals(lastPos, '\r')) { lastPos++; } if (text.Span.SafeCharEquals(lastPos, '\n')) { lastPos++; } } else if (firstChar == '#') //block statement { var literal = text.Slice(varStartPos + 1); literal = literal.ParseTemplateScriptBlock(context, out var blockFragment); var length = text.Length - pos - literal.Length; blockFragment.OriginalText = text.Slice(pos, length); lastPos = pos + length; to.Add(blockFragment); } else { var literal = text.Slice(varStartPos).Span; literal = literal.ParseJsExpression(out var expr, filterExpression: true); var filters = new List <JsCallExpression>(); if (!literal.StartsWith("}}")) { literal = literal.AdvancePastWhitespace(); if (literal.FirstCharEquals(FilterSep)) { literal = literal.Advance(1); while (true) { literal = literal.ParseJsCallExpression(out var filter, filterExpression: true); filters.Add(filter); literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty()) { throw new SyntaxErrorException("Unterminated filter expression"); } if (literal.StartsWith("}}")) { literal = literal.Advance(2); break; } if (!literal.FirstCharEquals(FilterSep)) { throw new SyntaxErrorException( $"Expected filter separator '|' but was {literal.DebugFirstChar()}"); } literal = literal.Advance(1); } } else { if (!literal.IsNullOrEmpty()) { literal = literal.Advance(1); } } } else { literal = literal.Advance(2); } var length = text.Length - pos - literal.Length; var originalText = text.Slice(pos, length); lastPos = pos + length; var varFragment = new PageVariableFragment(originalText, expr, filters); to.Add(varFragment); var newLineLen = literal.StartsWith("\n") ? 1 : literal.StartsWith("\r\n") ? 2 : 0; if (newLineLen > 0) { var lastExpr = varFragment.FilterExpressions?.LastOrDefault(); var filterName = lastExpr?.Name ?? varFragment?.InitialExpression?.Name ?? varFragment.Binding; if (filterName != null && context.RemoveNewLineAfterFiltersNamed.Contains(filterName)) { lastPos += newLineLen; } } } } if (lastPos != text.Length) { var lastBlock = lastPos == 0 ? text : text.Slice(lastPos); to.Add(new PageStringFragment(lastBlock)); } return(to); }