diff --git a/src/Ramstack.ExpressionParser/Binder.cs b/src/Ramstack.ExpressionParser/Binder.cs
index 5614594..21fc014 100644
--- a/src/Ramstack.ExpressionParser/Binder.cs
+++ b/src/Ramstack.ExpressionParser/Binder.cs
@@ -18,7 +18,7 @@ public abstract class Binder
///
/// The representing the name of the requested type.
///
- /// The instance corresponding to the specified
+ /// The instance corresponding to the specified
/// if resolved successfully; otherwise, .
///
public abstract Type? BindToType(Identifier name);
diff --git a/src/Ramstack.ExpressionParser/DefaultBinder.cs b/src/Ramstack.ExpressionParser/DefaultBinder.cs
index df6ec27..0374e59 100644
--- a/src/Ramstack.ExpressionParser/DefaultBinder.cs
+++ b/src/Ramstack.ExpressionParser/DefaultBinder.cs
@@ -128,7 +128,9 @@ public void RegisterType(Type type, bool importAsStatic = false)
///
public override MemberInfo? BindToMember(Type? type, Identifier memberName, bool isStatic)
{
- var bindingFlags = BindingFlags.Public | (isStatic ? BindingFlags.Static : BindingFlags.Instance);
+ var bindingFlags = isStatic
+ ? BindingFlags.Public | BindingFlags.Static
+ : BindingFlags.Public | BindingFlags.Instance;
var q = type?.GetMembers(bindingFlags)
?? PredefinedType
@@ -158,8 +160,9 @@ private static IEnumerable GetMethods(Type type, string methodName,
? BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static
: BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance;
- return type.GetMethods(bindingFlags)
- .Where(m => StringComparer.OrdinalIgnoreCase.Equals(m.Name, methodName))
+ return type
+ .GetMethods(bindingFlags)
+ .Where(m => string.Equals(m.Name, methodName, StringComparison.OrdinalIgnoreCase))
.Distinct();
}
}
diff --git a/src/Ramstack.ExpressionParser/ExpressionBuilder.Helpers.cs b/src/Ramstack.ExpressionParser/ExpressionBuilder.Helpers.cs
index 6f46b63..aee65b2 100644
--- a/src/Ramstack.ExpressionParser/ExpressionBuilder.Helpers.cs
+++ b/src/Ramstack.ExpressionParser/ExpressionBuilder.Helpers.cs
@@ -71,9 +71,14 @@ private static List CreateInjectingArguments(MethodInfo method, IRea
var paramArrayType = parameter.ParameterType.GetElementType()!;
for (; i < args.Count; i++)
- paramArray.Add(Convert(args[i], paramArrayType));
+ paramArray.Add(
+ Convert(args[i], paramArrayType));
+
+ list.Add(
+ Expression.NewArrayInit(
+ paramArrayType,
+ paramArray));
- list.Add(Expression.NewArrayInit(paramArrayType, paramArray));
break;
}
@@ -112,10 +117,8 @@ private static Expression ApplyBinaryExpression(Identifier op, Func>>")
{
if (lhs.Type == typeof(int))
return Expression.Convert(
apply(Expression.Convert(lhs, typeof(uint)), rhs),
typeof(int));
-
+
if (lhs.Type == typeof(long))
return Expression.Convert(
apply(Expression.Convert(lhs, typeof(ulong)), rhs),
typeof(long));
}
-
+
return apply(lhs, rhs);
}
@@ -183,12 +186,28 @@ private static Expression ApplyBinaryExpression(Identifier op, Func CreateOperatorFactory(string @operator)
+ private static Func ResolveBinaryOperatorFactory(string @operator)
{
return @operator switch
{
"??" => Expression.Coalesce,
- "||" => Expression.OrElse,
"&&" => Expression.AndAlso,
- "|" => Expression.Or,
- "^" => Expression.ExclusiveOr,
- "&" => Expression.And,
+ "||" => Expression.OrElse,
"==" => Expression.Equal,
"!=" => Expression.NotEqual,
"<=" => Expression.LessThanOrEqual,
- "<" => Expression.LessThan,
">=" => Expression.GreaterThanOrEqual,
- ">" => Expression.GreaterThan,
">>" => Expression.RightShift,
- ">>>" => Expression.RightShift,
"<<" => Expression.LeftShift,
+ ">>>" => Expression.RightShift,
+ "<" => Expression.LessThan,
+ ">" => Expression.GreaterThan,
+ "&" => Expression.And,
+ "|" => Expression.Or,
+ "^" => Expression.ExclusiveOr,
"+" => Expression.Add,
"-" => Expression.Subtract,
"*" => Expression.Multiply,
diff --git a/src/Ramstack.ExpressionParser/ExpressionBuilder.cs b/src/Ramstack.ExpressionParser/ExpressionBuilder.cs
index dc8a05c..013853b 100644
--- a/src/Ramstack.ExpressionParser/ExpressionBuilder.cs
+++ b/src/Ramstack.ExpressionParser/ExpressionBuilder.cs
@@ -37,38 +37,38 @@ protected internal override Expression VisitBinary(Expr.Binary expr)
var lhs = Visit(expr.Left);
var rhs = Visit(expr.Right);
- var factory = CreateOperatorFactory(expr.Operator.Name);
+ var lhsType = lhs.Type;
+ var rhsType = rhs.Type;
- var l = lhs;
- var r = rhs;
+ var factory = ResolveBinaryOperatorFactory(expr.Operator.Name);
switch (expr.Operator.Name)
{
case "&&":
case "||":
- l = ApplyImplicitConversion(lhs, typeof(bool));
- r = ApplyImplicitConversion(rhs, typeof(bool));
+ lhs = ApplyImplicitConversion(lhs, typeof(bool));
+ rhs = ApplyImplicitConversion(rhs, typeof(bool));
- if (l is null)
- Error.MissingImplicitConversion(lhs.Type, typeof(bool));
+ if (lhs is null)
+ Error.MissingImplicitConversion(lhsType, typeof(bool));
- if (r is null)
- Error.MissingImplicitConversion(rhs.Type, typeof(bool));
+ if (rhs is null)
+ Error.MissingImplicitConversion(rhsType, typeof(bool));
break;
case "??":
- if (lhs.Type.IsValueType && !lhs.Type.IsNullable())
- Error.NonApplicableBinaryOperator(expr.Operator, lhs.Type, rhs.Type);
+ if (lhsType.IsValueType && !lhsType.IsNullable())
+ Error.NonApplicableBinaryOperator(expr.Operator, lhsType, rhsType);
- r = ApplyImplicitConversion(rhs, lhs.Type);
- if (r is null)
- Error.NonApplicableBinaryOperator(expr.Operator, lhs.Type, rhs.Type);
+ rhs = ApplyImplicitConversion(rhs, lhsType);
+ if (rhs is null)
+ Error.NonApplicableBinaryOperator(expr.Operator, lhsType, rhsType);
break;
case "+":
- if (lhs.Type != typeof(string) && rhs.Type != typeof(string))
+ if (lhsType != typeof(string) && rhsType != typeof(string))
break;
var arguments = new List();
@@ -137,11 +137,11 @@ void Flatten(Expression e)
try
{
- return ApplyBinaryExpression(expr.Operator, factory, l, r);
+ return ApplyBinaryExpression(expr.Operator, factory, lhs, rhs);
}
catch (Exception e) when (e is not ParseErrorException)
{
- Error.NonApplicableBinaryOperator(expr.Operator, lhs.Type, rhs.Type);
+ Error.NonApplicableBinaryOperator(expr.Operator, lhsType, rhsType);
}
return null!;
diff --git a/src/Ramstack.ExpressionParser/ExpressionParser.Parser.cs b/src/Ramstack.ExpressionParser/ExpressionParser.Parser.cs
index d4325ff..2376107 100644
--- a/src/Ramstack.ExpressionParser/ExpressionParser.Parser.cs
+++ b/src/Ramstack.ExpressionParser/ExpressionParser.Parser.cs
@@ -42,7 +42,8 @@ private static Parser CreateParser()
).Void();
var number_literal =
- ConstantNumberParser.NumericLiteral
+ ConstantNumberParser
+ .NumericLiteral
.Do(Expr (v) => new Expr.Literal(v));
var string_literal =
@@ -187,57 +188,57 @@ static Expr HijackMemberExpression(Expr result, Expr value)
var mul_expression =
prefix_expression.Fold(
- OneOf("*/%").ThenIgnore(S).Map(CreateIdentifier),
+ OneOf("*/%").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var add_expression =
mul_expression.Fold(
- OneOf("+-").ThenIgnore(S).Map(CreateIdentifier),
+ OneOf("+-").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var shift_expression =
add_expression.Fold(
- OneOf(["<<", ">>", ">>>"]).ThenIgnore(S).Map(CreateIdentifier),
+ OneOf(["<<", ">>", ">>>"]).ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var relational_expression =
shift_expression.Fold(
- OneOf(["<", ">", "<=", ">="]).ThenIgnore(S).Map(CreateIdentifier),
+ OneOf(["<", ">", "<=", ">="]).ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var equality_expression =
relational_expression.Fold(
- OneOf("==", "!=").ThenIgnore(S).Map(CreateIdentifier),
+ OneOf("==", "!=").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var bitwise_and_expression =
equality_expression.Fold(
- L('&').ThenIgnore(S).Map(CreateIdentifier),
+ L('&').ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var bitwise_xor_expression =
bitwise_and_expression.Fold(
- L('^').ThenIgnore(S).Map(CreateIdentifier),
+ L('^').ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var bitwise_or_expression =
bitwise_xor_expression.Fold(
- L('|').ThenIgnore(S).Map(CreateIdentifier),
+ L('|').ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var logical_and_expression =
bitwise_or_expression.Fold(
- L("&&").ThenIgnore(S).Map(CreateIdentifier),
+ L("&&").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var logical_or_expression =
logical_and_expression.Fold(
- L("||").ThenIgnore(S).Map(CreateIdentifier),
+ L("||").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var null_coalesce_expression =
logical_or_expression.FoldR(
- L("??").ThenIgnore(S).Map(CreateIdentifier),
+ L("??").ThenIgnore(S).Do(CreateIdentifier),
(lhs, rhs, op) => new Expr.Binary(op, lhs, rhs));
var conditional_expression = Deferred();
@@ -261,9 +262,9 @@ static Expr HijackMemberExpression(Expr result, Expr value)
return S.Then(expression);
}
- private static Identifier CreateIdentifier(Match m, string v) =>
- new(v);
+ private static Identifier CreateIdentifier(string v) =>
+ new Identifier(v);
- private static Identifier CreateIdentifier(Match m, char v) =>
- new(new string(v, 1));
+ private static Identifier CreateIdentifier(char v) =>
+ new Identifier(v.ToString());
}
diff --git a/src/Ramstack.ExpressionParser/Expressions/Expr.Unary.cs b/src/Ramstack.ExpressionParser/Expressions/Expr.Unary.cs
index 04b8fc7..cfc3060 100644
--- a/src/Ramstack.ExpressionParser/Expressions/Expr.Unary.cs
+++ b/src/Ramstack.ExpressionParser/Expressions/Expr.Unary.cs
@@ -3,7 +3,7 @@ namespace Ramstack.Parsing.Expressions;
partial class Expr
{
///
- /// Represents an unary operation expression in an expression tree, consisting of an operator and a single operand.
+ /// Represents a unary operation expression in an expression tree, consisting of an operator and a single operand.
///
/// The representing the unary operator, e.g., "-" or "int".
/// The specifying the kind of unary operation (e.g., arithmetic or conversion).
diff --git a/src/Ramstack.ExpressionParser/Expressions/Expr.cs b/src/Ramstack.ExpressionParser/Expressions/Expr.cs
index 59ad12a..26b189b 100644
--- a/src/Ramstack.ExpressionParser/Expressions/Expr.cs
+++ b/src/Ramstack.ExpressionParser/Expressions/Expr.cs
@@ -1,32 +1,32 @@
-namespace Ramstack.Parsing.Expressions;
-
-///
-/// Represents a node in an expression tree, serving as the base class for all expression types.
-///
-public abstract partial class Expr(ExprKind kind)
-{
- ///
- /// Gets the kind of this expression node.
- ///
- ///
- /// An value indicating the type of expression, such as a literal, binary operation, or reference.
- ///
- public ExprKind Kind { get; init; } = kind;
-
- ///
- /// Deconstructs the expression into its kind.
- ///
- /// The of this expression node, output as an enumeration value.
- public void Deconstruct(out ExprKind kind) =>
- kind = Kind;
-
- ///
- /// Accepts a visitor to process this expression node and return a result of type .
- ///
- /// The type of the result produced by the visitor.
- /// The instance that processes this expression.
- ///
- /// A result of type as determined by the visitor's implementation.
- ///
- public abstract T Accept(ExprVisitor visitor);
-}
+namespace Ramstack.Parsing.Expressions;
+
+///
+/// Represents a node in an expression tree, serving as the base class for all expression types.
+///
+public abstract partial class Expr(ExprKind kind)
+{
+ ///
+ /// Gets the kind of this expression node.
+ ///
+ ///
+ /// An value indicating the type of expression, such as a literal, binary operation, or reference.
+ ///
+ public ExprKind Kind { get; init; } = kind;
+
+ ///
+ /// Deconstructs the expression into its kind.
+ ///
+ /// The of this expression node, output as an enumeration value.
+ public void Deconstruct(out ExprKind kind) =>
+ kind = Kind;
+
+ ///
+ /// Accepts a visitor to process this expression node and return a result of type .
+ ///
+ /// The type of the result produced by the visitor.
+ /// The instance that processes this expression.
+ ///
+ /// A result of type as determined by the visitor's implementation.
+ ///
+ public abstract T Accept(ExprVisitor visitor);
+}
diff --git a/src/Ramstack.ExpressionParser/Expressions/ExprKind.cs b/src/Ramstack.ExpressionParser/Expressions/ExprKind.cs
index 04791ca..1ec4735 100644
--- a/src/Ramstack.ExpressionParser/Expressions/ExprKind.cs
+++ b/src/Ramstack.ExpressionParser/Expressions/ExprKind.cs
@@ -1,79 +1,79 @@
-namespace Ramstack.Parsing.Expressions;
-
-///
-/// Defines the possible types of nodes in an expression tree used by the expression parser.
-///
-public enum ExprKind
-{
- ///
- /// Represents a reference to a variable, parameter, or member in the expression.
- ///
- ///
- /// In the expression x, this would indicate a reference to the variable "x".
- ///
- Reference,
-
- ///
- /// Represents a constant value, such as a number or string literal.
- ///
- ///
- /// In the expression 42 or "hello", this denotes a literal value.
- ///
- Literal,
-
- ///
- /// Represents a binary operation, such as addition or subtraction, involving two operands.
- ///
- ///
- /// In the expression a + b, this indicates the addition operation.
- ///
- Binary,
-
- ///
- /// Represents a method invocation within the expression.
- ///
- ///
- /// In the expression Math.Abs(-5), this denotes the method call to "Abs".
- ///
- Call,
-
- ///
- /// Represents an indexing operation or access to a parameterized property.
- ///
- ///
- /// In the expression array[0], this indicates an index operation.
- ///
- Index,
-
- ///
- /// Represents a read operation on a field or property of an object.
- ///
- ///
- /// In the expression obj.Property, this denotes accessing the "Property" member.
- ///
- MemberAccess,
-
- ///
- /// Represents a unary operation, such as negation or logical NOT, involving a single operand.
- ///
- ///
- /// In the expression -x, this indicates the negation operation.
- ///
- Unary,
-
- ///
- /// Represents a conditional (ternary) operation with a condition, true branch, and false branch.
- ///
- ///
- /// In the expression a > b ? a : b, this denotes a conditional operation.
- ///
- Conditional,
-
- ///
- /// Represents an expression enclosed in parentheses to enforce precedence or grouping.
- ///
- ///
- /// In the expression (a + b), this indicates a parenthesized sub-expression.
- ///
- Parenthesized
-}
+namespace Ramstack.Parsing.Expressions;
+
+///
+/// Defines the possible types of nodes in an expression tree used by the expression parser.
+///
+public enum ExprKind
+{
+ ///
+ /// Represents a reference to a variable, parameter, or member in the expression.
+ ///
+ ///
+ /// In the expression x, this would indicate a reference to the variable "x".
+ ///
+ Reference,
+
+ ///
+ /// Represents a constant value, such as a number or string literal.
+ ///
+ ///
+ /// In the expression 42 or "hello", this denotes a literal value.
+ ///
+ Literal,
+
+ ///
+ /// Represents a binary operation, such as addition or subtraction, involving two operands.
+ ///
+ ///
+ /// In the expression a + b, this indicates the addition operation.
+ ///
+ Binary,
+
+ ///
+ /// Represents a method invocation within the expression.
+ ///
+ ///
+ /// In the expression Math.Abs(-5), this denotes the method call to "Abs".
+ ///
+ Call,
+
+ ///
+ /// Represents an indexing operation or access to a parameterized property.
+ ///
+ ///
+ /// In the expression array[0], this indicates an index operation.
+ ///
+ Index,
+
+ ///
+ /// Represents a read operation on a field or property of an object.
+ ///
+ ///
+ /// In the expression obj.Property, this denotes accessing the "Property" member.
+ ///
+ MemberAccess,
+
+ ///
+ /// Represents a unary operation, such as negation or logical NOT, involving a single operand.
+ ///
+ ///
+ /// In the expression -x, this indicates the negation operation.
+ ///
+ Unary,
+
+ ///
+ /// Represents a conditional (ternary) operation with a condition, true branch, and false branch.
+ ///
+ ///
+ /// In the expression a > b ? a : b, this denotes a conditional operation.
+ ///
+ Conditional,
+
+ ///
+ /// Represents an expression enclosed in parentheses to enforce precedence or grouping.
+ ///
+ ///
+ /// In the expression (a + b), this indicates a parenthesized sub-expression.
+ ///
+ Parenthesized
+}
diff --git a/src/Ramstack.ExpressionParser/Expressions/ExprVisitor.cs b/src/Ramstack.ExpressionParser/Expressions/ExprVisitor.cs
index 25762a9..9e1c315 100644
--- a/src/Ramstack.ExpressionParser/Expressions/ExprVisitor.cs
+++ b/src/Ramstack.ExpressionParser/Expressions/ExprVisitor.cs
@@ -14,19 +14,8 @@ public abstract class ExprVisitor
///
/// A result of type produced by the corresponding visit method.
///
- public virtual T Visit(Expr expr) => expr.Kind switch
- {
- ExprKind.Reference => VisitReference((Expr.Reference)expr),
- ExprKind.Literal => VisitLiteral((Expr.Literal)expr),
- ExprKind.Binary => VisitBinary((Expr.Binary)expr),
- ExprKind.Call => VisitCall((Expr.Call)expr),
- ExprKind.Index => VisitIndex((Expr.Indexer)expr),
- ExprKind.MemberAccess => VisitMemberAccess((Expr.MemberAccess)expr),
- ExprKind.Unary => VisitUnary((Expr.Unary)expr),
- ExprKind.Conditional => VisitConditional((Expr.Conditional)expr),
- ExprKind.Parenthesized => VisitParenthesized((Expr.Parenthesized)expr),
- _ => throw new ArgumentOutOfRangeException(nameof(expr))
- };
+ public virtual T Visit(Expr expr) =>
+ expr.Accept(this);
///
/// Visits a list of expressions and returns a collection of results.
diff --git a/src/Ramstack.ExpressionParser/Expressions/UnaryType.cs b/src/Ramstack.ExpressionParser/Expressions/UnaryType.cs
index 4da0230..ef344e8 100644
--- a/src/Ramstack.ExpressionParser/Expressions/UnaryType.cs
+++ b/src/Ramstack.ExpressionParser/Expressions/UnaryType.cs
@@ -1,47 +1,47 @@
-namespace Ramstack.Parsing.Expressions;
-
-///
-/// Defines the types of unary operations supported in an expression tree.
-///
-public enum UnaryType
-{
- ///
- /// Represents a type cast or conversion operation, such as converting a value to a specific type.
- ///
- ///
- /// In the expression x:int, this indicates a conversion of x to an integer.
- ///
- Convert,
-
- ///
- /// Represents an arithmetic negation operation.
- ///
- ///
- /// In the expression -x, this indicates the arithmetic negation of x.
- ///
- Negate,
-
- ///
- /// Represents a logical negation operation.
- ///
- ///
- /// In the expression !x, this indicates a logical NOT operation on x.
- ///
- Not,
-
- ///
- /// Represents a bitwise ones complement operation, flipping all bits of a value.
- ///
- ///
- /// In the expression ~x, this indicates a ones complement operation on x.
- ///
- OnesComplement,
-
- ///
- /// Represents a unary plus operation.
- ///
- ///
- /// In the expression +x, this indicates a unary plus operation on x.
- ///
- UnaryPlus
-}
+namespace Ramstack.Parsing.Expressions;
+
+///
+/// Defines the types of unary operations supported in an expression tree.
+///
+public enum UnaryType
+{
+ ///
+ /// Represents a type cast or conversion operation, such as converting a value to a specific type.
+ ///
+ ///
+ /// In the expression x:int, this indicates a conversion of x to an integer.
+ ///
+ Convert,
+
+ ///
+ /// Represents an arithmetic negation operation.
+ ///
+ ///
+ /// In the expression -x, this indicates the arithmetic negation of x.
+ ///
+ Negate,
+
+ ///
+ /// Represents a logical negation operation.
+ ///
+ ///
+ /// In the expression !x, this indicates a logical NOT operation on x.
+ ///
+ Not,
+
+ ///
+ /// Represents a bitwise ones complement operation, flipping all bits of a value.
+ ///
+ ///
+ /// In the expression ~x, this indicates a ones complement operation on x.
+ ///
+ OnesComplement,
+
+ ///
+ /// Represents a unary plus operation.
+ ///
+ ///
+ /// In the expression +x, this indicates a unary plus operation on x.
+ ///
+ UnaryPlus
+}
diff --git a/src/Ramstack.ExpressionParser/ParseErrorException.cs b/src/Ramstack.ExpressionParser/ParseErrorException.cs
index 56e173d..04cd7e8 100644
--- a/src/Ramstack.ExpressionParser/ParseErrorException.cs
+++ b/src/Ramstack.ExpressionParser/ParseErrorException.cs
@@ -15,11 +15,11 @@ public ParseErrorException(string? message) : base(message)
}
///
- /// Initializes a new instance of the class
+ /// Initializes a new instance of the class
/// with a specified error message and a reference to the inner exception that caused this exception.
///
/// The message that describes the parsing error.
- /// The exception that caused the current exception,
+ /// The exception that caused the current exception,
/// or if no inner exception is specified.
public ParseErrorException(string? message, Exception? innerException) : base(message, innerException)
{
diff --git a/src/Ramstack.ExpressionParser/Parsers/ConstantNumberParser.cs b/src/Ramstack.ExpressionParser/Parsers/ConstantNumberParser.cs
index 44b3508..222bff9 100644
--- a/src/Ramstack.ExpressionParser/Parsers/ConstantNumberParser.cs
+++ b/src/Ramstack.ExpressionParser/Parsers/ConstantNumberParser.cs
@@ -102,7 +102,7 @@ private static int TryParseInteger(ReadOnlySpan s, out ulong value)
//
// Check for overflow
- //
+ //
if (r > ulong.MaxValue / 10
|| (r == ulong.MaxValue / 10 && d > ulong.MaxValue % 10))
goto FAIL;
@@ -143,7 +143,7 @@ private static int TryParseHexInteger(ReadOnlySpan s, out ulong value)
//
// Check for overflow
- //
+ //
if (r > ulong.MaxValue / 16)
goto FAIL;
@@ -181,7 +181,7 @@ private static int TryParseBinInteger(ReadOnlySpan s, out ulong value)
//
// Check for overflow
- //
+ //
if (r > ulong.MaxValue >> 1)
goto FAIL;
@@ -344,7 +344,7 @@ private static int AdjustNumericType(ReadOnlySpan s, ulong number, out obj
// 6.4.5.3 Integer literals
//
// The type of an integer literal is determined as follows:
- //
+ //
// * If the literal has no suffix, it has the first of these types in which its value can be represented: int, uint, long, ulong.
// * If the literal is suffixed by U or u, it has the first of these types in which its value can be represented: uint, ulong.
// * If the literal is suffixed by L or l, it has the first of these types in which its value can be represented: long, ulong.
diff --git a/tests/Rmastack.ExpressionParser.Tests/Data/Errors.txt b/tests/Rmastack.ExpressionParser.Tests/Data/Errors.txt
index d300ea1..f6a5764 100644
--- a/tests/Rmastack.ExpressionParser.Tests/Data/Errors.txt
+++ b/tests/Rmastack.ExpressionParser.Tests/Data/Errors.txt
@@ -84,3 +84,49 @@ Ambiguous match found:\n Char Chars [Int32] (in System.String)
"test"["a"]
Ambiguous match found:\n Char Chars [Int32] (in System.String)
+
+StringSplitOptions.None | StringComparison.Ordinal
+Operator '|' cannot be applied to operands of type 'System.StringSplitOptions' and 'System.StringComparison'.
+
+#######################################
+###### Binary Numeric Promotions ######
+#######################################
+
+#######################################
+# If either operand is of type decimal, a binding-time error occurs
+# if the other operand is of type float or double.
+
+1.0 + 2.0m
+Operator '+' cannot be applied to operands of type 'System.Double' and 'System.Decimal'.
+
+1.0m + 2.0d
+Operator '+' cannot be applied to operands of type 'System.Decimal' and 'System.Double'.
+
+1.0f + 2.0m
+Operator '+' cannot be applied to operands of type 'System.Single' and 'System.Decimal'.
+
+1.0m + 2.0f
+Operator '+' cannot be applied to operands of type 'System.Decimal' and 'System.Single'.
+
+#######################################
+# If either operand is of type ulong, a binding-time error occurs
+# if the other operand is of type sbyte, short, int, or long.
+
+1ul + 2:sbyte
+Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.SByte'.
+
+1ul + 2:short
+Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int16'.
+
+1ul + 2:int
+Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int32'.
+
+1ul + 2:long
+Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int64'.
+
+#######################################
+###### Unary Numeric Promotions ######
+#######################################
+
+-1ul
+Unary operator '-' cannot be applied to operand of type 'System.UInt64'.
diff --git a/tests/Rmastack.ExpressionParser.Tests/Data/Expressions.txt b/tests/Rmastack.ExpressionParser.Tests/Data/Expressions.txt
index 4967d26..3dd97f7 100644
--- a/tests/Rmastack.ExpressionParser.Tests/Data/Expressions.txt
+++ b/tests/Rmastack.ExpressionParser.Tests/Data/Expressions.txt
@@ -187,6 +187,9 @@ IIF(((10 == 10) OrElse (20 == 20)), IIF((1 > 0), 10, 20), IIF((0 < 1), 30, 40))
StringSplitOptions.None & ~StringSplitOptions.RemoveEmptyEntries
Convert((Convert(StringSplitOptions.None, Int32) & Convert(Convert(~(Convert(StringSplitOptions.RemoveEmptyEntries, Int32)), StringSplitOptions), Int32)), StringSplitOptions)
+StringSplitOptions.None | StringSplitOptions.RemoveEmptyEntries
+Convert((Convert(StringSplitOptions.None, Int32) | Convert(StringSplitOptions.RemoveEmptyEntries, Int32)), StringSplitOptions)
+
~StringSplitOptions.RemoveEmptyEntries
Convert(~(Convert(StringSplitOptions.RemoveEmptyEntries, Int32)), StringSplitOptions)
@@ -195,3 +198,270 @@ Convert(~(Convert(StringSplitOptions.RemoveEmptyEntries, Int32)), StringSplitOpt
true ^ false
(True ^ False)
+
+true | false
+(True Or False)
+
+true & false
+(True And False)
+
+#######################################
+# Precedence test
+1 + 2 - 4 * 5 / 4 << 1 & -3 ^ 17 | ~5 >> 2 >>> 1 % 5
+((((((1 + 2) - ((4 * 5) / 4)) << 1) & -3) ^ 17) | Convert((Convert((~(5) >> 2), UInt32) >> (1 % 5)), Int32))
+
+#######################################
+###### Binary Numeric Promotions ######
+#######################################
+
+#######################################
+# If either operand is of type decimal, the other operand is converted to type decimal
+1m + 2
+(1 + Convert(2, Decimal))
+
+1 + 2m
+(Convert(1, Decimal) + 2)
+
+1m + 2:byte
+(1 + Convert(Convert(2, Byte), Decimal))
+
+1m + 2:sbyte
+(1 + Convert(Convert(2, SByte), Decimal))
+
+1m + 2:short
+(1 + Convert(Convert(2, Int16), Decimal))
+
+1m + 2:ushort
+(1 + Convert(Convert(2, UInt16), Decimal))
+
+1m + 2:int
+(1 + Convert(2, Decimal))
+
+1m + 2:uint
+(1 + Convert(Convert(2, UInt32), Decimal))
+
+1m + 2:long
+(1 + Convert(Convert(2, Int64), Decimal))
+
+1m + 2:ulong
+(1 + Convert(Convert(2, UInt64), Decimal))
+
+
+#######################################
+# If either operand is of type double, the other operand is converted to type double.
+
+1d + 2
+(1 + Convert(2, Double))
+
+1 + 2d
+(Convert(1, Double) + 2)
+
+1.0 + 2:byte
+(1 + Convert(Convert(2, Byte), Double))
+
+1.0 + 2:sbyte
+(1 + Convert(Convert(2, SByte), Double))
+
+1.0 + 2:short
+(1 + Convert(Convert(2, Int16), Double))
+
+1.0 + 2:ushort
+(1 + Convert(Convert(2, UInt16), Double))
+
+1.0 + 2:int
+(1 + Convert(2, Double))
+
+1.0 + 2:uint
+(1 + Convert(Convert(2, UInt32), Double))
+
+1.0 + 2:long
+(1 + Convert(Convert(2, Int64), Double))
+
+1.0 + 2:ulong
+(1 + Convert(Convert(2, UInt64), Double))
+
+#######################################
+# If either operand is of type float, the other operand is converted to type float.
+
+1f + 2
+(1 + Convert(2, Single))
+
+1 + 2f
+(Convert(1, Single) + 2)
+
+1.0f + 2:byte
+(1 + Convert(Convert(2, Byte), Single))
+
+1.0f + 2:sbyte
+(1 + Convert(Convert(2, SByte), Single))
+
+1.0f + 2:short
+(1 + Convert(Convert(2, Int16), Single))
+
+1.0f + 2:ushort
+(1 + Convert(Convert(2, UInt16), Single))
+
+1.0f + 2:int
+(1 + Convert(2, Single))
+
+1.0f + 2:uint
+(1 + Convert(Convert(2, UInt32), Single))
+
+1.0f + 2:long
+(1 + Convert(Convert(2, Int64), Single))
+
+1.0f + 2:ulong
+(1 + Convert(Convert(2, UInt64), Single))
+
+#######################################
+# If either operand is of type ulong, the other operand is converted to type ulong
+
+1ul + 2u
+(1 + Convert(2, UInt64))
+
+1u + 2ul
+(Convert(1, UInt64) + 2)
+
+1ul + 2:byte
+(1 + Convert(Convert(2, Byte), UInt64))
+
+1ul + 2:ushort
+(1 + Convert(Convert(2, UInt16), UInt64))
+
+1ul + 2:uint
+(1 + Convert(Convert(2, UInt32), UInt64))
+
+1ul + 2:ulong
+(1 + Convert(2, UInt64))
+
+#######################################
+# If either operand is of type long, the other operand is converted to type long.
+
+1L + 2
+(1 + Convert(2, Int64))
+
+1 + 2L
+(Convert(1, Int64) + 2)
+
+1L + 2:byte
+(1 + Convert(Convert(2, Byte), Int64))
+
+1L + 2:sbyte
+(1 + Convert(Convert(2, SByte), Int64))
+
+1L + 2:short
+(1 + Convert(Convert(2, Int16), Int64))
+
+1L + 2:ushort
+(1 + Convert(Convert(2, UInt16), Int64))
+
+1L + 2:int
+(1 + Convert(2, Int64))
+
+1L + 2:uint
+(1 + Convert(Convert(2, UInt32), Int64))
+
+1L + 2:long
+(1 + Convert(2, Int64))
+
+#######################################
+# If either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
+# If either operand is of type uint, the other operand is converted to type uint.
+
+1u + 2
+(Convert(1, Int64) + Convert(2, Int64))
+
+1 + 2u
+(Convert(1, Int64) + Convert(2, Int64))
+
+1u + 2:byte
+(1 + Convert(Convert(2, Byte), UInt32))
+
+1u + 2:sbyte
+(Convert(1, Int64) + Convert(Convert(2, SByte), Int64))
+
+1u + 2:short
+(Convert(1, Int64) + Convert(Convert(2, Int16), Int64))
+
+1u + 2:ushort
+(1 + Convert(Convert(2, UInt16), UInt32))
+
+1u + 2:int
+(Convert(1, Int64) + Convert(2, Int64))
+
+1u + 2:uint
+(1 + Convert(2, UInt32))
+
+#######################################
+# Otherwise, both operands are converted to type int.
+
+1 + 2:byte
+(1 + Convert(Convert(2, Byte), Int32))
+
+1 + 2:sbyte
+(1 + Convert(Convert(2, SByte), Int32))
+
+1 + 2:short
+(1 + Convert(Convert(2, Int16), Int32))
+
+1 + 2:ushort
+(1 + Convert(Convert(2, UInt16), Int32))
+
+1 + 2:int
+(1 + 2)
+
+
+#######################################
+###### Unary Numeric Promotions ######
+#######################################
+
+#######################################
+# + operator
+
++1:byte
++Convert(Convert(1, Byte), Int32)
+
++1:sbyte
++Convert(Convert(1, SByte), Int32)
+
++1:short
++Convert(Convert(1, Int16), Int32)
+
++1:ushort
++Convert(Convert(1, UInt16), Int32)
+
++1:int
++1
+
++1u
++1
+
++1L
++1
+
++1ul
++1
+
+#######################################
+# - operator
+
+-1:byte
+-Convert(Convert(1, Byte), Int32)
+
+-1:sbyte
+-Convert(Convert(1, SByte), Int32)
+
+-1:short
+-Convert(Convert(1, Int16), Int32)
+
+-1:ushort
+-Convert(Convert(1, UInt16), Int32)
+
+-1:int
+-1
+
+-1u
+Convert(1, Int64)
+
+-1L
+-1
diff --git a/tests/Rmastack.ExpressionParser.Tests/ExpressionParserTest.cs b/tests/Rmastack.ExpressionParser.Tests/ExpressionParserTest.cs
index 10984d0..eb6b9fb 100644
--- a/tests/Rmastack.ExpressionParser.Tests/ExpressionParserTest.cs
+++ b/tests/Rmastack.ExpressionParser.Tests/ExpressionParserTest.cs
@@ -93,11 +93,11 @@ private static List