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