# Caw A small, interpreted programming language, built from scratch to understand how programming languages work. Named after the sound a crow makes. Source files end in `.caw`. ```caw // Count crows. let crows = 3 fn describe(n) { if n == 1 { return "one crow" } else { return str(n) + " crows" } } while crows > 0 { print(describe(crows)) crows = crows - 1 } ``` ## Status Early. Very early. Currently building the lexer. - [x] Specification ([SPEC.md](SPEC.md)) - [ ] Lexer — text into tokens *(in progress)* - [ ] Parser — tokens into a syntax tree - [ ] Evaluator — run the tree - [ ] Functions and scope - [ ] Test suite Caw does not run yet. This is deliberate: the repository exists from the beginning so the history shows how a language gets built, not just the finished result. ## Why this exists This is a learning project. The goal is understanding — how text becomes behaviour, and how a pile of files becomes a project other people can join. Caw is not trying to be a good language. It is trying to be a legible one. If you want a serious small language to learn from, read [Crafting Interpreters](https://craftinginterpreters.com/) — it's free, and it's the best book on the subject. ## How it works Caw is an interpreter written in Python. It runs your code in three stages: ``` "let x = 1 + 2" raw text | lexer caw/lexer.py LET IDENT ASSIGN ... tokens: labelled chunks | parser caw/parser.py assign a syntax tree: structure / \ x add / \ 1 2 | evaluator caw/interp.py x is now 3 something happened ``` Each stage knows less than you'd think. The lexer has no idea what `if` means; it only knows that `if` is a keyword. Structure is the parser's problem and meaning is the evaluator's. That separation is the whole trick. ## Layout | Path | What's in it | |------------------|------------------------------------------------| | `SPEC.md` | the language specification — start here | | `caw/tokens.py` | token types and the keyword table | | `caw/lexer.py` | text into tokens | | `examples/` | example `.caw` programs | | `tests/` | automated tests | ## Requirements Python 3.9 or newer. No dependencies. ## Contributing Contributions welcome, especially from other people learning this stuff. Because this is a learning project, **explanations are as valuable as code.** A pull request that makes a confusing function clearer, or adds a comment explaining *why* rather than *what*, is genuinely as useful here as a new feature. If you're adding a language feature, update `SPEC.md` in the same change. The spec is the contract; code that disagrees with it is a bug in one of the two. ## Licence [MIT](LICENSE) — do what you like with it, just keep the copyright notice.