public BinaryExpressionOrOperator(ScriptBinaryOperator @operator, ScriptToken operatorToken)
 {
     Expression    = null;
     Operator      = @operator;
     OperatorToken = operatorToken;
     CallKind      = FunctionCallKind.None;
 }
Beispiel #2
0
        public override ScriptNode Visit(ScriptFunctionCall node)
        {
            if (_isScientific && !node.ExplicitCall)
            {
                var newNode = node.GetScientificExpression(_context);
                if (newNode != node)
                {
                    return(Visit((ScriptNode)newNode));
                }
            }

            var functionCall = (ScriptFunctionCall)base.Visit(node);

            // Make sure that we have always a parenthesis for function calls
            if (_isScientific)
            {
                if (_flags.HasFlags(ScriptFormatterFlags.ExplicitParenthesis) || functionCall.Arguments.Count > 1)
                {
                    functionCall.ExplicitCall = true;
                    functionCall.OpenParent ??= ScriptToken.OpenParen();
                    functionCall.CloseParen ??= ScriptToken.CloseParen();

                    // We remove any trailing spaces after the target cos (x) => cos(x)
                    functionCall.Target.RemoveTrailingSpace();
                    functionCall.Arguments.RemoveLeadingSpace();
                    functionCall.Arguments.MoveTrailingTriviasTo(functionCall.CloseParen, false);
                }
            }

            // Make sure that arguments are separated by a proper comma and space
            for (int i = 0; i < functionCall.Arguments.Count; i++)
            {
                var arg = functionCall.Arguments[i];

                // No need to nest expression for arguments
                arg = DeNestExpression(arg);

                if (i + 1 < functionCall.Arguments.Count)
                {
                    var lastToken = (IScriptTerminal)arg.FindLastTerminal();
                    if (_isScientific)
                    {
                        lastToken.AddCommaAfter();
                    }

                    if (_flags.HasFlags(ScriptFormatterFlags.AddSpaceBetweenOperators))
                    {
                        lastToken.AddSpaceAfter();
                    }
                }

                functionCall.Arguments[i] = arg;
            }

            return(functionCall);
        }
 public ScriptIndexerExpression()
 {
     OpenBracket  = ScriptToken.OpenBracket();
     CloseBracket = ScriptToken.CloseBracket();
 }
 public ScriptIsEmptyExpression()
 {
     QuestionToken = ScriptToken.Question();
 }
 public ScriptConditionalExpression()
 {
     QuestionToken = ScriptToken.Question();
     ColonToken    = ScriptToken.Colon();
 }
Beispiel #6
0
 public ScriptFrontMatter()
 {
     StartMarker = new ScriptToken(TokenType.FrontMatterMarker);
     EndMarker   = new ScriptToken(TokenType.FrontMatterMarker);
 }
 public ScriptObjectInitializerExpression()
 {
     OpenBrace  = ScriptToken.OpenBrace();
     Members    = new ScriptList <ScriptObjectMember>();
     CloseBrace = ScriptToken.CloseBrace();
 }
