Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion adrs/021-operator-precedence.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions compiler/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,9 @@ export class LineCompiler implements InstrVisitor<void>, ExprVisitor<void> {
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;
Expand Down
4 changes: 2 additions & 2 deletions packages/test-generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
53 changes: 37 additions & 16 deletions parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ export class Parser {
return this.or();
}

private operator<E extends Expr>(
private infixOperator<E extends Expr>(
kinds: TokenKind[],
operand: () => Expr,
factory: (l: Expr, o: TokenKind, r: Expr) => E,
Expand All @@ -806,24 +806,48 @@ export class Parser {
return expr;
}

private prefixOperator<E extends Expr>(
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),
);
}

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) => {
Expand All @@ -847,38 +871,35 @@ 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),
);
}

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),
);
}

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),
);
}

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 {
Expand Down
99 changes: 0 additions & 99 deletions test/__snapshots__/precedence.spec.ts.snap

This file was deleted.

10 changes: 10 additions & 0 deletions test/compiler/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading