Rust · standard library only · code intelligence
Atelier is a dependency-free code-intelligence engine for a small language, the semantic layer an editor sits on. Give it source text and a stream of edits and it returns tokens, a syntax tree, a scoped symbol table, live diagnostics, and the queries an IDE needs: go to definition, find references, hover, and a safe rename that refuses to change what a name resolves to. Pure Rust, standard library only, no crates. Click an identifier below and watch it resolve, live in your browser.
Atelier analyzes the code live as you type. Everything below runs entirely on this page with no server and no network calls.
Click any identifier in the editor. The engine resolves it and paints a colored box around its declaration, then scrolls it into view.
That same click fills the References panel with every occurrence of the symbol, declaration first. Click a row to jump to it.
Move the pointer over an identifier and hold still. A popover shows its kind, its name, where it is defined, and for a function its parameter count.
Press Run. The evaluator prints the value of each top-level expression statement, one per line, or reports a runtime error with its position.
Unresolved names, redefinitions, and parse errors get a red wavy underline in the editor and a line in the Diagnostics panel. Click a diagnostic to jump to it.
Pick a file on the left. Each sample highlights a different feature, and your edits stay per file while the page is open.
Atelier proves its headline claims against independent oracles over many random, adversarial programs, rather than asserting them. The generator emits shadowing, cross-scope references, redefinitions, hoisted forward references, nested scopes, and unicode identifiers.
# the correctness gates, run straight from the repo $ cargo test --release Running tests/gates.rs running 6 tests test gate_diagnostics_correct ... ok test gate_incremental_boundary_cases ... ok test gate_navigation_matches_reference_resolver ... ok test gate_diagnostics_deterministic ... ok test gate_rename_preserves_resolution ... ok test gate_incremental_equals_batch ... ok test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out # push the same gates harder; the fuzz count scales up on demand $ ATELIER_FUZZ_OPS=2000 cargo test --releaseIncremental work is an optimization, never a different answer. Two independent resolvers agreeing is real cross-validation, not a restatement, and the rename in this editor is the same one the tests hold to that bar.
Every query in the editor above is a CLI subcommand. A position is a byte offset or a one-based line:col, and the output is plain text an editor or a script can parse.
# diagnostics: unresolved names, redefinitions, and parse errors $ atelier analyze errors.at 2:5: Error: `count` is already defined in this scope [Redefinition] 3:1: Error: cannot find `total_of` in this scope [UnresolvedName] # find references: declaration first, then every use, with byte spans $ atelier refs fib.at 4:5 2 reference(s): def 4:5 (bytes 68..73) use 5:18 (bytes 97..102) # hover: kind, arity for a function, and where it is defined $ atelier hover fib.at 1:4 fn fib(1 params) defined at 1:4 (bytes 3..6) # run: the evaluator prints the value of each top-level expression $ atelier run fib.at 55
Atelier is not trying to replace a production language server. It is the readable, dependency-free version of the same core ideas, small enough to audit end to end.
Production language servers with deep, correct analysis, and large codebases and dependency trees to match. Powerful to use, hard to read or embed as a teaching artifact.
The standard machinery an editor talks to and the grammars it parses with. General and battle-tested, and a lot to wire up before you see go to definition resolve a single name.
The whole path from tokens to IDE queries in pure Rust with the standard library only, no crates. Go to definition, find references, hover, and a safe rename, with incremental re-analysis proven identical to a full re-analysis by tests you can run.
The pipeline, stage by stage
Text becomes tokens, tokens become a tree, the tree becomes a scoped symbol table, and the table answers the queries. An incremental layer wraps the whole pipeline so an edit updates only what changed.
A single left-to-right pass with absolute byte spans. Unicode aware, so it never splits a multi-byte character and never panics on arbitrary text.
Recursive descent with error recovery, output grouped per statement. Every path makes progress, so no input can hang it, and a malformed statement recovers to the next boundary.
A scope-stack walk that records every occurrence with the binding it resolves to. Functions hoist, let bindings are sequential, and inner scopes may shadow outer names.
Reuses the prefix untouched, shifts the suffix, and re-lexes and reparses only the region around an edit. The result is identical to a full re-analysis, not merely close.
Go to definition, find references, and hover all read the one recorded occurrence table, so the three answers can never disagree with each other.
Rewrites a binding and every reference, then compares a resolution fingerprint before and after. A rename that would capture or dangle a name is refused, not applied.
Three surfaces over one engine: a CLI for files, a Rust library for embedding, and the correctness gates that double as a fuzzer.
analyze, def, refs, hover, rename, and run on any file, plus demo for a built-in tour of every feature.
Analysis takes source and a stream of edits and answers queries by byte offset. Workspace holds many files and runs one. Both are plain Rust, no crates to pull in.
cargo test runs the navigation, incremental, diagnostics, and rename gates against independent oracles. ATELIER_FUZZ_OPS scales the same tests up into a fuzzer.
# build, test, and take the built-in tour of every feature cargo build --release cargo test ./target/release/atelier demo # the CLI works on any file; a position is a byte offset or 1-based line:col atelier analyze path/to/file # print diagnostics atelier def path/to/file 3:5 # definition of the symbol at 3:5 atelier refs path/to/file 3:5 # every reference to that symbol atelier hover path/to/file 3:5 # symbol info at that position atelier rename path/to/file 3:5 n # rename the symbol at 3:5 to n atelier run path/to/file # evaluate the program