Kora is a small, statically typed, programming language with a garbage collector. It compiles to native executables and JavaScript. Your programs run right in the browser with nothing to install.
Read the docs Β· Try the online playground
- Familiar C-like syntax:
if/while/for, functions, and blocks you already know. - Static typing with inference:
int,real,char,bool, arrays, and strings. - Arrays and strings with handy built-in methods (
push,pop,insert,remove,slice,extend,len). Astringis just an array ofchar. - Structs and methods: POD types
struct, attach behavior withimpl. - Generics over type parameters for
struct,impl, and functions (struct box<T>,T id<T>(x: T)), instantiated with turbofish (id::<int>(5),new box<int>{ v: 1 }). Instances are monomorphized, so generics cost nothing at runtime. - Functions are first class values. Pass, store, and return functions by value with the for callbacks, dispatch tables, and higher-order functions.
- Optionals (
T?) instead of null. The billion-dollar mistake - Runtime safety is a design choice: array indexing is
bounds-checked, integer division by zero,
pop()on an empty array, and force-unwrappingnoneall panic with a clear message instead of corrupting memory. - Modules which allow you to split a program, plus a small standard library (I/O, string helpers, math, and conversions) written in Kora.
- The native runtime written in C, the lingua-franca of programming languages.
- Runs in the browser through a WebAssembly-powered playground, and compiles to native binaries through an LLVM backend (LLVM 21 is required).
A generic stack, showing type inference, arrays, and generics over structs and impls:
import "std/io";
import "std/conv";
# A generic growable stack, built on a plain array.
struct stack<T> { items: [T] }
impl stack<T> {
void push(self, x: T) { self.items.push(x); }
T pop(self) { return self.items.pop(); }
int size(self) { return self.items.len(); }
}
int main() {
let s = new stack<int>{ items: [] }; # inferred: s : stack<int>
for x | [1, 2, 3, 4] {
s.push(x * x);
}
let sum = 0;
while (s.size() > 0) {
sum = sum + s.pop();
}
io.write(conv.to_string::<int>(sum)); # 30
io.write("\n");
return 0;
}The playground has proper Kora syntax highlighting. Sorry for the ruby code blocks here.
For more, res/cli/ has terminal programs (a Sudoku solver, a ray
tracer that renders to a PPM file, a calculator REPL, and a word counter) and
res/playground/ has playable versions of Snake, Tetris,
Pong, Pacman, Doom, and a Mandelbrot renderer.
One frontend feeds two backends. Source is lexed and parsed per module, assembled and import-resolved into a single program, monomorphized, then checked in three passes. Both backends lower the checked program to the same typed IR, so the native binary and the JavaScript output stay byte-identical.
ββββ COMPILER FRONTEND βββββββββββββββββββββββββββββββββββββββββββββββββββ
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Source files (.kora + imported modules) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ per module β
β β Lexer src/lexer β βββββ β
β β characters βββΆ tokens β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β βΌ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β Parser src/parser β βββββ€ β
β β tokens βββΆ AST β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β βΌ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β Loader + Import Resolver src/loader β βββββ β
β β assembles parsed modules; resolves imports β β
β β βββΆ LoadedProgram (module graph) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Generic Instantiator src/instantiate β β
β β monomorphize <T>; fill concrete β β
β β structs / impls / calls; prune type ifs β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Symbol Resolver β β
β β src/semantic_analyzer/symbol_resolver β β
β β symbol-table pass; cross-module binding β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Constant Evaluation β β
β β src/semantic_analyzer/const_eval β β
β β fold module-level lets, declaration order β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Type Checker β β
β β src/semantic_analyzer/type_checker β β
β β infer & check types; resolve methods β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Return-Flow Analysis β β
β β src/semantic_analyzer (ReturnChecker) β β
β β every path returns a value β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β β
β CompiledProgram (checked AST + types) β
β β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Typed IR Lowering src/ir β β
β β Name Mangling src/mangle β β
β β monomorphic ops, finalize mangled symbols, β β
β β explicit Wrap/Unwrap / Copy, lvalue detectionβ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β typed IR (ir::Program) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββ COMPILER BACKEND ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
β ββββββββββββββββββ΄βββββββββββββββββ β
β βΌ βΌ β
β ββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β
β β JavaScript Transpiler β β LLVM Lowering Pass β β
β β src/javascript_transpiler β β src/codegen (inkwell) β β
β ββββββββββββββββββββββββββββββ β emits an LLVM IR module β β
β β ββββββββββββββββββββββββββββββ β
β βΌ β β
β ββββββββββββββββββββββββββββββ βΌ β
β β Async Coloring pass β ββββββββββββββββββββββββββββββ β
β β marks fns that block on β β Object File Emission β β
β β an async extern as async β β src/codegen (TargetMachine)β β
β ββββββββββββββββββββββββββββββ β LLVM IR βββΆ native .o β β
β β ββββββββββββββββββββββββββββββ β
β βΌ β β
β ββββββββββββββββββββββββββββββ βΌ β
β β Emit JavaScript β ββββββββββββββββββββββββββββββ β
β β + runtime inclusion: β β Linking β β
β β kora_node_runtime.js / β β src/codegen::link β β
β β kora_browser_runtime.js β β + libkora.c runtime β β
β ββββββββββββββββββββββββββββββ β + Boehm GC + mbedTLS β β
β β ββββββββββββββββββββββββββββββ β
β βββββββββ΄ββββββββββββ β β
β βΌ βΌ βΌ β
β βββββββββββββββ ββββββββββββββββββββββ ββββββββββββββββββββββ β
β β Node.js β β Playground β β native executable β β
β β (.js output)β β wasm compiler + β β (LLVM 21 + linker) β β
β βββββββββββββββ β browser runtime + β ββββββββββββββββββββββ β
β β canvas host worker β β
β ββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
wasm-pack build --target web --out-name compiler -- --no-default-features # build the wasm compiler
python -m http.server # serve at localhostThen open the printed URL and start typing.
To compile programs to native executables instead, build the compiler. Building the compiler requires lib LLVM 21 and a C compiler for the platform linker.
cargo build --release # build the compiler
kora program.kora -o program # native standalone binary
kora program.kora --emit-js # or print the JavaScriptRunning the test suite is cargo test (also requires LLVM 21).
module = { import | struct | impl | extern | function } ;
import = "import" STRING [ ident ] ";" ;
struct = "struct" ident [ typeparams ] "{" [ member { "," member } [ "," ] ] "}" ;
member = ident ":" type ;
impl = "impl" ident [ typeparams ] "{" { method } "}" ;
method = rettype ident "(" "self" [ "," [ param { "," param } [ "," ] ] ] ")" block ;
typeparams = "<" ident { "," ident } [ "," ] ">" ; (* generic parameters, e.g. <T> or <K, V> *)
extern = "extern" ( "void" | externtype ) ident "(" externparams ")" ";" ;
externparams= [ externparam { "," externparam } [ "," ] ] ;
externparam = ident ":" externtype ;
externtype = "int8" | "int16" | "int32" | "int64" (* C types only *)
| "uint8" | "uint16" | "uint32" | "uint64"
| "float32" | "float64" | "bool" | "char"
| "cint" | "cuint" | "clong" | "culong" | "csize"
| ( "cstring" | "opaque" ) [ "?" ] ;
function = rettype ident [ typeparams ] "(" params ")" block ;
rettype = "void" | type ;
params = [ param { "," param } [ "," ] ] ;
param = ident ":" type ;
type = rettype "(" [ type { "," type } [ "," ] ] ")" [ "?" ] (* function type, e.g. int(int, int) *)
| basetype [ "?" ] ; (* "?" makes it optional *)
basetype = "int" | "real" | "char" | "bool" | "string" | "opaque"
| ident [ typeargs ] (* struct name, or generic instance *)
| "[" type "]" ;
typeargs = "<" type { "," type } [ "," ] ">" ; (* generic arguments, e.g. <int> or <int, string> *)
statement = ";"
| expr ";"
| "let" ident [ ":" type ] "=" expr ";"
| "return" [ expr ] ";"
| "break" ";"
| "continue" ";"
| "if" "(" expr ")" statement [ "else" statement ]
| "while" "(" expr ")" statement
| "for" "(" forinit expr ";" expr ")" statement
| "for" ident "|" expr statement
| block ;
forinit = ";" | expr ";" | "let" ident [ ":" type ] "=" expr ";" ;
block = "{" { statement } "}" ;
expr = assign ;
assign = or [ "=" assign ] ;
or = and { "||" and } ;
and = eq { "&&" eq } ;
eq = rel { ( "==" | "!=" ) rel } ;
rel = add { ( "<" | ">" | "<=" | ">=" ) add } ;
add = mul { ( "+" | "-" | "|" | "^" ) mul } ;
mul = cast { ( "*" | "/" | "%" | "&" | "<<" | ">>" ) cast } ;
cast = unary { "as" type } ;
unary = ( "!" | "-" ) unary | postfix ;
postfix = primary { "(" args ")" | "[" expr "]" | "." ident | "!" | "::" typeargs } ;
(* "::" typeargs is turbofish: id::<int>() *)
args = [ expr { "," expr } [ "," ] ] ;
primary = INT | REAL | CHAR | STRING | "true" | "false" | "none"
| ident
| "(" expr ")"
| "[" [ expr { "," expr } [ "," ] ] "]"
| "new" type [ "[" expr "]"
| "{" [ field { "," field } [ "," ] ] "}" ] ;
field = ident ":" expr ;