blob: dff29d68be3ae367ac78ab014059945e075dfb89 [file] [log] [blame] [view]
Sketch🕴️c3ec07d2026-02-28 20:35:06 +04001# Implementation Plan: Function Definitions
Sketch🕴️719e8232026-02-28 19:07:50 +04002
Sketch🕴️c3ec07d2026-02-28 20:35:06 +04003## Overview
4Bottom-up implementation through the stack: token ast lexer parser evaluator repl integration tests. Each step maintains backward compatibility and follows TDD.
Sketch🕴️719e8232026-02-28 19:07:50 +04005
Sketch🕴️c3ec07d2026-02-28 20:35:06 +04006## Steps
Sketch🕴️719e8232026-02-28 19:07:50 +04007
Sketch🕴️c3ec07d2026-02-28 20:35:06 +04008### Step 1: Token layer (`token/token.go`)
9- Add `Ident`, `Comma`, `Equals` constants to `Type` enum
10- Update `String()` for new types
11- No tests needed pure data types
Sketch🕴️719e8232026-02-28 19:07:50 +040012
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040013### Step 2: AST layer (`ast/ast.go`)
14- Add `Ident` struct: `Name string`; implements `Node`
15- Add `FuncCall` struct: `Name string`, `Args []Node`; implements `Node`
16- Add `Statement` interface with sealed `stmt()` marker
17- Add `ExprStmt` struct: `Expr Node`; implements `Statement`
18- Add `FuncDef` struct: `Name string`, `Params []string`, `Body Node`; implements `Statement`
19- No tests needed pure data types
Sketch🕴️719e8232026-02-28 19:07:50 +040020
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040021### Step 3: Lexer (`lexer/lexer.go`)
22- Add `isLetter(ch byte) bool` helper
23- Before the single-char switch, add branch: if `isLetter(ch)`, scan identifier (letter then letters/digits), emit `Ident` token
24- Add `','` `Comma` and `'='` `Equals` to single-char switch
25- **Tests:** identifiers (`x`, `foo`, `f1`), comma, equals, full definition `f(x) = x + 1`, call `f(1, 2)`, mixed with numbers
Sketch🕴️719e8232026-02-28 19:07:50 +040026
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040027### Step 4: Parser (`parser/parser.go`)
28- Extend `factor()`:
29 - `Ident` followed by `LParen` parse `FuncCall`: consume `(`, parse args as comma-separated exprs, consume `)`
30 - `Ident` not followed by `LParen` return `&ast.Ident{Name}`
31- Add `parseFuncDef()`: expects `Ident(` params `) = expr`
32- Add `ParseLine(tokens) (Statement, error)`:
33 - Scan for `Equals` token (not inside parens)
34 - If found `parseFuncDef()` `*ast.FuncDef`
35 - If not `expr()` `*ast.ExprStmt{Expr}`
36- Keep `Parse()` unchanged for backward compat
37- **Tests:** ParseLine for defs and exprs, factor for ident and func call, error cases
Sketch🕴️719e8232026-02-28 19:07:50 +040038
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040039### Step 5: Evaluator (`evaluator/evaluator.go`)
40- Add `Evaluator` struct with `funcs map[string]*ast.FuncDef`
41- `New() *Evaluator`
42- `Define(def *ast.FuncDef) error` error on redefinition
43- `Eval(node ast.Node, env map[string]float64) (float64, error)`:
44 - `*ast.NumberLit` return value
45 - `*ast.BinaryExpr` recurse left/right with same env
46 - `*ast.Ident` lookup in env, error if not found
47 - `*ast.FuncCall` lookup func, eval args in caller env, bind params, eval body in new env
48- Keep package-level `Eval(node) (float64, error)` as backward-compat wrapper
49- **Tests:** all existing tests still pass, new tests for Ident, FuncCall, Define, errors
Sketch🕴️719e8232026-02-28 19:07:50 +040050
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040051### Step 6: REPL (`repl/repl.go`)
52- In `Run()`: create `evaluator.New()` before loop
53- Replace `evalLine()` with inline logic using `ParseLine()`
54- `*ast.FuncDef` `ev.Define(def)`, print `"defined <name>"`
55- `*ast.ExprStmt` `ev.Eval(stmt.Expr, nil)`, print result
56- **Tests:** define + call across lines, redefine error, undefined func error
Sketch🕴️719e8232026-02-28 19:07:50 +040057
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040058### Step 7: Integration tests (`integration_test.go`)
59- Update `eval()`/`evalErr()` helpers to use `Evaluator` struct
60- Add tests:
61 - Define and call single-param function
62 - Define and call multi-param function
63 - Cross-function calls
64 - Nested function calls in expressions
65 - Error: undefined function
66 - Error: wrong argument count
67 - Error: function redefinition
68 - Error: undefined variable
Sketch🕴️719e8232026-02-28 19:07:50 +040069
Sketch🕴️c3ec07d2026-02-28 20:35:06 +040070## Backward Compatibility
71- `Parse()` remains unchanged returns `ast.Node`
72- Package-level `Eval()` remains wraps `New().Eval(node, nil)`
73- Existing tests must continue to pass at every step