Math Expression Evaluator — Implementation Plan
Phase: Implement
Steps are ordered. Each step includes writing the code and its unit tests (TDD).
Step 1: Project Skeleton
go mod init matheval- Create directory structure:
cmd/matheval/, token/, lexer/, ast/, parser/, evaluator/, repl/ - Create placeholder
main.go
Step 2: Token Package
- Define
Type enum constants - Define
Token struct - Add
String() method on Type for debugging
Step 3: Lexer
- Implement
Tokenize(input string) ([]Token, error) - Handle: whitespace skipping, number literals (integers and decimals), operators
+-*/, parentheses (), EOF, invalid characters - Tests: valid expressions, decimal numbers, invalid chars, empty input, whitespace-only
Step 4: AST Package
- Define
Node interface with sealed marker - Define
NumberLit struct - Define
BinaryExpr struct
Step 5: Parser
- Implement recursive-descent parser following grammar:
expr → term (('+' | '-') term)*term → factor (('*' | '/') factor)*factor → NUMBER | '(' expr ')'
- Internal parser struct to track position in token slice
- Return error on: unexpected token, mismatched parens, trailing tokens
- Tests: single number, simple binary, precedence, parentheses, nested parens, error cases
Step 6: Evaluator
- Implement
Eval(node ast.Node) (float64, error) - Recursively walk AST
- Return error on division by zero
- Tests: literals, all 4 operators, nested expressions, division by zero
Step 7: REPL
- Implement
Run(r io.Reader, w io.Writer) - Read line, tokenize, parse, evaluate, print result or error
- Loop until EOF
- Tests: successful expression, error expression, multi-line session
Step 8: main.go
- Wire
repl.Run(os.Stdin, os.Stdout)
Step 9: Integration Test
- End-to-end test: feed expression string through all stages, verify result
- Test edge cases: deeply nested parens, long expressions
Step 10: Final Commit & README
- Write README.md with usage instructions
- Final commit