public static Func <ScriptScopeContext, object, object> GetMemberExpression(Type targetType, ReadOnlyMemory <char> expression) { if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } if (expression.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(expression)); } var key = targetType.FullName + ':' + expression; if (BinderCache.TryGetValue(key, out var fn)) { return(fn); } BinderCache[key] = fn = Compile(targetType, expression); return(fn); }
public Action <ScriptScopeContext, object, object> GetAssignExpression(Type targetType, ReadOnlyMemory <char> expression) { if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } if (expression.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(expression)); } var key = targetType.FullName + ':' + expression; if (AssignExpressionCache.TryGetValue(key, out var fn)) { return(fn); } AssignExpressionCache[key] = fn = SharpPageUtils.CompileAssign(targetType, expression); return(fn); }
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> 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); }