public override Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token)
        {
            // block.Argument key is unique to exact memory fragment, not string equality
            var invokerCtx = (Tuple <string, StaticMethodInvoker>)scope.Context.CacheMemory.GetOrAdd(block.Argument, key => {
                var literal = block.Argument.Span.ParseVarName(out var name);
                var strName = name.ToString();
                literal     = literal.AdvancePastWhitespace();

                literal  = literal.AdvancePastWhitespace();
                var args = TypeConstants.EmptyStringArray;
                if (!literal.IsEmpty)
                {
                    literal = literal.ParseArgumentsList(out var argIdentifiers);
                    args    = new string[argIdentifiers.Count];
                    for (var i = 0; i < argIdentifiers.Count; i++)
                    {
                        args[i] = argIdentifiers[i].Name;
                    }
                }

                StaticMethodInvoker invoker = null;

                // Allow recursion by initializing lazy Delegate
                MethodInvoker LazyInvoker = (instance, paramValues) => {
                    if (invoker == null)
                    {
                        throw new NotSupportedException($"Uninitialized function '{strName}'");
                    }

                    return(invoker(instance, paramValues));
                };

                invoker = (paramValues) => {
                    scope.PageResult.StackDepth++;
                    try
                    {
                        var page       = new SharpPage(Context, block.Body);
                        var pageResult = new PageResult(page)
                        {
                            Args =
                            {
                                [strName] = LazyInvoker
                            },
                            StackDepth = scope.PageResult.StackDepth
                        };

                        var len = Math.Min(paramValues.Length, args.Length);
                        for (int i = 0; i < len; i++)
                        {
                            var paramValue           = paramValues[i];
                            pageResult.Args[args[i]] = paramValue;
                        }

                        if (pageResult.EvaluateResult(out var returnValue))
                        {
                            return(returnValue);
                        }

                        return(IgnoreResult.Value);
                    }
                    finally
                    {
                        scope.PageResult.StackDepth--;
                    }
                };
Example #2
0
        public override Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token)
        {
            var invokerCtx = (Tuple <string, StaticMethodInvoker>)scope.Context.CacheMemory.GetOrAdd(block.Argument, key => {
                var literal = block.Argument.Span.ParseVarName(out var name);
                var strName = name.ToString();
                literal     = literal.AdvancePastWhitespace();

                literal  = literal.AdvancePastWhitespace();
                var args = TypeConstants.EmptyStringList;
                if (!literal.IsEmpty)
                {
                    literal = literal.ParseArgumentsList(out var argIdentifiers);
                    args    = argIdentifiers.Map(x => x.Name);
                }

                var strFragment = (PageStringFragment)block.Body[0];

                var script       = ScriptPreprocessors.TransformStatementBody(strFragment.ValueString);
                var parsedScript = scope.Context.OneTimePage(script);

                StaticMethodInvoker invoker = null;

                // Allow recursion by initializing lazy Delegate
                object LazyInvoker(object instance, object[] paramValues)
                {
                    if (invoker == null)
                    {
                        throw new NotSupportedException($"Uninitialized function '{strName}'");
                    }

                    return(invoker(instance, paramValues));
                }

                invoker = (paramValues) => {
                    scope.PageResult.StackDepth++;
                    try
                    {
                        var pageResult = new PageResult(parsedScript)
                        {
                            Args =
                            {
                                [strName] = (MethodInvoker)LazyInvoker
                            },
                            StackDepth = scope.PageResult.StackDepth
                        };

                        var len = Math.Min(paramValues.Length, args.Count);
                        for (int i = 0; i < len; i++)
                        {
                            var paramValue           = paramValues[i];
                            pageResult.Args[args[i]] = paramValue;
                        }

                        var discard = ScriptContextUtils.GetPageResultOutput(pageResult);
                        if (pageResult.ReturnValue == null)
                        {
                            throw new NotSupportedException(ScriptContextUtils.ErrorNoReturn);
                        }

                        return(pageResult.ReturnValue.Result);
                    }
                    finally
                    {
                        scope.PageResult.StackDepth--;
                    }
                };

                return(Tuple.Create(strName, invoker));
            });

            scope.PageResult.Args[invokerCtx.Item1] = invokerCtx.Item2;

            return(TypeConstants.EmptyTask);
        }