a little project for my own learning
Python 99%
<1%

README.md

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.

// 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.

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 — 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 — do what you like with it, just keep the copyright notice.