Exemplo n.º 1
0
        public static object Call(TemplateContext context, ScriptNode callerContext, object functionObject, List <ScriptExpression> arguments = null)
        {
            if (callerContext == null)
            {
                throw new ArgumentNullException(nameof(callerContext));
            }
            if (functionObject == null)
            {
                throw new ScriptRuntimeException(callerContext.Span, $"The target function [{callerContext}] is null");
            }
            var function       = functionObject as ScriptFunction;
            var externFunction = functionObject as IScriptCustomFunction;

            if (function == null && externFunction == null)
            {
                throw new ScriptRuntimeException(callerContext.Span, $"Invalid object function [{functionObject?.GetType()}]");
            }

            ScriptBlockStatement blockDelegate = null;

            if (context.BlockDelegates.Count > 0)
            {
                blockDelegate = context.BlockDelegates.Pop();
            }

            var argumentValues = new ScriptArray();

            if (arguments != null)
            {
                foreach (var argument in arguments)
                {
                    var value = context.Evaluate(argument);

                    // Handle parameters expansion for a function call when the operator ^ is used
                    var unaryExpression = argument as ScriptUnaryExpression;
                    if (unaryExpression != null && unaryExpression.ExpandParameters(value, argumentValues))
                    {
                        continue;
                    }

                    argumentValues.Add(value);
                }
            }

            // Handle pipe arguments here
            if (context.PipeArguments.Count > 0)
            {
                var additionalArgument = context.PipeArguments.Pop();

                var value = context.Evaluate(additionalArgument);

                // Handle parameters expansion for a function call when the operator ~ is used
                var unaryExpression = additionalArgument as ScriptUnaryExpression;
                if (unaryExpression == null || !unaryExpression.ExpandParameters(value, argumentValues))
                {
                    argumentValues.Add(value);
                }
            }

            object result = null;

            context.EnterFunction(callerContext);
            try
            {
                if (externFunction != null)
                {
                    result = externFunction.Invoke(context, callerContext, argumentValues, blockDelegate);
                }
                else
                {
                    context.SetValue(ScriptVariable.Arguments, argumentValues, true);

                    // Set the block delegate
                    if (blockDelegate != null)
                    {
                        context.SetValue(ScriptVariable.BlockDelegate, blockDelegate, true);
                    }
                    result = context.Evaluate(function.Body);
                }
            }
            finally
            {
                context.ExitFunction();
            }

            // Restore the flow state to none
            context.FlowState = ScriptFlowState.None;
            return(result);
        }
Exemplo n.º 2
0
        public static object Call(TemplateContext context, ScriptNode callerContext, object functionObject, bool processPipeArguments, List <ScriptExpression> arguments = null)
        {
            if (callerContext == null)
            {
                throw new ArgumentNullException(nameof(callerContext));
            }
            if (functionObject == null)
            {
                throw new ScriptRuntimeException(callerContext.Span, $"The target function `{callerContext}` is null");
            }
            var function       = functionObject as ScriptFunction;
            var externFunction = functionObject as IScriptCustomFunction;

            if (function == null && externFunction == null)
            {
                throw new ScriptRuntimeException(callerContext.Span, $"Invalid target function `{callerContext}`( as `{functionObject?.GetType()}`)");
            }

            ScriptBlockStatement blockDelegate = null;

            if (context.BlockDelegates.Count > 0)
            {
                blockDelegate = context.BlockDelegates.Pop();
            }

            // We can't cache this array because it might be collect by the function
            // So we absolutely need to generate a new array everytime we call a function
            var argumentValues = new ScriptArray();

            // Handle pipe arguments here
            if (processPipeArguments && context.PipeArguments.Count > 0)
            {
                argumentValues.AddRange(context.PipeArguments);
                context.PipeArguments.Clear();
            }

            // Process direct arguments
            if (arguments != null)
            {
                foreach (var argument in arguments)
                {
                    object value;

                    // Handle named arguments
                    var namedArg = argument as ScriptNamedArgument;
                    if (namedArg != null)
                    {
                        // In case of a ScriptFunction, we write the named argument into the ScriptArray directly
                        if (externFunction == null)
                        {
                            // We can't add an argument that is "size" for array
                            if (argumentValues.CanWrite(namedArg.Name))
                            {
                                argumentValues.SetValue(context, callerContext.Span, namedArg.Name, context.Evaluate(namedArg), false);
                                continue;
                            }

                            // Otherwise pass as a regular argument
                            value = context.Evaluate(namedArg);
                        }
                        else
                        {
                            // Named argument are passed as is to the IScriptCustomFunction
                            value = argument;
                        }
                    }
                    else
                    {
                        value = context.Evaluate(argument);
                    }

                    // Handle parameters expansion for a function call when the operator ^ is used
                    var unaryExpression = argument as ScriptUnaryExpression;
                    if (unaryExpression != null && unaryExpression.Operator == ScriptUnaryOperator.FunctionParametersExpand)
                    {
                        var valueEnumerator = value as IEnumerable;
                        if (valueEnumerator != null)
                        {
                            foreach (var subValue in valueEnumerator)
                            {
                                argumentValues.Add(subValue);
                            }
                            continue;
                        }
                    }

                    argumentValues.Add(value);
                }
            }

            object result = null;

            context.EnterFunction(callerContext);
            try
            {
                if (externFunction != null)
                {
                    result = externFunction.Invoke(context, callerContext, argumentValues, blockDelegate);
                }
                else
                {
                    context.SetValue(ScriptVariable.Arguments, argumentValues, true);

                    // Set the block delegate
                    if (blockDelegate != null)
                    {
                        context.SetValue(ScriptVariable.BlockDelegate, blockDelegate, true);
                    }
                    result = context.Evaluate(function.Body);
                }
            }
            finally
            {
                context.ExitFunction();
            }

            // Restore the flow state to none
            context.FlowState = ScriptFlowState.None;
            return(result);
        }