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>;