Show HN: Topaz – A small application language that compiles through Rust

yo_tafo1 pts0 comments

Hi HN, I m Matt, CTO at STUDIO HAZE in Seoul. I ve wanted to build a programming language for twenty years, ever since Ruby got me wondering what a small language out of Korea might look like. Today I m opening the repo for the first time, as Topaz v5.2.Topaz reads like Python or TypeScript, runs on a reference interpreter (topaz run), and builds a self-contained native binary by lowering to Rust, then handing off to the Rust toolchain (topaz build). function factorial(n: int) - int { if n 2 { return 1 } return n * factorial(n - 1) } print( 10! = {factorial(10)} ) // 10! = 3628800 The idea: application logic should have a small, fixed surface with one obvious way to write each thing, and the compiler does the hard part underneath. Writing glue in Python and TS, I kept re-making the same policy decisions — errors, absence, cleanup. Topaz decides those once: Result for recoverable failure, optionals for absence, defer for cleanup.Identifiers are Unicode from the lexer up, with no implicit normalization — names compare by scalar sequence, so what you typed is what matches. Deliberate, not an oversight: NFC and NFD forms aren t silently merged, and the module resolver rejects imports that would collide under NFC/NFD or case folding. function 인사하기(이름: string) - string { return 안녕하세요, {이름}님! } print(인사하기( 토파즈 )) // 안녕하세요, 토파즈님! sql, sh, and path strings are tagged templates: interpolations stay structurally separate from the literal text, so a value is never spliced into the query as raw SQL. Below, a classic injection attempt; the printed value is the template s structure, not a concatenated string: let user = ; DROP TABLE t; -- let q = sql SELECT * FROM t WHERE name = {user} print( {q} ) // sql template, 2 part(s), 1 interpolation(s) To be clear on scope: this is a representation, not a database driver — there s no query-execution or parameter-binding layer yet. Injection is impossible by construction at this layer; a driver that consumes the value safely is future work.Why compile through Rust instead of C or LLVM? I m not trying to replace Rust — if you want to write Rust, write Rust. It s just a good thing to land on: I inherit its memory safety and a mature backend for free, the build is reproducible, and the binary needs no Topaz runtime. Topaz is what you write; Rust is what it becomes.Every fixture runs through both the interpreter and the compiler, and their stdout and exit status must agree; the moment they diverge, a test goes red. Both engines share the same runtime value model, so agreement is structural, not coincidental. cargo test --workspace is green at 635 tests. CI runs on Linux, macOS, and Windows, and every commit clears clippy -D warnings and cargo fmt --check.Implementation notes: - Whole toolchain (lexer, parser, checker, interpreter, emitter) is pure Rust, zero crates.io dependencies, forbid(unsafe_code). - The module resolver rejects path collisions from platform-specific case folding or normalization, keeping imports unambiguous across OSes. Some history, since opening at v5.2 looks odd: v1 was a Lisp dialect (now separate), v2 a Python-like surface, v3 and v4 an internal tool we ran next to Rust in our products. v5.2 is the first version I m comfortable showing.The honest catch: it s early, with basically no ecosystem yet. The topaz binary runs, checks, and emits on its own, but topaz build shells out to cargo, so that command needs a working Rust toolchain. This is not easy Rust. It s a small application surface that happens to compile through Rust.Docs at https://topaz.ooo. License Apache-2.0. Try it with: topaz run examples/hello.tpz topaz build examples/hello.tpz --out-dir out --run I d love feedback on the diagnostics, the generated Rust, the module semantics, and Unicode edge cases. Please tear into it.

topaz rust quot code build small

Related Articles