The Glyph programming language compiler, written in Rust.
Glyph transpiles to C (GNU statement expressions) and builds with GCC or clang into
plain native binaries. It also hosts NeuralScript (.ns), a typed AOT tensor
language for CPU/CUDA code generation.
Glyphc joins explicit systems programming and typed ML graphs in one inspectable toolchain: from source to native artifacts without a mandatory Python or GC layer. The project manifesto is available in Russian as Философия Glyphc.
┌──────────┐ glyphc ┌────────────┐ gcc/clang ┌─────────┐
│ .glyph │ ──────────▶ │ .c │ ─────────────▶ │ binary │
└──────────┘ (Rust) └────────────┘ └─────────┘
- Static typing:
Int64,UInt64,Float64,Bool,String,Bytes - Flow-sensitive static analysis: using a
List/Mapafter.free()(or freeing it twice) is rejected at compile time until reassignment - User types:
@struct,@enumwith payload data in variants @implmethods:obj.method(args), receiver is the first parameter- Control flow:
if/else,match(including variant patterns with payload),while,loop,for .. in - Guards:
#guard(cond) else { ... }; - Modules:
@module,@use,@pub, qualified callsmath::sqrt @constnamed constants (compiled tostatic const)- Typed lists
List<T>: literals[..], indexingarr[i], slicesarr[a..b]/arr[a..=b], ranges0..10,.len(),append,for x in xs,++concatenation,==for POD lists, refcounted buffers withxs.free() - Maps
Map<String, V>: literal#{ "k": v }, indexingm["k"]read/write,.put(),.get() -> Option<V>,.len(),.free(), iterationfor k in myields keys Result/Optionwith payloads anddrop(box)freeing- Generic functions:
@fn identity<T>(x: T) -> T— monomorphization, type inference by argument andletannotations, nested types (Option<T>,List<T>) - Concurrency (M:N worker pool):
@fn async, lazy handlesAsync<T>,spawn/await, typed channelsChannel<T>(capacity),send/recv/close,selectover recv/await withtimeout(ms)/defaultarms - Built-in test framework:
@test, asserts,glyphc test glyphc fmt: comment-preserving canonical indentation +--check/--write
NeuralScript (.ns) — neural-network DSL, now integrated into glyphc as glyphc nns.
The original C++ implementation was ported to Rust with byte-identical codegen and merged
into the single glyphc binary.
glyphc nns file.ns --check # typecheck only, no codegen
glyphc nns file.ns --cpp # emit C++ to stdout
glyphc nns file.ns --cpp --runtime # emit C++ + runtime header
glyphc nns examples/nns/mlp.ns --cpp --runtime | gcc -x c - -o a.out && ./a.out
glyphc nns file.ns --cuda --runtime # emit CUDA + runtime header
glyphc nns file.ns --cuda --runtime -o out.cu # write to fileFlags: --check (no codegen), --cpp / --cuda (select backend), --runtime (prepend
runtime header), -o/--output <file> (write to file instead of stdout).
Examples live in examples/nns/*.ns (e.g. examples/nns/mlp.ns). The complete
reference is in docs/nns.md.
Requires Rust (1.85+) and gcc (or clang) on PATH.
The easiest installation is the release installer:
curl -fsSL https://raw.githubusercontent.com/MrModelOS/Glyph/main/install.sh | bash
# optional: install into ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/MrModelOS/Glyph/main/install.sh | bash -s -- --prefix ~/.local/binFor a source install or development checkout:
cargo install --git https://github.com/MrModelOS/Glyph --locked
# or
git clone https://github.com/MrModelOS/Glyph.git
cd Glyph
cargo build --releaseA container image can be built locally with docker build -t glyphc .; the
resulting image exposes the glyphc binary. Tagged Linux, macOS, and Windows
archives with SHA-256 checksums are published on the
Releases page. The documentation
site is built from docs/ by the Pages workflow.
Start a project with the built-in scaffold:
glyphc new hello
cd hello
glyphc buildOr compile a single file:
hello.glyph:
@fn main() -> Void {
let name: String = "World";
let greeting: String = "Hello, " ++ name ++ "!";
print(greeting);
}glyphc run --input hello.glyph
# Hello, World!There is also a real interactive demo — the 15-puzzle — with lists, slicing,
read_line, and @tests:
glyphc run --input examples/fifteen.glyph| Subcommand | Description |
|---|---|
compile --input f.glyph [-o out.c] [--emit-ir] [--no-typecheck] |
Transpile to C (default output.c) |
check --input f.glyph |
Check syntax and types without codegen |
tokens --input f.glyph |
Show the token stream |
ast --input f.glyph |
Show the AST |
run --input f.glyph [--compiler gcc] [--opt -O2] |
Compile and run (inherits stdio) |
build [--profile dev|release] |
Build a project described by glyph.toml |
fmt --input f.glyph [--write] [--check] |
Canonical indentation/whitespace; comments preserved (prints to stdout by default) |
test [-i f.glyph] [--compiler gcc] [--opt -O2] |
Run @test functions (scans ./src without -i) |
nns <file.ns> [--check] [--cpp] [--simd] [--cuda] [--runtime] [--mlir] [--fp16] [-o <file>] |
NeuralScript tensor compiler: --check shape-check only, --cpp/--simd/--cuda select the backend (default CUDA), --runtime emits the C-ABI runtime, --mlir dumps IR, --fp16 enables the experimental CUDA header mode, -o writes to a file (default stdout) |
new <name> / init [name] |
Create a glyph.toml project scaffold |
lsp |
LSP server alias for glyphc --lsp (also glyphc --lsp as flag) — live diagnostics, hover, completion, go-to-definition |
glyphc --lsp |
LSP server (flag form): live diagnostics (lexer/parser/typechecker, full spans), hover and completion |
Common flags: -h/--help, -V/--version. nns details: docs/nns.md; editor setup: docs/editors.md. A minimal VS Code extension is available in editors/vscode-glyph.
Full reference: English · Русский. Highlights:
@struct Point { x: Float64, y: Float64 }
@impl Point {
@fn norm(p: Point) -> Float64 {
return sqrt(p.x * p.x + p.y * p.y);
}
}
@enum Shape {
Circle(Float64),
Rectangle(Float64, Float64),
Point,
}
@fn area(s: Shape) -> Float64 {
match s {
| Shape::Circle(r) => 3.14159 * r * r
| Shape::Rectangle(w, h) => w * h
| Shape::Point => 0.0
}
}
@fn distance(a: Point, b: Point) -> Float64 {
let dx: Float64 = b.x - a.x;
let dy: Float64 = b.y - a.y;
return sqrt(dx * dx + dy * dy);
}
@fn main() -> Void {
let p: Point = Point { x: 3.0, y: 4.0 };
print_float(p.norm()); // 5.0
let arr: List<Int64> = [1, 2, 3];
arr.append(4);
let both: List<Int64> = arr ++ arr;
let slice: List<Int64> = arr[1..3];
print_float(area(Shape::Circle(5.0)));
}Errors and generics:
@fn divide(a: Int64, b: Int64) -> Result<Int64, String> {
#guard(b != 0) else {
return Result::Err("division by zero");
};
return Result::Ok(a / b);
}
@fn identity<T>(x: T) -> T { return x; }
@fn main() {
let q: Int64 = match divide(10, 2) {
| Ok(v) => v,
| Err(e) => -1
};
let s: String = identity("hello");
print_int(q);
}Concurrency, modules, and asserts are documented in docs/language.md.
cargo build
cargo test # 100 unit + 25 integration tests (CLI smoke + NeuralScript)
examples/run_all.sh # compiles and runs every example
glyphc test -i examples/fifteen.glyphexamples/fifteen.glyph is a real interactive program (15-puzzle) written in Glyph:
lists, slicing, functions, read_line, and @tests. examples/list_refs.glyph
demonstrates the refcounted list semantics, and examples/maps.glyph shows the
Map<String, V> runtime (#{} literal, indexing, put/get/len/free, for k in m).
Glyph compiles to C and inherits the C toolchain: scalar code compiles to the
same machine code, and the runtime overhead is proportional to the
allocation/GC features you use. The table below compares identical algorithms
on one machine (min of 3 runs, gcc 16.2.1 -O2, rustc 1.98.1 --release with
LTO; meant to show the ballpark, not to be a rigorous benchmark).
workload glyph c rust ratio (glyph/c)
loop_sum 476ms 471ms 549ms 1.01x
list_append 13ms 14ms 14ms 0.93x
map_put_get 43ms 40ms 43ms 1.07x
Hardware: 11th Gen Intel Core i5-1135G7, 2026-09-10. loop_sum sums
i % 7 over a runtime size (400M iterations); list_append appends 5M
int64s to a dynamic array and sums them; map_put_get puts+gets 500k
string-key entries across a 100-key churn. All three implementations produce
identical output. Reproduce with:
bash bench/gen.sh /tmp/bench 5000000
LOOP_IN=400000000 bash bench/run.sh /tmp/benchNotes:
loop_sumis at parity with C (1.01x) and edges out Rust (549ms vs 476ms) — the loop, modulo and integer arithmetic emit the same code gcc would write by hand, minus LLVM's optimizer noise on the hot induction loop.list_appenduses a refcounted growable buffer that doubles its capacity geometrically, so appends amortize to O(1) like C'sreallocarray; the runtime helpers arestatic inline, so the hot loop inlines to a plain store — at parity with C.map_put_getrehashes geometrically (load factor ≤ 0.75) and keys built temporarily byint_to_string/++/substring... are freed right after the put/get/index call, so the string churn that used to be measured (and leak) is gone. At 1.07x it sits between C (fixed 256 buckets) and Rust's hashbrown.
- Runtime is unmanaged:
Result/Optionpayloads are heap boxes freed viadrop(box); async handles and channels are not auto-released - Generics cover functions only (no generic structs/enums/impl, no trait bounds); calling a generic function inside a generic body needs concrete types
List<T>:==/!=works only for POD scalars; slices are copiesMap<String, V>: iteration (for k in m) walks hash buckets, so key order is not insertion order; keys areStringonly- The use-after-free / double-free detector is statement-flow based and does not
track aliases:
let y = xs; xs.free(); y.len()is not yet caught, and a free inside amatcharm is treated as having happened after thematch - Concurrency: no GC; async generic functions unsupported;
selectarms must berecv()/awaitand its wait loop polls at ~1 ms granularity - LSP server: diagnostics from lexer/parser/typechecker with full source spans, cursor hover and keyword completion; textDocumentSync = Full
MIT