Skip to main content

cyrs_syntax/
lib.rs

1//! `cyrs-syntax` — lexer, recovering parser, lossless CST.
2//!
3//! Reference: spec 0001 §4. The [`SyntaxKind`] enum in [`kind`] is the
4//! canonical grammar reference; treat it as authoritative. The CST is a
5//! [`rowan`] green/red tree parameterised by [`Lang`]; it preserves every
6//! byte of the input (including trivia and malformed fragments).
7//!
8//! The parser is event-based (spec 0001 §4.2): it emits an event stream
9//! that a builder later uses to construct the rowan tree. This lets the
10//! parser rewrite events for associativity and error grouping before tree
11//! construction commits.
12//!
13//! Everything in this crate is domain-free (spec §2). There are no
14//! references to any consumer-specific concept.
15//!
16//! ## Typed diagnostic codes for embedders (cy-emb3)
17//!
18//! [`SyntaxError::code`] is a `u16` that mirrors the discriminant of
19//! the `DiagCode` enum in `cyrs-diag`. The numeric form keeps this
20//! crate at the bottom of the crate graph (no edge from `cyrs-syntax`
21//! to `cyrs-diag`), but matching on raw `u16` values is brittle —
22//! any future renumbering would silently break embedders.
23//!
24//! Embedders that already depend on `cyrs-diag` (typically via
25//! `cyrs-db` for diagnostic rendering, see
26//! `docs/integration-depth.md`) should lift the numeric code to the
27//! typed enum at the boundary:
28//!
29//! ```ignore
30//! use cyrs_diag::DiagCode;
31//! use cyrs_syntax::parse;
32//!
33//! let parse = parse("MATCH");
34//! for err in parse.errors() {
35//!     match DiagCode::from(err) {
36//!         DiagCode::E0001 => { /* generic syntax */ }
37//!         DiagCode::E0007 => { /* expected statement */ }
38//!         _ => { /* other */ }
39//!     }
40//! }
41//! ```
42//!
43//! See `cyrs_diag::DiagCode::try_from_u16` for a fallible variant
44//! that distinguishes "unknown numeric" from "registered E0001".
45
46// Embedders: see ../../docs/integration-depth.md before depending on this surface.
47
48#![forbid(unsafe_code)]
49#![doc(html_root_url = "https://docs.rs/cyrs-syntax/0.0.1")]
50
51pub(crate) mod builder;
52pub mod edit;
53pub(crate) mod grammar;
54pub mod kind;
55pub mod lexer;
56pub mod line_index;
57pub mod parser;
58pub mod range_ext;
59
60pub use edit::{TextEdit, incremental_reparse};
61pub use kind::SyntaxKind;
62pub use lexer::{LexError, LexToken, lex, validate_tokens};
63pub use line_index::{LineCol, LineIndex, WideLineCol};
64pub use parser::{Parse, SyntaxError, parse};
65pub use range_ext::TextRangeExt;
66
67use rowan::Language;
68
69/// Language marker for the Cypher rowan tree.
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
71pub enum Lang {}
72
73impl Language for Lang {
74    type Kind = SyntaxKind;
75
76    fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
77        SyntaxKind::from_u16(raw.0).expect("SyntaxKind round-trip: invalid raw kind")
78    }
79
80    fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
81        rowan::SyntaxKind(kind as u16)
82    }
83}
84
85/// Cypher-flavoured alias for `rowan::SyntaxNode` — a typed handle on
86/// a node in the CST.
87pub type SyntaxNode = rowan::SyntaxNode<Lang>;
88/// Cypher-flavoured alias for `rowan::SyntaxToken` — a leaf token in
89/// the CST.
90pub type SyntaxToken = rowan::SyntaxToken<Lang>;
91/// Cypher-flavoured alias for `rowan::SyntaxElement` — a sum of
92/// `SyntaxNode | SyntaxToken` used when walking a tree.
93pub type SyntaxElement = rowan::SyntaxElement<Lang>;
94/// Cypher-flavoured alias for `rowan::SyntaxNodeChildren` — a node's
95/// immediate child iterator.
96pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<Lang>;
97/// Cypher-flavoured alias for `rowan::api::PreorderWithTokens` — a
98/// pre-order walk that visits both nodes and tokens.
99pub type PreorderWithTokens = rowan::api::PreorderWithTokens<Lang>;
100
101/// Byte offset range in the source text. Re-exported from `text-size` for
102/// convenience so downstream crates can depend only on `cyrs-syntax`.
103pub use text_size::{TextLen, TextRange, TextSize};