Beispiel #8
0
 public ScriptAssignExpression()
 {
     EqualToken = ScriptToken.Equal();
 }
 public ScriptMemberExpression()
 {
     DotToken = ScriptToken.Dot();
 }
 public ScriptArrayInitializerExpression()
 {
     OpenBracketToken  = ScriptToken.OpenBracket();
     Values            = new ScriptList <ScriptExpression>();
     CloseBracketToken = ScriptToken.CloseBracket();
 }
        private static ScriptExpression ParseBinaryExpressionTree(BinaryExpressionIterator it, int precedence, bool isExpectingExpression)
        {
            ScriptExpression leftOperand = null;

            while (it.HasCurrent)
            {
                var op          = it.Current;
                var nextOperand = op.Expression;

                if (nextOperand == null)
                {
                    var newPrecedence = Parser.GetDefaultBinaryOperatorPrecedence(op.Operator);

                    // Probe if the next argument is a function call
                    if (!isExpectingExpression && it.HasNext && it.PeekNext().CallKind != FunctionCallKind.None)
                    {
                        // If it is a function call, use its precedence
                        newPrecedence = newPrecedence < ImplicitFunctionCallPrecedence ? newPrecedence : ImplicitFunctionCallPrecedence;
                    }

                    if (newPrecedence <= precedence)
                    {
                        break;
                    }

                    it.MoveNext(); // Skip operator

                    var binary = new ScriptBinaryExpression
                    {
                        Left          = leftOperand,
                        Operator      = op.Operator,
                        OperatorToken = op.OperatorToken ?? ScriptToken.Star(), // Force an explicit token so that we don't enter an infinite loop when formatting an expression
                        Span          =
                        {
                            Start = leftOperand.Span.Start
                        },
                    };

                    binary.Right    = ParseBinaryExpressionTree(it, newPrecedence, isExpectingExpression);
                    binary.Span.End = binary.Right.Span.End;
                    leftOperand     = binary;
                }
                else
                {
                    if (!isExpectingExpression && op.CallKind != FunctionCallKind.None)
                    {
                        var functionCall = new ScriptFunctionCall
                        {
                            Target       = nextOperand,
                            ExplicitCall = true,
                            Span         =
                            {
                                Start = nextOperand.Span.Start
                            }
                        };

                        // Skip the function and move to the operator
                        if (!it.MoveNext())
                        {
                            throw new ScriptRuntimeException(nextOperand.Span, $"The function is expecting at least one argument");
                        }

                        // We are expecting only an implicit multiply. Anything else is invalid.
                        if (it.Current.Expression == null && (it.Current.Operator != ScriptBinaryOperator.Multiply || it.Current.OperatorToken != null))
                        {
                            throw new ScriptRuntimeException(nextOperand.Span, $"The function expecting one argument cannot be followed by the operator {it.Current.OperatorToken?.ToString() ?? it.Current.Operator.ToText()}");
                        }

                        // Skip the operator
                        if (!it.MoveNext())
                        {
                            throw new ScriptRuntimeException(nextOperand.Span, $"The function is expecting at least one argument");
                        }

                        var argExpression = ParseBinaryExpressionTree(it, ImplicitFunctionCallPrecedence, op.CallKind == FunctionCallKind.Expression);
                        functionCall.Arguments.Add(argExpression);
                        functionCall.Span.End = argExpression.Span.End;

                        leftOperand = functionCall;
                        continue;
                    }

                    leftOperand = nextOperand;
                    it.MoveNext();
                }
            }

            return(leftOperand);
        }
        private ScriptExpression Rewrite(TemplateContext context, int precedence, bool expectingExpression = false)
        {
            ScriptExpression leftValue = null;

            while (_index < Count)
            {
                ScriptExpression nextExpression = this[_index];

                // leftValue (*/^%)
                if (nextExpression is ScriptArgumentBinary bin)
                {
                    if (leftValue == null)
                    {
                        throw new ScriptRuntimeException(nextExpression.Span, precedence == 0 ? "This operator cannot be after a function call." : "This operator cannot be applied here.");
                    }

                    // Power has higher precedence than */%
                    var newPrecedence = Parser.GetDefaultBinaryOperatorPrecedence(bin.Operator);

                    if (newPrecedence <= precedence) // if new operator has lower precedence than previous, exit
                    {
                        break;
                    }

                    var rightArgExpr = this[_index + 1];
                    if (rightArgExpr is IScriptVariablePath)
                    {
                        var rightArg = context.Evaluate(rightArgExpr, true);
                        if (rightArg is IScriptCustomFunction function)
                        {
                            var maxArg = function.RequiredParameterCount;
                            if (maxArg >= 1 && PrecedenceTopLevel != precedence)
                            {
                                break;
                            }
                        }
                    }

                    // Skip the binary argument
                    _index++;
                    var rightValue = Rewrite(context, newPrecedence);

                    leftValue = new ScriptBinaryExpression()
                    {
                        Left          = leftValue,
                        Operator      = bin.Operator,
                        OperatorToken = bin.Operator.ToToken(),
                        Right         = rightValue,
                    };
                    continue;
                }

                object result = null;
                if (!expectingExpression && nextExpression is IScriptVariablePath)
                {
                    var restoreStrictVariables = context.StrictVariables;

                    // Don't fail on trying to lookup for a variable
                    context.StrictVariables = false;
                    try
                    {
                        result = context.Evaluate(nextExpression, true);
                    }
                    catch (ScriptRuntimeException) when(context.IgnoreExceptionsWhileRewritingScientific)
                    {
                        // ignore any exceptions during trial evaluating as we could try to evaluate
                        // variable that aren't setup
                    }
                    finally
                    {
                        context.StrictVariables = restoreStrictVariables;
                    }

                    // If one argument is a function, the remaining arguments
                    if (result is IScriptCustomFunction function)
                    {
                        var maxArg = function.RequiredParameterCount != 0 ? function.RequiredParameterCount : function.ParameterCount > 0 ? 1 : 0;

                        if (maxArg > 0)
                        {
                            if (PrecedenceTopLevel == precedence || leftValue == null)
                            {
                                var functionCall = new ScriptFunctionCall {
                                    Target = (ScriptExpression)nextExpression.Clone(), ExplicitCall = true
                                };
                                _index++;

                                var isExpectingExpression = function.IsParameterType <ScriptExpression>(0);

                                if (_index == Count)
                                {
                                    throw new ScriptRuntimeException(nextExpression.Span, "The function is expecting a parameter");
                                }

                                var arg = Rewrite(context, 0, isExpectingExpression);

                                functionCall.Arguments.Add(arg);

                                if (leftValue == null)
                                {
                                    leftValue = functionCall;
                                }
                                else
                                {
                                    leftValue = new ScriptBinaryExpression()
                                    {
                                        Left          = leftValue,
                                        Operator      = ScriptBinaryOperator.Multiply,
                                        OperatorToken = ScriptToken.Star(),
                                        Right         = functionCall,
                                    };
                                }
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }

                {
                    if (leftValue == null)
                    {
                        leftValue = (ScriptExpression)nextExpression.Clone();
                        _index++;
                    }
                    else
                    {
                        int precedenceOfImplicitMultiply = result is IScriptCustomImplicitMultiplyPrecedence ? PrecedenceOfMultiply : PrecedenceOfMultiply + 1;

                        if (precedenceOfImplicitMultiply <= precedence)
                        {
                            break;
                        }
                        // Implicit  the binary argument
                        var rightValue = Rewrite(context, precedenceOfImplicitMultiply);

                        if (rightValue is ScriptLiteral)
                        {
                            throw new ScriptRuntimeException(rightValue.Span, "Cannot use a literal on the right side of an implicit multiplication.");
                        }

                        leftValue = new ScriptBinaryExpression()
                        {
                            Left          = leftValue,
                            Operator      = ScriptBinaryOperator.Multiply,
                            OperatorToken = ScriptToken.Star(),
                            Right         = rightValue,
                        };
                    }
                }
            }

            return(leftValue);
        }
Beispiel #13
0
 public ScriptNestedExpression()
 {
     OpenParen  = ScriptToken.OpenParen();
     CloseParen = ScriptToken.CloseParen();
 }