$ show amber-lang/amber
Amber is a Rust-based compiler that transpiles a high-level, statically-typed programming language into shell scripts (Bash, Zsh, Ksh). It provides a modern language with features like functions, type inference, generics, optional arguments, failable types, imports, loops, range expressions, array operations, and a standard library for file system, text, HTTP, math, and environment operations. The compiler architecture is modular: a CLI entry point (src/main.rs) dispatches to subcommands (build, run, eval, check, docs, test). The compilation pipeline (src/compiler.rs) orchestrates tokenization via heraclitus-compiler, parsing into a typed AST, type checking with control-flow analysis, translation to an intermediate fragment AST, optimization passes (unused variable removal, ephemeral variable elimination), and final shell code generation with post-processing (e.g., shell syntax checking). The system supports multiple shell targets and generates version-specific code. The codebase is well-structured with procedural macros (meta crate) for keyword registration and context management, and a comprehensive test suite using snapshot testing (insta). While alpha quality, the engineering is serious and the architecture shows thoughtful design patterns.
The LLM identified 4 files worth highlighting for reuse:
Defines the FragmentKind enum and FragmentRenderable trait that form the core of the shell code generation pipeline. Each fragment type (Raw, VarStmt, VarExpr, Block, Interpolable, Subprocess, List, etc.) implements a specific rendering strategy, allowing compositional and shell-target-aware code output. This pattern is isolated, reusable for any code generator that needs to compose output from typed AST nodes, and demonstrates clean separation of concerns.
Implements an unused variable removal optimization pass over the fragment AST. It tracks variable definitions and uses across scopes (including conditional blocks), uses a symbol table to detect dead writes, and safely removes them. This is a self-contained dataflow analysis that could be extracted and applied to other IRs or languages requiring dead-code elimination.
Provides macros (e.g., parse_expression!, typecheck_expression!, translate_expression!) that declare precedence groups and dispatch to the appropriate expression handler. This pattern decouples expression parsing/typechecking/translation logic from the precedence hierarchy, enabling clean addition of new operators. It is a reusable pattern for any language compiler that needs to manage operator precedence without boilerplate.
Implements ParserMetadata, a complex scoped state manager for the parser that tracks variables, functions, imports, and compiler flags. It uses a stack-based save/reset mechanism (via ContextManager derive macro) to handle nested scopes. This is a well-encapsulated symbol table pattern that could be reused in any language processor requiring scope management.