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/// (docs/ROADMAP.md epic E1.1, typl reference §1.4 and §2). The node variants
7/// are the typl grammar's node inventory (epic E1.2a) — 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`, epic E1.2a).
115 // The full parser (task E1.2b) 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`, epic E2.1a —
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`, epic E2.4 — 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`, epic E2.13 — ridl
173 // reference §14.5). `service_def` is authored by E2 task 8 (absent from
174 // Appendix C).
175 ServiceDef,
176 DottedName,
177 // Nodes of the rsdl grammar (`family.ungram` — rsdl reference §3, §4,
178 // Appendix B).
179 SystemDef,
180 ComponentDef,
181 ComponentLine,
182 DistributionDef,
183 DeploymentDef,
184 MachineDef,
185 MemberLine,
186 Reference,
187 /// A recovery node: error recovery wraps the tokens it skips in one of
188 /// these, so broken input still produces a lossless tree. It is the one
189 /// node kind with no rule in `family.ungram`, and the last variant — the
190 /// `kind_from_raw` assertion below guards the range up to it.
191 ErrorNode,
192}
193
194impl SyntaxKind {
195 /// Whitespace and comments — tokens that carry no grammatical meaning but
196 /// must stay in the tree for losslessness. Doc comments are trivia too: the
197 /// grammar reads them from the trivia preceding a definition.
198 pub fn is_trivia(self) -> bool {
199 matches!(
200 self,
201 SyntaxKind::Whitespace
202 | SyntaxKind::LineComment
203 | SyntaxKind::BlockComment
204 | SyntaxKind::DocComment
205 )
206 }
207}
208
209impl From<SyntaxKind> for rowan::SyntaxKind {
210 fn from(kind: SyntaxKind) -> Self {
211 Self(kind as u16)
212 }
213}
214
215/// The rowan [`Language`](rowan::Language) instance for the RIDL family. It
216/// binds rowan's raw `u16` kinds to [`SyntaxKind`] through the enum's
217/// `#[repr(u16)]` discriminants.
218#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
219pub enum RidlLanguage {}
220
221impl rowan::Language for RidlLanguage {
222 type Kind = SyntaxKind;
223
224 fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
225 assert!(
226 raw.0 <= SyntaxKind::ErrorNode as u16,
227 "raw kind {} is out of range for SyntaxKind",
228 raw.0,
229 );
230 // SAFETY: SyntaxKind is `#[repr(u16)]` with contiguous discriminants
231 // from 0 up to and including `ErrorNode`. The assertion above proves
232 // `raw.0` names one of them, so the transmute produces a valid variant.
233 unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
234 }
235
236 fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
237 kind.into()
238 }
239}
240
241/// A node in the red (cursor) tree over [`RidlLanguage`].
242pub type SyntaxNode = rowan::SyntaxNode<RidlLanguage>;
243/// A token in the red (cursor) tree over [`RidlLanguage`].
244pub type SyntaxToken = rowan::SyntaxToken<RidlLanguage>;