Docs
About
Teddy is a small programming language inspired by the language-building chapter of Eloquent JavaScript by Marijn Haverbeke. The aim is to understand interpreters and compilers by building a language from first principles (my own lexer, parser, AST and code generator) rather than following the book verbatim. It diverges from the book’s example in design and execution, reflecting experiments and ideas formed along the way.
The name is not just because “teddy” is the canonical toy name, but because the word’s origin (President Teddy Roosevelt) is one I find interesting. It also feels fitting: an innocuous name with a hint of larger ambition beneath it.
I wrote the language in 2024 while learning JavaScript (see the original). This version keeps that code as it was, adds TypeScript types around it, and gives it a playground.
How it works
What the book calls a “parser” reads source code and produces a data structure (an AST) that reflects the structure of the program. Teddy splits that job into two steps, then adds a third that produces JavaScript:
- Lex: break the code into tokens (atoms).
- Parse: build an AST (Abstract Syntax Tree) from those tokens.
- Transpile: turn the AST into JavaScript. JS for now; an AST could become any language.
Isn’t it misleading to call this a language?
It just translates into JS, and I wouldn’t argue otherwise. It’s still worth doing, because it teaches how a language breaks code into tokens, how it builds an AST from them, and how an AST becomes something a machine can run.
Why “atoms”?
It isn’t poor poetry. An atom literally means “something that cannot be broken up any further”. In the same way, a token is the smallest piece of information a language considers legal.
A guide to Teddy
suppose votingAge -> 18, suppose age -> 10;
suppose name -> "john";
if(age < 15)
print(name, "cannot vote");
elseIf(age < votingAge)
print(name, "should vote soon");
else
print(name, "can vote");
suppose greeting -> 'hello ${name}';
print(greeting);
suppose add -> function(x, y)
{
return x + y;
};
print(add(2, 3));Data types
| Type | Syntax | Example |
|---|---|---|
| Number (primitive) | Integers. | 18, -5 |
| String (primitive) | Characters between double quotes. | "john" |
| Template literal (primitive) | Characters between single quotes, with ${…} interpolation. | 'hello ${name}' |
| Object (non-primitive) | Key-value pairs between braces. | {name: "john", age: 21} |
| Array (non-primitive) | Values between brackets; nesting allowed. | [1, 2, {name: "bob"}, ["x"]] |
Keywords
| Keyword | Meaning | Example |
|---|---|---|
suppose | Declares a non-const, loosely typed binding. | suppose x -> 1; |
function | Declares a function. | function(x, y) { return x + y; }; |
return | Returns a value from a function. | return x; |
if, elseIf, else | Like if, else if and else in JS. | elseIf(age < 18) |
Operators
| Kind | Operators | Note |
|---|---|---|
| Assignment | -> | |
| Arithmetic | + - * / % | |
| Comparison | = == != !== < > <= >= | = becomes JS ==, and == becomes JS ===. |
Everything else
- Teddy’s console.log.
- JavaScript
- JS is the proto-language behind Teddy. Inside expressions and blocks, JS functions and values work as they are (Math.max(1, 2), true). Only print can be called as a statement on its own.
- Comments
- Start with // and run to the end of the line.
- Blocks
- { … } can be nested.
- Bad code
- Usually isn’t reported as a syntax error. It is mostly ignored, sometimes throws, and sometimes runs forever. The playground stops anything that runs longer than 2 seconds.
Teddy