crisp-lang 1.5.2

Crisp language toolchain — .crp to Rust to native (bins: crisp, reveal)
crisp-lang-1.5.2 is not a library.

The Crisp Programming Language

CI License Version Rust Tests Spec Docs

Explicit on demand, implicit by default.

Crisp (.crp) is a systems language that transpiles to Rust. You write compact source; crisp infers types, ownership, and error propagation, emits Rust, and rustc is the soundness boundary.

This is a Rust-hosted bootstrap compiler (v1.5.2) — public release track. It is not self-hosted yet (ROADMAP Phase 2 / milestone v2.0.0). The language document remains spec v0.2.0-draft — treat “spec-complete” claims cautiously; see known limitations and spec ↔ impl deltas.

Known Rust Result APIs from rust = true deps lower to Crisp ambient errors (CrispError::Thrown + ?) — see examples/rust_import, examples/net_http (#55).

Spec: docs/spec/CrispLang-SPECS-0.2.0.md
Quickstart: QUICKSTART.md
Web docs: crisp-lang.org · branch docs
Roadmap: ROADMAP.md
Changelog: CHANGELOG.md
Contributing: CONTRIBUTING.md
Security: SECURITY.md
Milestone: v1.5.0

License: MIT OR Apache-2.0 (LICENSE, LICENSE-MIT, LICENSE-APACHE).

Philosophy

Crisp is optimized for writing and local reading. Semantics are defined by lowering to Rust, not by a separate runtime or VM.

In practice that means:

  • Types, borrows, lifetimes, and error sets are inferred globally when the source stays silent.
  • When you need precision — public APIs, performance-sensitive paths, or ambiguous usage — you annotate, and the compiler treats those annotations as hard constraints.
  • reveal is the “show your work” companion to crisp: it prints inferred types, ownership (& / &mut), lifetimes, error sets, traits, and the emitted Rust that compact .crp source leaves implicit. See QUICKSTART §10.

Crisp is a front end that produces Rust. Rust remains the authority on memory safety and data races. Crisp’s own borrow/region passes exist to drive good diagnostics and to decide what to emit (&, &mut, owned, .clone() fallbacks); they are not claimed as an independent soundness boundary. If generated Rust fails to compile, that is a crisp bug, not a user error.

Design goals: native code via rustc; HM-style type inference; deterministic global ownership dataflow; ambient fallible functions lowered to a uniform Result<T, CrispError>; compact syntax; tooling-first ergonomics.

Non-goals: scripting semantics; a GC; a stable library ABI across separately compiled units; pretending Crisp’s checker replaces rustc; claiming full enum/trait/shape coverage while those remain incomplete.

Architecture

Crisp v0.2.0 (spec) retargets from “direct-to-LLVM language” to source → CIR → Rust → native. The unit of compilation is the whole program or a sealed crate — inferred signatures depend on call sites, so ad-hoc separate compilation without a lockfile is not supported.

.crp sources
    │
    ▼
Lexer → Parser → Resolve → Type inference → Ownership → Regions → Errors
    │
    ▼
CIR (typed, ownership-resolved IR)
    │
    ▼
Rust emission  ──►  rustc  ──►  native binary
    │
    └── probe emit + rustc (§7.6 fallbacks when ownership disagrees)
Stage Crate / tool Role
Lex / parse crisp-lexer, crisp-parser UTF-8 .crp, expression-based AST, spans
Resolve crisp-resolve File modules, use, prelude, visibility
Typeck crisp-typeck HM inference + constraint solving
Ownership crisp-ownership Global usage → & / &mut / owned; §7.6 fallbacks
Regions / errors crisp-regions, crisp-errors Lifetimes, ambient !CrispError
IR crisp-cir Typed CIR consumed by emit
Emit crisp-rust-emit Rust project under target/rust/, tests, crisp.lock
CLI crisp check, emit, build, run, test
Inspect reveal Companion CLI: inferred types/ownership/errors, traits, emitted Rust (QUICKSTART §10)
IDE crisp-lsp Stdio LSP host (hover, inlay hints, diagnostics) + CrispAnalysis API (#56)

Sealed crates (crisp.lock): a crate’s pub API has fully resolved signatures frozen at publish time. Downstream code analyzes against the lockfile, not re-inferred internals — the explicit tradeoff for whole-program inference inside a boundary.

Type vs ownership inference: HM-style unification handles types; ownership is a separate deterministic dataflow pass over the typed program. They are not unified — affine ownership does not compose with HM unification.

Language (summary)

Area Surface Lowers to
Functions name(args) = expr or { … } block fn with inferred/annotated params
Bindings x := value let / let mut
Types type T = { … }, float, int, str, … Rust structs / aliases / f64 / i64 / String
Errors f() ! E, throw, catch Result<T, CrispError>
Modules one file = one module; use m { f } generated mod tree
Tests test, test_compile_fail injected #[test] in emitted crate
Async / FFI async, await, extern "C" Tokio / extern blocks (see examples)

Comments: -- and nested {- -}. String interpolation: "hello {name}". Exponentiation: **.powf().

Status

v1.5.2crisp / crisp-lang naming (#68); crates.io republish (#66). Includes v1.5.1 loops and v1.5.0 shapes / LSP / traits.

Still open: first crates.io publish track (#66), repo visibility (#58); trait bounds / dyn Trait remain partial (#59). See ROADMAP.md.

MSRV: Rust 1.85 (rust-version in root Cargo.toml). CI runs Ubuntu + macOS on stable, plus an MSRV job.

Quick start

Install the compiler from crates.io (puts crisp and reveal on your PATH via ~/.cargo/bin):

cargo install crisp-lang --locked
crisp --version

You still need a Rust toolchain (1.85+) with cargo / rustc — Crisp lowers to a Cargo project and builds with rustc.

Hello world (no clone)

mkdir -p hello/src && cd hello

cat > crisp.toml <<'EOF'
[package]
name = "hello"
version = "0.1.0"
edition = "2026"

[build]
target = "rust"
runtime = "tokio"
error_model = "enum"
EOF

cat > src/main.crp <<'EOF'
greet(name) = "hello " ++ name

pub main() = {
    msg := greet("world")
    print(msg)
}
EOF

crisp run .

Expected output:

"hello world"

From this repository

git clone https://github.com/jose-compu/crisp.git
cd crisp
# already installed via cargo install crisp-lang, or:
# cargo install --path crates/crpc --locked
crisp run examples/hello

Other commands on a project:

crisp check .                 # resolve + typecheck
crisp emit .                  # write Rust under target/rust/
crisp build .                 # emit + cargo build

Optional LSP:

cargo install crisp-lsp --locked

See QUICKSTART.md for project layout, modules, tests, and fallible functions. crates.io notes: docs/CRATES_IO.md (#66).

Examples

Example Topics Notes
hello, math, float_demo, enums Basics, integers, floats, enum + match crisp test
show_trait, trait_defaults, shapes Traits, defaults, data shapes crisp test
std_traits, rust_import, net_http Show/Eq/Ord, Rust crates, thin HTTP
defaults, inventory, server Struct defaults, domain modules, config
fallible, fallible_chain !, throw, catch, error chains
vec_ops, data_pipeline vec stdlib, fallible IO
patterns, match Pattern matching (literal-oriented today) see limitations
async_hello, async_spawn Async / Tokio
ffi, unsafe_math C FFI, unsafe
sealed crisp.lock sealed public API
kitchen_sink, ownership_demo Combined features
workshop Small multi-file workshop crisp test
design_patterns GoF-style multi-module patterns crisp test / check
abnormal_suite Compile-fail edge cases typecheck / fail tests

Repository layout

crates/          Rust compiler workspace (lexer → emit, crisp, lsp, reveal)
docs/            Spec, limitations, error catalog, web site scaffold
examples/        Sample .crp projects
std/             Standard library (Crisp prelude and modules)
tests/           Integration placeholders (fixtures live under crates/)

Contributing / building

cargo build --release -p crisp-lang
cargo test --workspace --verbose
cargo fmt --all --check
cargo clippy --workspace -- -D warnings

See CONTRIBUTING.md. Spec conformance and e2e coverage live under crates/crisp-rust-emit/tests/ and crates/crpc/tests/.