5.6 KiB
Components
Decodal is split into a small runtime core and separate syntax tooling components. The public surface is intentionally organized by use case: execute Decodal with Rust or WebAssembly, edit Decodal on the Web with Lezer and CodeMirror, and integrate Decodal into general-purpose editors with Tree-sitter.
Runtime components
Rust crate
The decodal crate is the primary Rust runtime and embedding API.
It owns parsing, evaluation, materialization, diagnostics, host-provided values, and schema/decode traits.
Rust applications should use this crate when they want to load Decodal source, evaluate it, or embed Decodal into a host program.
Important paths:
crates/decodal-core/
crates/decodal-derive/
decodal-derive provides optional derive macros for Rust struct integration.
It is a companion to the runtime crate rather than an editor or syntax-highlighting component.
WebAssembly package
decodal-wasm exposes the runtime to browsers.
The documentation site playground uses it to evaluate Decodal entirely in the browser.
Important paths:
crates/decodal-wasm/
packages/decodal-wasm/
The npm package is decodal-wasm.
The JSR package is @hare/decodal-wasm.
The generated files in packages/decodal-wasm/ are committed so the site can build without requiring every consumer to run wasm-pack first.
The WebAssembly package is for execution, not syntax highlighting.
Language tools
Semantic editor integration lives in the host-configurable language service crate.
It depends only on the runtime and accepts the same HostEnvironment implementation used by a production application.
The LSP crate adapts that service to the Language Server Protocol over stdin/stdout.
It provides full document synchronization, semantic diagnostics, and whole-document formatting.
A host-specific LSP binary injects its loader and global schema configuration without reimplementing evaluation rules.
Important paths:
crates/decodal-language-service/
crates/decodal-lsp/
The default decodal-lsp binary reads Decodal imports from the filesystem.
Embedded hosts can call its library entry point with a custom LspEnvironment to reuse structured imports and to make unsaved external documents, such as Markdown, visible to the loader.
Source formatting lives in a separate Rust language tools crate. It uses the canonical Decodal AST together with the runtime lexer's lossless syntax tokens, so native LSP and WebAssembly callers execute the same formatter implementation.
This component is responsible for operations that must preserve source text details such as comments and whitespace. It is used by the CodeMirror package's bundled formatter WebAssembly and can also be used by an LSP adapter for formatting. It does not depend on Tree-sitter or Lezer.
Important paths:
crates/decodal-language-tools/
The current language tools crate exposes the formatter.
Web editor components
The Web playground editor uses CodeMirror 6 with a generated Lezer parser. Lezer provides syntax highlighting, folding, indentation, and editor syntax tree behavior. The browser formatter command calls the canonical Rust formatter compiled to WebAssembly.
Important paths:
editors/lezer-decodal/decodal.grammar
packages/decodal-codemirror/src/decodal.js
packages/decodal-codemirror/src/decodal-parser.js
packages/decodal-codemirror/src/decodal-parser.terms.js
packages/decodal-codemirror/src/format.js
packages/decodal-codemirror/wasm/
The npm package is decodal-codemirror.
The JSR package is @hare/decodal-codemirror.
The Lezer grammar is derived from the canonical grammar documentation, but it is not a literal copy of the EBNF. Precedence and token conflict handling are represented in the Lezer grammar in the form CodeMirror needs.
General editor components
Tree-sitter is the portable editor-integration grammar. Editors such as Zed, Neovim, Helix, and Emacs should consume this component when they need Decodal parsing or highlighting outside the Web playground.
Important paths:
editors/tree-sitter-decodal/grammar.js
editors/tree-sitter-decodal/queries/highlights.scm
editors/tree-sitter-decodal/queries/locals.scm
editors/tree-sitter-decodal/src/
The generated parser sources under editors/tree-sitter-decodal/src/ are committed so editor integrations can consume the grammar without regenerating it first.
Canonical grammar
The human-readable grammar lives in:
doc/manual/souce/language/grammar.md
This EBNF is the language-level reference. The Rust parser, Lezer grammar, and Tree-sitter grammar should be kept aligned with it, but each implementation may encode precedence and recovery behavior in the form required by its parser generator or runtime.
Syntax token API
The decodal crate exposes tokenize_source, tokenize_source_with_source_id, SyntaxToken, and SyntaxTokenKind for source-preserving tooling.
Comments have explicit tokens, while whitespace is represented by gaps between token spans and can be recovered from the original source.
The evaluator parser and formatter therefore share one lexical definition without making Tree-sitter an upstream dependency.
Consumers should otherwise use the component matching their environment:
- Rust execution and embedding:
decodal - Browser execution:
decodal-wasm - Web formatting and editor syntax: canonical formatter / CodeMirror / Lezer
- Semantic editor analysis:
decodal-language-service - Language Server Protocol integration:
decodal-lsp - Rust formatting:
decodal-language-tools - General editor syntax: Tree-sitter
Tree-sitter and Lezer remain downstream editor grammars and are not dependencies of the runtime formatter.