public sealed override PrecedenceKind GetPrecedenceKind(OperatorPrecedence precedence) { switch (precedence) { case OperatorPrecedence.NullCoalescing: return(PrecedenceKind.Coalesce); case OperatorPrecedence.ConditionalOr: case OperatorPrecedence.ConditionalAnd: return(PrecedenceKind.Logical); case OperatorPrecedence.LogicalOr: case OperatorPrecedence.LogicalXor: case OperatorPrecedence.LogicalAnd: return(PrecedenceKind.Bitwise); case OperatorPrecedence.Equality: return(PrecedenceKind.Equality); case OperatorPrecedence.RelationalAndTypeTesting: return(PrecedenceKind.Relational); case OperatorPrecedence.Shift: return(PrecedenceKind.Shift); case OperatorPrecedence.Additive: case OperatorPrecedence.Multiplicative: return(PrecedenceKind.Arithmetic); default: return(PrecedenceKind.Other); } }
public void Stringify( StringBuilder builder, OperatorPrecedence caller, Dictionary <string, IExpression> variables ) { builder.Append("\"" + Value + "\""); }
public void Stringify( StringBuilder builder, OperatorPrecedence caller, Dictionary <string, IExpression> variables ) { builder.Append(Value.ToString("0.####")); //builder.Append(" "); builder.Append(Units.PrettyPrint()); }
public override OperatorPrecedence GetPrecedence() { OperatorPrecedence precedence = PrecedenceOfToken(Terms[0].Op); // Check all terms have the same precedence foreach (var t in Terms) { System.Diagnostics.Debug.Assert(PrecedenceOfToken(t.Op) == precedence); } return(precedence); }
private static bool IsFixable(SyntaxNode node, SyntaxKind parentKind) { if (node != null) { int groupNumber = GetGroupNumber(parentKind); return(groupNumber != 0 && groupNumber == GetGroupNumber(node) && OperatorPrecedence.GetPrecedence(node) < OperatorPrecedence.GetPrecedence(parentKind)); } return(false); }
public void Stringify( StringBuilder builder, OperatorPrecedence caller, Dictionary <string, IExpression> variables ) { if (variables.ContainsKey(Name)) { variables[Name].Stringify(builder, caller, variables); } else { builder.Append(Name); } }
private void WriteNestedExpression(BoundExpression node, OperatorPrecedence parentPrecedence) { if (node is BoundBinaryExpression binaryExpression) { WriteNestedExpression( binaryExpression, parentPrecedence, binaryExpression.Operator.SyntaxKind.GetBinaryOperatorPrecedence() ?? throw new Exception("Invalid operator") ); } else { node.Accept(this); } }
private void WriteNestedExpression( BoundNode node, OperatorPrecedence parent, OperatorPrecedence current ) { if (parent >= current) { _writer.WritePunctuation("("); node.Accept(this); _writer.WritePunctuation(")"); } else { node.Accept(this); } }
/// <summary> /// Initializes a new instance of the <see cref="OperatorToken"/> struct. /// </summary> /// <param name="operatorType">Type of the operator.</param> public OperatorToken(OperatorType operatorType) { if (operatorType != OperatorType.Add && operatorType != OperatorType.Divide && operatorType != OperatorType.Multiply && operatorType != OperatorType.Subtract && operatorType != OperatorType.RaiseTo && operatorType != OperatorType.Modulo && operatorType != OperatorType.UnaryMinus) { throw new ArgumentException("The operator type is not of a valid type.", "operatorType"); } this._operatorType = operatorType; this._precedence = operatorType.GetOperatorPrecedence(); this._associativity = operatorType.GetAssociativity(); this._argumentCount = operatorType.GetArgumentCount(); }
public static void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context) { var awaitExpression = (AwaitExpressionSyntax)context.Node; ExpressionSyntax expression = awaitExpression.Expression; if (expression?.IsKind(SyntaxKind.ParenthesizedExpression) == true) { var parenthesizedExpression = (ParenthesizedExpressionSyntax)expression; ExpressionSyntax innerExpression = parenthesizedExpression.Expression; if (innerExpression != null && OperatorPrecedence.GetPrecedence(innerExpression.Kind()) <= OperatorPrecedence.GetPrecedence(SyntaxKind.AwaitExpression)) { AnalyzeParenthesizedExpression(context, parenthesizedExpression); } } }
public void Stringify( StringBuilder builder, OperatorPrecedence caller, Dictionary <string, IExpression> variables ) { if (caller < OperatorPrecedence.AdditionSubtraction) { builder.Append("("); } Left.Stringify(builder, OperatorPrecedence.AdditionSubtraction, variables); builder.Append(" + "); Right.Stringify(builder, OperatorPrecedence.AdditionSubtraction, variables); if (caller < OperatorPrecedence.AdditionSubtraction) { builder.Append(")"); } }
public void Stringify( StringBuilder builder, OperatorPrecedence caller, Dictionary <string, IExpression> variables ) { if (caller < OperatorPrecedence.MultiplicationDivision) { builder.Append("("); } Left.Stringify(builder, OperatorPrecedence.MultiplicationDivision, variables); builder.Append(" ÷ "); Right.Stringify(builder, OperatorPrecedence.MultiplicationDivision, variables); if (caller < OperatorPrecedence.MultiplicationDivision) { builder.Append(")"); } }
private TreeNode parseBinaryOperator(OperatorPrecedence minPrecedence = OperatorPrecedence.Min) { TreeNode result = parseUnaryOperator(); while (isBinaryOperator()) { string op = peek(); OperatorPrecedence precendence = operatorPrecedence[op]; if (precendence >= minPrecedence) { advance(); result = new BinaryOperator(op, result, this.parseBinaryOperator(minPrecedence + 1)); } else { break; } } return(result); }
public static void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context) { var awaitExpression = (AwaitExpressionSyntax)context.Node; if (!(awaitExpression.Expression is ParenthesizedExpressionSyntax parenthesizedExpression)) { return; } ExpressionSyntax expression = parenthesizedExpression.Expression; if (expression?.IsMissing != false) { return; } if (OperatorPrecedence.GetPrecedence(expression.Kind()) > OperatorPrecedence.GetPrecedence(SyntaxKind.AwaitExpression)) { return; } AnalyzeParenthesizedExpression(context, parenthesizedExpression); }
/** * <summary> * Constructor for the Operator class. * </summary> * <param name="Character"> * Which operator it is. * </param> * <param name="Precedence"> * What the precedence is. * </param> */ public Operator(char Character, OperatorPrecedence Precedence) { this.Character = Character; this.Precedence = Precedence; return; }
public Operator(OperatorType type, OperatorPrecedence precedence) { Type = type; Precedence = precedence; }
public string ToGroupedString(OperatorPrecedence surroundingPrecedence) { return(surroundingPrecedence > ExpressionPrecedence ? $"({this})" : ToString()); }
public ParametrizedCode Build(OperatorPrecedence operatorPrecedence) => new ParametrizedCode(stringParts.ToArray(), parameters.ToArray(), operatorPrecedence);
private IExpression CompileExpression(Queue <Token> tokens, OperatorPrecedence minimumPrecedence, IList <string> variables, bool isWithinFunction) { if (tokens == null) { throw new ArgumentNullException(nameof(tokens), "You must call Tokenise before compiling"); } IExpression leftHandSide = null; var currentToken = tokens.PeekOrDefault(); Token previousToken = null; while (currentToken != null) { if (this.registeredOperators.TryGetValue(currentToken.CurrentToken, out var op)) // Are we an IOperator? { var precedence = op.GetPrecedence(previousToken); if (precedence > minimumPrecedence) { tokens.Dequeue(); if (!op.CanGetCaptiveTokens(previousToken, currentToken, tokens)) { // Do it anyway to update the list of tokens op.GetCaptiveTokens(previousToken, currentToken, tokens); break; } else { IExpression rightHandSide = null; var captiveTokens = op.GetCaptiveTokens(previousToken, currentToken, tokens); if (captiveTokens.Length > 1) { var innerTokens = op.GetInnerCaptiveTokens(captiveTokens); rightHandSide = this.CompileExpression(new Queue <Token>(innerTokens), OperatorPrecedence.Minimum, variables, isWithinFunction); currentToken = captiveTokens[captiveTokens.Length - 1]; } else { rightHandSide = this.CompileExpression(tokens, precedence, variables, isWithinFunction); // We are at the end of an expression so fake it up. currentToken = new Token(")", -1); } leftHandSide = op.BuildExpression(previousToken, new[] { leftHandSide, rightHandSide }, this.options); } } else { break; } } else if (this.registeredFunctions.TryGetValue(currentToken.CurrentToken, out var function)) // or an IFunction? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); var expressions = new List <IExpression>(); var captiveTokens = new Queue <Token>(); var parenCount = 0; tokens.Dequeue(); // Loop through the list of tokens and split by ParameterSeparator character while (tokens.Count > 0) { var nextToken = tokens.Dequeue(); if (string.Equals(nextToken.CurrentToken, "(", StringComparison.Ordinal)) { parenCount++; } else if (string.Equals(nextToken.CurrentToken, ")", StringComparison.Ordinal)) { parenCount--; } if (!(parenCount == 1 && nextToken.CurrentToken == "(") && !(parenCount == 0 && nextToken.CurrentToken == ")")) { captiveTokens.Enqueue(nextToken); } if (parenCount == 0 && captiveTokens.Any()) { expressions.Add(this.CompileExpression(captiveTokens, minimumPrecedence: OperatorPrecedence.Minimum, variables: variables, isWithinFunction: true)); captiveTokens.Clear(); } else if (string.Equals(nextToken.CurrentToken, ParameterSeparator.ToString(), StringComparison.Ordinal) && parenCount == 1) { // TODO: Should we expect expressions to be null??? expressions.Add(this.CompileExpression(captiveTokens, minimumPrecedence: 0, variables: variables, isWithinFunction: true)); captiveTokens.Clear(); } if (parenCount <= 0) { break; } } leftHandSide = new FunctionExpression(currentToken.CurrentToken, function, expressions.ToArray()); } else if (currentToken.CurrentToken.IsNumeric(this.currentCulture)) // Or a number { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); if (int.TryParse(currentToken.CurrentToken, NumberStyles.Any, this.currentCulture, out var intValue)) { leftHandSide = new ConstantValueExpression(intValue); } else if (decimal.TryParse(currentToken.CurrentToken, NumberStyles.Any, this.currentCulture, out var decimalValue)) { leftHandSide = new ConstantValueExpression(decimalValue); } else if (double.TryParse(currentToken.CurrentToken, NumberStyles.Any, this.currentCulture, out var doubleValue)) { leftHandSide = new ConstantValueExpression(doubleValue); } else if (float.TryParse(currentToken.CurrentToken, NumberStyles.Any, this.currentCulture, out var floatValue)) { leftHandSide = new ConstantValueExpression(floatValue); } else if (long.TryParse(currentToken.CurrentToken, NumberStyles.Any, this.currentCulture, out var longValue)) { leftHandSide = new ConstantValueExpression(longValue); } } else if (currentToken.CurrentToken.StartsWith("[") && currentToken.CurrentToken.EndsWith("]")) // or a variable? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); var variableName = currentToken.CurrentToken.Replace("[", "").Replace("]", ""); leftHandSide = new VariableExpression(variableName); if (!variables.Contains(variableName, this.stringComparer)) { variables.Add(variableName); } } else if (string.Equals(currentToken.CurrentToken, "true", StringComparison.OrdinalIgnoreCase)) // or a boolean? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(true); } else if (string.Equals(currentToken.CurrentToken, "false", StringComparison.OrdinalIgnoreCase)) { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(false); } else if (string.Equals(currentToken.CurrentToken, "null", StringComparison.OrdinalIgnoreCase)) // or a null? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(null); } else if (currentToken.CurrentToken.StartsWith(DateSeparator.ToString()) && currentToken.CurrentToken.EndsWith(DateSeparator.ToString())) // or a date? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); var dateToken = currentToken.CurrentToken.Replace(DateSeparator.ToString(), ""); // If we can't parse the date let's check for some known tags. if (!DateTime.TryParse(dateToken, out var date)) { if (string.Equals("TODAY", dateToken, StringComparison.OrdinalIgnoreCase)) { date = DateTime.Today; } else if (string.Equals("NOW", dateToken, StringComparison.OrdinalIgnoreCase)) { date = DateTime.Now; } else { throw new UnrecognisedTokenException(dateToken); } } leftHandSide = new ConstantValueExpression(date); } else if ((currentToken.CurrentToken.StartsWith("'") && currentToken.CurrentToken.EndsWith("'")) || (currentToken.CurrentToken.StartsWith("\"") && currentToken.CurrentToken.EndsWith("\""))) { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(CleanString(currentToken.CurrentToken.Substring(1, currentToken.Length - 2))); } else if (string.Equals(currentToken.CurrentToken, ParameterSeparator.ToString(), StringComparison.Ordinal)) // Make sure we ignore the parameter separator { if (!isWithinFunction) { throw new ExpressiveException($"Unexpected token '{currentToken.CurrentToken}' at position {currentToken.StartIndex}"); } tokens.Dequeue(); } else { tokens.Dequeue(); if (options.HasFlag(ExpressiveOptions.UnknownTokensAsVariables)) { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); var variableName = currentToken.CurrentToken; leftHandSide = new VariableExpression(variableName); if (!variables.Contains(variableName, this.stringComparer)) { variables.Add(variableName); } } else { throw new UnrecognisedTokenException(currentToken.CurrentToken); } } previousToken = currentToken; currentToken = tokens.PeekOrDefault(); } return(leftHandSide); }
private IExpression CompileExpression(Queue <Token> tokens, OperatorPrecedence minimumPrecedence, IList <string> variables, bool isWithinFunction) { if (tokens == null) { throw new ArgumentNullException("tokens", "You must call Tokenise before compiling"); } IExpression leftHandSide = null; var currentToken = tokens.PeekOrDefault(); Token previousToken = null; while (currentToken != null) { Func <IExpression[], IDictionary <string, object>, object> function = null; IOperator op = null; if (_registeredOperators.TryGetValue(currentToken.CurrentToken, out op)) // Are we an IOperator? { var precedence = op.GetPrecedence(previousToken); if (precedence > minimumPrecedence) { tokens.Dequeue(); if (!op.CanGetCaptiveTokens(previousToken, currentToken, tokens)) { // Do it anyway to update the list of tokens op.GetCaptiveTokens(previousToken, currentToken, tokens); break; } else { IExpression rightHandSide = null; var captiveTokens = op.GetCaptiveTokens(previousToken, currentToken, tokens); if (captiveTokens.Length > 1) { var innerTokens = op.GetInnerCaptiveTokens(captiveTokens); rightHandSide = CompileExpression(new Queue <Token>(innerTokens), OperatorPrecedence.Minimum, variables, isWithinFunction); currentToken = captiveTokens[captiveTokens.Length - 1]; } else { rightHandSide = CompileExpression(tokens, precedence, variables, isWithinFunction); // We are at the end of an expression so fake it up. currentToken = new Token(")", -1); } leftHandSide = op.BuildExpression(previousToken, new[] { leftHandSide, rightHandSide }, _options); } } else { break; } } else if (_registeredFunctions.TryGetValue(currentToken.CurrentToken, out function)) // or an IFunction? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); var expressions = new List <IExpression>(); var captiveTokens = new Queue <Token>(); var parenCount = 0; tokens.Dequeue(); // Loop through the list of tokens and split by ParameterSeparator character while (tokens.Count > 0) { var nextToken = tokens.Dequeue(); if (string.Equals(nextToken.CurrentToken, "(", StringComparison.Ordinal)) { parenCount++; } else if (string.Equals(nextToken.CurrentToken, ")", StringComparison.Ordinal)) { parenCount--; } if (!(parenCount == 1 && nextToken.CurrentToken == "(") && !(parenCount == 0 && nextToken.CurrentToken == ")")) { captiveTokens.Enqueue(nextToken); } if (parenCount == 0 && captiveTokens.Any()) { expressions.Add(CompileExpression(captiveTokens, minimumPrecedence: OperatorPrecedence.Minimum, variables: variables, isWithinFunction: true)); captiveTokens.Clear(); } else if (string.Equals(nextToken.CurrentToken, ParameterSeparator.ToString(), StringComparison.Ordinal) && parenCount == 1) { // TODO: Should we expect expressions to be null??? expressions.Add(CompileExpression(captiveTokens, minimumPrecedence: 0, variables: variables, isWithinFunction: true)); captiveTokens.Clear(); } if (parenCount <= 0) { break; } } leftHandSide = new FunctionExpression(currentToken.CurrentToken, function, expressions.ToArray()); } else if (currentToken.CurrentToken.IsNumeric()) // Or a number { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); int intValue = 0; decimal decimalValue = 0.0M; double doubleValue = 0.0; float floatValue = 0.0f; long longValue = 0; if (int.TryParse(currentToken.CurrentToken, out intValue)) { leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Integer, intValue); } else if (decimal.TryParse(currentToken.CurrentToken, out decimalValue)) { leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Decimal, decimalValue); } else if (double.TryParse(currentToken.CurrentToken, out doubleValue)) { leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Double, doubleValue); } else if (float.TryParse(currentToken.CurrentToken, out floatValue)) { leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Float, floatValue); } else if (long.TryParse(currentToken.CurrentToken, out longValue)) { leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Long, longValue); } } else if (currentToken.CurrentToken.StartsWith("[") && currentToken.CurrentToken.EndsWith("]")) // or a variable? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); string variableName = currentToken.CurrentToken.Replace("[", "").Replace("]", ""); leftHandSide = new VariableExpression(variableName); if (!variables.Contains(variableName, _stringComparer)) { variables.Add(variableName); } } else if (string.Equals(currentToken.CurrentToken, "true", StringComparison.OrdinalIgnoreCase)) // or a boolean? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Boolean, true); } else if (string.Equals(currentToken.CurrentToken, "false", StringComparison.OrdinalIgnoreCase)) { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Boolean, false); } else if (string.Equals(currentToken.CurrentToken, "null", StringComparison.OrdinalIgnoreCase)) // or a null? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Null, null); } else if (currentToken.CurrentToken.StartsWith(DateSeparator.ToString()) && currentToken.CurrentToken.EndsWith(DateSeparator.ToString())) // or a date? { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); string dateToken = currentToken.CurrentToken.Replace(DateSeparator.ToString(), ""); DateTime date = DateTime.MinValue; // If we can't parse the date let's check for some known tags. if (!DateTime.TryParse(dateToken, out date)) { if (string.Equals("TODAY", dateToken, StringComparison.OrdinalIgnoreCase)) { date = DateTime.Today; } else if (string.Equals("NOW", dateToken, StringComparison.OrdinalIgnoreCase)) { date = DateTime.Now; } else { throw new UnrecognisedTokenException(dateToken); } } leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.DateTime, date); } else if ((currentToken.CurrentToken.StartsWith("'") && currentToken.CurrentToken.EndsWith("'")) || (currentToken.CurrentToken.StartsWith("\"") && currentToken.CurrentToken.EndsWith("\""))) { this.CheckForExistingParticipant(leftHandSide, currentToken, isWithinFunction); tokens.Dequeue(); leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.String, CleanString(currentToken.CurrentToken.Substring(1, currentToken.Length - 2))); } else if (string.Equals(currentToken.CurrentToken, ParameterSeparator.ToString(), StringComparison.Ordinal)) // Make sure we ignore the parameter separator { // TODO should we throw an exception if we are not within a function? if (!isWithinFunction) { throw new ExpressiveException($"Unexpected token '{currentToken}'"); } tokens.Dequeue(); //throw new InvalidOperationException("Unrecognised token '" + currentToken + "'"); //if (!string.Equals(currentToken, ParameterSeparator.ToString(), StringComparison.Ordinal)) // Make sure we ignore the parameter separator //{ // currentToken = CleanString(currentToken); // leftHandSide = new ConstantValueExpression(ConstantValueExpressionType.Unknown, currentToken); //} } else { tokens.Dequeue(); throw new UnrecognisedTokenException(currentToken.CurrentToken); } previousToken = currentToken; currentToken = tokens.PeekOrDefault(); } return(leftHandSide); }
/// <summary> /// Initializes a new instance of the <see cref="OperatorPrecedenceAttribute"/> class. /// </summary> /// <param name="precedence">The precedence.</param> public OperatorPrecedenceAttribute(OperatorPrecedence precedence) : base() { this.Precedence = precedence; }
public OperatorStackItem(OperatorPrecedence precedence) : this(null, precedence) { }
public OperatorStackItem(IMathExpression expression, OperatorPrecedence precedence) { Expression = expression; Precedence = precedence; }
/// <summary> /// For expressions, we switch to a precedence climbing parser. /// </summary> public IExpressionSyntax ParseExpression(OperatorPrecedence minPrecedence) { var expression = ParseAtom(); for (; ;) { IBinaryOperatorToken? @operator = null; OperatorPrecedence? precedence = null; var leftAssociative = true; switch (Tokens.Current) { case IEqualsToken _: case IPlusEqualsToken _: case IMinusEqualsToken _: case IAsteriskEqualsToken _: case ISlashEqualsToken _: if (minPrecedence <= OperatorPrecedence.Assignment) { var assignmentOperator = BuildAssignmentOperator(Tokens.RequiredToken <IAssignmentToken>()); var rightOperand = ParseExpression(); if (expression is IAssignableExpressionSyntax assignableExpression) { expression = new AssignmentExpressionSyntax(assignableExpression, assignmentOperator, rightOperand); } else { // Don't assign expression, so it is just the right hand side of the assignment Add(ParseError.CantAssignIntoExpression(File, expression.Span)); } continue; } break; case IQuestionQuestionToken _: if (minPrecedence <= OperatorPrecedence.Coalesce) { precedence = OperatorPrecedence.Coalesce; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IOrKeywordToken _: if (minPrecedence <= OperatorPrecedence.LogicalOr) { precedence = OperatorPrecedence.LogicalOr; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IAndKeywordToken _: if (minPrecedence <= OperatorPrecedence.LogicalAnd) { precedence = OperatorPrecedence.LogicalAnd; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IEqualsEqualsToken _: case INotEqualToken _: if (minPrecedence <= OperatorPrecedence.Equality) { precedence = OperatorPrecedence.Equality; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case ILessThanToken _: case ILessThanOrEqualToken _: case IGreaterThanToken _: case IGreaterThanOrEqualToken _: case ILessThanColonToken _: // Subtype operator case IAsKeywordToken _: if (minPrecedence <= OperatorPrecedence.Relational) { precedence = OperatorPrecedence.Relational; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IDotDotToken _: case ILessThanDotDotToken _: case IDotDotLessThanToken _: case ILessThanDotDotLessThanToken _: if (minPrecedence <= OperatorPrecedence.Range) { precedence = OperatorPrecedence.Range; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IPlusToken _: case IMinusToken _: if (minPrecedence <= OperatorPrecedence.Additive) { precedence = OperatorPrecedence.Additive; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IAsteriskToken _: case ISlashToken _: if (minPrecedence <= OperatorPrecedence.Multiplicative) { precedence = OperatorPrecedence.Multiplicative; @operator = Tokens.RequiredToken <IBinaryOperatorToken>(); } break; case IDotToken _: case IQuestionDotToken _: if (minPrecedence <= OperatorPrecedence.Primary) { // Member Access var accessOperator = BuildAccessOperator(Tokens.RequiredToken <IAccessOperatorToken>()); var nameSyntax = ParseName(); if (!(Tokens.Current is IOpenParenToken)) { var memberAccessSpan = TextSpan.Covering(expression.Span, nameSyntax.Span); expression = new QualifiedNameExpressionSyntax(memberAccessSpan, expression, accessOperator, nameSyntax.ToExpression()); } else { Tokens.RequiredToken <IOpenParenToken>(); var arguments = ParseArguments(); var closeParenSpan = Tokens.Expect <ICloseParenToken>(); var invocationSpan = TextSpan.Covering(expression.Span, closeParenSpan); expression = new QualifiedInvocationExpressionSyntax(invocationSpan, expression, nameSyntax.Name, nameSyntax.Span, arguments); } continue; } break; default: return(expression); } if (!(@operator is null) && precedence is OperatorPrecedence operatorPrecedence) { if (leftAssociative) { operatorPrecedence += 1; } var rightOperand = ParseExpression(operatorPrecedence); expression = BuildBinaryOperatorExpression(expression, @operator, rightOperand); }
public static JsSymbolicParameter CreateCodePlaceholder(string code, OperatorPrecedence operatorPrecedence) => new JsSymbolicParameter( new CodeSymbolicParameter("AdHoc placeholder"), new CodeParameterAssignment(code, operatorPrecedence) );
/// <summary> /// For expressions, we switch to a precedence climbing parser. /// </summary> public ExpressionSyntax ParseExpression(OperatorPrecedence minPrecedence) { var expression = ParseAtom(); for (; ;) { IOperatorToken @operator = null; OperatorPrecedence?precedence = null; var leftAssociative = true; switch (Tokens.Current) { case IEqualsToken _: case IPlusEqualsToken _: case IMinusEqualsToken _: case IAsteriskEqualsToken _: case ISlashEqualsToken _: if (minPrecedence <= OperatorPrecedence.Assignment) { precedence = OperatorPrecedence.Assignment; leftAssociative = false; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IQuestionQuestionToken _: if (minPrecedence <= OperatorPrecedence.Coalesce) { precedence = OperatorPrecedence.Coalesce; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IOrKeywordToken _: if (minPrecedence <= OperatorPrecedence.LogicalOr) { precedence = OperatorPrecedence.LogicalOr; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IAndKeywordToken _: if (minPrecedence <= OperatorPrecedence.LogicalAnd) { precedence = OperatorPrecedence.LogicalAnd; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IEqualsEqualsToken _: case INotEqualToken _: if (minPrecedence <= OperatorPrecedence.Equality) { precedence = OperatorPrecedence.Equality; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case ILessThanToken _: case ILessThanOrEqualToken _: case IGreaterThanToken _: case IGreaterThanOrEqualToken _: case ILessThanColonToken _: // Subtype operator case IAsKeywordToken _: if (minPrecedence <= OperatorPrecedence.Relational) { precedence = OperatorPrecedence.Relational; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IColonToken _: // type kind if (minPrecedence <= OperatorPrecedence.Relational) { var colon = Tokens.Expect <IColonToken>(); TypeKind typeKind; switch (Tokens.Current) { case IClassKeywordToken _: typeKind = TypeKind.Class; break; case IStructKeywordToken _: typeKind = TypeKind.Struct; break; default: Tokens.Expect <ITypeKindKeywordToken>(); // We saw a colon without what we expected after, just assume it is missing continue; } var typeKindSpan = Tokens.Expect <ITypeKindKeywordToken>(); var span = TextSpan.Covering(colon, typeKindSpan); expression = new TypeKindExpressionSyntax(span, typeKind); continue; } break; case IDotDotToken _: case ILessThanDotDotToken _: case IDotDotLessThanToken _: case ILessThanDotDotLessThanToken _: if (minPrecedence <= OperatorPrecedence.Range) { precedence = OperatorPrecedence.Range; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IPlusToken _: case IMinusToken _: if (minPrecedence <= OperatorPrecedence.Additive) { precedence = OperatorPrecedence.Additive; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IAsteriskToken _: case ISlashToken _: if (minPrecedence <= OperatorPrecedence.Multiplicative) { precedence = OperatorPrecedence.Multiplicative; @operator = Tokens.RequiredToken <IOperatorToken>(); } break; case IDollarToken _: if (minPrecedence <= OperatorPrecedence.Lifetime) { Tokens.Expect <IDollarToken>(); var(nameSpan, lifetime) = ParseLifetimeName(); expression = new ReferenceLifetimeSyntax(expression, nameSpan, lifetime); continue; } break; case IQuestionToken _: if (minPrecedence <= OperatorPrecedence.Unary) { var question = Tokens.Required <IQuestionToken>(); var span = TextSpan.Covering(expression.Span, question); expression = new UnaryExpressionSyntax(span, UnaryOperatorFixity.Postfix, UnaryOperator.Question, expression); continue; } break; case IOpenParenToken _: if (minPrecedence <= OperatorPrecedence.Primary) { var callee = expression; Tokens.Expect <IOpenParenToken>(); var arguments = ParseArguments(); var closeParenSpan = Tokens.Expect <ICloseParenToken>(); var span = TextSpan.Covering(callee.Span, closeParenSpan); expression = new InvocationSyntax(span, callee, arguments); continue; } break; case IDotToken _: case ICaretDotToken _: case IQuestionDotToken _: if (minPrecedence <= OperatorPrecedence.Primary) { // Member Access var accessOperator = BuildAccessOperator(Tokens.RequiredToken <IAccessOperatorToken>()); var member = ParseSimpleName(); var span = TextSpan.Covering(expression.Span, member.Span); expression = new MemberAccessExpressionSyntax(span, expression, accessOperator, member); continue; } break; default: return(expression); } if (@operator is IOperatorToken operatorToken && precedence is OperatorPrecedence operatorPrecedence) { if (leftAssociative) { operatorPrecedence += 1; } var rightOperand = ParseExpression(operatorPrecedence); expression = BuildOperatorExpression(expression, operatorToken, rightOperand); }