1use crate::document::constructor::{DocumentConstructor, Scope};
21use crate::document::interpreter_sink::InterpreterSink;
22use crate::document::{ConstructorError, InsertError, NodeId};
23use crate::path::PathSegment;
24use crate::prelude_internal::*;
25use crate::source::{
26 BindingSource, Comment, EureSource, SectionSource, SourceDocument, SourceId, SourceKey,
27 SourcePath, SourcePathSegment, Trivia,
28};
29
30#[derive(Debug)]
32enum BuilderContext {
33 EureBlock {
35 source_id: SourceId,
37 saved_path: SourcePath,
39 saved_trivia: Vec<Trivia>,
41 },
42 SectionItems {
44 trivia_before: Vec<Trivia>,
46 path: SourcePath,
48 value: Option<NodeId>,
50 bindings: Vec<BindingSource>,
52 },
53}
54
55pub struct SourceConstructor {
92 inner: DocumentConstructor,
94
95 sources: Vec<EureSource>,
97
98 builder_stack: Vec<BuilderContext>,
100
101 pending_path: Vec<SourcePathSegment>,
103
104 pending_trivia: Vec<Trivia>,
106
107 last_bound_node: Option<NodeId>,
109
110 last_block_id: Option<SourceId>,
112}
113
114impl Default for SourceConstructor {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120impl SourceConstructor {
121 #[must_use]
123 pub fn new() -> Self {
124 let sources = vec![EureSource::default()];
126
127 Self {
128 inner: DocumentConstructor::new(),
129 sources,
130 builder_stack: vec![BuilderContext::EureBlock {
131 source_id: SourceId(0),
132 saved_path: Vec::new(),
133 saved_trivia: Vec::new(),
134 }],
135 pending_path: Vec::new(),
136 pending_trivia: Vec::new(),
137 last_bound_node: None,
138 last_block_id: None,
139 }
140 }
141
142 #[must_use]
144 pub fn finish(mut self) -> SourceDocument {
145 if !self.pending_trivia.is_empty() {
147 self.sources[0].trailing_trivia = std::mem::take(&mut self.pending_trivia);
148 }
149 SourceDocument::new(self.inner.finish(), self.sources)
150 }
151
152 fn current_source_mut(&mut self) -> &mut EureSource {
156 for ctx in self.builder_stack.iter().rev() {
157 if let BuilderContext::EureBlock { source_id, .. } = ctx {
158 return &mut self.sources[source_id.0];
159 }
160 }
161 &mut self.sources[0]
163 }
164
165 pub fn begin_scope(&mut self) -> Scope {
174 InterpreterSink::begin_scope(self)
175 }
176
177 pub fn end_scope(&mut self, scope: Scope) -> Result<(), InsertError> {
179 InterpreterSink::end_scope(self, scope)
180 }
181
182 pub fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, InsertError> {
184 InterpreterSink::navigate(self, segment)
185 }
186
187 pub fn require_hole(&self) -> Result<(), InsertError> {
189 InterpreterSink::require_hole(self)
190 }
191
192 pub fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertError> {
194 InterpreterSink::bind_primitive(self, value)
195 }
196
197 pub fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), InsertError> {
199 InterpreterSink::bind_hole(self, label)
200 }
201
202 pub fn bind_empty_map(&mut self) -> Result<(), InsertError> {
204 InterpreterSink::bind_empty_map(self)
205 }
206
207 pub fn bind_empty_array(&mut self) -> Result<(), InsertError> {
209 InterpreterSink::bind_empty_array(self)
210 }
211
212 pub fn bind_empty_tuple(&mut self) -> Result<(), InsertError> {
214 InterpreterSink::bind_empty_tuple(self)
215 }
216
217 pub fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), InsertError> {
219 InterpreterSink::bind_from(self, value)
220 }
221
222 pub fn current_node_id(&self) -> NodeId {
224 InterpreterSink::current_node_id(self)
225 }
226
227 pub fn current_path(&self) -> &[PathSegment] {
229 InterpreterSink::current_path(self)
230 }
231
232 pub fn document(&self) -> &EureDocument {
234 InterpreterSink::document(self)
235 }
236
237 pub fn document_mut(&mut self) -> &mut EureDocument {
239 InterpreterSink::document_mut(self)
240 }
241
242 pub fn begin_eure_block(&mut self) {
248 InterpreterSink::begin_eure_block(self)
249 }
250
251 pub fn set_block_value(&mut self) -> Result<(), InsertError> {
253 InterpreterSink::set_block_value(self)
254 }
255
256 pub fn end_eure_block(&mut self) -> Result<(), InsertError> {
258 InterpreterSink::end_eure_block(self)
259 }
260
261 pub fn begin_binding(&mut self) {
263 InterpreterSink::begin_binding(self)
264 }
265
266 pub fn end_binding_value(&mut self) -> Result<(), InsertError> {
268 InterpreterSink::end_binding_value(self)
269 }
270
271 pub fn end_binding_block(&mut self) -> Result<(), InsertError> {
273 InterpreterSink::end_binding_block(self)
274 }
275
276 pub fn begin_section(&mut self) {
278 InterpreterSink::begin_section(self)
279 }
280
281 pub fn begin_section_items(&mut self) {
283 InterpreterSink::begin_section_items(self)
284 }
285
286 pub fn end_section_items(&mut self) -> Result<(), InsertError> {
288 InterpreterSink::end_section_items(self)
289 }
290
291 pub fn end_section_block(&mut self) -> Result<(), InsertError> {
293 InterpreterSink::end_section_block(self)
294 }
295
296 pub fn comment(&mut self, comment: Comment) {
298 InterpreterSink::comment(self, comment)
299 }
300
301 pub fn blank_line(&mut self) {
303 InterpreterSink::blank_line(self)
304 }
305
306 pub fn add_trivia(&mut self, trivia: Trivia) {
308 self.pending_trivia.push(trivia);
309 }
310
311 fn path_segment_to_source(segment: &PathSegment) -> SourcePathSegment {
317 match segment {
318 PathSegment::Ident(id) => SourcePathSegment::ident(id.clone()),
319 PathSegment::Extension(id) => SourcePathSegment::extension(id.clone()),
320 PathSegment::Value(key) => SourcePathSegment {
321 key: Self::object_key_to_source_key(key),
322 array: None,
323 },
324 PathSegment::TupleIndex(idx) => SourcePathSegment {
325 key: SourceKey::TupleIndex(*idx),
326 array: None,
327 },
328 PathSegment::ArrayIndex(_) => {
329 unreachable!(
332 "ArrayIndex should be merged with previous segment, not converted directly"
333 )
334 }
335 }
336 }
337
338 fn object_key_to_source_key(key: &ObjectKey) -> SourceKey {
340 match key {
341 ObjectKey::String(s) => {
342 if let Ok(id) = s.parse::<Identifier>() {
344 SourceKey::Ident(id)
345 } else {
346 SourceKey::quoted(s.clone())
347 }
348 }
349 ObjectKey::Number(n) => {
350 if let Ok(n64) = i64::try_from(n) {
352 SourceKey::Integer(n64)
353 } else {
354 SourceKey::quoted(n.to_string())
355 }
356 }
357 ObjectKey::Tuple(keys) => {
358 SourceKey::Tuple(keys.iter().map(Self::object_key_to_source_key).collect())
359 }
360 }
361 }
362
363 fn push_binding(&mut self, mut binding: BindingSource) {
365 binding.trivia_before = std::mem::take(&mut self.pending_trivia);
367
368 match self.builder_stack.last_mut() {
369 Some(BuilderContext::SectionItems { bindings, .. }) => {
370 bindings.push(binding);
371 }
372 Some(BuilderContext::EureBlock { source_id, .. }) => {
373 self.sources[source_id.0].bindings.push(binding);
374 }
375 None => {
376 self.sources[0].bindings.push(binding);
378 }
379 }
380 }
381
382 fn push_section(&mut self, mut section: SectionSource, trivia: Vec<Trivia>) {
384 section.trivia_before = trivia;
386 self.current_source_mut().sections.push(section);
387 }
388}
389
390impl InterpreterSink for SourceConstructor {
391 type Error = InsertError;
392 type Scope = Scope;
393
394 fn begin_scope(&mut self) -> Self::Scope {
395 self.inner.begin_scope()
396 }
397
398 fn end_scope(&mut self, scope: Self::Scope) -> Result<(), Self::Error> {
399 InterpreterSink::end_scope(&mut self.inner, scope)
400 }
401
402 fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, Self::Error> {
403 if let PathSegment::ArrayIndex(idx) = &segment {
405 let last = self.pending_path.last_mut().ok_or_else(|| InsertError {
406 kind: ConstructorError::StandaloneArrayIndex.into(),
407 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
408 })?;
409 last.array = Some(*idx);
410 } else {
411 let source_segment = Self::path_segment_to_source(&segment);
412 self.pending_path.push(source_segment);
413 }
414
415 InterpreterSink::navigate(&mut self.inner, segment)
416 }
417
418 fn require_hole(&self) -> Result<(), Self::Error> {
419 self.inner.require_hole()
420 }
421
422 fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), Self::Error> {
423 self.last_bound_node = Some(self.inner.current_node_id());
424 InterpreterSink::bind_primitive(&mut self.inner, value)
425 }
426
427 fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), Self::Error> {
428 self.last_bound_node = Some(self.inner.current_node_id());
429 InterpreterSink::bind_hole(&mut self.inner, label)
430 }
431
432 fn bind_empty_map(&mut self) -> Result<(), Self::Error> {
433 self.last_bound_node = Some(self.inner.current_node_id());
434 InterpreterSink::bind_empty_map(&mut self.inner)
435 }
436
437 fn bind_empty_array(&mut self) -> Result<(), Self::Error> {
438 self.last_bound_node = Some(self.inner.current_node_id());
439 InterpreterSink::bind_empty_array(&mut self.inner)
440 }
441
442 fn bind_empty_tuple(&mut self) -> Result<(), Self::Error> {
443 self.last_bound_node = Some(self.inner.current_node_id());
444 InterpreterSink::bind_empty_tuple(&mut self.inner)
445 }
446
447 fn current_node_id(&self) -> NodeId {
448 self.inner.current_node_id()
449 }
450
451 fn current_path(&self) -> &[PathSegment] {
452 self.inner.current_path()
453 }
454
455 fn document(&self) -> &EureDocument {
456 self.inner.document()
457 }
458
459 fn document_mut(&mut self) -> &mut EureDocument {
460 self.inner.document_mut()
461 }
462
463 fn begin_eure_block(&mut self) {
468 let source_id = SourceId(self.sources.len());
470 self.sources.push(EureSource::default());
471
472 let saved_path = std::mem::take(&mut self.pending_path);
474 let saved_trivia = std::mem::take(&mut self.pending_trivia);
475
476 self.builder_stack.push(BuilderContext::EureBlock {
478 source_id,
479 saved_path,
480 saved_trivia,
481 });
482 }
483
484 fn set_block_value(&mut self) -> Result<(), Self::Error> {
485 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
487 kind: ConstructorError::MissingBindBeforeSetBlockValue.into(),
488 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
489 })?;
490 self.current_source_mut().value = Some(node_id);
491 Ok(())
492 }
493
494 fn end_eure_block(&mut self) -> Result<(), Self::Error> {
495 if !self.pending_trivia.is_empty() {
497 let source_id = match self.builder_stack.last() {
498 Some(BuilderContext::EureBlock { source_id, .. }) => *source_id,
499 _ => {
500 return Err(InsertError {
501 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
502 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
503 });
504 }
505 };
506 self.sources[source_id.0].trailing_trivia = std::mem::take(&mut self.pending_trivia);
507 }
508
509 match self.builder_stack.pop() {
511 Some(BuilderContext::EureBlock {
512 source_id,
513 saved_path,
514 saved_trivia,
515 }) => {
516 self.last_block_id = Some(source_id);
517 self.pending_path = saved_path;
519 self.pending_trivia = saved_trivia;
520 Ok(())
521 }
522 _ => Err(InsertError {
523 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
524 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
525 }),
526 }
527 }
528
529 fn begin_binding(&mut self) {
530 self.pending_path.clear();
531 }
532
533 fn end_binding_value(&mut self) -> Result<(), Self::Error> {
534 let path = std::mem::take(&mut self.pending_path);
536 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
537 kind: ConstructorError::MissingBindBeforeEndBindingValue.into(),
538 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
539 })?;
540
541 let binding = BindingSource::value(path, node_id);
542 self.push_binding(binding);
543 Ok(())
544 }
545
546 fn end_binding_block(&mut self) -> Result<(), Self::Error> {
547 let path = std::mem::take(&mut self.pending_path);
549 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
550 kind: ConstructorError::MissingEndEureBlockBeforeEndBindingBlock.into(),
551 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
552 })?;
553
554 let binding = BindingSource::block(path, source_id);
555 self.push_binding(binding);
556 Ok(())
557 }
558
559 fn begin_section(&mut self) {
560 self.pending_path.clear();
561 }
562
563 fn begin_section_items(&mut self) {
564 let path = std::mem::take(&mut self.pending_path);
566 let trivia_before = std::mem::take(&mut self.pending_trivia);
567
568 let value = self.last_bound_node.take();
570
571 self.builder_stack.push(BuilderContext::SectionItems {
572 trivia_before,
573 path,
574 value,
575 bindings: Vec::new(),
576 });
577 }
578
579 fn end_section_items(&mut self) -> Result<(), Self::Error> {
580 match self.builder_stack.pop() {
582 Some(BuilderContext::SectionItems {
583 trivia_before,
584 path,
585 value,
586 bindings,
587 }) => {
588 let section = SectionSource::items(path, value, bindings);
589 self.push_section(section, trivia_before);
590 Ok(())
591 }
592 _ => Err(InsertError {
593 kind: ConstructorError::InvalidBuilderStackForEndSectionItems.into(),
594 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
595 }),
596 }
597 }
598
599 fn end_section_block(&mut self) -> Result<(), Self::Error> {
600 let path = std::mem::take(&mut self.pending_path);
602 let trivia_before = std::mem::take(&mut self.pending_trivia);
603 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
604 kind: ConstructorError::MissingEndEureBlockBeforeEndSectionBlock.into(),
605 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
606 })?;
607
608 let section = SectionSource::block(path, source_id);
609 self.push_section(section, trivia_before);
610 Ok(())
611 }
612
613 fn comment(&mut self, comment: Comment) {
614 self.pending_trivia.push(Trivia::Comment(comment));
615 }
616
617 fn blank_line(&mut self) {
618 self.pending_trivia.push(Trivia::BlankLine);
619 }
620}
621
622#[cfg(test)]
623mod tests {
624 use super::*;
625 use crate::document::InsertErrorKind;
626 use crate::source::{BindSource, SectionBody};
627
628 fn ident(s: &str) -> Identifier {
629 s.parse().unwrap()
630 }
631
632 #[test]
637 fn test_pattern1_simple_binding() {
638 let mut constructor = SourceConstructor::new();
639
640 constructor.begin_binding();
642 let scope = constructor.begin_scope();
643 constructor
644 .navigate(PathSegment::Ident(ident("name")))
645 .unwrap();
646 constructor
647 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
648 .unwrap();
649 constructor.end_scope(scope).unwrap();
650 constructor.end_binding_value().unwrap();
651
652 let source_doc = constructor.finish();
653
654 let root = source_doc.root_source();
656 assert_eq!(root.bindings.len(), 1);
657 assert!(root.sections.is_empty());
658 assert!(root.value.is_none());
659
660 let binding = &root.bindings[0];
661 assert_eq!(binding.path.len(), 1);
662 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("name")));
663 match &binding.bind {
664 BindSource::Value(node_id) => {
665 assert!(node_id.0 > 0); }
667 _ => panic!("Expected BindSource::Value"),
668 }
669 }
670
671 #[test]
672 fn test_pattern1_nested_path() {
673 let mut constructor = SourceConstructor::new();
674
675 constructor.begin_binding();
677 let scope = constructor.begin_scope();
678 constructor
679 .navigate(PathSegment::Ident(ident("a")))
680 .unwrap();
681 constructor
682 .navigate(PathSegment::Ident(ident("b")))
683 .unwrap();
684 constructor
685 .navigate(PathSegment::Ident(ident("c")))
686 .unwrap();
687 constructor
688 .bind_primitive(PrimitiveValue::Integer(42.into()))
689 .unwrap();
690 constructor.end_scope(scope).unwrap();
691 constructor.end_binding_value().unwrap();
692
693 let source_doc = constructor.finish();
694
695 let root = source_doc.root_source();
696 assert_eq!(root.bindings.len(), 1);
697
698 let binding = &root.bindings[0];
699 assert_eq!(binding.path.len(), 3);
700 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("a")));
701 assert_eq!(binding.path[1].key, SourceKey::Ident(ident("b")));
702 assert_eq!(binding.path[2].key, SourceKey::Ident(ident("c")));
703 }
704
705 #[test]
710 fn test_pattern2_binding_block() {
711 let mut constructor = SourceConstructor::new();
712
713 constructor.begin_binding();
715 let scope = constructor.begin_scope();
716 constructor
717 .navigate(PathSegment::Ident(ident("user")))
718 .unwrap();
719 constructor.begin_eure_block();
720
721 constructor.begin_binding();
723 let inner_scope = constructor.begin_scope();
724 constructor
725 .navigate(PathSegment::Ident(ident("name")))
726 .unwrap();
727 constructor
728 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Bob")))
729 .unwrap();
730 constructor.end_scope(inner_scope).unwrap();
731 constructor.end_binding_value().unwrap();
732
733 constructor.end_eure_block().unwrap();
734 constructor.end_scope(scope).unwrap();
735 constructor.end_binding_block().unwrap();
736
737 let source_doc = constructor.finish();
738
739 let root = source_doc.root_source();
741 assert_eq!(root.bindings.len(), 1);
742
743 let binding = &root.bindings[0];
744 assert_eq!(binding.path.len(), 1);
745 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("user")));
746
747 match &binding.bind {
748 BindSource::Block(source_id) => {
749 let inner_source = source_doc.source(*source_id);
750 assert!(inner_source.value.is_none());
751 assert_eq!(inner_source.bindings.len(), 1);
752 assert_eq!(
753 inner_source.bindings[0].path[0].key,
754 SourceKey::Ident(ident("name"))
755 );
756 }
757 _ => panic!("Expected BindSource::Block"),
758 }
759 }
760
761 #[test]
766 fn test_pattern3_binding_value_block() {
767 let mut constructor = SourceConstructor::new();
768
769 constructor.begin_binding();
771 let scope = constructor.begin_scope();
772 constructor
773 .navigate(PathSegment::Ident(ident("data")))
774 .unwrap();
775 constructor.begin_eure_block();
776
777 constructor.bind_empty_array().unwrap();
779 constructor.set_block_value().unwrap();
780
781 constructor.begin_binding();
783 let inner_scope = constructor.begin_scope();
784 constructor
785 .navigate(PathSegment::Extension(ident("schema")))
786 .unwrap();
787 constructor
788 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
789 .unwrap();
790 constructor.end_scope(inner_scope).unwrap();
791 constructor.end_binding_value().unwrap();
792
793 constructor.end_eure_block().unwrap();
794 constructor.end_scope(scope).unwrap();
795 constructor.end_binding_block().unwrap();
796
797 let source_doc = constructor.finish();
798
799 let root = source_doc.root_source();
800 assert_eq!(root.bindings.len(), 1);
801
802 let binding = &root.bindings[0];
803 match &binding.bind {
804 BindSource::Block(source_id) => {
805 let inner_source = source_doc.source(*source_id);
806 assert!(inner_source.value.is_some());
808 assert_eq!(inner_source.bindings.len(), 1);
810 }
811 _ => panic!("Expected BindSource::Block"),
812 }
813 }
814
815 #[test]
820 fn test_pattern4_section_items() {
821 let mut constructor = SourceConstructor::new();
822
823 constructor.begin_section();
829 let scope = constructor.begin_scope();
830 constructor
831 .navigate(PathSegment::Ident(ident("server")))
832 .unwrap();
833 constructor.begin_section_items();
834
835 constructor.begin_binding();
837 let inner_scope1 = constructor.begin_scope();
838 constructor
839 .navigate(PathSegment::Ident(ident("host")))
840 .unwrap();
841 constructor
842 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
843 .unwrap();
844 constructor.end_scope(inner_scope1).unwrap();
845 constructor.end_binding_value().unwrap();
846
847 constructor.begin_binding();
849 let inner_scope2 = constructor.begin_scope();
850 constructor
851 .navigate(PathSegment::Ident(ident("port")))
852 .unwrap();
853 constructor
854 .bind_primitive(PrimitiveValue::Integer(8080.into()))
855 .unwrap();
856 constructor.end_scope(inner_scope2).unwrap();
857 constructor.end_binding_value().unwrap();
858
859 constructor.end_section_items().unwrap();
860 constructor.end_scope(scope).unwrap();
861
862 let source_doc = constructor.finish();
863
864 let root = source_doc.root_source();
865 assert!(root.bindings.is_empty());
866 assert_eq!(root.sections.len(), 1);
867
868 let section = &root.sections[0];
869 assert_eq!(section.path.len(), 1);
870 assert_eq!(section.path[0].key, SourceKey::Ident(ident("server")));
871
872 match §ion.body {
873 SectionBody::Items { value, bindings } => {
874 assert!(value.is_none());
875 assert_eq!(bindings.len(), 2);
876 assert_eq!(bindings[0].path[0].key, SourceKey::Ident(ident("host")));
877 assert_eq!(bindings[1].path[0].key, SourceKey::Ident(ident("port")));
878 }
879 _ => panic!("Expected SectionBody::Items"),
880 }
881 }
882
883 #[test]
888 fn test_pattern5_section_block() {
889 let mut constructor = SourceConstructor::new();
890
891 constructor.begin_section();
893 let scope = constructor.begin_scope();
894 constructor
895 .navigate(PathSegment::Ident(ident("server")))
896 .unwrap();
897 constructor.begin_eure_block();
898
899 constructor.begin_binding();
901 let inner_scope = constructor.begin_scope();
902 constructor
903 .navigate(PathSegment::Ident(ident("host")))
904 .unwrap();
905 constructor
906 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
907 .unwrap();
908 constructor.end_scope(inner_scope).unwrap();
909 constructor.end_binding_value().unwrap();
910
911 constructor.end_eure_block().unwrap();
912 constructor.end_scope(scope).unwrap();
913 constructor.end_section_block().unwrap();
914
915 let source_doc = constructor.finish();
916
917 let root = source_doc.root_source();
918 assert!(root.bindings.is_empty());
919 assert_eq!(root.sections.len(), 1);
920
921 let section = &root.sections[0];
922 match §ion.body {
923 SectionBody::Block(source_id) => {
924 let inner_source = source_doc.source(*source_id);
925 assert!(inner_source.value.is_none());
926 assert_eq!(inner_source.bindings.len(), 1);
927 }
928 _ => panic!("Expected SectionBody::Block"),
929 }
930 }
931
932 #[test]
937 fn test_pattern6_section_value_block() {
938 let mut constructor = SourceConstructor::new();
939
940 constructor.begin_section();
942 let scope = constructor.begin_scope();
943 constructor
944 .navigate(PathSegment::Ident(ident("data")))
945 .unwrap();
946 constructor.begin_eure_block();
947
948 constructor.bind_empty_array().unwrap();
950 constructor.set_block_value().unwrap();
951
952 constructor.begin_binding();
954 let inner_scope = constructor.begin_scope();
955 constructor
956 .navigate(PathSegment::Extension(ident("schema")))
957 .unwrap();
958 constructor
959 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
960 .unwrap();
961 constructor.end_scope(inner_scope).unwrap();
962 constructor.end_binding_value().unwrap();
963
964 constructor.end_eure_block().unwrap();
965 constructor.end_scope(scope).unwrap();
966 constructor.end_section_block().unwrap();
967
968 let source_doc = constructor.finish();
969
970 let root = source_doc.root_source();
971 assert_eq!(root.sections.len(), 1);
972
973 let section = &root.sections[0];
974 match §ion.body {
975 SectionBody::Block(source_id) => {
976 let inner_source = source_doc.source(*source_id);
977 assert!(inner_source.value.is_some());
979 assert_eq!(inner_source.bindings.len(), 1);
981 }
982 _ => panic!("Expected SectionBody::Block"),
983 }
984 }
985
986 #[test]
991 fn test_array_index_with_key() {
992 let mut constructor = SourceConstructor::new();
994
995 constructor.begin_binding();
996 let scope = constructor.begin_scope();
997 constructor
998 .navigate(PathSegment::Ident(ident("items")))
999 .unwrap();
1000 constructor
1001 .navigate(PathSegment::ArrayIndex(Some(0)))
1002 .unwrap();
1003 constructor
1004 .bind_primitive(PrimitiveValue::Text(Text::plaintext("first")))
1005 .unwrap();
1006 constructor.end_scope(scope).unwrap();
1007 constructor.end_binding_value().unwrap();
1008
1009 let source_doc = constructor.finish();
1010
1011 let root = source_doc.root_source();
1012 assert_eq!(root.bindings.len(), 1);
1013
1014 let binding = &root.bindings[0];
1015 assert_eq!(binding.path.len(), 1);
1017 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1018 assert_eq!(binding.path[0].array, Some(Some(0)));
1019 }
1020
1021 #[test]
1022 fn test_array_push_marker() {
1023 let mut constructor = SourceConstructor::new();
1025
1026 constructor.begin_binding();
1027 let scope = constructor.begin_scope();
1028 constructor
1029 .navigate(PathSegment::Ident(ident("items")))
1030 .unwrap();
1031 constructor.navigate(PathSegment::ArrayIndex(None)).unwrap();
1032 constructor
1033 .bind_primitive(PrimitiveValue::Text(Text::plaintext("new")))
1034 .unwrap();
1035 constructor.end_scope(scope).unwrap();
1036 constructor.end_binding_value().unwrap();
1037
1038 let source_doc = constructor.finish();
1039
1040 let root = source_doc.root_source();
1041 let binding = &root.bindings[0];
1042 assert_eq!(binding.path.len(), 1);
1043 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1044 assert_eq!(binding.path[0].array, Some(None));
1046 }
1047
1048 #[test]
1049 fn test_standalone_array_index_returns_error() {
1050 let mut constructor = SourceConstructor::new();
1052
1053 constructor.begin_binding();
1054 let _scope = constructor.begin_scope();
1055 let result = constructor.navigate(PathSegment::ArrayIndex(Some(0)));
1057 assert!(matches!(
1058 result,
1059 Err(InsertError {
1060 kind: InsertErrorKind::ConstructorError(ConstructorError::StandaloneArrayIndex),
1061 ..
1062 })
1063 ));
1064 }
1065
1066 #[test]
1071 fn test_end_binding_value_without_bind_returns_error() {
1072 let mut constructor = SourceConstructor::new();
1073
1074 constructor.begin_binding();
1075 let scope = constructor.begin_scope();
1076 constructor
1077 .navigate(PathSegment::Ident(ident("name")))
1078 .unwrap();
1079 constructor.end_scope(scope).unwrap();
1081 let result = constructor.end_binding_value();
1082 assert!(matches!(
1083 result,
1084 Err(InsertError {
1085 kind: InsertErrorKind::ConstructorError(
1086 ConstructorError::MissingBindBeforeEndBindingValue
1087 ),
1088 ..
1089 })
1090 ));
1091 }
1092
1093 #[test]
1094 fn test_set_block_value_without_bind_returns_error() {
1095 let mut constructor = SourceConstructor::new();
1096
1097 constructor.begin_binding();
1098 let _scope = constructor.begin_scope();
1099 constructor
1100 .navigate(PathSegment::Ident(ident("data")))
1101 .unwrap();
1102 constructor.begin_eure_block();
1103 let result = constructor.set_block_value();
1105 assert!(matches!(
1106 result,
1107 Err(InsertError {
1108 kind: InsertErrorKind::ConstructorError(
1109 ConstructorError::MissingBindBeforeSetBlockValue
1110 ),
1111 ..
1112 })
1113 ));
1114 }
1115
1116 #[test]
1117 fn test_end_binding_block_without_end_eure_block_returns_error() {
1118 let mut constructor = SourceConstructor::new();
1119
1120 constructor.begin_binding();
1121 let scope = constructor.begin_scope();
1122 constructor
1123 .navigate(PathSegment::Ident(ident("data")))
1124 .unwrap();
1125 constructor.end_scope(scope).unwrap();
1127 let result = constructor.end_binding_block();
1128 assert!(matches!(
1129 result,
1130 Err(InsertError {
1131 kind: InsertErrorKind::ConstructorError(
1132 ConstructorError::MissingEndEureBlockBeforeEndBindingBlock
1133 ),
1134 ..
1135 })
1136 ));
1137 }
1138
1139 #[test]
1144 fn test_multiple_bindings() {
1145 let mut constructor = SourceConstructor::new();
1146
1147 for (name, value) in [("a", 1), ("b", 2)] {
1149 constructor.begin_binding();
1150 let scope = constructor.begin_scope();
1151 constructor
1152 .navigate(PathSegment::Ident(ident(name)))
1153 .unwrap();
1154 constructor
1155 .bind_primitive(PrimitiveValue::Integer(value.into()))
1156 .unwrap();
1157 constructor.end_scope(scope).unwrap();
1158 constructor.end_binding_value().unwrap();
1159 }
1160
1161 let source_doc = constructor.finish();
1162
1163 let root = source_doc.root_source();
1164 assert_eq!(root.bindings.len(), 2);
1165 assert_eq!(root.bindings[0].path[0].key, SourceKey::Ident(ident("a")));
1166 assert_eq!(root.bindings[1].path[0].key, SourceKey::Ident(ident("b")));
1167 }
1168
1169 #[test]
1170 fn test_nested_blocks() {
1171 let mut constructor = SourceConstructor::new();
1172
1173 constructor.begin_binding();
1175 let scope1 = constructor.begin_scope();
1176 constructor
1177 .navigate(PathSegment::Ident(ident("outer")))
1178 .unwrap();
1179 constructor.begin_eure_block();
1180
1181 constructor.begin_binding();
1182 let scope2 = constructor.begin_scope();
1183 constructor
1184 .navigate(PathSegment::Ident(ident("inner")))
1185 .unwrap();
1186 constructor.begin_eure_block();
1187
1188 constructor.begin_binding();
1189 let scope3 = constructor.begin_scope();
1190 constructor
1191 .navigate(PathSegment::Ident(ident("value")))
1192 .unwrap();
1193 constructor
1194 .bind_primitive(PrimitiveValue::Integer(1.into()))
1195 .unwrap();
1196 constructor.end_scope(scope3).unwrap();
1197 constructor.end_binding_value().unwrap();
1198
1199 constructor.end_eure_block().unwrap();
1200 constructor.end_scope(scope2).unwrap();
1201 constructor.end_binding_block().unwrap();
1202
1203 constructor.end_eure_block().unwrap();
1204 constructor.end_scope(scope1).unwrap();
1205 constructor.end_binding_block().unwrap();
1206
1207 let source_doc = constructor.finish();
1208
1209 let root = source_doc.root_source();
1211 assert_eq!(root.bindings.len(), 1);
1212
1213 if let BindSource::Block(outer_id) = &root.bindings[0].bind {
1214 let outer = source_doc.source(*outer_id);
1215 assert_eq!(outer.bindings.len(), 1);
1216
1217 if let BindSource::Block(inner_id) = &outer.bindings[0].bind {
1218 let inner = source_doc.source(*inner_id);
1219 assert_eq!(inner.bindings.len(), 1);
1220 assert!(matches!(inner.bindings[0].bind, BindSource::Value(_)));
1221 } else {
1222 panic!("Expected inner block");
1223 }
1224 } else {
1225 panic!("Expected outer block");
1226 }
1227 }
1228
1229 #[test]
1234 fn test_trivia_before_binding() {
1235 let mut constructor = SourceConstructor::new();
1236
1237 constructor.comment(Comment::Line("This is a comment".to_string()));
1239 constructor.blank_line();
1240
1241 constructor.begin_binding();
1243 let scope = constructor.begin_scope();
1244 constructor
1245 .navigate(PathSegment::Ident(ident("name")))
1246 .unwrap();
1247 constructor
1248 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1249 .unwrap();
1250 constructor.end_scope(scope).unwrap();
1251 constructor.end_binding_value().unwrap();
1252
1253 let source_doc = constructor.finish();
1254
1255 let root = source_doc.root_source();
1256 assert_eq!(root.bindings.len(), 1);
1257
1258 let binding = &root.bindings[0];
1260 assert_eq!(binding.trivia_before.len(), 2);
1261 assert!(matches!(
1262 &binding.trivia_before[0],
1263 Trivia::Comment(Comment::Line(s)) if s == "This is a comment"
1264 ));
1265 assert!(matches!(&binding.trivia_before[1], Trivia::BlankLine));
1266 }
1267
1268 #[test]
1269 fn test_trivia_before_section() {
1270 let mut constructor = SourceConstructor::new();
1271
1272 constructor.blank_line();
1274
1275 constructor.begin_section();
1277 let scope = constructor.begin_scope();
1278 constructor
1279 .navigate(PathSegment::Ident(ident("server")))
1280 .unwrap();
1281 constructor.begin_section_items();
1282
1283 constructor.begin_binding();
1285 let inner_scope = constructor.begin_scope();
1286 constructor
1287 .navigate(PathSegment::Ident(ident("host")))
1288 .unwrap();
1289 constructor
1290 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
1291 .unwrap();
1292 constructor.end_scope(inner_scope).unwrap();
1293 constructor.end_binding_value().unwrap();
1294
1295 constructor.end_section_items().unwrap();
1296 constructor.end_scope(scope).unwrap();
1297
1298 let source_doc = constructor.finish();
1299
1300 let root = source_doc.root_source();
1301 assert_eq!(root.sections.len(), 1);
1302
1303 let section = &root.sections[0];
1305 assert_eq!(section.trivia_before.len(), 1);
1306 assert!(matches!(§ion.trivia_before[0], Trivia::BlankLine));
1307 }
1308
1309 #[test]
1310 fn test_trailing_trivia() {
1311 let mut constructor = SourceConstructor::new();
1312
1313 constructor.begin_binding();
1315 let scope = constructor.begin_scope();
1316 constructor
1317 .navigate(PathSegment::Ident(ident("name")))
1318 .unwrap();
1319 constructor
1320 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1321 .unwrap();
1322 constructor.end_scope(scope).unwrap();
1323 constructor.end_binding_value().unwrap();
1324
1325 constructor.blank_line();
1327 constructor.comment(Comment::Line("end of file".to_string()));
1328
1329 let source_doc = constructor.finish();
1330
1331 let root = source_doc.root_source();
1332 assert_eq!(root.trailing_trivia.len(), 2);
1333 assert!(matches!(&root.trailing_trivia[0], Trivia::BlankLine));
1334 assert!(matches!(
1335 &root.trailing_trivia[1],
1336 Trivia::Comment(Comment::Line(s)) if s == "end of file"
1337 ));
1338 }
1339
1340 #[test]
1341 fn test_trivia_between_bindings() {
1342 let mut constructor = SourceConstructor::new();
1343
1344 constructor.begin_binding();
1346 let scope1 = constructor.begin_scope();
1347 constructor
1348 .navigate(PathSegment::Ident(ident("a")))
1349 .unwrap();
1350 constructor
1351 .bind_primitive(PrimitiveValue::Integer(1.into()))
1352 .unwrap();
1353 constructor.end_scope(scope1).unwrap();
1354 constructor.end_binding_value().unwrap();
1355
1356 constructor.blank_line();
1358 constructor.comment(Comment::Line("Second binding".to_string()));
1359
1360 constructor.begin_binding();
1362 let scope2 = constructor.begin_scope();
1363 constructor
1364 .navigate(PathSegment::Ident(ident("b")))
1365 .unwrap();
1366 constructor
1367 .bind_primitive(PrimitiveValue::Integer(2.into()))
1368 .unwrap();
1369 constructor.end_scope(scope2).unwrap();
1370 constructor.end_binding_value().unwrap();
1371
1372 let source_doc = constructor.finish();
1373
1374 let root = source_doc.root_source();
1375 assert_eq!(root.bindings.len(), 2);
1376
1377 assert!(root.bindings[0].trivia_before.is_empty());
1379
1380 assert_eq!(root.bindings[1].trivia_before.len(), 2);
1382 assert!(matches!(
1383 &root.bindings[1].trivia_before[0],
1384 Trivia::BlankLine
1385 ));
1386 assert!(matches!(
1387 &root.bindings[1].trivia_before[1],
1388 Trivia::Comment(Comment::Line(s)) if s == "Second binding"
1389 ));
1390 }
1391}