KataScript · experimental
A language,
from first
principles.
A small programming language.
An open workbench for understanding it.
Write expressions, model data, and follow an idea all the way from source to execution.
cargo run -- ks hello.ks↗func make_counter(start: Int, step: Int): Func { let value = start ret func(): Int { value = value + step ret value }}let next = make_counter(0, 1)let tens = make_counter(0, 10)print("next: {next()}")print("next: {next()}")print("tens: {tens()}")print("next: {next()}")print("tens: {tens()}")next: 1
next: 2
tens: 10
next: 3
tens: 20
[
{
"node": {
"FuncDef": {
"name": {
"node": "make_counter",
"span": [
5,
17
]
},
"params": [
{
"name": {
"node": "start",
"span": [
18,
23
]
},
"type_ann": {
"node": {
"Name": "Int"
},
"span": [
25,
28
]
}
},
{
"name": {
"node": "step",
"span": [
30,
34
]
},
"type_ann": {
"node": {
"Name": "Int"
},
"span": [
36,
39
]
}
}
],
"ret_type": {
"node": {
"Name": "Func"
},
"span": [
42,
46
]
},
"body": [
{
"node": {
"Let": {
"pattern": {
"node": {
"Binding": {
"node": "value",
"span": [
57,
62
]
}
},
"span": [
57,
62
]
},
"type_ann": null,
"value": {
"node": {
"Name": "start"
},
"span": [
65,
70
]
}
}
},
"span": [
53,
70
]
},
{
"node": {
"Ret": {
"keyword": [
75,
78
],
"value": {
"node": {
"FuncExpr": {
"params": [],
"ret_type": {
"node": {
"Name": "Int"
},
"span": [
87,
90
]
},
"body": [
{
"node": {
"Assign": {
"target": {
"Name": "value"
},
"value": {
"node": {
"BinOp": {
"op": "Add",
"left": {
"node": {
"Name": "value"
},
"span": [
109,
114
]
},
"right": {
"node": {
"Name": "step"
},
"span": [
117,
121
]
}
}
},
"span": [
109,
121
]
}
}
},
"span": [
101,
121
]
},
{
"node": {
"Ret": {
"keyword": [
130,
133
],
"value": {
"node": {
"Name": "value"
},
"span": [
134,
139
]
}
}
},
"span": [
130,
139
]
}
]
}
},
"span": [
79,
145
]
}
}
},
"span": [
75,
145
]
}
]
}
},
"span": [
0,
147
]
},
{
"node": {
"Let": {
"pattern": {
"node": {
"Binding": {
"node": "next",
"span": [
152,
156
]
}
},
"span": [
152,
156
]
},
"type_ann": null,
"value": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "make_counter"
},
"span": [
159,
171
]
},
"args": [
{
"node": {
"Int": "0"
},
"span": [
172,
173
]
},
{
"node": {
"Int": "1"
},
"span": [
175,
176
]
}
],
"args_span": [
171,
177
]
}
},
"span": [
159,
177
]
}
}
},
"span": [
148,
177
]
},
{
"node": {
"Let": {
"pattern": {
"node": {
"Binding": {
"node": "tens",
"span": [
182,
186
]
}
},
"span": [
182,
186
]
},
"type_ann": null,
"value": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "make_counter"
},
"span": [
189,
201
]
},
"args": [
{
"node": {
"Int": "0"
},
"span": [
202,
203
]
},
{
"node": {
"Int": "10"
},
"span": [
205,
207
]
}
],
"args_span": [
201,
208
]
}
},
"span": [
189,
208
]
}
}
},
"span": [
178,
208
]
},
{
"node": {
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "print"
},
"span": [
209,
214
]
},
"args": [
{
"node": {
"Interp": {
"parts": [
{
"Lit": "next: "
},
{
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "next"
},
"span": [
223,
227
]
},
"args": [],
"args_span": [
227,
229
]
}
},
"span": [
223,
229
]
}
}
]
}
},
"span": [
215,
231
]
}
],
"args_span": [
214,
232
]
}
},
"span": [
209,
232
]
}
},
"span": [
209,
232
]
},
{
"node": {
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "print"
},
"span": [
233,
238
]
},
"args": [
{
"node": {
"Interp": {
"parts": [
{
"Lit": "next: "
},
{
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "next"
},
"span": [
247,
251
]
},
"args": [],
"args_span": [
251,
253
]
}
},
"span": [
247,
253
]
}
}
]
}
},
"span": [
239,
255
]
}
],
"args_span": [
238,
256
]
}
},
"span": [
233,
256
]
}
},
"span": [
233,
256
]
},
{
"node": {
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "print"
},
"span": [
257,
262
]
},
"args": [
{
"node": {
"Interp": {
"parts": [
{
"Lit": "tens: "
},
{
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "tens"
},
"span": [
271,
275
]
},
"args": [],
"args_span": [
275,
277
]
}
},
"span": [
271,
277
]
}
}
]
}
},
"span": [
263,
279
]
}
],
"args_span": [
262,
280
]
}
},
"span": [
257,
280
]
}
},
"span": [
257,
280
]
},
{
"node": {
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "print"
},
"span": [
281,
286
]
},
"args": [
{
"node": {
"Interp": {
"parts": [
{
"Lit": "next: "
},
{
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "next"
},
"span": [
295,
299
]
},
"args": [],
"args_span": [
299,
301
]
}
},
"span": [
295,
301
]
}
}
]
}
},
"span": [
287,
303
]
}
],
"args_span": [
286,
304
]
}
},
"span": [
281,
304
]
}
},
"span": [
281,
304
]
},
{
"node": {
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "print"
},
"span": [
305,
310
]
},
"args": [
{
"node": {
"Interp": {
"parts": [
{
"Lit": "tens: "
},
{
"Expr": {
"node": {
"Call": {
"callee": {
"node": {
"Name": "tens"
},
"span": [
319,
323
]
},
"args": [],
"args_span": [
323,
325
]
}
},
"span": [
319,
325
]
}
}
]
}
},
"span": [
311,
327
]
}
],
"args_span": [
310,
328
]
}
},
"span": [
305,
328
]
}
},
"span": [
305,
328
]
}
]Two counters. Two captured values. One function.
Walk through the example →
A PLACE TO START
Read it. Run it. Take it apart.
Choose a path through the language.
Get your bearings
Install kata, run a file, and find your way around the workbench.
Read the docs 02Learn the language
From a first binding to closures, types, and the iterator protocol.
Follow the guide 03Make something
Build a word counter, keep state in a closure, and work with results.
Start a tutorialSMALL ENOUGH TO INSPECT
The machinery
is part of the story.
Kata is a personal language workbench: a Rust interpreter, a terminal REPL, and a standard library written partly in KataScript itself.
It is experimental. The design is open, the implementation is readable, and the rough edges are documented.
Look inside the repository ↗- 01SourceYour program, in a
.ksfile.let n = 42 - 02Tokens & syntaxA lexer and parser give it structure.
--dump-ast - 03ExecutionValues, scopes, and runtime checks.
42 : Int
FROM THE WORKBENCH
Notes on a language in progress.
A home for KataScript
A new place for the language guide, practical tutorials, and examples you can inspect and run.
A closure keeps a binding
A small counter reveals what a function carries out of the scope where it was created.
Three ways to name a type
Why KataScript separates product types, sum types, and interfaces into kind, enum, and type.