mos-core
Core document model, IDs, source spans, diagnostics, and shared error types for Mosaic.
This is the lowest Mosaic crate. Every compiler phase may depend on it; it must not depend on parsing, evaluation, layout, fonts, CLI, or backends.
Purpose
- Provide the lowered semantic
Documentgraph used after parsing/evaluation. - Define stable-ish IDs and typed node/attribute structures shared by later phases.
- Carry source locations and diagnostics in a backend-agnostic shape.
- Offer a small
CoreError/Resultconvenience layer for crates that need one.
Public Model
Document owns a node arena keyed by NodeId. Document::new(file) eagerly creates the root
NodeKind::Document at NodeId(0). Lowering code adds nodes with alloc or alloc_child; unknown
parents in alloc_child panic intentionally because detached nodes are compiler bugs, not user
input.
Main public types:
NodeId,ContentHash,StyleId: small opaque identifiers/newtypes.NodeKind: semantic node kinds known to Mosaic, including current shipped shapes such as documents, sections, paragraphs, inline text/emphasis/strong, lists/list items, references, images, and figures. Some enum variants exist for planned domains but do not imply implementation.Node: semantic node withid,kind,SourceSpan,content_hash,style_id, child IDs, and attributes.AttrMap/AttrValue: string-keyed semantic attributes. Values currently cover booleans, integers, floats, strings, lists, point lengths, and shared byte buffers for decoded image data.SourceSpan: byte range in a source file.Document::{get,get_mut,nodes,len,is_empty}: read/update/traverse the arena.
Example:
use PathBuf;
use ;
let file = from;
let mut doc = new;
let para = doc.alloc_child;
assert_eq!;
Diagnostics And Errors
Diagnostic is the user-facing reporting type. It stores:
Severity: error, warning, note, or help.DiagnosticCode: stable static code such asE001.- message, optional
SourceSpan, notes, and source-edit suggestions.
Diagnostic::error(code, message) builds an unspanned error; with_span attaches source location.
linecol(src, byte_offset) converts byte offsets to 1-based line/column pairs, counting Unicode
scalar values and clamping invalid or out-of-range offsets safely.
CoreError is intentionally small:
Unimplemented(&'static str)for explicit stubs.Diagnostic(Box<Diagnostic>)for user-facing compiler errors.
Bad documents should flow through diagnostics/errors. Panics are reserved for internal invariant violations such as linking a node to an unknown parent.
Crate Boundaries
Allowed here:
- semantic document data structures;
- source spans and diagnostic data;
- minimal shared error types;
- domain-neutral helpers such as
linecol.
Keep out:
- parser/CST behavior and directive parsing;
- lowering, label resolution, metadata policy, image decoding;
- layout, pagination, font metrics, shaping;
- PDF/HTML/EPUB emission;
- CLI output formatting, exit codes, project manifest semantics, cache persistence.
Current downstream flow is roughly:
mos-parse -> mos-eval -> mos-core::Document -> mos-layout -> mos-pdf
mos-core supplies the shared model; those crates own phase-specific behavior.
Known Non-Goals
- Hash-derived stable
NodeIds are not implemented; current IDs are monotonic allocation order. ContentHashandStyleIdare carried but not a persistent incremental cache contract.- Presence of node kinds such as math, tables, citations, theorems, footnotes, bibliography, or raw nodes does not mean those language features are shipped.
- No backend-specific attributes should be introduced unless all consumers can tolerate them.
- No file IO, package registry, watcher, formatter, LSP behavior, or build orchestration lives here.