Skip to main content

ridl_syntax/
syntax_kind.rs

1//! Token and node kinds shared by the lexer ([`crate::lexer`]) and the grammar.
2
3/// The kinds of syntax tokens and nodes the family grammar produces.
4///
5/// The token variants are the full family token set the lexer recognises
6/// (typl reference §1.4 and §2). The node variants
7/// are the typl grammar's node inventory — one variant per rule
8/// in `family.ungram`, plus [`ErrorNode`](SyntaxKind::ErrorNode) for recovery.
9/// [`RidlLanguage`] maps between this enum and rowan's raw kind through the
10/// `#[repr(u16)]` discriminants, so the node variants stay grouped at the end
11/// with [`ErrorNode`](SyntaxKind::ErrorNode) last — that is the range the
12/// `kind_from_raw` assertion below guards.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[repr(u16)]
15pub enum SyntaxKind {
16    // Tokens — the full family lexer (typl reference §1.4, §2).
17    //
18    // Keywords the typl profile uses (typl reference §1.4). Each used keyword
19    // maps to a distinct variant; every family-registry word the typl profile
20    // does not use maps to `ReservedWord` instead.
21    PackageKw,
22    ImportKw,
23    AsKw,
24    InternalKw,
25    TypeKw,
26    ConstKw,
27    StructKw,
28    EnumKw,
29    EnumsetKw,
30    UnionKw,
31    BooleanKw,
32    IntegerKw,
33    FloatKw,
34    StringKw,
35    BytesKw,
36    TrueKw,
37    FalseKw,
38    StepKw,
39    MatchKw,
40    ReservedKw,
41    ErrorKw,
42    // Keywords the ridl profile activates beyond typl's set (ridl reference
43    // §2.3): the interaction and container words plus the expr-core pair.
44    // Under `Profile::Typl` these words still lex to `ReservedWord`.
45    InterfaceKw,
46    ServiceKw,
47    SignalKw,
48    EventKw,
49    CommandKw,
50    QueryKw,
51    FixedKw,
52    RequireKw,
53    EnsureKw,
54    // Keywords the rsdl profile activates beyond typl's set (rsdl reference
55    // §2). Under `Profile::Typl` and `Profile::Ridl` these words still lex to
56    // `ReservedWord`.
57    SystemKw,
58    ComponentKw,
59    DistributionKw,
60    DeploymentKw,
61    MachineKw,
62    OffersKw,
63    RequiresKw,
64    ForKw,
65    /// A family-registry word that the active profile does not use (typl
66    /// reference §1.4). Reserved in every profile, never a valid identifier.
67    ReservedWord,
68    // Names and literals.
69    Ident,
70    IntNumber,
71    FloatNumber,
72    String,
73    Regex,
74    Duration,
75    // Punctuation.
76    Colon,
77    Eq,
78    LBracket,
79    RBracket,
80    LBrace,
81    RBrace,
82    LParen,
83    RParen,
84    DotDot,
85    Dot,
86    Slash,
87    Comma,
88    Question,
89    Semicolon,
90    At,
91    Pipe,
92    Percent,
93    Minus,
94    // Expression operators (ridl reference §13, general form expr core).
95    // Family tokens like `Duration`: the lexer recognises them under every
96    // profile; the typl grammar simply never accepts them.
97    Lt,
98    Le,
99    Gt,
100    Ge,
101    EqEq,
102    Neq,
103    AmpAmp,
104    PipePipe,
105    Bang,
106    Plus,
107    Star,
108    // Trivia and the catch-all for unrecognised input.
109    Whitespace,
110    LineComment,
111    BlockComment,
112    DocComment,
113    Error,
114    // Nodes — the typl grammar's node inventory (`family.ungram`).
115    // The full parser produces them; until it lands, the
116    // generated typed AST casts over trees built directly in tests.
117    SourceFile,
118    PackageDecl,
119    Import,
120    TypeDef,
121    ConstDef,
122    StructDef,
123    FieldDef,
124    ReservedEntry,
125    EnumDef,
126    EnumValue,
127    EnumSetDef,
128    EnumSetBit,
129    UnionDef,
130    UnionArm,
131    TupleType,
132    TupleField,
133    ArrayType,
134    MapType,
135    OptionalType,
136    PathType,
137    PrimitiveType,
138    UnitExpr,
139    Constraint,
140    Bound,
141    Name,
142    QualifiedName,
143    Literal,
144    InitValue,
145    // Nodes of the ridl interaction grammar (`family.ungram`,
146    // ridl reference Appendix C, ADR-0008 decisions 1 and 2).
147    InterfaceDef,
148    SignalDef,
149    EventDef,
150    CommandDef,
151    QueryDef,
152    FixedDef,
153    Param,
154    ParamList,
155    ReturnType,
156    StreamType,
157    FallibleType,
158    Timing,
159    TimingRange,
160    AttrBlock,
161    // Nodes of the attribute and guaranteed-subset expression grammar
162    // (`family.ungram`, general form §4.2, expr-core
163    // specification §3.1).
164    Attribute,
165    AttrValue,
166    BinaryExpr,
167    PrefixExpr,
168    MemberExpr,
169    PathExpr,
170    ParenExpr,
171    LiteralExpr,
172    // Nodes of the ridl service grammar (`family.ungram`, ridl reference §14.5). `service_def` is not in
173    // Appendix C.
174    ServiceDef,
175    DottedName,
176    // Nodes of the rsdl grammar (`family.ungram` — rsdl reference §3, §4,
177    // Appendix B).
178    SystemDef,
179    ComponentDef,
180    ComponentLine,
181    DistributionDef,
182    DeploymentDef,
183    MachineDef,
184    MemberLine,
185    Reference,
186    /// A recovery node: error recovery wraps the tokens it skips in one of
187    /// these, so broken input still produces a lossless tree. It is the one
188    /// node kind with no rule in `family.ungram`, and the last variant — the
189    /// `kind_from_raw` assertion below guards the range up to it.
190    ErrorNode,
191}
192
193impl SyntaxKind {
194    /// Whitespace and comments — tokens that carry no grammatical meaning but
195    /// must stay in the tree for losslessness. Doc comments are trivia too: the
196    /// grammar reads them from the trivia preceding a definition.
197    pub fn is_trivia(self) -> bool {
198        matches!(
199            self,
200            SyntaxKind::Whitespace
201                | SyntaxKind::LineComment
202                | SyntaxKind::BlockComment
203                | SyntaxKind::DocComment
204        )
205    }
206}
207
208impl From<SyntaxKind> for rowan::SyntaxKind {
209    fn from(kind: SyntaxKind) -> Self {
210        Self(kind as u16)
211    }
212}
213
214/// The rowan [`Language`](rowan::Language) instance for the RIDL family. It
215/// binds rowan's raw `u16` kinds to [`SyntaxKind`] through the enum's
216/// `#[repr(u16)]` discriminants.
217#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
218pub enum RidlLanguage {}
219
220impl rowan::Language for RidlLanguage {
221    type Kind = SyntaxKind;
222
223    fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
224        assert!(
225            raw.0 <= SyntaxKind::ErrorNode as u16,
226            "raw kind {} is out of range for SyntaxKind",
227            raw.0,
228        );
229        // SAFETY: SyntaxKind is `#[repr(u16)]` with contiguous discriminants
230        // from 0 up to and including `ErrorNode`. The assertion above proves
231        // `raw.0` names one of them, so the transmute produces a valid variant.
232        unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
233    }
234
235    fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
236        kind.into()
237    }
238}
239
240/// A node in the red (cursor) tree over [`RidlLanguage`].
241pub type SyntaxNode = rowan::SyntaxNode<RidlLanguage>;
242/// A token in the red (cursor) tree over [`RidlLanguage`].
243pub type SyntaxToken = rowan::SyntaxToken<RidlLanguage>;