Dependently-typed programming language for the BEAM virtual machine with first-class finite state machines and SMT-backed verification.
Cure compiles .cure source files to BEAM bytecode, enabling programs to run
natively on the Erlang VM alongside Erlang and Elixir code.
flowchart TD
A[.cure source] -->|Cure.Compiler.Lexer| B[Token stream]
B -->|Cure.Compiler.Parser| C[MetaAST — Metastatic 3-tuples]
C -->|Cure.Types.Checker| D[Typed MetaAST]
D -->|Cure.Compiler.Codegen| E[Erlang Abstract Forms]
E -->|:compile.forms/2| F[BEAM bytecode]
Every pipeline stage emits structured events via Cure.Pipeline.Events,
backed by an Elixir Registry in PubSub mode. External tools (LSP, profilers,
IDE plugins) can subscribe to observe and react to compilation in real time.
Cure uses Metastatic's MetaAST 3-tuple format as its internal AST:
{type_atom, keyword_meta, children_or_value}This provides a well-defined, layered AST structure and interoperability with Metastatic's cross-language analysis tools.
- Dependent types -- types that depend on values, verified at compile time
- Refinement types -- constrained subtypes checked via SMT solver
- Records -- named product types with construction (
Point{x: 1, y: 2}), field access (p.x), and functional update (Point{p | x: new_x}); compile to BEAM maps; type-checked with per-field schemas - First-class FSMs -- finite state machines as language constructs with
compile-time verification (reachability, deadlock freedom, hard event validation),
dual-mode compilation (simple
gen_statemor callbackGenServer), Finitomata-inspired!/?event suffixes, inlineon_transitionhandlers, and lifecycle callbacks (on_enter,on_exit,on_failure,on_timer) - Typed actors and supervisors (v0.25.0) --
actor Namecontainers compile to loadedGenServermodules;sup Namecontainers compile to verifiedSupervisorbehaviour modules with compile-time checks on strategy / intensity / period / child-id uniqueness / restart / shutdown.Std.Actor,Std.Process, andStd.Supervisorexpose the runtime from Cure source - Applications and releases (v0.26.0) -- an
app Namecontainer declares the project's OTPApplicationcallback in Cure source withvsn,description,root,applications,env,on_start,on_stop, andon_phase :nameclauses. The compiler rejects projects with more than oneappcontainer and cross-checks its name and start phases against[application]inCure.toml. Thecure releasesubcommand (alsomix cure.release) packages the compiler output as a bootable BEAM release under_build/cure/rel/<name>/.Std.Appexposesensure_all_started,start,stop,get_env,put_env,which_applications,loaded_applications, andstart_phasefrom Cure source - Melquiades Operator (v0.25.0) --
pid <-| message(unicode aliaspid ✉ message) is a typed send operator that lowers to Erlang's!; the type checker unifies the message type against the receiver's inbox ADT - Indentation-structured -- no closing delimiters, visual layout determines scope
- Expression-oriented -- everything is an expression, the last expression in a block is its value
- BEAM-native -- compiles to standard BEAM bytecode, full OTP interoperability
- Protocols -- ad-hoc polymorphism via
proto/implwith guard-based dispatch compiled to multi-clause BEAM functions - Effect system --
! Io, Exception, ...annotations; inferred when omitted
mod MyApp.Math
use Std.{Result, Option}
type Sign = Positive | Negative | Zero
fn factorial(n: Nat) -> Nat
| 0 -> 1
| n -> n * factorial(n - 1)
fn classify(x: Int) -> Sign
| x when x > 0 -> Positive
| x when x < 0 -> Negative
| _ -> Zero
fn safe_divide(a: Int, b: {x: Int | x != 0}) -> Int = a / b
# Compile a Cure source file to BEAM bytecode
mix cure.compile path/to/file.cure
# Compile all .cure files in a directory
mix cure.compile path/to/dir/ --output-dir _build/cure/ebincure repl drops you into a readline-grade loop backed by a raw-mode
line editor with live Cure syntax highlighting (via makeup_cure +
marcli), persistent history, incremental reverse search, Tab
completion, and a minimal vi mode:
cure(1)> fn add_ints(a: Int, b: Int) -> Int = a + b
defined add/2
cure(2)> :t add_ints(1, 2)
add_ints(1, 2) : Int
cure(3)> :bench Std.List.map([1, 2], fn (x) -> x + 1) 10000
n=10000 min=1 us avg=2 us p95=3 us max=42 us
Key bindings (emacs mode): Left/Right cursor, Up/Down for
history, Ctrl+A/Ctrl+E begin/end of line, Ctrl+W kill word,
Ctrl+K/Ctrl+U kill to end/start, Ctrl+R incremental history
search, Tab completion for meta-commands, file paths, loaded
modules and Cure keywords, Ctrl+L clear screen, Ctrl+C abort
line, Ctrl+D EOF. A minimal vi mode is available via :mode vi.
Meta-commands include :t, :effects, :load, :reload, :use,
:fmt, :holes, :env, :reset, :history, :search, :save,
:edit, :time, :bench, :ast, :theme, :mode, :color,
:clear, :help, :quit. See docs/REPL.md.
From Elixir code:
# Compile and load into the running VM
{:ok, module} = Cure.Compiler.compile_and_load(source)
module.my_function(args)
# Compile with type checking enabled
{:ok, module} = Cure.Compiler.compile_and_load(source, check_types: true)
# Compile to disk
{:ok, module, warnings} = Cure.Compiler.compile_file("hello.cure")Cure-- root module, versionCure.Pipeline.Events-- PubSub event system (Registry-backed); every pipeline stage emits structured events that external tools can subscribe toCure.Compiler-- orchestrator: source -> lex -> parse -> [check] -> codegen -> .beamCure.Compiler.Token-- token struct (type,value,line,col)Cure.Compiler.Lexer-- tokenizer for the full Cure syntax (keywords, operators, literals, indentation, string interpolation, FSM transitions)Cure.Compiler.Parser-- Pratt (precedence-climbing) parser producing MetaAST 3-tuples; indentation-aware, handles all expression and structural forms (functions, modules, records, types, protocols, implementations, imports, FSMs)Cure.Compiler.Parser.Precedence-- operator binding power tableCure.Compiler.Codegen-- MetaAST to Erlang abstract forms; compiles expressions, patterns, module assembly,@externFFI wrappers, multi-clause functions, ADT constructors (tagged tuples), records (maps)Cure.Compiler.BeamWriter-- compiles Erlang abstract forms to BEAM bytecode via:compile.forms/2and writes.beamfilesCure.Types.Type-- canonical type representations (primitives, composites, ADTs,{:named, Name}record references, function types, effects); subtyping, join, type-expression resolutionCure.Types.Env-- scoped typing environment with variable bindings and named type definitions (Env.extend_type/3,Env.lookup_type/2)Cure.Types.Checker-- bidirectional type checker; validates literals, variables, operators, function definitions, calls, let bindings, conditionals, pattern matching, blocks, collections, lambdas, records (construction, field access, update), modules (two-pass with record schema registration); emits:type_checkerpipeline eventsCure.FSM.Verifier-- structural FSM verification: reachability (BFS), deadlock freedom, terminal state validation, hard event validation, ambiguous transition warnings; emits:fsm_verifiereventsCure.FSM.Compiler-- dual-mode FSM compiler: simple mode generatesgen_statemBEAM modules; callback mode (withon_transitionblock) generatesGenServer-based modules with embedded transition tables. Supports!(hard/auto-fire) and?(soft/silent) event suffixes, lifecycle callbacks (on_enter,on_exit,on_failure,on_timer), and introspection (transitions/0,allowed?/2,responds?/2)Cure.Actor.Compiler-- compilesactorcontainers into loadedGenServermodules viaCode.compile_string/2; returns{:ok, {:actor, module()}}Cure.Actor.Runtime-- ETS-backed actor registry supervised byCure.Supervisor; spawn / stop / lookup / list / monitor-driven cleanup.Cure.Actor.Stateis the shared runtime struct carryingcaller/meta/payloadCure.Sup.Verifier-- structural supervisor verification (strategy, intensity, period, child-id uniqueness, restart / shutdown, self- reference cycles); emits:sup_verifiereventsCure.Sup.Compiler-- compilessupcontainers into loadedSupervisor-behaviour modules; returns{:ok, {:supervisor, module()}}Cure.Sup.Runtime-- lazy ETS-backed registry for running supervisor trees (start/1,2,stop/1,lookup/1,which_children/1,list/0)Cure.Process.Builtins/Cure.Sup.Builtins-- FFI bridges wiringStd.ProcessandStd.Supervisorto the runtimeCure.App.Verifier-- structural verification forappcontainers: duplicate declaration check, single-app-per-project enforcement,appvs[application].namename match, start-phase consistency, root-supervisor resolvability (emits:app_verifierevents, surfacesE051/E053/E054)Cure.App.Compiler-- compilesappcontainers into loadedApplication-behaviour modules viaCode.compile_string/2; generatesstart/2,stop/1, and (when declared)start_phase/3; returns{:ok, {:app, module()}}Cure.App.Resource-- emits the OTP<name>.appresource file into the output directory; threads metadata from the container and[application](vsn,applications,included_applications,registered,env,start_phases)Cure.App.Builtins-- FFI bridge wiringStd.Appto:applicationwith plain-atom return shapesCure.Release-- builds a bootable BEAM release under_build/cure/rel/<name>/:.rel/start.boot/start.scriptassembly via:systools,sys.config/vm.argscopying, and the POSIXbin/<name>runner script (emits:releaseevents, surfacesE052/E055)Cure.Compiler.Errors-- structured error formatter with source locations for all pipeline stages (lex, parse, type, codegen, FSM verifier)Cure.Types.Protocol-- protocol definition and implementation tracking; type-to-guard mapping, dispatch clause generationCure.Types.Refinement-- refinement type operations; SMT-backed subtype checking, satisfiability verification, construction from parser ASTCure.SMT.Process-- Z3 solver process management via Erlang port; interactive query execution with timeout and sentinel-based response parsingCure.SMT.Translator-- MetaAST to SMT-LIB2 translation; operator mapping, variable collection, logic inference, query generationCure.SMT.Solver-- high-level constraint API; satisfiability checking, implication proving, refinement subtype verification; Z3 fallbackCure.Types.PatternChecker-- pattern exhaustiveness and redundancy analysis; coverage checking for Bool, Result/Option ADTs, List, infinite types; integrated into type checker as warningsMix.Tasks.Cure.Compile--mix cure.compiletask with formatted error outputMix.Tasks.Cure.CompileStdlib--mix cure.compile_stdlibcompiles the standard libraryMix.Tasks.Cure.Release--mix cure.releasebuilds a bootable BEAM release for the project'sappcontainer (v0.26.0)
The standard library is self-hosted -- written in Cure itself under lib/std/.
Compile it with mix cure.compile_stdlib.
Std.Core(36 functions) -- identity, compose, pipe, boolean ops, comparisons, Result type (ok, error, is_ok, map_ok, and_then, or_else), Option type (some, none, is_some, unwrap, map_option, flat_map_option)Std.List(25 functions) -- length, head, tail, last, cons, append, concat, reverse, map, filter, foldl, foldr, flat_map, zip_with, nth, take, drop, contains, find, any, all, sum, product, countStd.Math(18 functions) -- abs, sqrt, pow, log, log2, log10, ceil, floor, round, pi, max, min, clamp, sign, negate, is_even, is_odd, safe_divStd.String(17 functions) -- length, is_empty, concat, downcase, upcase, trim, from_int, from_float, from_atom, to_int, to_float, to_atom, split, repeat, reverseStd.Pair(9 functions) -- element, first, second, swap, map_first, map_second, map_both, to_list, from_listStd.Access(protocol + 6 lenses + 6 nested helpers) -- Elixir-styleAccessbehaviour for Cure. Protocol callbacksfetch/2,get_and_update/3,pop/2with implementations for maps (records included) and keyword-style lists; direct helpersfetch_bang,get,get_and_update,pop; composable lenseskey,key_default,key_bang,elem_at,at,all,filter; and nested traversal helpersfetch_in,get_in,put_in,update_in,get_and_update_in,pop_inStd.Show(6 functions) -- Show protocol withshow/1dispatch for Int, Float, String, Bool, Atom;show_line/1convenienceStd.Io(8 functions) -- put_chars, println, print, int_to_string, float_to_string, atom_to_string, print_int, print_floatStd.System(10 functions) -- monotonic_time, system_time, timestamp_ms, timestamp_us, self, node, system_info, otp_version, cpu_count, exitStd.Actor(8 functions, v0.25.0) -- spawn, spawn_with_payload, spawn_named, stop, send, get_state, is_alive, lookup. Cure-facing surface for compiled actor modules; backed byCure.Actor.BuiltinsandCure.Actor.RuntimeStd.Process(9 functions, v0.25.0) -- link, unlink, monitor, demonitor, trap_exit, exit, self, is_alive. Raw BEAM process primitives; backed by:erlangBIFs with thin wrappers inCure.Process.BuiltinsStd.Supervisor(7 functions, v0.25.0) -- start, start_with, stop, which_children, count_children, lookup, list. Convenience API over compiled supervisor trees; backed byCure.Sup.BuiltinsandCure.Sup.RuntimeStd.App(9 functions, v0.26.0) -- ensure_all_started, start, stop, get_env, get_env with default, put_env, which_applications, loaded_applications, start_phase. Cure-facing surface for the generatedCure.App.<Name>application module; backed byCure.App.Builtins(thin wrappers over:application)
See the examples/ directory for sample Cure programs:
hello.cure-- minimal module with a greeting functionmath.cure-- arithmetic, multi-clause factorial, conditionalstraffic_light.cure-- FSM definition with wildcard transitionslist_basics.cure-- list operations (map, filter, fold)result_handling.cure-- Result type error handling with and_thenpattern_guards.cure-- pattern matching, guards, match expressionsrecursion.cure-- recursive functions (factorial, fibonacci, reverse)protocols.cure-- protocol definition and dispatchffi.cure-- calling Erlang functions via @externadt.cure-- algebraic data types (Option, Result, Color)records.cure-- record definition, construction, field access, and functional update withTypeName{base | field: val}syntaxcure_turnstile/-- full example project: callback-mode FSM withon_transitionhandler, GenServer wrapper, and testscure_spline/-- full example project: natural cubic spline interpolation library in Cure (Thomas algorithm, per-segment cubic coefficients, evaluation/derivative/sampling), with an Elixir wrapper, a demo that renders an ASCII plot of a fitted sine, and a 25-case test suitecure_moneta/-- full example project: money and ledger library; multi-line ADT (Currency), refinement types (PositiveAmount,Rate),Money{amount, currency, fractional_units}record (EUR/JPY/OMR-aware display),ShowandEqprotocols, FX conversion via@externFFI, ledger mutations withResult-chaining, and a payment transaction FSM with hard (dispatch!), soft (retry?,cancel?), wildcard,on_timer,on_enter, andon_failurecallbackscure_colony/-- v0.25.0 supervision-tree demo: a worker actor, an echo actor, and asup Colonysupervisor wiring them under a:one_for_onestrategy with per-childrestartandshutdownoverrides. Exercisesactor,sup, and the Melquiades Operator end to endcure_forge/-- v0.26.0 fully-fledged application demo: a metrics actor, a logger actor, a queue actor, and a pool actor, wired under asup Forge.Roottree that is itself therootof anapp CureForgecontainer. Exercisesapp(withvsn,description,env,applications,on_start,on_stop, andon_phase :warm_cache), end-to-end message passing between actors through the Melquiades Operator<-|,Std.Appenvironment reads, andcure releasepackagingcure_motif/-- length-indexed step sequencer showcase: refinement types for every MIDI-domain primitive,Std.Vector-backedPattern(n)helpers with observable length claims, an@record-annotated callback-modeEnvelopeFSM,Cure.Temporalliveness proofs over the FSM graph, a three-actor supervision tree (Clock,Sequencer,Voice), a Melquiades-relay sequencer, anapp CureMotifcontainer, and an Elixir-side ASCII piano-roll renderer driven byCureMotif.Demo.run/0
Compile and run:
cure compile examples/hello.cure
cure run examples/recursion.cure
cure check examples/protocols.cure- Language Specification -- syntax, keywords, operators, all constructs
- Type System -- bidirectional checking, refinement types, SMT verification
- FSM Guide -- FSM definition, compilation, runtime, verification
- Supervision -- typed actors,
supcontainers, the Melquiades Operator, links and monitors (v0.25.0) - Applications --
appcontainers,Cure.toml[application]/[release]sections, thecure releasesubcommand, andStd.App(v0.26.0) - Documentation Tooling --
cure docpipeline,[doc]config, placeholder interpolation, Makeup highlighting, REPL Markdown renderer (v0.29.0) - John --
mix cure.john,cure john, and the:johnREPL meta-command; collector / renderer / Marcli fallback reference (v0.30.0) - Standard Library -- API reference for the stdlib modules (every module now ships a
## Examplesblock)
mix deps.get
mix compile
mix testmix format
mix credo --strict
mix dialyzerAll core milestones complete. The full compilation pipeline is operational: lexer, parser, bidirectional type checker with record types, refinement types and exhaustiveness analysis, protocol dispatch codegen, BEAM code generation, FSM compilation with structural verification, effect system, documentation generator, formatter, stdlib, CLI, CI, and example programs.
- v0.32.0 -- Trust, Export, Recall, Narrate: proof-carrying packages
(
mix cure.verify), cross-language ADT export to proto3 (mix cure.export_types), REPL session snapshots (cure snap), and a narrative architecture generator (cure story). Error codesE065-E070. - v0.30.2 / v0.30.1:
johnpolish -- UTF-8 fixes formix cure.john, structurederl_crash.dumpsummaries, ASCII-only banners, dialyzer cleanups. - v0.30.0 -- John: a single panoramic diagnostic exposed via
mix cure.john,cure john, and the:johnREPL meta-command; reports Cure / BEAM / system / project / runtime state as Markdown-to-ANSI. - v0.29.0 -- Make Documentation Great:
cure docproduces an ExDoc-like two-pane site driven by[doc]inCure.toml; stdlib gains## Examplesblocks; website ships/stdlib; REPL gets a block-aware Markdown renderer; Vim and VS Code plugins re-aligned with the current grammar. - v0.28.0 -- Talk Back: parser error recovery (
E063), "did you mean?" suggestions,cure fmt --dry-run,cure blessSocratic type-error assistant,@record+cure replayFSM time-travel, Playground with live type-checking and sandboxed evaluator. Patches v0.28.1 / v0.28.2 promoted REPL top-level declarations (Cure.REPL.Session) into the checker env. - v0.27.0 -- See Your System Breathe: observability and verification:
Cure.OTel,cure top,cure trace,Cure.Temporal(LTL bounded model checker),Cure.Protocol(session-typed binary protocols),Cure.Types.Synth(typed-hole suggestions); new stdlib modulesStd.Time,Std.Regex,Std.CRDT; OSC 8 clickable error paths; LiveView Playground. - v0.26.0 -- Applications and Releases:
appcontainer,[application]/[release]sections inCure.toml,cure releasepackaging,Std.App. Error codesE051-E055. - v0.25.0 -- Typed Supervision Trees: Melquiades Operator
<-|(alias✉), typedactorandsupcontainers compiling toGenServer/Supervisormodules,Std.Actor/Std.Process/Std.Supervisor. - v0.24.0 -- The REPL You Deserve: raw-mode line editor with live
Makeup-powered syntax highlighting, persistent history,
Ctrl+Rincremental search, Tab completion, minimal vi mode, Marcli-rendered:help. - v0.23.0 -- Packaging, Proof, and Polish: remote package registry
(
Cure.Project.Registry), Ed25519 signing, transparency log,cure publish,cure doctor,cure fix,cure test --cover,Std.Json,Std.Http, property shrinking. Error codesE038-E042. - v0.22.0 -- Loose Ends: multi-statement lambda bodies (brace and
endforms), binary comprehension generators,byte_sizerefinements on trailing binary segments, first-class FSM state struct. - v0.21.0 -- Through the Segments: Erlang-style binary destructuring
with exhaustiveness (
E031), multi-linetypeADTs, ADT function-arrow payloads, deepletdestructuring,@derive(Functor, Monoid, JSON), algebra formatter as default,Std.Access. - v0.20.0 -- The Shape of Things: plain
#comments as AST nodes, full bitstring segment grammar (<<x::utf8, rest::binary>>),Inspect.Algebra-style pretty printer, structural pattern refinement narrowing. - v0.19.0 -- Bring the Furniture:
proofcontainers,assert_type, record field defaults,@derive(Show, Eq, Ord), property-based testing, lazy iterator protocol, package-version resolver, mutual-recursion totality, multi-head cons patterns. - v0.18.0 -- Deep Destructuring: nested patterns across tuples, lists,
maps, records, and ADT constructors; pin operator
^x; repeated-variable equality guards; record field punning; nested-exhaustiveness analyser. - v0.17.0 -- Proofs & Polish: Toward Idris: dependent pairs / Pi types /
propositional equality, type-level normaliser, unification with implicit
args, typed holes, totality checker, path-sensitive refinement, REPL,
cure watch, LSP inlay hints / rename / semantic tokens,cure new,Cure.lock,cure bench, doctests, MIT license, VS Code extension scaffold. - v0.16.0 -- Finitomata-Inspired FSM Rewrite: dual-mode FSM compilation,
hard (
event!) / soft (event?) suffixes, lifecycle callbacks (on_enter,on_exit,on_failure,on_timer), introspection API. - v0.15.0 -- Developer Experience: public
Cure.quote/ printer API, effect system, HTML doc generator, formatter, first REPL,Std.Test. - v0.14.0 -- Real-World Readiness:
Cure.tomlpackage management (path deps), cross-module protocol registry,cure testwithStd.Test. - v0.13.0 -- Depth Over Breadth: dependent-type verification at call
sites, type-level arithmetic in return types, LSP code actions /
definition / incremental compile, advanced optimizer (inlining /
monomorphisation / guard simplification),
Std.Map/Std.Set/Std.Option/Std.Functor. - v0.12.0 -- The Complete Rewrite: rewrite from Erlang to Elixir, import resolution, dependent-type representation, typeclass derive, LSP symbols, Z3 model parser, FSM type-safety analysis, Levenshtein-based suggestions.
- v0.11.0 -- First Roadmap Complete: nine self-hosted stdlib modules, protocol/typeclass system, Z3 SMT integration with refinement types, guard refinement, type-directed optimizer, pattern-exhaustiveness checker, FSM runtime, LSP, CLI escript, MCP server.
- v0.10.0 -- Project Bootstrap: initial Elixir project, lexer with
indentation tracking, Pratt parser, BEAM codegen, type-system foundation,
FSM
gen_statemcompiler, CLI, CI, examples.
To be determined.