blob: 99b0e327d1070cdc493ccdd77f4c540eec59ca07 [file] [log] [blame]
Sketch🕴️b05c53f2026-02-28 19:13:36 +04001package parser
2
3import (
4 "matheval/ast"
5 "matheval/token"
6 "testing"
7)
8
Sketch🕴️547feda2026-02-28 20:55:39 +04009// --- Parse (backward compatibility) ---
Sketch🕴️b05c53f2026-02-28 19:13:36 +040010
Sketch🕴️547feda2026-02-28 20:55:39 +040011func TestParse_SingleNumber(t *testing.T) {
12 tokens := []token.Token{
13 {Type: token.Number, Literal: "42", Pos: 0},
14 {Type: token.EOF, Literal: "", Pos: 2},
15 }
16 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040017 if err != nil {
18 t.Fatalf("unexpected error: %v", err)
19 }
20 num, ok := node.(*ast.NumberLit)
21 if !ok {
22 t.Fatalf("expected *ast.NumberLit, got %T", node)
23 }
24 if num.Value != 42 {
Sketch🕴️547feda2026-02-28 20:55:39 +040025 t.Fatalf("expected 42, got %v", num.Value)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040026 }
27}
28
Sketch🕴️547feda2026-02-28 20:55:39 +040029func TestParse_BinaryExpr(t *testing.T) {
30 tokens := []token.Token{
31 {Type: token.Number, Literal: "1", Pos: 0},
32 {Type: token.Plus, Literal: "+", Pos: 2},
33 {Type: token.Number, Literal: "2", Pos: 4},
34 {Type: token.EOF, Literal: "", Pos: 5},
35 }
36 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040037 if err != nil {
38 t.Fatalf("unexpected error: %v", err)
39 }
Sketch🕴️547feda2026-02-28 20:55:39 +040040 bin, ok := node.(*ast.BinaryExpr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040041 if !ok {
42 t.Fatalf("expected *ast.BinaryExpr, got %T", node)
43 }
Sketch🕴️547feda2026-02-28 20:55:39 +040044 if bin.Op != token.Plus {
45 t.Fatalf("expected Plus, got %v", bin.Op)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040046 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +040047}
48
Sketch🕴️547feda2026-02-28 20:55:39 +040049// --- factor: Ident ---
50
51func TestParse_Ident(t *testing.T) {
52 tokens := []token.Token{
53 {Type: token.Ident, Literal: "x", Pos: 0},
54 {Type: token.EOF, Literal: "", Pos: 1},
55 }
56 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040057 if err != nil {
58 t.Fatalf("unexpected error: %v", err)
59 }
Sketch🕴️547feda2026-02-28 20:55:39 +040060 ident, ok := node.(*ast.Ident)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040061 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +040062 t.Fatalf("expected *ast.Ident, got %T", node)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040063 }
Sketch🕴️547feda2026-02-28 20:55:39 +040064 if ident.Name != "x" {
65 t.Fatalf("expected 'x', got %q", ident.Name)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040066 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +040067}
68
Sketch🕴️547feda2026-02-28 20:55:39 +040069func TestParse_IdentInExpr(t *testing.T) {
70 // x + 1
71 tokens := []token.Token{
72 {Type: token.Ident, Literal: "x", Pos: 0},
73 {Type: token.Plus, Literal: "+", Pos: 2},
74 {Type: token.Number, Literal: "1", Pos: 4},
75 {Type: token.EOF, Literal: "", Pos: 5},
76 }
77 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040078 if err != nil {
79 t.Fatalf("unexpected error: %v", err)
80 }
Sketch🕴️547feda2026-02-28 20:55:39 +040081 bin, ok := node.(*ast.BinaryExpr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040082 if !ok {
83 t.Fatalf("expected *ast.BinaryExpr, got %T", node)
84 }
Sketch🕴️547feda2026-02-28 20:55:39 +040085 left, ok := bin.Left.(*ast.Ident)
86 if !ok {
87 t.Fatalf("expected left to be *ast.Ident, got %T", bin.Left)
Sketch🕴️b05c53f2026-02-28 19:13:36 +040088 }
Sketch🕴️547feda2026-02-28 20:55:39 +040089 if left.Name != "x" {
90 t.Fatalf("expected 'x', got %q", left.Name)
91 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +040092}
93
Sketch🕴️547feda2026-02-28 20:55:39 +040094// --- factor: FuncCall ---
95
96func TestParse_FuncCallNoArgs(t *testing.T) {
97 // f()
98 tokens := []token.Token{
99 {Type: token.Ident, Literal: "f", Pos: 0},
100 {Type: token.LParen, Literal: "(", Pos: 1},
101 {Type: token.RParen, Literal: ")", Pos: 2},
102 {Type: token.EOF, Literal: "", Pos: 3},
103 }
104 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400105 if err != nil {
106 t.Fatalf("unexpected error: %v", err)
107 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400108 fc, ok := node.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400109 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400110 t.Fatalf("expected *ast.FuncCall, got %T", node)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400111 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400112 if fc.Name != "f" {
113 t.Fatalf("expected 'f', got %q", fc.Name)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400114 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400115 if len(fc.Args) != 0 {
116 t.Fatalf("expected 0 args, got %d", len(fc.Args))
117 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400118}
119
Sketch🕴️547feda2026-02-28 20:55:39 +0400120func TestParse_FuncCallOneArg(t *testing.T) {
121 // f(42)
122 tokens := []token.Token{
123 {Type: token.Ident, Literal: "f", Pos: 0},
124 {Type: token.LParen, Literal: "(", Pos: 1},
125 {Type: token.Number, Literal: "42", Pos: 2},
126 {Type: token.RParen, Literal: ")", Pos: 4},
127 {Type: token.EOF, Literal: "", Pos: 5},
128 }
129 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400130 if err != nil {
131 t.Fatalf("unexpected error: %v", err)
132 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400133 fc, ok := node.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400134 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400135 t.Fatalf("expected *ast.FuncCall, got %T", node)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400136 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400137 if fc.Name != "f" {
138 t.Fatalf("expected 'f', got %q", fc.Name)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400139 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400140 if len(fc.Args) != 1 {
141 t.Fatalf("expected 1 arg, got %d", len(fc.Args))
142 }
143 arg, ok := fc.Args[0].(*ast.NumberLit)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400144 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400145 t.Fatalf("expected arg to be *ast.NumberLit, got %T", fc.Args[0])
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400146 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400147 if arg.Value != 42 {
148 t.Fatalf("expected 42, got %v", arg.Value)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400149 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400150}
151
Sketch🕴️547feda2026-02-28 20:55:39 +0400152func TestParse_FuncCallMultiArgs(t *testing.T) {
153 // f(1, 2, 3)
154 tokens := []token.Token{
155 {Type: token.Ident, Literal: "f", Pos: 0},
156 {Type: token.LParen, Literal: "(", Pos: 1},
157 {Type: token.Number, Literal: "1", Pos: 2},
158 {Type: token.Comma, Literal: ",", Pos: 3},
159 {Type: token.Number, Literal: "2", Pos: 5},
160 {Type: token.Comma, Literal: ",", Pos: 6},
161 {Type: token.Number, Literal: "3", Pos: 8},
162 {Type: token.RParen, Literal: ")", Pos: 9},
163 {Type: token.EOF, Literal: "", Pos: 10},
164 }
165 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400166 if err != nil {
167 t.Fatalf("unexpected error: %v", err)
168 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400169 fc, ok := node.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400170 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400171 t.Fatalf("expected *ast.FuncCall, got %T", node)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400172 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400173 if len(fc.Args) != 3 {
174 t.Fatalf("expected 3 args, got %d", len(fc.Args))
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400175 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400176}
177
Sketch🕴️547feda2026-02-28 20:55:39 +0400178func TestParse_FuncCallExprArgs(t *testing.T) {
179 // f(1+2, 3*4)
180 tokens := []token.Token{
181 {Type: token.Ident, Literal: "f", Pos: 0},
182 {Type: token.LParen, Literal: "(", Pos: 1},
183 {Type: token.Number, Literal: "1", Pos: 2},
184 {Type: token.Plus, Literal: "+", Pos: 3},
185 {Type: token.Number, Literal: "2", Pos: 4},
186 {Type: token.Comma, Literal: ",", Pos: 5},
187 {Type: token.Number, Literal: "3", Pos: 7},
188 {Type: token.Star, Literal: "*", Pos: 8},
189 {Type: token.Number, Literal: "4", Pos: 9},
190 {Type: token.RParen, Literal: ")", Pos: 10},
191 {Type: token.EOF, Literal: "", Pos: 11},
192 }
193 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400194 if err != nil {
195 t.Fatalf("unexpected error: %v", err)
196 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400197 fc, ok := node.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400198 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400199 t.Fatalf("expected *ast.FuncCall, got %T", node)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400200 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400201 if len(fc.Args) != 2 {
202 t.Fatalf("expected 2 args, got %d", len(fc.Args))
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400203 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400204 // First arg: 1+2
205 _, ok = fc.Args[0].(*ast.BinaryExpr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400206 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400207 t.Fatalf("expected first arg to be *ast.BinaryExpr, got %T", fc.Args[0])
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400208 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400209}
210
Sketch🕴️547feda2026-02-28 20:55:39 +0400211func TestParse_FuncCallInExpr(t *testing.T) {
212 // f(1) + 2
213 tokens := []token.Token{
214 {Type: token.Ident, Literal: "f", Pos: 0},
215 {Type: token.LParen, Literal: "(", Pos: 1},
216 {Type: token.Number, Literal: "1", Pos: 2},
217 {Type: token.RParen, Literal: ")", Pos: 3},
218 {Type: token.Plus, Literal: "+", Pos: 5},
219 {Type: token.Number, Literal: "2", Pos: 7},
220 {Type: token.EOF, Literal: "", Pos: 8},
221 }
222 node, err := Parse(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400223 if err != nil {
224 t.Fatalf("unexpected error: %v", err)
225 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400226 bin, ok := node.(*ast.BinaryExpr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400227 if !ok {
228 t.Fatalf("expected *ast.BinaryExpr, got %T", node)
229 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400230 _, ok = bin.Left.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400231 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400232 t.Fatalf("expected left to be *ast.FuncCall, got %T", bin.Left)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400233 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400234}
235
Sketch🕴️547feda2026-02-28 20:55:39 +0400236func TestParse_FuncCallMissingRParen(t *testing.T) {
237 // f(1
238 tokens := []token.Token{
239 {Type: token.Ident, Literal: "f", Pos: 0},
240 {Type: token.LParen, Literal: "(", Pos: 1},
241 {Type: token.Number, Literal: "1", Pos: 2},
242 {Type: token.EOF, Literal: "", Pos: 3},
243 }
244 _, err := Parse(tokens)
245 if err == nil {
246 t.Fatal("expected error for missing closing paren in func call")
247 }
248}
249
250// --- ParseLine: expression statement ---
251
252func TestParseLine_ExprStmt(t *testing.T) {
253 // "1 + 2"
254 tokens := []token.Token{
255 {Type: token.Number, Literal: "1", Pos: 0},
256 {Type: token.Plus, Literal: "+", Pos: 2},
257 {Type: token.Number, Literal: "2", Pos: 4},
258 {Type: token.EOF, Literal: "", Pos: 5},
259 }
260 stmt, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400261 if err != nil {
262 t.Fatalf("unexpected error: %v", err)
263 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400264 es, ok := stmt.(*ast.ExprStmt)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400265 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400266 t.Fatalf("expected *ast.ExprStmt, got %T", stmt)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400267 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400268 _, ok = es.Expr.(*ast.BinaryExpr)
269 if !ok {
270 t.Fatalf("expected expr to be *ast.BinaryExpr, got %T", es.Expr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400271 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400272}
273
Sketch🕴️547feda2026-02-28 20:55:39 +0400274func TestParseLine_ExprStmtFuncCall(t *testing.T) {
275 // "f(1)"
276 tokens := []token.Token{
277 {Type: token.Ident, Literal: "f", Pos: 0},
278 {Type: token.LParen, Literal: "(", Pos: 1},
279 {Type: token.Number, Literal: "1", Pos: 2},
280 {Type: token.RParen, Literal: ")", Pos: 3},
281 {Type: token.EOF, Literal: "", Pos: 4},
282 }
283 stmt, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400284 if err != nil {
285 t.Fatalf("unexpected error: %v", err)
286 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400287 es, ok := stmt.(*ast.ExprStmt)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400288 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400289 t.Fatalf("expected *ast.ExprStmt, got %T", stmt)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400290 }
Sketch🕴️547feda2026-02-28 20:55:39 +0400291 _, ok = es.Expr.(*ast.FuncCall)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400292 if !ok {
Sketch🕴️547feda2026-02-28 20:55:39 +0400293 t.Fatalf("expected expr to be *ast.FuncCall, got %T", es.Expr)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400294 }
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400295}
296
Sketch🕴️547feda2026-02-28 20:55:39 +0400297// --- ParseLine: function definition ---
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400298
Sketch🕴️547feda2026-02-28 20:55:39 +0400299func TestParseLine_FuncDefSingleParam(t *testing.T) {
300 // "f(x) = x + 1"
301 tokens := []token.Token{
302 {Type: token.Ident, Literal: "f", Pos: 0},
303 {Type: token.LParen, Literal: "(", Pos: 1},
304 {Type: token.Ident, Literal: "x", Pos: 2},
305 {Type: token.RParen, Literal: ")", Pos: 3},
306 {Type: token.Equals, Literal: "=", Pos: 5},
307 {Type: token.Ident, Literal: "x", Pos: 7},
308 {Type: token.Plus, Literal: "+", Pos: 9},
309 {Type: token.Number, Literal: "1", Pos: 11},
310 {Type: token.EOF, Literal: "", Pos: 12},
311 }
312 stmt, err := ParseLine(tokens)
313 if err != nil {
314 t.Fatalf("unexpected error: %v", err)
315 }
316 fd, ok := stmt.(*ast.FuncDef)
317 if !ok {
318 t.Fatalf("expected *ast.FuncDef, got %T", stmt)
319 }
320 if fd.Name != "f" {
321 t.Fatalf("expected name 'f', got %q", fd.Name)
322 }
323 if len(fd.Params) != 1 || fd.Params[0] != "x" {
324 t.Fatalf("expected params [x], got %v", fd.Params)
325 }
326 // Body should be x + 1
327 bin, ok := fd.Body.(*ast.BinaryExpr)
328 if !ok {
329 t.Fatalf("expected body to be *ast.BinaryExpr, got %T", fd.Body)
330 }
331 if bin.Op != token.Plus {
332 t.Fatalf("expected Plus in body, got %v", bin.Op)
333 }
334}
335
336func TestParseLine_FuncDefMultiParam(t *testing.T) {
337 // "add(x, y) = x + y"
338 tokens := []token.Token{
339 {Type: token.Ident, Literal: "add", Pos: 0},
340 {Type: token.LParen, Literal: "(", Pos: 3},
341 {Type: token.Ident, Literal: "x", Pos: 4},
342 {Type: token.Comma, Literal: ",", Pos: 5},
343 {Type: token.Ident, Literal: "y", Pos: 7},
344 {Type: token.RParen, Literal: ")", Pos: 8},
345 {Type: token.Equals, Literal: "=", Pos: 10},
346 {Type: token.Ident, Literal: "x", Pos: 12},
347 {Type: token.Plus, Literal: "+", Pos: 14},
348 {Type: token.Ident, Literal: "y", Pos: 16},
349 {Type: token.EOF, Literal: "", Pos: 17},
350 }
351 stmt, err := ParseLine(tokens)
352 if err != nil {
353 t.Fatalf("unexpected error: %v", err)
354 }
355 fd, ok := stmt.(*ast.FuncDef)
356 if !ok {
357 t.Fatalf("expected *ast.FuncDef, got %T", stmt)
358 }
359 if fd.Name != "add" {
360 t.Fatalf("expected name 'add', got %q", fd.Name)
361 }
362 if len(fd.Params) != 2 || fd.Params[0] != "x" || fd.Params[1] != "y" {
363 t.Fatalf("expected params [x y], got %v", fd.Params)
364 }
365}
366
367func TestParseLine_FuncDefNoParams(t *testing.T) {
368 // "c() = 42"
369 tokens := []token.Token{
370 {Type: token.Ident, Literal: "c", Pos: 0},
371 {Type: token.LParen, Literal: "(", Pos: 1},
372 {Type: token.RParen, Literal: ")", Pos: 2},
373 {Type: token.Equals, Literal: "=", Pos: 4},
374 {Type: token.Number, Literal: "42", Pos: 6},
375 {Type: token.EOF, Literal: "", Pos: 8},
376 }
377 stmt, err := ParseLine(tokens)
378 if err != nil {
379 t.Fatalf("unexpected error: %v", err)
380 }
381 fd, ok := stmt.(*ast.FuncDef)
382 if !ok {
383 t.Fatalf("expected *ast.FuncDef, got %T", stmt)
384 }
385 if fd.Name != "c" {
386 t.Fatalf("expected name 'c', got %q", fd.Name)
387 }
388 if len(fd.Params) != 0 {
389 t.Fatalf("expected 0 params, got %d", len(fd.Params))
390 }
391}
392
393// --- ParseLine: error cases ---
394
395func TestParseLine_Empty(t *testing.T) {
396 tokens := []token.Token{
397 {Type: token.EOF, Literal: "", Pos: 0},
398 }
399 _, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400400 if err == nil {
401 t.Fatal("expected error for empty input")
402 }
403}
404
Sketch🕴️547feda2026-02-28 20:55:39 +0400405func TestParseLine_FuncDefMissingBody(t *testing.T) {
406 // "f(x) ="
407 tokens := []token.Token{
408 {Type: token.Ident, Literal: "f", Pos: 0},
409 {Type: token.LParen, Literal: "(", Pos: 1},
410 {Type: token.Ident, Literal: "x", Pos: 2},
411 {Type: token.RParen, Literal: ")", Pos: 3},
412 {Type: token.Equals, Literal: "=", Pos: 5},
413 {Type: token.EOF, Literal: "", Pos: 6},
414 }
415 _, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400416 if err == nil {
Sketch🕴️547feda2026-02-28 20:55:39 +0400417 t.Fatal("expected error for missing function body")
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400418 }
419}
420
Sketch🕴️547feda2026-02-28 20:55:39 +0400421func TestParseLine_FuncDefBadParams(t *testing.T) {
422 // "f(1) = 2" — params must be identifiers
423 tokens := []token.Token{
424 {Type: token.Ident, Literal: "f", Pos: 0},
425 {Type: token.LParen, Literal: "(", Pos: 1},
426 {Type: token.Number, Literal: "1", Pos: 2},
427 {Type: token.RParen, Literal: ")", Pos: 3},
428 {Type: token.Equals, Literal: "=", Pos: 5},
429 {Type: token.Number, Literal: "2", Pos: 7},
430 {Type: token.EOF, Literal: "", Pos: 8},
431 }
432 _, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400433 if err == nil {
Sketch🕴️547feda2026-02-28 20:55:39 +0400434 t.Fatal("expected error for numeric parameter in func def")
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400435 }
436}
437
Sketch🕴️547feda2026-02-28 20:55:39 +0400438func TestParseLine_FuncDefTrailingTokens(t *testing.T) {
439 // "f(x) = x 1" — extra token after body
440 tokens := []token.Token{
441 {Type: token.Ident, Literal: "f", Pos: 0},
442 {Type: token.LParen, Literal: "(", Pos: 1},
443 {Type: token.Ident, Literal: "x", Pos: 2},
444 {Type: token.RParen, Literal: ")", Pos: 3},
445 {Type: token.Equals, Literal: "=", Pos: 5},
446 {Type: token.Ident, Literal: "x", Pos: 7},
447 {Type: token.Number, Literal: "1", Pos: 9},
448 {Type: token.EOF, Literal: "", Pos: 10},
449 }
450 _, err := ParseLine(tokens)
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400451 if err == nil {
Sketch🕴️547feda2026-02-28 20:55:39 +0400452 t.Fatal("expected error for trailing tokens after function body")
Sketch🕴️b05c53f2026-02-28 19:13:36 +0400453 }
454}