diff --git a/adrs/021-operator-precedence.md b/adrs/021-operator-precedence.md index 672a380..e6a529f 100644 --- a/adrs/021-operator-precedence.md +++ b/adrs/021-operator-precedence.md @@ -16,11 +16,12 @@ Operator precedence is encoded in the parser. Matanuska's parser uses recursive | ----------- | ------------------------------------- | | or | `or` | | and | `and` | +| not | `not` | | equalities | `=`, `==`, `<>`, `!=` | | comparisons | `>`, `<`, `>=`, `<=` | | terms | `+`, `-` (minus) | | factors | `/`, `*` | -| unaries | `not`, `-` (negative) | +| unaries | `+`, (positive), `-` (negative) | | primaries | literals, variables, `(...)` (groups) | ## Reserved Operators diff --git a/compiler/base.ts b/compiler/base.ts index 34b389a..3561462 100644 --- a/compiler/base.ts +++ b/compiler/base.ts @@ -792,6 +792,9 @@ export class LineCompiler implements InstrVisitor, ExprVisitor { visitUnaryExpr(unary: Unary): void { unary.expr.accept(this); switch (unary.op) { + case TokenKind.Plus: + // No-op + break; case TokenKind.Minus: this.emitByte(OpCode.Neg); break; diff --git a/packages/test-generator/index.ts b/packages/test-generator/index.ts index 2d29b99..e40e567 100644 --- a/packages/test-generator/index.ts +++ b/packages/test-generator/index.ts @@ -3,11 +3,11 @@ import * as path from 'path'; import { Config, loadConfig } from './config'; import { formatFile } from './format'; -import { generatePrecedenceTest } from './precedence'; +// import { generatePrecedenceTest } from './precedence'; import { activate } from './activate'; export const GENERATORS: Array<[string, (c: Config) => string]> = [ - ['precedence.spec.ts', generatePrecedenceTest], + // ['precedence.spec.ts', generatePrecedenceTest], ]; export async function main( diff --git a/parser.ts b/parser.ts index 67c8448..4692370 100644 --- a/parser.ts +++ b/parser.ts @@ -789,7 +789,7 @@ export class Parser { return this.or(); } - private operator( + private infixOperator( kinds: TokenKind[], operand: () => Expr, factory: (l: Expr, o: TokenKind, r: Expr) => E, @@ -806,8 +806,24 @@ export class Parser { return expr; } + private prefixOperator( + kinds: TokenKind[], + operand: () => Expr, + factory: (o: TokenKind, e: Expr) => E, + ): Expr { + const unary = this.prefixOperator.bind(this, kinds, operand, factory); + if (this.match(...kinds)) { + const op = this.previous!.kind; + const right = unary(); + + return factory(op, right); + } + + return operand(); + } + private or(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.Or], this.and.bind(this), (l, o, r) => new Logical(l, o, r), @@ -815,15 +831,23 @@ export class Parser { } private and(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.And], - this.equality.bind(this), + this.not.bind(this), (l, o, r) => new Logical(l, o, r), ); } + private not(): Expr { + return this.prefixOperator( + [TokenKind.Not], + this.equality.bind(this), + (o, e) => new Unary(o, e), + ); + } + private equality(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.Eq, TokenKind.EqEq, TokenKind.BangEq, TokenKind.Ne], this.comparison.bind(this), (left, op, right) => { @@ -847,7 +871,7 @@ export class Parser { } private comparison(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.Gt, TokenKind.Ge, TokenKind.Lt, TokenKind.Le], this.term.bind(this), (l, o, r) => new Binary(l, o, r), @@ -855,7 +879,7 @@ export class Parser { } private term(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.Minus, TokenKind.Plus], this.factor.bind(this), (l, o, r) => new Binary(l, o, r), @@ -863,7 +887,7 @@ export class Parser { } private factor(): Expr { - return this.operator( + return this.infixOperator( [TokenKind.Slash, TokenKind.Star], this.unary.bind(this), (l, o, r) => new Binary(l, o, r), @@ -871,14 +895,11 @@ export class Parser { } private unary(): Expr { - if (this.match(TokenKind.Not, TokenKind.Minus)) { - const op = this.previous!.kind; - const right = this.unary(); - - return new Unary(op, right); - } - - return this.primary(); + return this.prefixOperator( + [TokenKind.Minus, TokenKind.Plus], + this.primary.bind(this), + (o, e) => new Unary(o, e), + ); } private primary(): Expr { diff --git a/test/__snapshots__/precedence.spec.ts.snap b/test/__snapshots__/precedence.spec.ts.snap deleted file mode 100644 index 4bf93b2..0000000 --- a/test/__snapshots__/precedence.spec.ts.snap +++ /dev/null @@ -1,99 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`operator precedence > 15 = - 14 + 13 * 12 or 11 / 10 < 9 != 8 <> 7 == 6 > 5 - 4 and 3 >= 2 >= not 1 1`] = ` -Logical { - "left": Binary { - "left": IntLiteral { - "value": 15, - }, - "op": "==", - "right": Binary { - "left": Unary { - "expr": IntLiteral { - "value": 14, - }, - "op": "-", - }, - "op": "+", - "right": Binary { - "left": IntLiteral { - "value": 13, - }, - "op": "*", - "right": IntLiteral { - "value": 12, - }, - }, - }, - }, - "op": "or", - "right": Logical { - "left": Binary { - "left": Binary { - "left": Binary { - "left": Binary { - "left": Binary { - "left": IntLiteral { - "value": 11, - }, - "op": "/", - "right": IntLiteral { - "value": 10, - }, - }, - "op": "<", - "right": IntLiteral { - "value": 9, - }, - }, - "op": "<>", - "right": IntLiteral { - "value": 8, - }, - }, - "op": "<>", - "right": IntLiteral { - "value": 7, - }, - }, - "op": "==", - "right": Binary { - "left": IntLiteral { - "value": 6, - }, - "op": ">", - "right": Binary { - "left": IntLiteral { - "value": 5, - }, - "op": "-", - "right": IntLiteral { - "value": 4, - }, - }, - }, - }, - "op": "and", - "right": Binary { - "left": Binary { - "left": IntLiteral { - "value": 3, - }, - "op": ">=", - "right": IntLiteral { - "value": 2, - }, - }, - "op": ">=", - "right": Unary { - "expr": IntLiteral { - "value": 1, - }, - "op": "not", - }, - }, - }, -} -`; - -exports[`operator precedence > 15 = - 14 + 13 * 12 or 11 / 10 < 9 != 8 <> 7 == 6 > 5 - 4 and 3 >= 2 >= not 1 2`] = `[ParseWarning]`; diff --git a/test/compiler/expr.ts b/test/compiler/expr.ts index ba3e3e6..2b1e4d8 100644 --- a/test/compiler/expr.ts +++ b/test/compiler/expr.ts @@ -147,6 +147,16 @@ export const EXPRESSION_STATEMENTS: TestCase[] = [ }), ], + [ + '+1', + new Expression(new Unary(TokenKind.Plus, new IntLiteral(1))), + chunk({ + constants: [1], + code: [OpCode.Constant, 0], + lines: [100, 100], + }), + ], + [ 'i% + 1', new Expression( diff --git a/test/parser/__snapshots__/precedence.spec.ts.snap b/test/parser/__snapshots__/precedence.spec.ts.snap new file mode 100644 index 0000000..c36856b --- /dev/null +++ b/test/parser/__snapshots__/precedence.spec.ts.snap @@ -0,0 +1,3396 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`infix left-associativity > *, / are left associative > 1 * 2 / 3 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix left-associativity > *, / are left associative > 1 * 2 / 3 2`] = `null`; + +exports[`infix left-associativity > +, - are left associative > 1 + 2 - 3 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix left-associativity > +, - are left associative > 1 + 2 - 3 2`] = `null`; + +exports[`infix left-associativity > =, ==, <>, != are left associative > 1 = 2 == 3 <> 4 != 5 1`] = ` +Binary { + "left": Binary { + "left": Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 4, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 5, + }, +} +`; + +exports[`infix left-associativity > =, ==, <>, != are left associative > 1 = 2 == 3 <> 4 != 5 2`] = `[ParseWarning]`; + +exports[`infix left-associativity > >, <, >=, >= are left associative > 1 > 2 < 3 >= 4 >= 5 1`] = ` +Binary { + "left": Binary { + "left": Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 4, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 5, + }, +} +`; + +exports[`infix left-associativity > >, <, >=, >= are left associative > 1 > 2 < 3 >= 4 >= 5 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 * 2 + 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 * 2 + 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 * 2 - 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 * 2 - 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 + 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 + 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 + 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 + 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 / 2 + 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 / 2 + 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 / 2 - 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 / 2 - 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 - 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 - 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. +, - > 1 - 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. +, - > 1 - 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 != 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 != 2 * 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 != 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 != 2 / 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 * 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 / 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 <> 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 <> 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 <> 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 <> 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 = 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 = 2 * 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 = 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 = 2 / 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 == 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 == 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 == 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. =, ==, <>, != > 1 == 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 < 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 < 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 > 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 > 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 >= 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 >= 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 >= 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 * 2 >= 3 binds to the left 4`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 < 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 < 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 > 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 > 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 >= 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 >= 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 >= 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 / 2 >= 3 binds to the left 4`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 < 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 < 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 < 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 < 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 > 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 > 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 > 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 > 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 * 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 * 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 * 3 binds to the right 4`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 / 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 / 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. >, <, >=, >= > 1 >= 2 / 3 binds to the right 4`] = `null`; + +exports[`infix precedence > *, / vs. and > 1 * 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. and > 1 * 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. and > 1 / 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. and > 1 / 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. and > 1 and 2 * 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. and > 1 and 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. and > 1 and 2 / 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. and > 1 and 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. or > 1 * 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "*", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. or > 1 * 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. or > 1 / 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "/", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > *, / vs. or > 1 / 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > *, / vs. or > 1 or 2 * 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. or > 1 or 2 * 3 binds to the right 2`] = `null`; + +exports[`infix precedence > *, / vs. or > 1 or 2 / 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "/", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > *, / vs. or > 1 or 2 / 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 != 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 != 2 + 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 != 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 != 2 - 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 + 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 <> 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 <> 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 <> 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 <> 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 = 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 = 2 + 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 = 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 = 2 - 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 == 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 == 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 == 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 == 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. =, ==, <>, != > 1 - 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 < 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 < 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 > 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 > 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 >= 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 >= 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 >= 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 + 2 >= 3 binds to the left 4`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 < 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 < 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 < 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 < 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 > 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 > 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 > 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 > 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 + 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 + 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 + 3 binds to the right 4`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 - 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 - 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 >= 2 - 3 binds to the right 4`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 < 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 < 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 > 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 > 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 >= 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 >= 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 >= 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. >, <, >=, >= > 1 - 2 >= 3 binds to the left 4`] = `null`; + +exports[`infix precedence > +, - vs. and > 1 + 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. and > 1 + 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. and > 1 - 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. and > 1 - 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. and > 1 and 2 + 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. and > 1 and 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. and > 1 and 2 - 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. and > 1 and 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. or > 1 + 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. or > 1 + 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. or > 1 - 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > +, - vs. or > 1 - 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > +, - vs. or > 1 or 2 + 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "+", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. or > 1 or 2 + 3 binds to the right 2`] = `null`; + +exports[`infix precedence > +, - vs. or > 1 or 2 - 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "-", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > +, - vs. or > 1 or 2 - 3 binds to the right 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 != 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 != 2 and 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 <> 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 <> 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 = 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 = 2 and 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 == 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 == 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 != 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 != 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 <> 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 <> 3 binds to the right 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 = 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 = 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 == 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. and > 1 and 2 == 3 binds to the right 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 != 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 != 2 or 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 <> 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 <> 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 = 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 = 2 or 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 == 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 == 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 != 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 != 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 <> 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 <> 3 binds to the right 2`] = `null`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 = 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 = 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 == 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > =, ==, <>, != vs. or > 1 or 2 == 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 < 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 < 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 > 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 > 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 >= 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 >= 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 >= 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 != 2 >= 3 binds to the right 4`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 < 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 < 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 < 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 > 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 > 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 >= 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 >= 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 >= 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<>", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 <> 2 >= 3 binds to the right 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 < 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 < 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 > 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 > 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 >= 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 >= 3 binds to the right 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 >= 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 = 2 >= 3 binds to the right 4`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 < 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 < 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 > 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 > 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 >= 3 binds to the right 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 >= 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 >= 3 binds to the right 3`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "==", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 == 2 >= 3 binds to the right 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 > 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 != 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 != 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 != 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 != 3 binds to the left 4`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 <> 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 <> 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 <> 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "<>", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 <> 3 binds to the left 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 = 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 = 3 binds to the left 2`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 = 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 = 3 binds to the left 4`] = `[ParseWarning]`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 == 3 binds to the left 1`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 == 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 == 3 binds to the left 3`] = ` +Binary { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "==", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. =, ==, <>, != > 1 >= 2 == 3 binds to the left 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 < 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 < 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 > 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 > 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 >= 2 and 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 >= 2 and 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 >= 2 and 3 binds to the left 3`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 >= 2 and 3 binds to the left 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 < 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 < 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 > 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 > 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 >= 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 >= 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 >= 3 binds to the right 3`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. and > 1 and 2 >= 3 binds to the right 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 < 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "<", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 < 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 > 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 > 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 >= 2 or 3 binds to the left 1`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 >= 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 >= 2 or 3 binds to the left 3`] = ` +Logical { + "left": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": ">=", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 >= 2 or 3 binds to the left 4`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 < 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "<", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 < 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 > 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 > 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 >= 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 >= 3 binds to the right 2`] = `null`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 >= 3 binds to the right 3`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": ">=", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > >, <, >=, >= vs. or > 1 or 2 >= 3 binds to the right 4`] = `null`; + +exports[`infix precedence > and vs. or > 1 and 2 or 3 binds to the left 1`] = ` +Logical { + "left": Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "and", + "right": IntLiteral { + "value": 2, + }, + }, + "op": "or", + "right": IntLiteral { + "value": 3, + }, +} +`; + +exports[`infix precedence > and vs. or > 1 and 2 or 3 binds to the left 2`] = `null`; + +exports[`infix precedence > and vs. or > 1 or 2 and 3 binds to the right 1`] = ` +Logical { + "left": IntLiteral { + "value": 1, + }, + "op": "or", + "right": Logical { + "left": IntLiteral { + "value": 2, + }, + "op": "and", + "right": IntLiteral { + "value": 3, + }, + }, +} +`; + +exports[`infix precedence > and vs. or > 1 or 2 and 3 binds to the right 2`] = `null`; + +exports[`logical > not 1 + 2 * 3 / 4 1`] = ` +Unary { + "expr": Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": Binary { + "left": Binary { + "left": IntLiteral { + "value": 2, + }, + "op": "*", + "right": IntLiteral { + "value": 3, + }, + }, + "op": "/", + "right": IntLiteral { + "value": 4, + }, + }, + }, + "op": "not", +} +`; + +exports[`logical > not 1 + 2 * 3 / 4 2`] = `null`; + +exports[`logical > not a? and not b? 1`] = ` +Logical { + "left": Unary { + "expr": Variable { + "ident": Token { + "index": 7, + "kind": "", + "offsetEnd": 9, + "offsetStart": 7, + "row": 1, + "text": "a?", + "value": "a?", + }, + }, + "op": "not", + }, + "op": "and", + "right": Unary { + "expr": Variable { + "ident": Token { + "index": 18, + "kind": "", + "offsetEnd": 20, + "offsetStart": 18, + "row": 1, + "text": "b?", + "value": "b?", + }, + }, + "op": "not", + }, +} +`; + +exports[`logical > not a? and not b? 2`] = `null`; + +exports[`logical > not a? or not b? 1`] = ` +Logical { + "left": Unary { + "expr": Variable { + "ident": Token { + "index": 7, + "kind": "", + "offsetEnd": 9, + "offsetStart": 7, + "row": 1, + "text": "a?", + "value": "a?", + }, + }, + "op": "not", + }, + "op": "or", + "right": Unary { + "expr": Variable { + "ident": Token { + "index": 17, + "kind": "", + "offsetEnd": 19, + "offsetStart": 17, + "row": 1, + "text": "b?", + "value": "b?", + }, + }, + "op": "not", + }, +} +`; + +exports[`logical > not a? or not b? 2`] = `null`; + +exports[`prefix twice > + + 1 1`] = ` +Unary { + "expr": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "+", + }, + "op": "+", +} +`; + +exports[`prefix twice > + + 1 2`] = `null`; + +exports[`prefix twice > - - 1 1`] = ` +Unary { + "expr": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "-", + }, + "op": "-", +} +`; + +exports[`prefix twice > - - 1 2`] = `null`; + +exports[`prefix twice > not not 1 1`] = ` +Unary { + "expr": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "not", + }, + "op": "not", +} +`; + +exports[`prefix twice > not not 1 2`] = `null`; + +exports[`prefix/infix precedence > + 1 + 1 1`] = ` +Binary { + "left": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "+", + }, + "op": "+", + "right": IntLiteral { + "value": 1, + }, +} +`; + +exports[`prefix/infix precedence > + 1 + 1 2`] = `null`; + +exports[`prefix/infix precedence > - 1 - 1 1`] = ` +Binary { + "left": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "-", + }, + "op": "-", + "right": IntLiteral { + "value": 1, + }, +} +`; + +exports[`prefix/infix precedence > - 1 - 1 2`] = `null`; + +exports[`prefix/infix precedence > 1 + + 1 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "+", + "right": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "+", + }, +} +`; + +exports[`prefix/infix precedence > 1 + + 1 2`] = `null`; + +exports[`prefix/infix precedence > 1 - - 1 1`] = ` +Binary { + "left": IntLiteral { + "value": 1, + }, + "op": "-", + "right": Unary { + "expr": IntLiteral { + "value": 1, + }, + "op": "-", + }, +} +`; + +exports[`prefix/infix precedence > 1 - - 1 2`] = `null`; diff --git a/test/parser/__snapshots__/program.spec.ts.snap b/test/parser/__snapshots__/program.spec.ts.snap index 27a94f0..23b7c4a 100644 --- a/test/parser/__snapshots__/program.spec.ts.snap +++ b/test/parser/__snapshots__/program.spec.ts.snap @@ -2,10 +2,10 @@ exports[`bare expression starting with an integer 1`] = ` ":1:0: warning: Line numbers should be in factors of 10 - 1 + 1 + 1 * 1 ^ -:1:2: error: Unexpected token + - 1 + 1 +:1:2: error: Unexpected token * + 1 * 1 ^" `; diff --git a/test/parser/precedence.spec.ts b/test/parser/precedence.spec.ts new file mode 100644 index 0000000..6afa22b --- /dev/null +++ b/test/parser/precedence.spec.ts @@ -0,0 +1,154 @@ +import { describe, test, expect } from 'vitest'; + +import { FILENAME } from '../helpers/files'; +import { parseProgram } from '../helpers/parser'; + +type PrefixOp = { prefix: string }; +type InfixOp = { infix: string }; +// type PostfixOp = { postfix: string }; + +// type Op = PrefixOp | InfixOp | PostfixOp; + +const OR_OPS = infix(['or']); +const AND_OPS = infix(['and']); +const NOT_OPS = prefix(['not']); +const EQUALITY_OPS = infix(['=', '==', '<>', '!=']); +const COMPARISON_OPS = infix(['>', '<', '>=', '>=']); +const TERM_OPS = infix(['+', '-']); +const FACTOR_OPS = infix(['*', '/']); +const UNARY_OPS = prefix(['+', '-']); + +/* +function isPrefix(op: any): op is PrefixOp { + return op.prefix; +} + +function isInfix(op: any): op is InfixOp { + return op.infix; +} + +function isPostfix(op: any): op is PostfixOp { + return op.postfix; +} +*/ + +function prefix(ops: string[]): PrefixOp[] { + return ops.map((o): PrefixOp => ({ prefix: o })); +} + +function infix(ops: string[]): InfixOp[] { + return ops.map((o): InfixOp => ({ infix: o })); +} + +/* +function postfix(ops: string[]): PostfixOp[] { + return ops.map((o): PostfixOp => ({ postfix: o })); +} +*/ + +function testExpr(name: string, expr: string): void { + test(name, () => { + const [ast, warning] = parseProgram(`10 ${expr}`, FILENAME); + + expect((ast.lines[0].instructions[0] as any).expression).toMatchSnapshot(); + expect(warning).toMatchSnapshot(); + }); +} + +function infixPrecedenceTestCases( + ops: Array, +): Array<[InfixOp[], InfixOp[]]> { + const cases: Array<[InfixOp[], InfixOp[]]> = []; + + for (let i = 0; i < ops.length - 1; i++) { + for (let j = i + 1; j < ops.length; j++) { + cases.push([ops[i], ops[j]]); + } + } + + return cases; +} + +function infixPrecedenceTest(higher: InfixOp[], lower: InfixOp[]): void { + const higherName = higher.map((o) => o.infix).join(', '); + const lowerName = lower.map((o) => o.infix).join(', '); + + describe(`${higherName} vs. ${lowerName}`, () => { + for (const high of higher) { + for (const low of lower) { + const leftExpr = `1 ${high.infix} 2 ${low.infix} 3`; + const rightExpr = `1 ${low.infix} 2 ${high.infix} 3`; + + testExpr(`${leftExpr} binds to the left`, leftExpr); + testExpr(`${rightExpr} binds to the right`, rightExpr); + } + } + }); +} + +describe('infix precedence', () => { + for (const [higher, lower] of infixPrecedenceTestCases([ + FACTOR_OPS, + TERM_OPS, + COMPARISON_OPS, + EQUALITY_OPS, + AND_OPS, + OR_OPS, + ])) { + infixPrecedenceTest(higher, lower); + } +}); + +function infixLeftAssociativeTest(ops: InfixOp[]): void { + const name = ops.map((o) => o.infix).join(', '); + let i = 2; + const expr = ops.reduce((e, op) => { + e += ` ${op.infix} ${i}`; + i++; + return e; + }, '1'); + + describe(`${name} are left associative`, () => { + testExpr(expr, expr); + }); +} + +describe('infix left-associativity', () => { + for (const cases of [FACTOR_OPS, TERM_OPS, COMPARISON_OPS, EQUALITY_OPS]) { + infixLeftAssociativeTest(cases); + } +}); + +function prefixInfixPrecedenceTest(op: string): void { + const a = `1 ${op} ${op} 1`; + const b = `${op} 1 ${op} 1`; + testExpr(a, a); + testExpr(b, b); +} + +describe('prefix/infix precedence', () => { + for (const op of ['+', '-']) { + prefixInfixPrecedenceTest(op); + } +}); + +function prefixTwiceTest(op: PrefixOp): void { + const expr = `${op.prefix} ${op.prefix} 1`; + testExpr(expr, expr); +} + +describe('prefix twice', () => { + for (const op of NOT_OPS.concat(UNARY_OPS)) { + prefixTwiceTest(op); + } +}); + +describe('logical', () => { + for (const expr of [ + 'not 1 + 2 * 3 / 4', + 'not a? and not b?', + 'not a? or not b?', + ]) { + testExpr(expr, expr); + } +}); diff --git a/test/parser/program.spec.ts b/test/parser/program.spec.ts index 449a84b..87ce476 100644 --- a/test/parser/program.spec.ts +++ b/test/parser/program.spec.ts @@ -25,7 +25,7 @@ import { parseInput, parseProgram } from '../helpers/parser'; // statement. That's a boatload of state, but I think it's doable. test('bare expression starting with an integer', () => { throws(() => { - parseInput('1 + 1'); + parseInput('1 * 1'); }); }); diff --git a/test/precedence.spec.ts b/test/precedence.spec.ts deleted file mode 100644 index a7846d8..0000000 --- a/test/precedence.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -// This test is automatically generated by @matanuska/test-generator. -// See ./packages/test-generator/README.md for more details. - -import { describe, test, expect } from 'vitest'; - -import { FILENAME } from './helpers/files'; -import { parseProgram } from './helpers/parser'; - -const EXPR = - '15 = - 14 + 13 * 12 or 11 / 10 < 9 != 8 <> 7 == 6 > 5 - 4 and 3 >= 2 >= not 1'; - -describe('operator precedence', () => { - test(EXPR, () => { - const [ast, warning] = parseProgram(`10 ${EXPR}`, FILENAME); - - expect((ast.lines[0].instructions[0] as any).expression).toMatchSnapshot(); - expect(warning).toMatchSnapshot(); - }); -});