Design
FormaLang is an embeddable compiler frontend for a statically
typed, declarative language. An application puts the frontend inside
itself. The frontend parses .fv source, checks it, and gives a fully
resolved Intermediate Representation (IR). The application supplies the
backend, through the IrPass and Backend traits.
.fv source → FormaLang (in your application) → IrModule → your backend → result
The frontend stops at the IR. It has no runtime, no interpreter and no code generator. Thus one frontend serves many kinds of backend:
- An interpreter or a JIT compiler, that runs the program.
- A query engine, for example in a database, that runs a query that a user wrote in FormaLang.
- A code generator, that writes source in another language.
- Editor tooling, that reads the AST and the analysis.
Embeddable
The frontend fits inside another program:
- No I/O of its own. The library reads a file only through a
ModuleResolver. AMemoryResolvergives the modules from memory, for a host with no file system. - No global state. Two compiles share nothing, and a compile can run on any thread.
- No runtime. The output is data: the
IrModule. The host decides what runs, and when. - Many targets. The library builds for a native host and for
wasm32. The same frontend runs in a server, in a database and in a browser. - Errors as data. Each error is a
CompilerErrorwith its place in the source.report_errorsmakes a report that a person can read.
Single-Crate Design
The compiler is a single Rust crate (formalang). All phases share
types directly: no IPC, serialization, or process boundaries. The
compile does not run on the thread of the caller. Each public entry
point runs its work on a thread of its own, with a stack that fits the
nesting of the program. See Pipeline.
Logic Model
FormaLang logic is pure and declarative:
- Conditionals (
if/else, optional unwrapping) - Iteration (
forover an array, a range or a sequence) - Pattern matching (
matchon enums) - Struct/enum/trait definitions with generics and constraints
A program touches the world only through the host. An extern fn or an
extern impl declares what the host gives, and the frontend checks
each call against the declaration.
The IR is complete. Each type, name, call target and overload is resolved, so a backend does no analysis of its own.
Use Cases
- A query language: a database or a search engine takes queries
that its users write in FormaLang, and runs them on its own data.
extern fngives the data as a lazySeq<T>. - User-written logic in an application: rules, configuration that computes, UI definitions and state machines, checked before they run.
- An interpreter or a JIT compiler: a backend that runs the
IrModuledirectly. - Code generation: emit TypeScript, Swift, Kotlin or any other
language from one
.fvsource. - Editor tooling: hover, completion and go-to-definition through
compile_with_analyzer. - Static analysis and linting: walk the AST or the IR with a visitor.