public BinaryExpressionOrOperator(ScriptBinaryOperator @operator, ScriptToken operatorToken) { Expression = null; Operator = @operator; OperatorToken = operatorToken; CallKind = FunctionCallKind.None; }
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(); }
public ScriptFrontMatter() { StartMarker = new ScriptToken(TokenType.FrontMatterMarker); EndMarker = new ScriptToken(TokenType.FrontMatterMarker); }
public ScriptObjectInitializerExpression() { OpenBrace = ScriptToken.OpenBrace(); Members = new ScriptList <ScriptObjectMember>(); CloseBrace = ScriptToken.CloseBrace(); }
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); }
public ScriptNestedExpression() { OpenParen = ScriptToken.OpenParen(); CloseParen = ScriptToken.CloseParen(); }