Skip to main content

luau_syntax/
cst.rs

1use crate::ast::{
2    AstString, Attribute, Block, Expression, Function, GenericType, GenericTypePack, Statement,
3    Type, TypePack,
4};
5use crate::lexer::QuoteStyle as LexerQuoteStyle;
6use crate::location::Position;
7use luau_common::{DenseHashHasher, DenseHashMap};
8
9#[derive(Debug, Clone)]
10pub struct CstNodeMap<'ast> {
11    nodes: DenseHashMap<AstNodeKey, Option<CstNode<'ast>>, AstNodeKeyHasher>,
12}
13
14impl Default for CstNodeMap<'_> {
15    fn default() -> Self {
16        Self {
17            nodes: DenseHashMap::new(AstNodeKey::empty()),
18        }
19    }
20}
21
22impl PartialEq for CstNodeMap<'_> {
23    fn eq(&self, other: &Self) -> bool {
24        self.nodes.len() == other.nodes.len()
25            && self
26                .nodes
27                .iter()
28                .all(|(key, value)| other.nodes.get(key) == Some(value))
29    }
30}
31
32impl<'ast> CstNodeMap<'ast> {
33    pub fn is_empty(&self) -> bool {
34        self.nodes.is_empty()
35    }
36
37    pub(crate) fn insert(&mut self, node: impl AstNodeKeySource, cst: CstNode<'ast>) {
38        self.nodes.insert(node.key(), Some(cst));
39    }
40
41    pub(crate) fn get(&self, node: impl AstNodeKeySource) -> Option<&CstNode<'ast>> {
42        self.nodes.get(&node.key()).and_then(Option::as_ref)
43    }
44
45    pub fn get_block(&self, block: Block) -> Option<&CstNode<'ast>> {
46        self.get(block.as_statement())
47    }
48
49    pub fn get_statement(&self, statement: Statement) -> Option<&CstNode<'ast>> {
50        self.get(statement)
51    }
52
53    pub fn get_expression(&self, expression: Expression) -> Option<&CstNode<'ast>> {
54        self.get(expression)
55    }
56
57    pub fn get_function(&self, function: &Function) -> Option<&CstNode<'ast>> {
58        self.get(function)
59    }
60
61    pub fn get_attribute(&self, attribute: &Attribute) -> Option<&CstNode<'ast>> {
62        self.get(attribute)
63    }
64
65    pub fn get_type(&self, annotation: Type) -> Option<&CstNode<'ast>> {
66        self.get(annotation)
67    }
68
69    pub fn get_type_pack(&self, annotation: TypePack) -> Option<&CstNode<'ast>> {
70        self.get(annotation)
71    }
72
73    pub fn get_generic_type(&self, generic: &GenericType) -> Option<&CstNode<'ast>> {
74        self.get(generic)
75    }
76
77    pub fn get_generic_type_pack(&self, generic: &GenericTypePack) -> Option<&CstNode<'ast>> {
78        self.get(generic)
79    }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub(crate) struct AstNodeKey(usize);
84
85impl AstNodeKey {
86    fn empty() -> Self {
87        Self(0)
88    }
89
90    fn from_ref<T>(node: &T) -> Self {
91        Self((node as *const T).cast::<()>() as usize)
92    }
93
94    fn from_ptr(ptr: *const ()) -> Self {
95        Self(ptr as usize)
96    }
97}
98
99pub(crate) trait AstNodeKeySource {
100    fn key(self) -> AstNodeKey;
101}
102
103impl AstNodeKeySource for Expression<'_> {
104    fn key(self) -> AstNodeKey {
105        AstNodeKey::from_ptr(self.as_ptr())
106    }
107}
108
109impl AstNodeKeySource for Statement<'_> {
110    fn key(self) -> AstNodeKey {
111        AstNodeKey::from_ptr(self.as_ptr())
112    }
113}
114
115impl AstNodeKeySource for Block<'_> {
116    fn key(self) -> AstNodeKey {
117        self.as_statement().key()
118    }
119}
120
121impl AstNodeKeySource for Type<'_> {
122    fn key(self) -> AstNodeKey {
123        AstNodeKey::from_ptr(self.as_ptr())
124    }
125}
126
127impl AstNodeKeySource for TypePack<'_> {
128    fn key(self) -> AstNodeKey {
129        AstNodeKey::from_ptr(self.as_ptr())
130    }
131}
132
133impl<T> AstNodeKeySource for &T {
134    fn key(self) -> AstNodeKey {
135        AstNodeKey::from_ref(self)
136    }
137}
138
139#[derive(Debug, Clone, Copy)]
140struct AstNodeKeyHasher;
141
142impl DenseHashHasher<AstNodeKey> for AstNodeKeyHasher {
143    fn hash(key: &AstNodeKey) -> u64 {
144        let key = key.0;
145        ((key >> 4) ^ (key >> 9)) as u64
146    }
147}
148
149#[derive(Debug, Clone, PartialEq)]
150pub enum CstNode<'ast> {
151    ExprConstantNumber(CstExprConstantNumber<'ast>),
152    ExprConstantInteger(CstExprConstantInteger<'ast>),
153    ExprConstantString(CstExprConstantString<'ast>),
154    ExprCall(CstExprCall),
155    ExprGroup(CstExprGroup),
156    ExprIndexExpr(CstExprIndexExpr),
157    ExprFunction(CstExprFunction<'ast>),
158    Attribute(CstAttribute),
159    ExprTable(CstExprTable),
160    ExprOp(CstExprOp),
161    ExprTypeAssertion(CstExprTypeAssertion),
162    ExprIfElse(CstExprIfElse),
163    ExprInterpString(CstExprInterpString<'ast>),
164    ExprExplicitTypeInstantiation(CstExprExplicitTypeInstantiation),
165    StatDo(CstStatDo),
166    StatRepeat(CstStatRepeat),
167    StatReturn(CstStatReturn),
168    StatLocal(CstStatLocal<'ast>),
169    StatFor(CstStatFor),
170    StatForIn(CstStatForIn<'ast>),
171    StatAssign(CstStatAssign<'ast>),
172    StatCompoundAssign(CstStatCompoundAssign),
173    StatFunction(CstStatFunction),
174    StatLocalFunction(CstStatLocalFunction),
175    GenericType(CstGenericType),
176    GenericTypePack(CstGenericTypePack),
177    StatTypeAlias(CstStatTypeAlias),
178    StatTypeFunction(CstStatTypeFunction),
179    TypeReference(CstTypeReference),
180    TypeGroup(CstTypeGroup),
181    TypeTable(CstTypeTable<'ast>),
182    TypeFunction(CstTypeFunction),
183    TypeTypeof(CstTypeTypeof),
184    TypeUnion(CstTypeUnion),
185    TypeIntersection(CstTypeIntersection),
186    TypeSingletonString(CstTypeSingletonString<'ast>),
187    TypePackExplicit(CstTypePackExplicit),
188    TypePackGeneric(CstTypePackGeneric),
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
192pub struct CstExprConstantNumber<'ast> {
193    pub value: AstString<'ast>,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
197pub struct CstExprConstantInteger<'ast> {
198    pub value: AstString<'ast>,
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
202pub struct CstExprConstantString<'ast> {
203    pub source_string: AstString<'ast>,
204    pub quote_style: CstStringQuoteStyle,
205    pub block_depth: u32,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub enum CstStringQuoteStyle {
210    QuotedSingle,
211    QuotedDouble,
212    QuotedRaw,
213    QuotedInterp,
214}
215
216impl From<LexerQuoteStyle> for CstStringQuoteStyle {
217    fn from(quote_style: LexerQuoteStyle) -> Self {
218        match quote_style {
219            LexerQuoteStyle::Single => Self::QuotedSingle,
220            LexerQuoteStyle::Double => Self::QuotedDouble,
221        }
222    }
223}
224
225#[derive(Debug, Clone, PartialEq)]
226pub struct CstTypeInstantiation {
227    pub left_arrow_1: Position,
228    pub left_arrow_2: Position,
229    pub comma_positions: Vec<Position>,
230    pub right_arrow_1: Position,
231    pub right_arrow_2: Position,
232}
233
234impl Default for CstTypeInstantiation {
235    fn default() -> Self {
236        Self {
237            left_arrow_1: Position::missing(),
238            left_arrow_2: Position::missing(),
239            comma_positions: Vec::new(),
240            right_arrow_1: Position::missing(),
241            right_arrow_2: Position::missing(),
242        }
243    }
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub struct CstExprCall {
248    pub open_parens: Option<Position>,
249    pub close_parens: Option<Position>,
250    pub comma_positions: Vec<Position>,
251    pub explicit_types: Option<CstTypeInstantiation>,
252}
253
254#[derive(Debug, Clone, PartialEq)]
255pub struct CstExprGroup {
256    pub close_position: Position,
257}
258
259#[derive(Debug, Clone, PartialEq)]
260pub struct CstExprIndexExpr {
261    pub open_bracket: Position,
262    pub close_bracket: Position,
263}
264
265#[derive(Debug, Clone, PartialEq)]
266pub struct CstExprFunction<'ast> {
267    pub attr_lists: Vec<CstAttrList>,
268    pub function_keyword: Position,
269    pub open_generics: Position,
270    pub generics_commas: &'ast [Position],
271    pub close_generics: Position,
272    pub argument_annotation_colons: &'ast [Position],
273    pub argument_commas: &'ast [Position],
274    pub vararg_annotation_colon: Position,
275    pub return_specifier: Position,
276}
277
278impl Default for CstExprFunction<'_> {
279    fn default() -> Self {
280        Self {
281            attr_lists: Vec::new(),
282            function_keyword: Position::missing(),
283            open_generics: Position::missing(),
284            generics_commas: &[],
285            close_generics: Position::missing(),
286            argument_annotation_colons: &[],
287            argument_commas: &[],
288            vararg_annotation_colon: Position::missing(),
289            return_specifier: Position::missing(),
290        }
291    }
292}
293
294#[derive(Debug, Clone, PartialEq, Eq)]
295pub struct CstAttrList {
296    pub at_bracket_position: Position,
297    pub close_bracket_position: Position,
298    pub comma_positions: Vec<Position>,
299}
300
301#[derive(Debug, Clone, PartialEq, Eq)]
302pub enum CstAttribute {
303    Simple {
304        has_at: bool,
305    },
306    Parametrized {
307        open_paren_position: Option<Position>,
308        close_paren_position: Option<Position>,
309        argument_commas: Vec<Position>,
310    },
311}
312
313#[derive(Debug, Clone, PartialEq)]
314pub struct CstExprTable {
315    pub items: Vec<CstExprTableItem>,
316}
317
318#[derive(Debug, Clone, PartialEq)]
319pub struct CstExprTableItem {
320    pub indexer_open: Option<Position>,
321    pub indexer_close: Option<Position>,
322    pub equals: Option<Position>,
323    pub separator: Option<TableSeparator>,
324    pub separator_position: Option<Position>,
325}
326
327#[derive(Debug, Clone, Copy, PartialEq, Eq)]
328pub enum TableSeparator {
329    Comma,
330    Semicolon,
331}
332
333#[derive(Debug, Clone, PartialEq)]
334pub struct CstExprOp {
335    pub op: Position,
336}
337
338#[derive(Debug, Clone, PartialEq)]
339pub struct CstExprTypeAssertion {
340    pub op: Position,
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq)]
344pub struct CstExprIfElse {
345    pub then_position: Position,
346    pub else_position: Position,
347    pub is_else_if: bool,
348}
349
350#[derive(Debug, Clone, PartialEq)]
351pub struct CstExprInterpString<'ast> {
352    pub source_strings: Vec<AstString<'ast>>,
353    pub string_positions: Vec<Position>,
354}
355
356#[derive(Debug, Clone, PartialEq)]
357pub struct CstExprExplicitTypeInstantiation {
358    pub instantiation: CstTypeInstantiation,
359}
360
361#[derive(Debug, Clone, PartialEq)]
362pub struct CstStatDo {
363    pub stats_start: Position,
364    pub end: Position,
365}
366
367#[derive(Debug, Clone, PartialEq)]
368pub struct CstStatRepeat {
369    pub until: Position,
370}
371
372#[derive(Debug, Clone, PartialEq)]
373pub struct CstStatReturn {
374    pub comma_positions: Vec<Position>,
375}
376
377#[derive(Debug, Clone, PartialEq)]
378pub struct CstStatLocal<'ast> {
379    pub declaration_keyword_position: Position,
380    pub variable_annotation_colons: &'ast [Position],
381    pub variable_commas: &'ast [Position],
382    pub value_commas: &'ast [Position],
383}
384
385#[derive(Debug, Clone, PartialEq)]
386pub struct CstStatFor {
387    pub annotation_colon: Position,
388    pub equals: Position,
389    pub end_comma: Position,
390    pub step_comma: Option<Position>,
391}
392
393#[derive(Debug, Clone, PartialEq)]
394pub struct CstStatForIn<'ast> {
395    pub variable_annotation_colons: &'ast [Position],
396    pub variable_commas: &'ast [Position],
397    pub value_commas: &'ast [Position],
398}
399
400#[derive(Debug, Clone, PartialEq)]
401pub struct CstStatAssign<'ast> {
402    pub variable_commas: &'ast [Position],
403    pub equals: Position,
404    pub value_commas: &'ast [Position],
405}
406
407#[derive(Debug, Clone, PartialEq)]
408pub struct CstStatCompoundAssign {
409    pub op: Position,
410}
411
412#[derive(Debug, Clone, PartialEq)]
413pub struct CstStatFunction {
414    pub attr_lists: Vec<CstAttrList>,
415    pub function_keyword: Position,
416}
417
418#[derive(Debug, Clone, PartialEq)]
419pub struct CstStatLocalFunction {
420    pub attr_lists: Vec<CstAttrList>,
421    pub local_keyword: Position,
422    pub function_keyword: Position,
423}
424
425#[derive(Debug, Clone, PartialEq)]
426pub struct CstGenericType {
427    pub default_equals: Option<Position>,
428}
429
430#[derive(Debug, Clone, PartialEq)]
431pub struct CstGenericTypePack {
432    pub ellipsis: Position,
433    pub default_equals: Option<Position>,
434}
435
436#[derive(Debug, Clone, PartialEq)]
437pub struct CstStatTypeAlias {
438    pub type_keyword: Position,
439    pub generics_open: Position,
440    pub generics_commas: Vec<Position>,
441    pub generics_close: Position,
442    pub equals: Position,
443}
444
445#[derive(Debug, Clone, PartialEq)]
446pub struct CstStatTypeFunction {
447    pub type_keyword: Position,
448    pub function_keyword: Position,
449}
450
451#[derive(Debug, Clone, PartialEq)]
452pub struct CstTypeReference {
453    pub prefix_dot: Option<Position>,
454    pub open_parameters: Position,
455    pub parameter_commas: Vec<Position>,
456    pub close_parameters: Position,
457}
458
459#[derive(Debug, Clone, PartialEq)]
460pub struct CstTypeGroup {
461    pub close_position: Position,
462}
463
464#[derive(Debug, Clone, PartialEq)]
465pub struct CstTypeTable<'ast> {
466    pub items: Vec<CstTypeTableItem<'ast>>,
467    pub is_array: bool,
468}
469
470#[derive(Debug, Clone, PartialEq)]
471pub struct CstTypeTableItem<'ast> {
472    pub kind: CstTypeTableItemKind,
473    pub indexer_open: Position,
474    pub indexer_close: Position,
475    pub colon: Position,
476    pub separator: Option<TableSeparator>,
477    pub separator_position: Option<Position>,
478    pub string_info: Option<CstExprConstantString<'ast>>,
479    pub string_position: Position,
480}
481
482#[derive(Debug, Clone, Copy, PartialEq, Eq)]
483pub enum CstTypeTableItemKind {
484    Indexer,
485    Property,
486    StringProperty,
487}
488
489#[derive(Debug, Clone, PartialEq)]
490pub struct CstTypeFunction {
491    pub open_generics: Position,
492    pub generics_commas: Vec<Position>,
493    pub close_generics: Position,
494    pub open_arguments: Position,
495    pub argument_name_colons: Vec<Option<Position>>,
496    pub argument_commas: Vec<Position>,
497    pub close_arguments: Position,
498    pub return_arrow: Position,
499}
500
501#[derive(Debug, Clone, PartialEq)]
502pub struct CstTypeTypeof {
503    pub open: Position,
504    pub close: Position,
505}
506
507#[derive(Debug, Clone, PartialEq)]
508pub struct CstTypeUnion {
509    pub leading: Option<Position>,
510    pub separators: Vec<Position>,
511}
512
513#[derive(Debug, Clone, PartialEq)]
514pub struct CstTypeIntersection {
515    pub leading: Option<Position>,
516    pub separators: Vec<Position>,
517}
518
519#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
520pub struct CstTypeSingletonString<'ast> {
521    pub source_string: AstString<'ast>,
522    pub quote_style: CstStringQuoteStyle,
523    pub block_depth: u32,
524}
525
526#[derive(Debug, Clone, PartialEq)]
527pub struct CstTypePackExplicit {
528    pub parentheses: Option<CstTypePackParentheses>,
529    pub comma_positions: Vec<Position>,
530}
531
532#[derive(Debug, Clone, Copy, PartialEq, Eq)]
533pub struct CstTypePackParentheses {
534    pub open: Position,
535    pub close: Position,
536}
537
538#[derive(Debug, Clone, PartialEq)]
539pub struct CstTypePackGeneric {
540    pub ellipsis: Position,
541}