public static List <PageFragment> ParseTemplatePage(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; var firstChar = text.Span[varStartPos]; if (firstChar == '*') //comment { lastPos = text.IndexOf("*}}", varStartPos) + 3; } else if (firstChar == '#') //block statement { var literal = text.Slice(varStartPos + 1); literal = literal.ParseVarName(out var blockNameSpan); var blockName = blockNameSpan.ToString(); var endExprPos = literal.IndexOf("}}"); if (endExprPos == -1) { throw new SyntaxErrorException($"Unterminated '{blockName}' block expression, near '{literal.DebugLiteral()}'"); } var blockExpr = literal.Slice(0, endExprPos).Trim(); literal = literal.Advance(endExprPos + 2); if (!ScriptConfig.DontEvaluateBlocksNamed.Contains(blockName)) { literal = literal.ParseStatementBody(blockNameSpan, out var body); var elseStatements = new List <PageElseBlock>(); while (literal.StartsWith("{{else")) { literal = literal.ParseElseStatement(blockName, out var elseStatement); elseStatements.Add(elseStatement); } literal = literal.Advance(2 + 1 + blockName.Length + 2); //remove new line after partial block end tag literal = literal.TrimFirstNewLine(); var length = text.Length - pos - literal.Length; var originalText = text.Slice(pos, length); lastPos = pos + length; var statement = new PageBlockFragment(originalText, blockName, blockExpr, body, elseStatements); to.Add(statement); } else { var endBlock = "{{/" + blockName + "}}"; var endBlockPos = literal.IndexOf(endBlock); if (endBlockPos == -1) { throw new SyntaxErrorException($"Unterminated end block '{endBlock}'"); } var endBlockBody = literal.Slice(0, endBlockPos); literal = literal.Advance(endBlockPos + endBlock.Length).TrimFirstNewLine(); var body = new List <PageFragment> { new PageStringFragment(endBlockBody) }; var length = text.Length - pos - literal.Length; var originalText = text.Slice(pos, length); lastPos = pos + length; var statement = new PageBlockFragment(originalText, blockName, blockExpr, body); to.Add(statement); } } 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 && ScriptConfig.RemoveNewLineAfterFiltersNamed.Contains(filterName)) { 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> ParseTemplatePage(StringSegment 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.Subsegment(lastPos, pos - lastPos); if (!block.IsNullOrEmpty()) { to.Add(new PageStringFragment(block)); } var varStartPos = pos + 2; var isComment = text.GetChar(varStartPos) == '*'; if (!isComment) { var literal = text.Subsegment(varStartPos).ParseNextToken(out object initialValue, out JsBinding initialBinding, allowWhitespaceSyntax: true); List <JsExpression> filterCommands = null; literal = literal.ParseNextToken(out _, out JsBinding filterOp); if (filterOp == JsBitwiseOr.Operator) { var varEndPos = 0; bool foundVarEnd = false; filterCommands = literal.ParseExpression <JsExpression>( separator: '|', atEndIndex: (str, strPos) => { while (str.Length > strPos && str.GetChar(strPos).IsWhiteSpace()) { strPos++; } if (str.Length > strPos + 1 && str.GetChar(strPos) == '}' && str.GetChar(strPos + 1) == '}') { foundVarEnd = true; varEndPos = varEndPos + 1 + strPos + 1; return(strPos); } return(null); }, allowWhitespaceSensitiveSyntax: true); if (!foundVarEnd) { throw new ArgumentException($"Invalid syntax near '{text.Subsegment(pos).SubstringWithElipsis(0, 50)}'"); } literal = literal.Advance(varEndPos); } else { literal = literal.Advance(1); } var length = text.Length - pos - literal.Length; var originalText = text.Subsegment(pos, length); lastPos = pos + length; var varFragment = new PageVariableFragment(originalText, initialValue, initialBinding, filterCommands); 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?.NameString ?? varFragment?.InitialExpression?.NameString ?? varFragment.BindingString; if (filterName != null && TemplateConfig.RemoveNewLineAfterFiltersNamed.Contains(filterName)) { lastPos += newLineLen; } } } else { lastPos = text.IndexOf("*}}", varStartPos) + 3; } } if (lastPos != text.Length) { var lastBlock = lastPos == 0 ? text : text.Subsegment(lastPos); to.Add(new PageStringFragment(lastBlock)); } return(to); }
public static List <PageFragment> ParseTemplatePage(StringSegment 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.Subsegment(lastPos, pos - lastPos); if (!block.IsNullOrEmpty()) { to.Add(new PageStringFragment(block)); } var varStartPos = pos + 2; var isComment = text.GetChar(varStartPos) == '*'; if (!isComment) { var literal = text.Subsegment(varStartPos); literal = literal.ParseJsExpression(out var expr, filterExpression: true); var filters = new List <JsCallExpression>(); if (!literal.StartsWith("}}")) { literal = literal.ParseJsToken(out var filterOp); if (filterOp == JsBitwiseOr.Operator) { 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.GetChar(0) != '|') { throw new SyntaxErrorException($"Expected filter separator '|' but was '{literal.GetChar(0)}'"); } 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.Subsegment(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.BindingString; if (filterName != null && TemplateConfig.RemoveNewLineAfterFiltersNamed.Contains(filterName)) { lastPos += newLineLen; } } } else { lastPos = text.IndexOf("*}}", varStartPos) + 3; } } if (lastPos != text.Length) { var lastBlock = lastPos == 0 ? text : text.Subsegment(lastPos); to.Add(new PageStringFragment(lastBlock)); } return(to); }
/// <summary> /// Equalses the specified other. /// </summary> /// <param name="other">The other.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> protected bool Equals(PageVariableFragment other) { return(OriginalText.Span.SequenceEqual(other.OriginalText.Span) && Equals(Expression, other.Expression) && FilterExpressions.EquivalentTo(other.FilterExpressions)); }
/// <summary> /// Initializes a new instance of the <see cref="JsFilterExpressionStatement"/> class. /// </summary> /// <param name="originalText">The original text.</param> /// <param name="expr">The expr.</param> /// <param name="filters">The filters.</param> public JsFilterExpressionStatement(string originalText, JsToken expr, params JsCallExpression[] filters) { FilterExpression = new PageVariableFragment(originalText.AsMemory(), expr, new List <JsCallExpression>(filters)); }
/// <summary> /// Initializes a new instance of the <see cref="JsFilterExpressionStatement"/> class. /// </summary> /// <param name="originalText">The original text.</param> /// <param name="expr">The expr.</param> /// <param name="filters">The filters.</param> public JsFilterExpressionStatement(ReadOnlyMemory <char> originalText, JsToken expr, List <JsCallExpression> filters) { FilterExpression = new PageVariableFragment(originalText, expr, filters); }