| Sketch🕴️ | 719e823 | 2026-02-28 19:07:50 +0400 | [diff] [blame] | 1 | # Math Expression Evaluator — Implementation Plan |
| 2 | |
| 3 | ## Phase: Implement |
| 4 | |
| 5 | Steps are ordered. Each step includes writing the code and its unit tests (TDD). |
| 6 | |
| 7 | ### Step 1: Project Skeleton |
| 8 | - `go mod init matheval` |
| 9 | - Create directory structure: `cmd/matheval/`, `token/`, `lexer/`, `ast/`, `parser/`, `evaluator/`, `repl/` |
| 10 | - Create placeholder `main.go` |
| 11 | |
| 12 | ### Step 2: Token Package |
| 13 | - Define `Type` enum constants |
| 14 | - Define `Token` struct |
| 15 | - Add `String()` method on `Type` for debugging |
| 16 | |
| 17 | ### Step 3: Lexer |
| 18 | - Implement `Tokenize(input string) ([]Token, error)` |
| 19 | - Handle: whitespace skipping, number literals (integers and decimals), operators `+-*/`, parentheses `()`, EOF, invalid characters |
| 20 | - **Tests:** valid expressions, decimal numbers, invalid chars, empty input, whitespace-only |
| 21 | |
| 22 | ### Step 4: AST Package |
| 23 | - Define `Node` interface with sealed marker |
| 24 | - Define `NumberLit` struct |
| 25 | - Define `BinaryExpr` struct |
| 26 | |
| 27 | ### Step 5: Parser |
| 28 | - Implement recursive-descent parser following grammar: |
| 29 | - `expr → term (('+' | '-') term)*` |
| 30 | - `term → factor (('*' | '/') factor)*` |
| 31 | - `factor → NUMBER | '(' expr ')'` |
| 32 | - Internal parser struct to track position in token slice |
| 33 | - Return error on: unexpected token, mismatched parens, trailing tokens |
| 34 | - **Tests:** single number, simple binary, precedence, parentheses, nested parens, error cases |
| 35 | |
| 36 | ### Step 6: Evaluator |
| 37 | - Implement `Eval(node ast.Node) (float64, error)` |
| 38 | - Recursively walk AST |
| 39 | - Return error on division by zero |
| 40 | - **Tests:** literals, all 4 operators, nested expressions, division by zero |
| 41 | |
| 42 | ### Step 7: REPL |
| 43 | - Implement `Run(r io.Reader, w io.Writer)` |
| 44 | - Read line, tokenize, parse, evaluate, print result or error |
| 45 | - Loop until EOF |
| 46 | - **Tests:** successful expression, error expression, multi-line session |
| 47 | |
| 48 | ### Step 8: main.go |
| 49 | - Wire `repl.Run(os.Stdin, os.Stdout)` |
| 50 | |
| 51 | ### Step 9: Integration Test |
| 52 | - End-to-end test: feed expression string through all stages, verify result |
| 53 | - Test edge cases: deeply nested parens, long expressions |
| 54 | |
| 55 | ### Step 10: Final Commit & README |
| 56 | - Write README.md with usage instructions |
| 57 | - Final commit |