public static object EvaluateCode(this ScriptContext context, string code, Dictionary <string, object> args = null) { var pageResult = GetCodePageResult(context, code, args); if (!pageResult.EvaluateResult(out var returnValue)) { throw new NotSupportedException(ScriptContextUtils.ErrorNoReturn); } return(ScriptLanguage.UnwrapValue(returnValue)); }
/// <summary> /// Evaluate #Script and return value /// </summary> public static object Evaluate(this ScriptContext context, string script, Dictionary <string, object> args = null) { var pageResult = new PageResult(context.SharpScriptPage(script)); args.Each((x, y) => pageResult.Args[x] = y); if (!pageResult.EvaluateResult(out var returnValue)) { throw new NotSupportedException(ScriptContextUtils.ErrorNoReturn); } return(ScriptLanguage.UnwrapValue(returnValue)); }
public static async Task <object> EvaluateCodeAsync(this ScriptContext context, string code, Dictionary <string, object> args = null) { var pageResult = GetCodePageResult(context, code, args); var ret = await pageResult.EvaluateResultAsync(); if (!ret.Item1) { throw new NotSupportedException(ScriptContextUtils.ErrorNoReturn); } return(ScriptLanguage.UnwrapValue(ret.Item2)); }
/// <summary> /// Evaluate #Script and convert returned value to T asynchronously /// </summary> public static async Task <object> EvaluateAsync(this ScriptContext context, string script, Dictionary <string, object> args = null) { var pageResult = new PageResult(context.SharpScriptPage(script)); args.Each((x, y) => pageResult.Args[x] = y); var ret = await pageResult.EvaluateResultAsync(); if (!ret.Item1) { throw new NotSupportedException(ScriptContextUtils.ErrorNoReturn); } return(ScriptLanguage.UnwrapValue(ret.Item2)); }
public async Task <SharpPage> Load() { if (IsImmutable) { return(this); } string contents; using (var stream = File.OpenRead()) { contents = await stream.ReadToEndAsync(); } foreach (var preprocessor in Context.Preprocessors) { contents = preprocessor(contents); } var lastModified = File.LastModified; var fileContents = contents.AsMemory(); var pageVars = new Dictionary <string, object>(); var pos = 0; var bodyContents = fileContents; fileContents.AdvancePastWhitespace().TryReadLine(out ReadOnlyMemory <char> line, ref pos); var lineComment = ScriptLanguage.LineComment; if (line.StartsWith(Format.ArgsPrefix) || (lineComment != null && line.StartsWith(lineComment + Format.ArgsPrefix))) { while (fileContents.TryReadLine(out line, ref pos)) { if (line.Trim().Length == 0) { continue; } if (line.StartsWith(Format.ArgsSuffix) || (lineComment != null && line.StartsWith(lineComment + Format.ArgsSuffix))) { break; } if (lineComment != null && line.StartsWith(lineComment)) { line = line.Slice(lineComment.Length).TrimStart(); } var colonPos = line.IndexOf(':'); var spacePos = line.IndexOf(' '); var bracePos = line.IndexOf('{'); var sep = colonPos >= 0 ? ':' : ' '; if (bracePos > 0 && spacePos > 0 && colonPos > spacePos) { sep = ' '; } line.SplitOnFirst(sep, out var first, out var last); var key = first.Trim().ToString(); pageVars[key] = !last.IsEmpty ? last.Trim().ToString() : ""; } //When page has variables body starts from first non whitespace after variables end var argsSuffixPos = line.LastIndexOf(Format.ArgsSuffix); if (argsSuffixPos >= 0) { //Start back from the end of the ArgsSuffix pos -= line.Length - argsSuffixPos - Format.ArgsSuffix.Length; } bodyContents = fileContents.SafeSlice(pos).AdvancePastWhitespace(); } var pageFragments = pageVars.TryGetValue("ignore", out object ignore) && ("page".Equals(ignore.ToString()) || "template".Equals(ignore.ToString())) ? new List <PageFragment> { new PageStringFragment(bodyContents) } : ScriptLanguage.Parse(Context, bodyContents); foreach (var fragment in pageFragments) { if (fragment is PageVariableFragment var && var.Binding == ScriptConstants.Page) { IsLayout = true; break; } } lock (semaphore) { LastModified = lastModified; LastModifiedCheck = DateTime.UtcNow; FileContents = fileContents; Args = pageVars; BodyContents = bodyContents; PageFragments = pageFragments.ToArray(); HasInit = true; LayoutPage = Format.ResolveLayout(this); } if (LayoutPage != null) { if (!LayoutPage.HasInit) { await LayoutPage.Load(); } else { if (Context.DebugMode || Context.CheckForModifiedPagesAfter != null && DateTime.UtcNow - LayoutPage.LastModifiedCheck >= Context.CheckForModifiedPagesAfter.Value) { LayoutPage.File.Refresh(); LayoutPage.LastModifiedCheck = DateTime.UtcNow; if (LayoutPage.File.LastModified != LayoutPage.LastModified) { await LayoutPage.Load(); } } } } return(this); }
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> 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); }