about summary refs log tree commit diff
path: root/pkg/lang
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/ast/op.go9
-rw-r--r--pkg/lang/parser/parser_test.go57
2 files changed, 62 insertions, 4 deletions
diff --git a/pkg/lang/ast/op.go b/pkg/lang/ast/op.go
index f5fce51..6f48e0c 100644
--- a/pkg/lang/ast/op.go
+++ b/pkg/lang/ast/op.go
@@ -59,14 +59,15 @@ func BinOpFromToken(tok token.Token) (BinOp, bool) {
 
 func (op BinOp) Precedence() int {
 	switch op {
-	case BinOpPlus, BinOpMinus:
+	case BinOpAssign:
 		return 1
-	case BinOpStar, BinOpSlash, BinOpPercent:
+	case BinOpEq, BinOpNeq, BinOpLt, BinOpLte, BinOpGt, BinOpGte:
 		return 2
-	case BinOpAssign:
+	case BinOpPlus, BinOpMinus:
 		return 3
-	case BinOpEq, BinOpNeq, BinOpLt, BinOpLte, BinOpGt, BinOpGte:
+	case BinOpStar, BinOpSlash, BinOpPercent:
 		return 4
+
 	default:
 		panic(fmt.Sprintf("unknown binary operator: %d", op))
 	}
diff --git a/pkg/lang/parser/parser_test.go b/pkg/lang/parser/parser_test.go
index 64dd67a..f48b6a5 100644
--- a/pkg/lang/parser/parser_test.go
+++ b/pkg/lang/parser/parser_test.go
@@ -210,6 +210,63 @@ func TestVarDecl(t *testing.T) {
 	}, program.Stmts[0])
 }
 
+func TestAssignPrecedence(t *testing.T) {
+	src := `y = 3 + 4 - x`
+
+	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: ast.StmtKindExpr,
+		Value: ast.StmtExpr{
+			Value: ast.Expr{
+				At:   source.NewLoc(0, 0),
+				Kind: ast.ExprKindBinary,
+				Value: ast.ExprBinary{
+					Left: ast.Expr{
+						At:    source.NewLoc(0, 0),
+						Kind:  ast.ExprKindIdent,
+						Value: ast.ExprIdent{Value: ast.IdentNode{At: source.NewLoc(0, 0), Value: "y"}},
+					},
+					Op: ast.BinOpAssign,
+					Right: ast.Expr{
+						At:   source.NewLoc(0, 4),
+						Kind: ast.ExprKindBinary,
+						Value: ast.ExprBinary{
+							Left: ast.Expr{
+								At:   source.NewLoc(0, 4),
+								Kind: ast.ExprKindBinary,
+								Value: ast.ExprBinary{
+									Left: ast.Expr{
+										At:    source.NewLoc(0, 4),
+										Kind:  ast.ExprKindIntLit,
+										Value: ast.ExprIntLit{Value: 3},
+									},
+									Op: ast.BinOpPlus,
+									Right: ast.Expr{
+										At:    source.NewLoc(0, 8),
+										Kind:  ast.ExprKindIntLit,
+										Value: ast.ExprIntLit{Value: 4},
+									},
+								},
+							},
+							Op: ast.BinOpMinus,
+							Right: ast.Expr{
+								At:    source.NewLoc(0, 12),
+								Kind:  ast.ExprKindIdent,
+								Value: ast.ExprIdent{Value: ast.IdentNode{At: source.NewLoc(0, 12), Value: "x"}},
+							},
+						},
+					},
+				},
+			},
+		},
+	}, program.Stmts[0])
+}
+
 func TestEmptyStmt(t *testing.T) {
 	src := `