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}