mos_parse/lib.rs
1//! Parser for the Mosaic source language (`.mos`).
2//!
3//! See manifest §3 (language design) and §6 stages 1–2 (parse + lower).
4//! Currently covers:
5//!
6//! - `= Heading` / `== Subheading` / `=== Subsubheading`,
7//! - paragraphs (newline-joined non-empty line groups),
8//! - inline `*emphasis*`, `**strong**`, and `` `inline code` ``,
9//! - `#set name(...)` blocks, recorded with span and name but interpreted
10//! later by the evaluator,
11//! - `#image(...)` and `#figure(...)` directives, sharing the same
12//! `key: value` body grammar as `#set` plus an optional leading
13//! positional string literal (`#image("path.png")`),
14//! - raw `#pre[[...]]` and `#code[[...]]` long-bracket blocks,
15//! - `<label>` attached to the preceding block (trailing on a heading or
16//! leading on a paragraph), and `@label` cross-references as inline
17//! [`InlineKind::Reference`] runs (manifest §3.3 and the MVP 1
18//! resolver).
19//!
20//! Anything outside that subset is preserved as text and a recoverable
21//! diagnostic is emitted; the parser never panics on user input
22//! (manifest §31).
23
24#![doc(
25 html_logo_url = "https://mosaic.kjanat.dev/assets/A4.svg",
26 html_favicon_url = "https://mosaic.kjanat.dev/assets/A4.svg"
27)]
28
29use std::path::Path;
30
31pub use syntax::{
32 DirectiveKind, Inline, InlineKind, Item, LengthUnit, ListItem, ParseResult, RawBlockKind,
33 RawBlockView, SetArg, SetValue, SyntaxTree,
34};
35
36mod block;
37mod directive;
38mod inline;
39mod list;
40mod parser;
41mod support;
42mod syntax;
43
44use parser::Parser;
45
46/// Parse a Mosaic source string. Always returns a [`ParseResult`]; the
47/// parser is recoverable per manifest §6 stage 1.
48///
49/// # Examples
50///
51/// ```
52/// use std::path::Path;
53///
54/// use mos_parse::{InlineKind, Item, parse};
55///
56/// let result = parse("= Hello\n", Path::new("main.mos"));
57///
58/// assert!(!result.has_errors());
59/// assert!(matches!(result.tree.items[0], Item::Heading { .. }));
60/// let Item::Heading { inlines, .. } = &result.tree.items[0] else {
61/// unreachable!();
62/// };
63/// assert_eq!(inlines[0].kind, InlineKind::Text);
64/// ```
65#[must_use]
66pub fn parse(src: &str, file: &Path) -> ParseResult {
67 Parser::new(src, file).run()
68}