diff options
| author | Mel <einebeere@gmail.com> | 2022-06-14 00:07:40 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-14 00:07:40 +0000 |
| commit | 3498876f06104515002191468fd99019d40051c2 (patch) | |
| tree | 7f1c3a34fe442382c82519a94ae089f22e252f71 /pkg/lang/parser | |
| parent | 14bdb59c24aef85f2a7c69f03ddacb7f56445e9e (diff) | |
| download | jinx-3498876f06104515002191468fd99019d40051c2.tar.zst jinx-3498876f06104515002191468fd99019d40051c2.zip | |
Fix BinExpr precendence not being drilled down
Diffstat (limited to 'pkg/lang/parser')
| -rw-r--r-- | pkg/lang/parser/bin_order.go | 34 | ||||
| -rw-r--r-- | pkg/lang/parser/exprs.go | 35 | ||||
| -rw-r--r-- | pkg/lang/parser/parser_test.go | 51 |
3 files changed, 90 insertions, 30 deletions
diff --git a/pkg/lang/parser/bin_order.go b/pkg/lang/parser/bin_order.go new file mode 100644 index 0000000..666d1fc --- /dev/null +++ b/pkg/lang/parser/bin_order.go @@ -0,0 +1,34 @@ +package parser + +import ( + "jinx/pkg/lang/ast" +) + +func (p *Parser) mergeIntoBinary(left ast.Expr, op ast.BinOp, right ast.Expr) ast.ExprBinary { + if right.Kind == ast.ExprKindBinary { + rightBin := right.Value.(ast.ExprBinary) + + needsSwitch := (op.Precedence() > rightBin.Op.Precedence()) || + (op.Precedence() == rightBin.Op.Precedence() && op.Associativity() == ast.AssociativityLeft) + + if needsSwitch { + leftBin := p.mergeIntoBinary(left, op, rightBin.Left) + + left = ast.Expr{ + At: left.At, + Kind: ast.ExprKindBinary, + Value: leftBin, + } + + right = rightBin.Right + + op = rightBin.Op + } + } + + return ast.ExprBinary{ + Left: left, + Op: op, + Right: right, + } +} diff --git a/pkg/lang/parser/exprs.go b/pkg/lang/parser/exprs.go index b08864a..ceda018 100644 --- a/pkg/lang/parser/exprs.go +++ b/pkg/lang/parser/exprs.go @@ -26,38 +26,13 @@ func (p *Parser) parseBinaryExpr() (ast.Expr, error) { return ast.Expr{}, err } - // Check precedence and associativity. - if right.Kind == ast.ExprKindBinary { - rightBin := right.Value.(ast.ExprBinary) - - needsSwitch := (op.Precedence() > rightBin.Op.Precedence()) || - (op.Precedence() == rightBin.Op.Precedence() && op.Associativity() == ast.AssociativityLeft) - - if needsSwitch { - left = ast.Expr{ - At: left.At, - Kind: ast.ExprKindBinary, - Value: ast.ExprBinary{ - Left: left, - Op: op, - Right: rightBin.Left, - }, - } - - right = rightBin.Right - - op = rightBin.Op - } - } + // Adjust for precedence and associativity. + binary := p.mergeIntoBinary(left, op, right) left = ast.Expr{ - At: left.At, - Kind: ast.ExprKindBinary, - Value: ast.ExprBinary{ - Left: left, - Op: op, - Right: right, - }, + At: left.At, + Kind: ast.ExprKindBinary, + Value: binary, } } diff --git a/pkg/lang/parser/parser_test.go b/pkg/lang/parser/parser_test.go index c3794e9..64dd67a 100644 --- a/pkg/lang/parser/parser_test.go +++ b/pkg/lang/parser/parser_test.go @@ -98,6 +98,57 @@ func TestLeftAssocBinaryExpr(t *testing.T) { }, program.Stmts[0]) } +func TestLeftAssocBinary4Expr(t *testing.T) { + src := `1 + 2 - 3 + 4` + p := cheatWithScanner(t, src) + program, err := p.Parse() + require.NoError(t, err) + + require.Equal(t, 1, len(program.Stmts)) + require.Equal(t, ast.Stmt{ + Kind: 11, + Value: ast.StmtExpr{ + Value: ast.Expr{ + Kind: ast.ExprKindBinary, + Value: ast.ExprBinary{ + Left: ast.Expr{ + Kind: ast.ExprKindBinary, + Value: ast.ExprBinary{ + Left: ast.Expr{ + Kind: ast.ExprKindBinary, + Value: ast.ExprBinary{ + Left: ast.Expr{ + Kind: ast.ExprKindIntLit, + Value: ast.ExprIntLit{Value: 1}, + }, + Op: ast.BinOpPlus, + Right: ast.Expr{ + At: source.NewLoc(0, 4), + Kind: ast.ExprKindIntLit, + Value: ast.ExprIntLit{Value: 2}, + }, + }, + }, + Op: ast.BinOpMinus, + Right: ast.Expr{ + At: source.NewLoc(0, 8), + Kind: ast.ExprKindIntLit, + Value: ast.ExprIntLit{Value: 3}, + }, + }, + }, + Op: ast.BinOpPlus, + Right: ast.Expr{ + At: source.NewLoc(0, 12), + Kind: ast.ExprKindIntLit, + Value: ast.ExprIntLit{Value: 4}, + }, + }, + }, + }, + }, program.Stmts[0]) +} + func TestRightAssocBinaryExpr(t *testing.T) { src := `x = y = z` p := cheatWithScanner(t, src) |
