This repository contains a C++17 compiler for the ATOM programming language. The compiler emits WebAssembly Text (WAT) and targets WASI. The project includes the language front-end (lexer, parser, type checking), code generation, and a comprehensive test/benchmark suite.
All code in this repository has been generated, refactored, corrected, or documented using OpenAI's coding Large Language Model (LLM) tool codex.
make clean
make all
./test_functions.sh
./test_benchmarks.sh- Compiler: C++17 (g++ or clang++)
- WASM toolchain:
wat2wasm(from WABT) - Runtime:
wasmtime
./atomc path/to/program.atom -o output.wat
wat2wasm output.wat -o output.wasm
wasmtime output.wasmFor quick iteration on a single file with expected output comparison:
./debug.sh path/to/program.atom [args...]- Indentation-based blocks, Python-style.
- Block headers end with a colon (
:). - Conditions for
ifandwhileuse parentheses. - Comments:
#or//to end of line.
Int: 64-bit signed integerReal: 64-bit floating pointBool:true/falseChar: single byte characterString: UTF-8 byte stringArray[T]orT[]: array typeVoid: no return valuenull: null literal for reference types
All variables are declared with an explicit type.
Int add(Int a, Int b):
return a + b
Int main():
Int result = add(2, 3)
"result=%i".println(result)
return 0
Inline function bodies are supported:
Int add(Int a, Int b) = a + b
Structures define fields and methods. Single inheritance is supported. Method calls are dynamically dispatched.
Animal:
String name
init(String name):
this.name = name
Void speak():
"...".println()
Dog: Animal:
Int age
init(String name, Int age):
this.name = name
this.age = age
Void speak():
"Woof".println()
inner is a statement used inside a base-class method to call the next override in the class hierarchy (the most-derived implementation relative to the current class).
Base:
Void log(String msg):
"[base]".print()
inner
Child: Base:
Void log(String msg):
msg.println()
Arrays are heap-allocated and store 64-bit slots. Reference values are stored as pointers.
Supported methods:
size()/count()->Intpush(value)pop()get(i)set(i, value)getInt(i)getString(i)
Out-of-bounds access returns:
-1for numeric arrays (Int,Real)nullfor reference arrays
- Double-quoted literals with escapes:
\n,\t,\r,\",\\ - Concatenation with
+ length()returns byte lengthprint()/println()output the string
Formatted printing supports:
%i(Int)%r(Real)%s(String)%b(Bool)
Unsupported format specifiers are printed literally.
Imports are parsed and used to include other source files:
import Math from "./math.atom"
import Utils as U from "./utils.atom"
Notes:
- Only
from "path"triggers a file import. - Paths without
/are resolved relative to the importing file. asaliases are parsed but not currently used during compilation.
The compiler looks for Int main(...) and exports _start for WASI.
Two supported signatures:
Int main():
return 0
Int main(String[] args):
"argc=%i".println(args.count())
return 0
args are populated from:
- stdin tokens when stdin is not a TTY (whitespace split), otherwise
- WASI argv (excluding argv[0]).
- Memory layout (class instances):
- offset
0: class id (i32) - offset
8: reference count (i64, not used for reclamation) - offset
16+: fields (8-byte aligned)
- offset
- Strings:
- offset
16: length (i64) - offset
24: data pointer (i32)
- offset
- Arrays:
- offset
16: length (i64) - offset
24: capacity (i64) - offset
32: data pointer (i32)
- offset
- Dynamic dispatch: method calls use a vtable table stored in linear memory and
call_indirect. - Inner dispatch:
inneruses a separate table to resolve the next override at runtime. - Reference counting helpers exist (
incref/decref), but the compiler does not currently emit retain/release or free memory.
compiler/— C++17 compiler sourcesbuild/— build artifacts (.o)testing/functions/— functional tests (.atom)testing/benchmarks/— benchmarks (.atomand.c)testing/stdin/— stdin fixtures (.in)testing/stdout/— expected outputs (.out)test_functions.sh,test_benchmarks.sh— test runnersdebug.sh— compile+run helper for a single file
<program> ::= <import_stmt>* (<structure_def> | <function_def>)*
<import_stmt> ::= "import" IDENTIFIER ("as" IDENTIFIER)? NEWLINE
<structure_def> ::= IDENTIFIER (":" IDENTIFIER)? ":" NEWLINE INDENT <structure_member>* DEDENT
<structure_member> ::= <var_decl> | <method_def>
# Function definition (standalone)
# Supports block body or inline assignment: Int add(a,b) = a+b
<function_def> ::= <type>? IDENTIFIER "(" <param_list>? ")" (":" NEWLINE INDENT <statement>* DEDENT | "=" <expression> NEWLINE)
<var_decl> ::= <type> IDENTIFIER ("=" <expression>)? NEWLINE
# Method definition (inside structures)
# Note: 'init' is matched here as an IDENTIFIER but treated semantically as a constructor
<method_def> ::= <type>? IDENTIFIER "(" <param_list>? ")" ":" NEWLINE INDENT <statement>* DEDENT
<param_list> ::= <type> IDENTIFIER ("," <type> IDENTIFIER)*
# Supports both Array[Int] and Int[] styles
<type> ::= <base_type> ("[" "]")*
<base_type> ::= "Int" | "Real" | "Bool" | "String" | "Char" | "Void"
| "Array" ("[" <type> "]")?
| IDENTIFIER
<statement> ::= <var_decl>
| <if_stmt>
| <while_stmt>
| <return_stmt>
| <expr_stmt>
| <inner_stmt>
<inner_stmt> ::= "inner" NEWLINE
<if_stmt> ::= "if" "(" <expression> ")" ":" NEWLINE INDENT <statement>* DEDENT ("else" ":" NEWLINE INDENT <statement>* DEDENT)?
<while_stmt> ::= "while" "(" <expression> ")" ":" NEWLINE INDENT <statement>* DEDENT
<return_stmt> ::= "return" <expression>? NEWLINE
<expr_stmt> ::= <expression> NEWLINE
<expression> ::= <logical_or>
<logical_or> ::= <logical_and> (("||") <logical_and>)*
<logical_and> ::= <equality> (("&&") <equality>)*
<equality> ::= <comparison> (("==" | "!=") <comparison>)*
<comparison> ::= <additive> (("<" | ">" | "<=" | ">=") <additive>)*
<additive> ::= <multiplicative> (("+" | "-") <multiplicative>)*
<multiplicative> ::= <unary> (("*" | "/") <unary>)*
<unary> ::= ("!")? <postfix>
# Postfix handles method calls (foo()), property access (foo.bar), and array access (foo[i])
<postfix> ::= <primary> (<call_access>)*
<call_access> ::= "(" <arg_list>? ")"
| "." IDENTIFIER
| "[" <expression> "]"
<arg_list> ::= <expression> ("," <expression>)*
<primary> ::= IDENTIFIER
| INTEGER
| REAL
| STRING
| CHAR
| "true" | "false"
| "null"
| "this"
| "inner"
| "(" <expression> ")"
| "[" <arg_list>? "]" # Array Literal: [] or [1, 2]
INTEGER ::= [0-9]+
REAL ::= [0-9]+\.[0-9]+
STRING ::= "\"(\\.|[^\"\\\\])*\""
CHAR ::= "'(\\.|[^'\\\\])'"
IDENTIFIER ::= [a-zA-Z_][a-zA-Z0-9_]*
COMMENT ::= "#" (~NEWLINE)* | "//" (~NEWLINE)*
SPDX-License-Identifier: OBL-1.0
Open Source Beer License (with Extra Bubbles)
Licensor: Atom Compiler Contributors
Human LLM Controller: jens@bennerhq.com
If we meet some day and you think this code is worth it, you can buy
the authors a beer (or two). If you see benner, make it a cold one.
If you pour beer on your computer, the compiler will not run faster.
If you pour beer on the authors, results may vary.