1pub mod bracketed;
2pub mod file;
3pub mod fix;
4pub mod from;
5pub mod generator;
6pub mod join;
7pub mod meta;
8pub mod object_reference;
9pub mod select;
10pub mod test_functions;
11
12use std::cell::{Cell, OnceCell};
13use std::fmt::Debug;
14use std::hash::{BuildHasher, Hash, Hasher};
15use std::rc::Rc;
16
17use hashbrown::{DefaultHashBuilder, HashMap};
18use itertools::enumerate;
19use smol_str::SmolStr;
20
21use crate::dialects::init::DialectKind;
22use crate::dialects::syntax::{SyntaxKind, SyntaxSet};
23use crate::lint_fix::LintFix;
24use crate::parser::markers::PositionMarker;
25use crate::parser::segments::fix::{FixPatch, SourceFix};
26use crate::parser::segments::object_reference::{ObjectReferenceKind, ObjectReferenceSegment};
27use crate::segments::AnchorEditInfo;
28use crate::templaters::TemplatedFile;
29
30pub struct SegmentBuilder {
31 node_or_token: NodeOrToken,
32}
33
34impl SegmentBuilder {
35 pub fn whitespace(id: u32, raw: &str) -> ErasedSegment {
36 SegmentBuilder::token(id, raw, SyntaxKind::Whitespace).finish()
37 }
38
39 pub fn newline(id: u32, raw: &str) -> ErasedSegment {
40 SegmentBuilder::token(id, raw, SyntaxKind::Newline).finish()
41 }
42
43 pub fn keyword(id: u32, raw: &str) -> ErasedSegment {
44 SegmentBuilder::token(id, raw, SyntaxKind::Keyword).finish()
45 }
46
47 pub fn comma(id: u32) -> ErasedSegment {
48 SegmentBuilder::token(id, ",", SyntaxKind::Comma).finish()
49 }
50
51 pub fn symbol(id: u32, raw: &str) -> ErasedSegment {
52 SegmentBuilder::token(id, raw, SyntaxKind::Symbol).finish()
53 }
54
55 pub fn node(
56 id: u32,
57 syntax_kind: SyntaxKind,
58 dialect: DialectKind,
59 segments: Vec<ErasedSegment>,
60 ) -> Self {
61 SegmentBuilder {
62 node_or_token: NodeOrToken {
63 id,
64 syntax_kind,
65 class_types: class_types(syntax_kind),
66 position_marker: None,
67 code_idx: OnceCell::new(),
68 kind: NodeOrTokenKind::Node(NodeData {
69 dialect,
70 segments,
71 raw: Default::default(),
72 source_fixes: vec![],
73 descendant_type_set: Default::default(),
74 raw_segments_with_ancestors: Default::default(),
75 }),
76 hash: OnceCell::new(),
77 template_info: None,
78 },
79 }
80 }
81
82 pub fn token(id: u32, raw: &str, syntax_kind: SyntaxKind) -> Self {
83 SegmentBuilder {
84 node_or_token: NodeOrToken {
85 id,
86 syntax_kind,
87 code_idx: OnceCell::new(),
88 class_types: class_types(syntax_kind),
89 position_marker: None,
90 kind: NodeOrTokenKind::Token(TokenData { raw: raw.into() }),
91 hash: OnceCell::new(),
92 template_info: None,
93 },
94 }
95 }
96
97 pub fn with_template_info(mut self, info: TemplateInfo) -> Self {
100 self.node_or_token.template_info = Some(Box::new(info));
101 self
102 }
103
104 pub fn position_from_segments(mut self) -> Self {
105 let segments = match &self.node_or_token.kind {
106 NodeOrTokenKind::Node(node) => &node.segments[..],
107 NodeOrTokenKind::Token(_) => &[],
108 };
109
110 self.node_or_token.position_marker = pos_marker(segments).into();
111 self
112 }
113
114 pub fn with_position(mut self, position: PositionMarker) -> Self {
115 self.node_or_token.position_marker = Some(position);
116 self
117 }
118
119 pub fn with_source_fixes(mut self, source_fixes: Vec<SourceFix>) -> Self {
120 if let NodeOrTokenKind::Node(ref mut node) = self.node_or_token.kind {
121 node.source_fixes = source_fixes;
122 }
123 self
124 }
125
126 pub fn finish(self) -> ErasedSegment {
127 ErasedSegment {
128 value: Rc::new(self.node_or_token),
129 }
130 }
131}
132
133#[derive(Debug, Default)]
134pub struct Tables {
135 counter: Cell<u32>,
136}
137
138impl Tables {
139 pub fn next_id(&self) -> u32 {
140 let id = self.counter.get();
141 self.counter.set(id + 1);
142 id
143 }
144}
145
146#[derive(Debug, Clone)]
147pub struct ErasedSegment {
148 pub(crate) value: Rc<NodeOrToken>,
149}
150
151impl Hash for ErasedSegment {
152 fn hash<H: Hasher>(&self, state: &mut H) {
153 self.hash_value().hash(state);
154 }
155}
156
157impl Eq for ErasedSegment {}
158
159impl ErasedSegment {
160 pub fn raw(&self) -> &SmolStr {
161 match &self.value.kind {
162 NodeOrTokenKind::Node(node) => node.raw.get_or_init(|| {
163 SmolStr::from_iter(self.segments().iter().map(|segment| segment.raw().as_str()))
164 }),
165 NodeOrTokenKind::Token(token) => &token.raw,
166 }
167 }
168
169 pub fn segments(&self) -> &[ErasedSegment] {
170 match &self.value.kind {
171 NodeOrTokenKind::Node(node) => &node.segments,
172 NodeOrTokenKind::Token(_) => &[],
173 }
174 }
175
176 pub fn get_type(&self) -> SyntaxKind {
177 self.value.syntax_kind
178 }
179
180 pub fn is_type(&self, kind: SyntaxKind) -> bool {
181 self.get_type() == kind
182 }
183
184 pub fn is_meta(&self) -> bool {
185 matches!(
186 self.value.syntax_kind,
187 SyntaxKind::Indent
188 | SyntaxKind::Implicit
189 | SyntaxKind::Dedent
190 | SyntaxKind::EndOfFile
191 | SyntaxKind::Placeholder
192 | SyntaxKind::TemplateLoop
193 )
194 }
195
196 pub fn template_info(&self) -> Option<&TemplateInfo> {
197 self.value.template_info.as_deref()
198 }
199
200 pub fn block_uuid(&self) -> Option<u32> {
201 self.value.template_info.as_ref().and_then(|i| i.block_uuid)
202 }
203
204 pub fn block_type(&self) -> Option<BlockType> {
205 self.value.template_info.as_ref().map(|i| i.block_type)
206 }
207
208 pub fn source_str(&self) -> SmolStr {
210 match self.value.template_info.as_ref() {
211 Some(info) => info.source_str.clone(),
212 None => self.raw().clone(),
213 }
214 }
215
216 pub fn is_code(&self) -> bool {
217 match &self.value.kind {
218 NodeOrTokenKind::Node(node) => node.segments.iter().any(|s| s.is_code()),
219 NodeOrTokenKind::Token(_) => {
220 !self.is_comment() && !self.is_whitespace() && !self.is_meta()
221 }
222 }
223 }
224
225 pub fn get_raw_segments(&self) -> Vec<ErasedSegment> {
226 self.recursive_crawl_all(false)
227 .into_iter()
228 .filter(|it| it.segments().is_empty())
229 .collect()
230 }
231
232 #[cfg(feature = "stringify")]
233 pub fn stringify(&self, code_only: bool) -> String {
234 serde_yaml::to_string(&self.to_serialised(code_only, true)).unwrap()
235 }
236
237 pub fn child(&self, seg_types: &SyntaxSet) -> Option<ErasedSegment> {
238 self.segments()
239 .iter()
240 .find(|seg| seg_types.contains(seg.get_type()))
241 .cloned()
242 }
243
244 pub fn recursive_crawl(
245 &self,
246 types: &SyntaxSet,
247 recurse_into: bool,
248 no_recursive_types: &SyntaxSet,
249 allow_self: bool,
250 ) -> Vec<ErasedSegment> {
251 let mut acc = Vec::new();
252
253 let matches = allow_self && self.class_types().intersects(types);
254 if matches {
255 acc.push(self.clone());
256 }
257
258 if !self.descendant_type_set().intersects(types) {
259 return acc;
260 }
261
262 if recurse_into || !matches {
263 for seg in self.segments() {
264 if no_recursive_types.is_empty() || !no_recursive_types.contains(seg.get_type()) {
265 let segments =
266 seg.recursive_crawl(types, recurse_into, no_recursive_types, true);
267 acc.extend(segments);
268 }
269 }
270 }
271
272 acc
273 }
274}
275
276impl ErasedSegment {
277 #[track_caller]
278 pub fn new(&self, segments: Vec<ErasedSegment>) -> ErasedSegment {
279 match &self.value.kind {
280 NodeOrTokenKind::Node(node) => {
281 let mut builder = SegmentBuilder::node(
282 self.value.id,
283 self.value.syntax_kind,
284 node.dialect,
285 segments,
286 )
287 .with_position(self.get_position_marker().unwrap().clone());
288 if !node.source_fixes.is_empty() {
290 builder = builder.with_source_fixes(node.source_fixes.clone());
291 }
292 builder.finish()
293 }
294 NodeOrTokenKind::Token(_) => self.deep_clone(),
295 }
296 }
297
298 fn change_segments(&self, segments: Vec<ErasedSegment>) -> ErasedSegment {
299 let NodeOrTokenKind::Node(node) = &self.value.kind else {
300 unimplemented!()
301 };
302
303 ErasedSegment {
304 value: Rc::new(NodeOrToken {
305 id: self.value.id,
306 syntax_kind: self.value.syntax_kind,
307 class_types: self.value.class_types.clone(),
308 position_marker: None,
309 code_idx: OnceCell::new(),
310 kind: NodeOrTokenKind::Node(NodeData {
311 dialect: node.dialect,
312 segments,
313 raw: node.raw.clone(),
314 source_fixes: node.source_fixes.clone(),
315 descendant_type_set: node.descendant_type_set.clone(),
316 raw_segments_with_ancestors: node.raw_segments_with_ancestors.clone(),
317 }),
318 hash: OnceCell::new(),
319 template_info: self.value.template_info.clone(),
320 }),
321 }
322 }
323
324 pub fn indent_val(&self) -> i8 {
325 self.value.syntax_kind.indent_val()
326 }
327
328 pub fn can_start_end_non_code(&self) -> bool {
329 matches!(
330 self.value.syntax_kind,
331 SyntaxKind::File | SyntaxKind::Unparsable
332 )
333 }
334
335 pub(crate) fn dialect(&self) -> DialectKind {
336 match &self.value.kind {
337 NodeOrTokenKind::Node(node) => node.dialect,
338 NodeOrTokenKind::Token(_) => todo!(),
339 }
340 }
341
342 pub fn get_start_loc(&self) -> (usize, usize) {
343 match self.get_position_marker() {
344 Some(pos_marker) => pos_marker.working_loc(),
345 None => unreachable!("{self:?} has no PositionMarker"),
346 }
347 }
348
349 pub fn get_end_loc(&self) -> (usize, usize) {
350 match self.get_position_marker() {
351 Some(pos_marker) => pos_marker.working_loc_after(self.raw()),
352 None => {
353 unreachable!("{self:?} has no PositionMarker")
354 }
355 }
356 }
357
358 pub fn is_templated(&self) -> bool {
359 if let Some(pos_marker) = self.get_position_marker() {
360 pos_marker.source_slice.start != pos_marker.source_slice.end && !pos_marker.is_literal()
361 } else {
362 panic!("PosMarker must be set");
363 }
364 }
365
366 pub fn iter_segments(&self, expanding: &SyntaxSet, pass_through: bool) -> Vec<ErasedSegment> {
367 let capacity = if expanding.is_empty() {
368 self.segments().len()
369 } else {
370 0
371 };
372 let mut result = Vec::with_capacity(capacity);
373 for segment in self.segments() {
374 if expanding.contains(segment.get_type()) {
375 let expanding = if pass_through {
376 expanding
377 } else {
378 &SyntaxSet::EMPTY
379 };
380 result.append(&mut segment.iter_segments(expanding, false));
381 } else {
382 result.push(segment.clone());
383 }
384 }
385 result
386 }
387
388 pub(crate) fn code_indices(&self) -> Rc<Vec<usize>> {
389 self.value
390 .code_idx
391 .get_or_init(|| {
392 Rc::from(
393 self.segments()
394 .iter()
395 .enumerate()
396 .filter(|(_, seg)| seg.is_code())
397 .map(|(idx, _)| idx)
398 .collect::<Vec<_>>(),
399 )
400 })
401 .clone()
402 }
403
404 pub fn children(
405 &self,
406 seg_types: &'static SyntaxSet,
407 ) -> impl Iterator<Item = &ErasedSegment> + '_ {
408 self.segments()
409 .iter()
410 .filter(move |seg| seg_types.contains(seg.get_type()))
411 }
412
413 pub fn iter_patches(&self, templated_file: &TemplatedFile) -> Vec<FixPatch> {
414 let mut acc = Vec::new();
415
416 let templated_raw = &templated_file.templated_str.as_ref().unwrap()
417 [self.get_position_marker().unwrap().templated_slice.clone()];
418
419 acc.extend(self.iter_source_fix_patches(templated_file));
421
422 let has_descendant_source_fixes = self
424 .recursive_crawl_all(false)
425 .iter()
426 .any(|s| !s.get_source_fixes().is_empty());
427
428 if self.raw() == templated_raw {
429 if has_descendant_source_fixes {
430 for descendant in self.recursive_crawl_all(false).into_iter().skip(1) {
434 acc.extend(descendant.iter_source_fix_patches(templated_file));
435 }
436 }
437 return acc;
438 }
439
440 if self.get_position_marker().is_none() {
441 return Vec::new();
442 }
443
444 let pos_marker = self.get_position_marker().unwrap();
445 if pos_marker.is_literal() && !has_descendant_source_fixes {
446 acc.extend(self.iter_source_fix_patches(templated_file));
447 acc.push(FixPatch::new(
448 pos_marker.templated_slice.clone(),
449 self.raw().clone(),
450 pos_marker.source_slice.clone(),
452 templated_file.templated_str.as_ref().unwrap()[pos_marker.templated_slice.clone()]
453 .to_string(),
454 templated_file.source_str[pos_marker.source_slice.clone()].to_string(),
455 ));
456 } else if self.segments().is_empty() {
457 return acc;
458 } else {
459 let mut segments = self.segments();
460
461 while !segments.is_empty()
462 && matches!(
463 segments.last().unwrap().get_type(),
464 SyntaxKind::EndOfFile
465 | SyntaxKind::Indent
466 | SyntaxKind::Dedent
467 | SyntaxKind::Implicit
468 )
469 {
470 segments = &segments[..segments.len() - 1];
471 }
472
473 let pos = self.get_position_marker().unwrap();
474 let mut source_idx = pos.source_slice.start;
475 let mut templated_idx = pos.templated_slice.start;
476 let mut insert_buff = String::new();
477
478 for segment in segments {
479 let pos_marker = segment.get_position_marker().unwrap();
480 if !segment.raw().is_empty() && pos_marker.is_point() {
481 insert_buff.push_str(segment.raw().as_ref());
482 continue;
483 }
484
485 let start_diff = pos_marker.templated_slice.start - templated_idx;
486
487 if start_diff > 0 || !insert_buff.is_empty() {
488 let fixed_raw = std::mem::take(&mut insert_buff);
489 let raw_segments = segment.get_raw_segments();
490 let first_segment_pos = raw_segments[0].get_position_marker().unwrap();
491
492 acc.push(FixPatch::new(
496 templated_idx..first_segment_pos.templated_slice.start.max(templated_idx),
497 fixed_raw.into(),
498 source_idx..first_segment_pos.source_slice.start.max(source_idx),
499 String::new(),
500 String::new(),
501 ));
502 }
503
504 acc.extend(segment.iter_patches(templated_file));
505
506 source_idx = pos_marker.source_slice.end;
507 templated_idx = pos_marker.templated_slice.end;
508 }
509
510 let end_diff = pos.templated_slice.end - templated_idx;
511 if end_diff != 0 || !insert_buff.is_empty() {
512 let source_slice = source_idx..pos.source_slice.end;
513 let templated_slice = templated_idx..pos.templated_slice.end;
514
515 let templated_str = templated_file.templated_str.as_ref().unwrap()
516 [templated_slice.clone()]
517 .to_owned();
518 let source_str = templated_file.source_str[source_slice.clone()].to_owned();
519
520 acc.push(FixPatch::new(
521 templated_slice,
522 insert_buff.into(),
523 source_slice,
524 templated_str,
525 source_str,
526 ));
527 }
528 }
529
530 acc
531 }
532
533 pub fn descendant_type_set(&self) -> &SyntaxSet {
534 match &self.value.kind {
535 NodeOrTokenKind::Node(node) => node.descendant_type_set.get_or_init(|| {
536 self.segments()
537 .iter()
538 .flat_map(|segment| {
539 segment
540 .descendant_type_set()
541 .clone()
542 .union(segment.class_types())
543 })
544 .collect()
545 }),
546 NodeOrTokenKind::Token(_) => const { &SyntaxSet::EMPTY },
547 }
548 }
549
550 pub fn is_comment(&self) -> bool {
551 matches!(
552 self.value.syntax_kind,
553 SyntaxKind::Comment
554 | SyntaxKind::InlineComment
555 | SyntaxKind::BlockComment
556 | SyntaxKind::NotebookStart
557 )
558 }
559
560 pub fn is_whitespace(&self) -> bool {
561 matches!(
562 self.value.syntax_kind,
563 SyntaxKind::Whitespace | SyntaxKind::Newline
564 )
565 }
566
567 pub fn is_indent(&self) -> bool {
568 matches!(
569 self.value.syntax_kind,
570 SyntaxKind::Indent | SyntaxKind::Implicit | SyntaxKind::Dedent
571 )
572 }
573
574 pub fn get_position_marker(&self) -> Option<&PositionMarker> {
575 self.value.position_marker.as_ref()
576 }
577
578 pub(crate) fn iter_source_fix_patches(&self, templated_file: &TemplatedFile) -> Vec<FixPatch> {
579 let source_fixes = self.get_source_fixes();
580 let mut patches = Vec::with_capacity(source_fixes.len());
581
582 for source_fix in &source_fixes {
583 patches.push(FixPatch::new(
584 source_fix.templated_slice.clone(),
585 source_fix.edit.clone(),
586 source_fix.source_slice.clone(),
588 templated_file.templated_str.clone().unwrap()[source_fix.templated_slice.clone()]
589 .to_string(),
590 templated_file.source_str[source_fix.source_slice.clone()].to_string(),
591 ));
592 }
593
594 patches
595 }
596
597 pub fn id(&self) -> u32 {
598 self.value.id
599 }
600
601 pub fn get_source_fixes(&self) -> Vec<SourceFix> {
603 match &self.value.kind {
604 NodeOrTokenKind::Node(node) => node.source_fixes.clone(),
605 NodeOrTokenKind::Token(_) => Vec::new(),
606 }
607 }
608
609 pub fn get_all_source_fixes(&self) -> Vec<SourceFix> {
611 let mut fixes = self.get_source_fixes();
612 for segment in self.segments() {
613 fixes.extend(segment.get_all_source_fixes());
614 }
615 fixes
616 }
617
618 pub fn edit(
619 &self,
620 id: u32,
621 raw: Option<String>,
622 _source_fixes: Option<Vec<SourceFix>>,
623 ) -> ErasedSegment {
624 match &self.value.kind {
625 NodeOrTokenKind::Node(_node) => {
626 todo!()
627 }
628 NodeOrTokenKind::Token(token) => {
629 let raw = raw.as_deref().unwrap_or(token.raw.as_ref());
630 SegmentBuilder::token(id, raw, self.value.syntax_kind)
631 .with_position(self.get_position_marker().unwrap().clone())
632 .finish()
633 }
634 }
635 }
636
637 pub fn class_types(&self) -> &SyntaxSet {
638 &self.value.class_types
639 }
640
641 pub(crate) fn first_non_whitespace_segment_raw_upper(&self) -> Option<String> {
642 for seg in self.get_raw_segments() {
643 if !seg.raw().is_empty() {
644 return Some(seg.raw().to_uppercase());
645 }
646 }
647 None
648 }
649
650 pub fn is(&self, other: &ErasedSegment) -> bool {
651 Rc::ptr_eq(&self.value, &other.value)
652 }
653
654 pub fn addr(&self) -> usize {
655 Rc::as_ptr(&self.value).addr()
656 }
657
658 pub fn direct_descendant_type_set(&self) -> SyntaxSet {
659 self.segments()
660 .iter()
661 .fold(SyntaxSet::EMPTY, |set, it| set.union(it.class_types()))
662 }
663
664 pub fn is_keyword(&self, p0: &str) -> bool {
665 self.is_type(SyntaxKind::Keyword) && self.raw().eq_ignore_ascii_case(p0)
666 }
667
668 pub fn hash_value(&self) -> u64 {
669 *self.value.hash.get_or_init(|| {
670 let mut hasher = DefaultHashBuilder::default().build_hasher();
671 self.get_type().hash(&mut hasher);
672 self.raw().hash(&mut hasher);
673
674 if let Some(marker) = &self.get_position_marker() {
675 marker.source_position().hash(&mut hasher);
676 } else {
677 None::<usize>.hash(&mut hasher);
678 }
679
680 hasher.finish()
681 })
682 }
683
684 pub fn deep_clone(&self) -> Self {
685 Self {
686 value: Rc::new(self.value.as_ref().clone()),
687 }
688 }
689
690 #[track_caller]
691 pub(crate) fn get_mut(&mut self) -> &mut NodeOrToken {
692 Rc::get_mut(&mut self.value).unwrap()
693 }
694
695 #[track_caller]
696 pub(crate) fn make_mut(&mut self) -> &mut NodeOrToken {
697 Rc::make_mut(&mut self.value)
698 }
699
700 pub fn reference(&self) -> ObjectReferenceSegment {
701 ObjectReferenceSegment(
702 self.clone(),
703 match self.get_type() {
704 SyntaxKind::TableReference => ObjectReferenceKind::Table,
705 SyntaxKind::WildcardIdentifier => ObjectReferenceKind::WildcardIdentifier,
706 _ => ObjectReferenceKind::Object,
707 },
708 )
709 }
710
711 pub fn recursive_crawl_all(&self, reverse: bool) -> Vec<ErasedSegment> {
712 let mut result = Vec::with_capacity(self.segments().len() + 1);
713
714 if reverse {
715 for seg in self.segments().iter().rev() {
716 result.append(&mut seg.recursive_crawl_all(reverse));
717 }
718 result.push(self.clone());
719 } else {
720 result.push(self.clone());
721 for seg in self.segments() {
722 result.append(&mut seg.recursive_crawl_all(reverse));
723 }
724 }
725
726 result
727 }
728
729 pub fn raw_segments_with_ancestors(&self) -> &[(ErasedSegment, Vec<PathStep>)] {
730 match &self.value.kind {
731 NodeOrTokenKind::Node(node) => node.raw_segments_with_ancestors.get_or_init(|| {
732 let mut buffer: Vec<(ErasedSegment, Vec<PathStep>)> =
733 Vec::with_capacity(self.segments().len());
734 let code_idxs = self.code_indices();
735
736 for (idx, seg) in self.segments().iter().enumerate() {
737 let new_step = vec![PathStep {
738 segment: self.clone(),
739 idx,
740 len: self.segments().len(),
741 code_idxs: code_idxs.clone(),
742 }];
743
744 if seg.segments().is_empty() {
750 buffer.push((seg.clone(), new_step));
751 } else {
752 let extended =
753 seg.raw_segments_with_ancestors()
754 .iter()
755 .map(|(raw_seg, stack)| {
756 let mut new_step = new_step.clone();
757 new_step.extend_from_slice(stack);
758 (raw_seg.clone(), new_step)
759 });
760
761 buffer.extend(extended);
762 }
763 }
764
765 buffer
766 }),
767 NodeOrTokenKind::Token(_) => &[],
768 }
769 }
770
771 pub fn path_to(&self, other: &ErasedSegment) -> Vec<PathStep> {
772 let midpoint = other;
773
774 for (idx, seg) in enumerate(self.segments()) {
775 let mut steps = vec![PathStep {
776 segment: self.clone(),
777 idx,
778 len: self.segments().len(),
779 code_idxs: self.code_indices(),
780 }];
781
782 if seg.eq(midpoint) {
783 return steps;
784 }
785
786 let res = seg.path_to(midpoint);
787
788 if !res.is_empty() {
789 steps.extend(res);
790 return steps;
791 }
792 }
793
794 Vec::new()
795 }
796
797 pub fn apply_fixes(
798 &self,
799 fixes: &mut HashMap<u32, AnchorEditInfo>,
800 ) -> (ErasedSegment, Vec<ErasedSegment>, Vec<ErasedSegment>) {
801 if fixes.is_empty() || self.segments().is_empty() {
802 return (self.clone(), Vec::new(), Vec::new());
803 }
804
805 let mut seg_buffer = Vec::new();
806 let mut has_applied_fixes = false;
807 let mut _requires_validate = false;
808
809 for seg in self.segments() {
810 let Some(mut anchor_info) = fixes.remove(&seg.id()) else {
814 seg_buffer.push(seg.clone());
815 continue;
816 };
817
818 if anchor_info.fixes.len() == 2
819 && matches!(anchor_info.fixes[0], LintFix::CreateAfter { .. })
820 {
821 anchor_info.fixes.reverse();
822 }
823
824 let fixes_count = anchor_info.fixes.len();
825 for lint_fix in anchor_info.fixes {
826 has_applied_fixes = true;
827
828 if matches!(lint_fix, LintFix::Delete { .. }) {
830 _requires_validate = true;
832 continue;
834 }
835
836 assert!(matches!(
838 lint_fix,
839 LintFix::Replace { .. }
840 | LintFix::CreateBefore { .. }
841 | LintFix::CreateAfter { .. }
842 ));
843
844 match lint_fix {
845 LintFix::CreateAfter { edit, .. } => {
846 if fixes_count == 1 {
847 seg_buffer.push(seg.clone());
851 }
852 for s in edit {
853 seg_buffer.push(s);
854 }
855 _requires_validate = true;
856 }
857 LintFix::CreateBefore { edit, .. } => {
858 for s in edit {
859 seg_buffer.push(s);
860 }
861 seg_buffer.push(seg.clone());
862 _requires_validate = true;
863 }
864 LintFix::Replace { edit, .. } => {
865 let mut consumed_pos = false;
866 let is_single_same_type =
867 edit.len() == 1 && edit[0].class_types() == seg.class_types();
868
869 for mut s in edit {
870 if !consumed_pos && s.raw() == seg.raw() {
871 consumed_pos = true;
872 s.make_mut()
873 .set_position_marker(seg.get_position_marker().cloned());
874 }
875 seg_buffer.push(s);
876 }
877
878 if !is_single_same_type {
879 _requires_validate = true;
880 }
881 }
882 LintFix::Delete { .. } => {
883 unreachable!()
885 }
886 }
887 }
888 }
889
890 if has_applied_fixes {
891 seg_buffer =
892 position_segments(&seg_buffer, self.get_position_marker().as_ref().unwrap());
893 }
894
895 let seg_queue = seg_buffer;
896 let mut seg_buffer = Vec::new();
897 for seg in seg_queue {
898 let (mid, pre, post) = seg.apply_fixes(fixes);
899
900 seg_buffer.extend(pre);
901 seg_buffer.push(mid);
902 seg_buffer.extend(post);
903 }
904
905 let seg_buffer =
906 position_segments(&seg_buffer, self.get_position_marker().as_ref().unwrap());
907 (self.new(seg_buffer), Vec::new(), Vec::new())
908 }
909}
910
911#[cfg(any(test, feature = "serde"))]
912pub mod serde {
913 use serde::ser::SerializeMap;
914 use serde::{Deserialize, Serialize};
915
916 use crate::parser::segments::ErasedSegment;
917
918 #[derive(Serialize, Deserialize)]
919 #[serde(untagged)]
920 pub enum SerialisedSegmentValue {
921 Single(String),
922 Nested(Vec<TupleSerialisedSegment>),
923 }
924
925 #[derive(Deserialize)]
926 pub struct TupleSerialisedSegment(String, SerialisedSegmentValue);
927
928 impl Serialize for TupleSerialisedSegment {
929 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
930 where
931 S: serde::Serializer,
932 {
933 let mut map = serializer.serialize_map(None)?;
934 map.serialize_key(&self.0)?;
935 map.serialize_value(&self.1)?;
936 map.end()
937 }
938 }
939
940 impl TupleSerialisedSegment {
941 pub fn sinlge(key: String, value: String) -> Self {
942 Self(key, SerialisedSegmentValue::Single(value))
943 }
944
945 pub fn nested(key: String, segments: Vec<TupleSerialisedSegment>) -> Self {
946 Self(key, SerialisedSegmentValue::Nested(segments))
947 }
948 }
949
950 impl ErasedSegment {
951 pub fn to_serialised(&self, code_only: bool, show_raw: bool) -> TupleSerialisedSegment {
952 if show_raw && self.segments().is_empty() {
953 TupleSerialisedSegment::sinlge(
954 self.get_type().as_str().to_string(),
955 self.raw().to_string(),
956 )
957 } else if code_only {
958 let segments = self
959 .segments()
960 .iter()
961 .filter(|seg| seg.is_code() && !seg.is_meta())
962 .map(|seg| seg.to_serialised(code_only, show_raw))
963 .collect::<Vec<_>>();
964
965 TupleSerialisedSegment::nested(self.get_type().as_str().to_string(), segments)
966 } else {
967 let segments = self
968 .segments()
969 .iter()
970 .map(|seg| seg.to_serialised(code_only, show_raw))
971 .collect::<Vec<_>>();
972
973 TupleSerialisedSegment::nested(self.get_type().as_str().to_string(), segments)
974 }
975 }
976 }
977}
978
979impl PartialEq for ErasedSegment {
980 fn eq(&self, other: &Self) -> bool {
981 if self.id() == other.id() {
982 return true;
983 }
984
985 let pos_self = self.get_position_marker();
986 let pos_other = other.get_position_marker();
987 if let Some((pos_self, pos_other)) = pos_self.zip(pos_other) {
988 self.get_type() == other.get_type()
989 && pos_self.working_loc() == pos_other.working_loc()
990 && self.raw() == other.raw()
991 } else {
992 false
993 }
994 }
995}
996
997pub fn position_segments(
998 segments: &[ErasedSegment],
999 parent_pos: &PositionMarker,
1000) -> Vec<ErasedSegment> {
1001 if segments.is_empty() {
1002 return Vec::new();
1003 }
1004
1005 let (mut line_no, mut line_pos) = { (parent_pos.working_line_no, parent_pos.working_line_pos) };
1006
1007 let mut segment_buffer: Vec<ErasedSegment> = Vec::new();
1008 for (idx, segment) in enumerate(segments) {
1009 let old_position = segment.get_position_marker();
1010
1011 let mut new_position = match old_position {
1012 Some(pos_marker) => pos_marker.clone(),
1013 None => {
1014 let start_point = if idx > 0 {
1015 let prev_seg = segment_buffer[idx - 1].clone();
1016 Some(prev_seg.get_position_marker().unwrap().end_point_marker())
1017 } else {
1018 Some(parent_pos.start_point_marker())
1019 };
1020
1021 let mut end_point = None;
1022 for fwd_seg in &segments[idx + 1..] {
1023 if fwd_seg.get_position_marker().is_some() {
1024 end_point = Some(
1025 fwd_seg.get_raw_segments()[0]
1026 .get_position_marker()
1027 .unwrap()
1028 .start_point_marker(),
1029 );
1030 break;
1031 }
1032 }
1033
1034 if let Some((start_point, end_point)) = start_point
1035 .as_ref()
1036 .zip(end_point.as_ref())
1037 .filter(|(start_point, end_point)| start_point != end_point)
1038 {
1039 PositionMarker::from_points(start_point, end_point)
1040 } else if let Some(start_point) = start_point.as_ref() {
1041 start_point.clone()
1042 } else if let Some(end_point) = end_point.as_ref() {
1043 end_point.clone()
1044 } else {
1045 unimplemented!("Unable to position new segment")
1046 }
1047 }
1048 };
1049
1050 new_position = new_position.with_working_position(line_no, line_pos);
1051 (line_no, line_pos) = PositionMarker::infer_next_position(segment.raw(), line_no, line_pos);
1052
1053 let mut new_seg = if !segment.segments().is_empty() && old_position != Some(&new_position) {
1054 let child_segments = position_segments(segment.segments(), &new_position);
1055 segment.change_segments(child_segments)
1056 } else {
1057 segment.deep_clone()
1058 };
1059
1060 new_seg.get_mut().set_position_marker(new_position.into());
1061 segment_buffer.push(new_seg);
1062 }
1063
1064 segment_buffer
1065}
1066
1067#[derive(Debug, Clone)]
1068pub struct NodeOrToken {
1069 id: u32,
1070 syntax_kind: SyntaxKind,
1071 class_types: SyntaxSet,
1072 position_marker: Option<PositionMarker>,
1073 kind: NodeOrTokenKind,
1074 code_idx: OnceCell<Rc<Vec<usize>>>,
1075 hash: OnceCell<u64>,
1076 template_info: Option<Box<TemplateInfo>>,
1079}
1080
1081#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1083pub enum BlockType {
1084 Literal,
1085 Templated,
1086 Comment,
1087 BlockStart,
1088 BlockMid,
1089 BlockEnd,
1090 SkippedSource,
1091 Compound,
1092 Endpoint,
1093}
1094
1095#[derive(Debug, Clone)]
1096pub struct TemplateInfo {
1097 pub block_type: BlockType,
1098 pub block_uuid: Option<u32>,
1100 pub source_str: SmolStr,
1102 pub is_template: bool,
1104}
1105
1106#[derive(Debug, Clone)]
1107#[allow(clippy::large_enum_variant)]
1108pub enum NodeOrTokenKind {
1109 Node(NodeData),
1110 Token(TokenData),
1111}
1112
1113impl NodeOrToken {
1114 pub fn set_position_marker(&mut self, position_marker: Option<PositionMarker>) {
1115 self.position_marker = position_marker;
1116 }
1117
1118 pub fn set_id(&mut self, id: u32) {
1119 self.id = id;
1120 }
1121}
1122
1123#[derive(Debug, Clone)]
1124pub struct NodeData {
1125 dialect: DialectKind,
1126 segments: Vec<ErasedSegment>,
1127 raw: OnceCell<SmolStr>,
1128 source_fixes: Vec<SourceFix>,
1129 descendant_type_set: OnceCell<SyntaxSet>,
1130 raw_segments_with_ancestors: OnceCell<Vec<(ErasedSegment, Vec<PathStep>)>>,
1131}
1132
1133#[derive(Debug, Clone, PartialEq)]
1134pub struct TokenData {
1135 raw: SmolStr,
1136}
1137
1138#[track_caller]
1139pub fn pos_marker(segments: &[ErasedSegment]) -> PositionMarker {
1140 let markers = segments.iter().filter_map(|seg| seg.get_position_marker());
1141
1142 PositionMarker::from_child_markers(markers)
1143}
1144
1145#[derive(Debug, Clone)]
1146pub struct PathStep {
1147 pub segment: ErasedSegment,
1148 pub idx: usize,
1149 pub len: usize,
1150 pub code_idxs: Rc<Vec<usize>>,
1151}
1152
1153fn class_types(syntax_kind: SyntaxKind) -> SyntaxSet {
1154 match syntax_kind {
1155 SyntaxKind::ColumnReference => SyntaxSet::new(&[SyntaxKind::ObjectReference, syntax_kind]),
1156 SyntaxKind::WildcardIdentifier => {
1157 SyntaxSet::new(&[SyntaxKind::WildcardIdentifier, SyntaxKind::ObjectReference])
1158 }
1159 SyntaxKind::TableReference => SyntaxSet::new(&[SyntaxKind::ObjectReference, syntax_kind]),
1160 _ => SyntaxSet::single(syntax_kind),
1161 }
1162}
1163
1164#[cfg(test)]
1165mod tests {
1166 use super::*;
1167 use crate::lint_fix::LintFix;
1168 use crate::linter::compute_anchor_edit_info;
1169 use crate::parser::segments::test_functions::{raw_seg, raw_segments};
1170
1171 #[test]
1172 fn test_parser_base_segments_raw_compare() {
1174 let template: TemplatedFile = "foobar".into();
1175 let rs1 = SegmentBuilder::token(0, "foobar", SyntaxKind::Word)
1176 .with_position(PositionMarker::new(
1177 0..6,
1178 0..6,
1179 template.clone(),
1180 None,
1181 None,
1182 ))
1183 .finish();
1184 let rs2 = SegmentBuilder::token(0, "foobar", SyntaxKind::Word)
1185 .with_position(PositionMarker::new(
1186 0..6,
1187 0..6,
1188 template.clone(),
1189 None,
1190 None,
1191 ))
1192 .finish();
1193
1194 assert_eq!(rs1, rs2)
1195 }
1196
1197 #[test]
1198 fn test_parser_base_segments_raw() {
1201 let raw_seg = raw_seg();
1202
1203 assert_eq!(raw_seg.raw(), "foobar");
1204 }
1205
1206 #[test]
1207 fn test_parser_base_segments_compute_anchor_edit_info() {
1209 let raw_segs = raw_segments();
1210 let tables = Tables::default();
1211
1212 let fixes = vec![
1216 LintFix::replace(
1217 raw_segs[0].clone(),
1218 vec![raw_segs[0].edit(tables.next_id(), Some("a".to_string()), None)],
1219 None,
1220 ),
1221 LintFix::replace(
1222 raw_segs[0].clone(),
1223 vec![raw_segs[0].edit(tables.next_id(), Some("a".to_string()), None)],
1224 None,
1225 ),
1226 LintFix::replace(
1227 raw_segs[0].clone(),
1228 vec![raw_segs[0].edit(tables.next_id(), Some("b".to_string()), None)],
1229 None,
1230 ),
1231 ];
1232
1233 let mut anchor_edit_info = Default::default();
1234 compute_anchor_edit_info(&mut anchor_edit_info, fixes);
1235
1236 assert_eq!(
1238 anchor_edit_info.keys().collect::<Vec<_>>(),
1239 vec![&raw_segs[0].id()]
1240 );
1241
1242 let anchor_info = anchor_edit_info.get(&raw_segs[0].id()).unwrap();
1243
1244 assert_eq!(anchor_info.replace, 2);
1246
1247 assert_eq!(
1250 anchor_info.fixes[0],
1251 LintFix::replace(
1252 raw_segs[0].clone(),
1253 vec![raw_segs[0].edit(tables.next_id(), Some("a".to_string()), None)],
1254 None,
1255 )
1256 );
1257 assert_eq!(
1258 anchor_info.fixes[1],
1259 LintFix::replace(
1260 raw_segs[0].clone(),
1261 vec![raw_segs[0].edit(tables.next_id(), Some("b".to_string()), None)],
1262 None,
1263 )
1264 );
1265
1266 assert_eq!(
1268 anchor_info.fixes[anchor_info.first_replace.unwrap()],
1269 LintFix::replace(
1270 raw_segs[0].clone(),
1271 vec![raw_segs[0].edit(tables.next_id(), Some("a".to_string()), None)],
1272 None,
1273 )
1274 );
1275 }
1276}