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 navigate_partial_map_entry(
189 &mut self,
190 key: crate::value::PartialObjectKey,
191 ) -> Result<NodeId, InsertError> {
192 self.pending_path.push(SourcePathSegment {
193 key: Self::partial_object_key_to_source_key(&key),
194 array: None,
195 });
196 self.inner.navigate_partial_map_entry(key)
197 }
198
199 pub fn require_hole(&self) -> Result<(), InsertError> {
201 InterpreterSink::require_hole(self)
202 }
203
204 pub fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertError> {
206 InterpreterSink::bind_primitive(self, value)
207 }
208
209 pub fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), InsertError> {
211 InterpreterSink::bind_hole(self, label)
212 }
213
214 pub fn bind_empty_map(&mut self) -> Result<(), InsertError> {
216 InterpreterSink::bind_empty_map(self)
217 }
218
219 pub fn bind_empty_partial_map(&mut self) -> Result<(), InsertError> {
221 self.last_bound_node = Some(self.inner.current_node_id());
222 self.inner.bind_empty_partial_map()
223 }
224
225 pub fn bind_empty_array(&mut self) -> Result<(), InsertError> {
227 InterpreterSink::bind_empty_array(self)
228 }
229
230 pub fn bind_empty_tuple(&mut self) -> Result<(), InsertError> {
232 InterpreterSink::bind_empty_tuple(self)
233 }
234
235 pub fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), InsertError> {
237 InterpreterSink::bind_from(self, value)
238 }
239
240 pub fn current_node_id(&self) -> NodeId {
242 InterpreterSink::current_node_id(self)
243 }
244
245 pub fn current_path(&self) -> &[PathSegment] {
247 InterpreterSink::current_path(self)
248 }
249
250 pub fn document(&self) -> &EureDocument {
252 InterpreterSink::document(self)
253 }
254
255 pub fn document_mut(&mut self) -> &mut EureDocument {
257 InterpreterSink::document_mut(self)
258 }
259
260 pub fn begin_eure_block(&mut self) {
266 InterpreterSink::begin_eure_block(self)
267 }
268
269 pub fn set_block_value(&mut self) -> Result<(), InsertError> {
271 InterpreterSink::set_block_value(self)
272 }
273
274 pub fn end_eure_block(&mut self) -> Result<(), InsertError> {
276 InterpreterSink::end_eure_block(self)
277 }
278
279 pub fn begin_binding(&mut self) {
281 InterpreterSink::begin_binding(self)
282 }
283
284 pub fn end_binding_value(&mut self) -> Result<(), InsertError> {
286 InterpreterSink::end_binding_value(self)
287 }
288
289 pub fn end_binding_block(&mut self) -> Result<(), InsertError> {
291 InterpreterSink::end_binding_block(self)
292 }
293
294 pub fn begin_section(&mut self) {
296 InterpreterSink::begin_section(self)
297 }
298
299 pub fn begin_section_items(&mut self) {
301 InterpreterSink::begin_section_items(self)
302 }
303
304 pub fn end_section_items(&mut self) -> Result<(), InsertError> {
306 InterpreterSink::end_section_items(self)
307 }
308
309 pub fn end_section_block(&mut self) -> Result<(), InsertError> {
311 InterpreterSink::end_section_block(self)
312 }
313
314 pub fn comment(&mut self, comment: Comment) {
316 InterpreterSink::comment(self, comment)
317 }
318
319 pub fn blank_line(&mut self) {
321 InterpreterSink::blank_line(self)
322 }
323
324 pub fn add_trivia(&mut self, trivia: Trivia) {
326 self.pending_trivia.push(trivia);
327 }
328
329 fn path_segment_to_source(segment: &PathSegment) -> SourcePathSegment {
335 match segment {
336 PathSegment::Ident(id) => SourcePathSegment::ident(id.clone()),
337 PathSegment::Extension(id) => SourcePathSegment::extension(id.clone()),
338 PathSegment::PartialValue(key) => SourcePathSegment {
339 key: Self::partial_object_key_to_source_key(key),
340 array: None,
341 },
342 PathSegment::HoleKey(label) => SourcePathSegment {
343 key: SourceKey::hole(label.clone()),
344 array: None,
345 },
346 PathSegment::Value(key) => SourcePathSegment {
347 key: Self::object_key_to_source_key(key),
348 array: None,
349 },
350 PathSegment::TupleIndex(idx) => SourcePathSegment {
351 key: SourceKey::TupleIndex(*idx),
352 array: None,
353 },
354 PathSegment::ArrayIndex(_) => {
355 unreachable!(
358 "ArrayIndex should be merged with previous segment, not converted directly"
359 )
360 }
361 }
362 }
363
364 fn partial_object_key_to_source_key(key: &crate::value::PartialObjectKey) -> SourceKey {
365 match key {
366 crate::value::PartialObjectKey::String(s) => {
367 if let Ok(id) = s.parse::<Identifier>() {
368 SourceKey::Ident(id)
369 } else {
370 SourceKey::quoted(s.clone())
371 }
372 }
373 crate::value::PartialObjectKey::Number(n) => {
374 if let Ok(n64) = i64::try_from(n) {
375 SourceKey::Integer(n64)
376 } else {
377 SourceKey::quoted(n.to_string())
378 }
379 }
380 crate::value::PartialObjectKey::Hole(label) => SourceKey::hole(label.clone()),
381 crate::value::PartialObjectKey::Tuple(keys) => SourceKey::Tuple(
382 keys.iter()
383 .map(Self::partial_object_key_to_source_key)
384 .collect(),
385 ),
386 }
387 }
388
389 fn object_key_to_source_key(key: &ObjectKey) -> SourceKey {
391 match key {
392 ObjectKey::String(s) => {
393 if let Ok(id) = s.parse::<Identifier>() {
395 SourceKey::Ident(id)
396 } else {
397 SourceKey::quoted(s.clone())
398 }
399 }
400 ObjectKey::Number(n) => {
401 if let Ok(n64) = i64::try_from(n) {
403 SourceKey::Integer(n64)
404 } else {
405 SourceKey::quoted(n.to_string())
406 }
407 }
408 ObjectKey::Tuple(keys) => {
409 SourceKey::Tuple(keys.iter().map(Self::object_key_to_source_key).collect())
410 }
411 }
412 }
413
414 fn push_binding(&mut self, mut binding: BindingSource) {
416 binding.trivia_before = std::mem::take(&mut self.pending_trivia);
418
419 match self.builder_stack.last_mut() {
420 Some(BuilderContext::SectionItems { bindings, .. }) => {
421 bindings.push(binding);
422 }
423 Some(BuilderContext::EureBlock { source_id, .. }) => {
424 self.sources[source_id.0].bindings.push(binding);
425 }
426 None => {
427 self.sources[0].bindings.push(binding);
429 }
430 }
431 }
432
433 fn push_section(&mut self, mut section: SectionSource, trivia: Vec<Trivia>) {
435 section.trivia_before = trivia;
437 self.current_source_mut().sections.push(section);
438 }
439}
440
441impl InterpreterSink for SourceConstructor {
442 type Error = InsertError;
443 type Scope = Scope;
444
445 fn begin_scope(&mut self) -> Self::Scope {
446 self.inner.begin_scope()
447 }
448
449 fn end_scope(&mut self, scope: Self::Scope) -> Result<(), Self::Error> {
450 InterpreterSink::end_scope(&mut self.inner, scope)
451 }
452
453 fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, Self::Error> {
454 if let PathSegment::ArrayIndex(idx) = &segment {
456 let last = self.pending_path.last_mut().ok_or_else(|| InsertError {
457 kind: ConstructorError::StandaloneArrayIndex.into(),
458 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
459 })?;
460 last.array = Some(*idx);
461 } else {
462 let source_segment = Self::path_segment_to_source(&segment);
463 self.pending_path.push(source_segment);
464 }
465
466 InterpreterSink::navigate(&mut self.inner, segment)
467 }
468
469 fn require_hole(&self) -> Result<(), Self::Error> {
470 self.inner.require_hole()
471 }
472
473 fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), Self::Error> {
474 self.last_bound_node = Some(self.inner.current_node_id());
475 InterpreterSink::bind_primitive(&mut self.inner, value)
476 }
477
478 fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), Self::Error> {
479 self.last_bound_node = Some(self.inner.current_node_id());
480 InterpreterSink::bind_hole(&mut self.inner, label)
481 }
482
483 fn bind_empty_map(&mut self) -> Result<(), Self::Error> {
484 self.last_bound_node = Some(self.inner.current_node_id());
485 InterpreterSink::bind_empty_map(&mut self.inner)
486 }
487
488 fn bind_empty_array(&mut self) -> Result<(), Self::Error> {
489 self.last_bound_node = Some(self.inner.current_node_id());
490 InterpreterSink::bind_empty_array(&mut self.inner)
491 }
492
493 fn bind_empty_tuple(&mut self) -> Result<(), Self::Error> {
494 self.last_bound_node = Some(self.inner.current_node_id());
495 InterpreterSink::bind_empty_tuple(&mut self.inner)
496 }
497
498 fn current_node_id(&self) -> NodeId {
499 self.inner.current_node_id()
500 }
501
502 fn current_path(&self) -> &[PathSegment] {
503 self.inner.current_path()
504 }
505
506 fn document(&self) -> &EureDocument {
507 self.inner.document()
508 }
509
510 fn document_mut(&mut self) -> &mut EureDocument {
511 self.inner.document_mut()
512 }
513
514 fn begin_eure_block(&mut self) {
519 let source_id = SourceId(self.sources.len());
521 self.sources.push(EureSource::default());
522
523 let saved_path = std::mem::take(&mut self.pending_path);
525 let saved_trivia = std::mem::take(&mut self.pending_trivia);
526
527 self.builder_stack.push(BuilderContext::EureBlock {
529 source_id,
530 saved_path,
531 saved_trivia,
532 });
533 }
534
535 fn set_block_value(&mut self) -> Result<(), Self::Error> {
536 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
538 kind: ConstructorError::MissingBindBeforeSetBlockValue.into(),
539 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
540 })?;
541 self.current_source_mut().value = Some(node_id);
542 Ok(())
543 }
544
545 fn end_eure_block(&mut self) -> Result<(), Self::Error> {
546 if !self.pending_trivia.is_empty() {
548 let source_id = match self.builder_stack.last() {
549 Some(BuilderContext::EureBlock { source_id, .. }) => *source_id,
550 _ => {
551 return Err(InsertError {
552 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
553 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
554 });
555 }
556 };
557 self.sources[source_id.0].trailing_trivia = std::mem::take(&mut self.pending_trivia);
558 }
559
560 match self.builder_stack.pop() {
562 Some(BuilderContext::EureBlock {
563 source_id,
564 saved_path,
565 saved_trivia,
566 }) => {
567 self.last_block_id = Some(source_id);
568 self.pending_path = saved_path;
570 self.pending_trivia = saved_trivia;
571 Ok(())
572 }
573 _ => Err(InsertError {
574 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
575 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
576 }),
577 }
578 }
579
580 fn begin_binding(&mut self) {
581 self.pending_path.clear();
582 }
583
584 fn end_binding_value(&mut self) -> Result<(), Self::Error> {
585 let path = std::mem::take(&mut self.pending_path);
587 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
588 kind: ConstructorError::MissingBindBeforeEndBindingValue.into(),
589 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
590 })?;
591
592 let binding = BindingSource::value(path, node_id);
593 self.push_binding(binding);
594 Ok(())
595 }
596
597 fn end_binding_block(&mut self) -> Result<(), Self::Error> {
598 let path = std::mem::take(&mut self.pending_path);
600 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
601 kind: ConstructorError::MissingEndEureBlockBeforeEndBindingBlock.into(),
602 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
603 })?;
604
605 let binding = BindingSource::block(path, source_id);
606 self.push_binding(binding);
607 Ok(())
608 }
609
610 fn begin_section(&mut self) {
611 self.pending_path.clear();
612 }
613
614 fn begin_section_items(&mut self) {
615 let path = std::mem::take(&mut self.pending_path);
617 let trivia_before = std::mem::take(&mut self.pending_trivia);
618
619 let value = self.last_bound_node.take();
621
622 self.builder_stack.push(BuilderContext::SectionItems {
623 trivia_before,
624 path,
625 value,
626 bindings: Vec::new(),
627 });
628 }
629
630 fn end_section_items(&mut self) -> Result<(), Self::Error> {
631 match self.builder_stack.pop() {
633 Some(BuilderContext::SectionItems {
634 trivia_before,
635 path,
636 value,
637 bindings,
638 }) => {
639 let section = SectionSource::items(path, value, bindings);
640 self.push_section(section, trivia_before);
641 Ok(())
642 }
643 _ => Err(InsertError {
644 kind: ConstructorError::InvalidBuilderStackForEndSectionItems.into(),
645 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
646 }),
647 }
648 }
649
650 fn end_section_block(&mut self) -> Result<(), Self::Error> {
651 let path = std::mem::take(&mut self.pending_path);
653 let trivia_before = std::mem::take(&mut self.pending_trivia);
654 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
655 kind: ConstructorError::MissingEndEureBlockBeforeEndSectionBlock.into(),
656 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
657 })?;
658
659 let section = SectionSource::block(path, source_id);
660 self.push_section(section, trivia_before);
661 Ok(())
662 }
663
664 fn comment(&mut self, comment: Comment) {
665 self.pending_trivia.push(Trivia::Comment(comment));
666 }
667
668 fn blank_line(&mut self) {
669 self.pending_trivia.push(Trivia::BlankLine);
670 }
671}
672
673#[cfg(test)]
674mod tests {
675 use super::*;
676 use crate::document::InsertErrorKind;
677 use crate::source::{BindSource, SectionBody};
678
679 fn ident(s: &str) -> Identifier {
680 s.parse().unwrap()
681 }
682
683 #[test]
688 fn test_pattern1_simple_binding() {
689 let mut constructor = SourceConstructor::new();
690
691 constructor.begin_binding();
693 let scope = constructor.begin_scope();
694 constructor
695 .navigate(PathSegment::Ident(ident("name")))
696 .unwrap();
697 constructor
698 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
699 .unwrap();
700 constructor.end_scope(scope).unwrap();
701 constructor.end_binding_value().unwrap();
702
703 let source_doc = constructor.finish();
704
705 let root = source_doc.root_source();
707 assert_eq!(root.bindings.len(), 1);
708 assert!(root.sections.is_empty());
709 assert!(root.value.is_none());
710
711 let binding = &root.bindings[0];
712 assert_eq!(binding.path.len(), 1);
713 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("name")));
714 match &binding.bind {
715 BindSource::Value(node_id) => {
716 assert!(node_id.0 > 0); }
718 _ => panic!("Expected BindSource::Value"),
719 }
720 }
721
722 #[test]
723 fn test_pattern1_nested_path() {
724 let mut constructor = SourceConstructor::new();
725
726 constructor.begin_binding();
728 let scope = constructor.begin_scope();
729 constructor
730 .navigate(PathSegment::Ident(ident("a")))
731 .unwrap();
732 constructor
733 .navigate(PathSegment::Ident(ident("b")))
734 .unwrap();
735 constructor
736 .navigate(PathSegment::Ident(ident("c")))
737 .unwrap();
738 constructor
739 .bind_primitive(PrimitiveValue::Integer(42.into()))
740 .unwrap();
741 constructor.end_scope(scope).unwrap();
742 constructor.end_binding_value().unwrap();
743
744 let source_doc = constructor.finish();
745
746 let root = source_doc.root_source();
747 assert_eq!(root.bindings.len(), 1);
748
749 let binding = &root.bindings[0];
750 assert_eq!(binding.path.len(), 3);
751 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("a")));
752 assert_eq!(binding.path[1].key, SourceKey::Ident(ident("b")));
753 assert_eq!(binding.path[2].key, SourceKey::Ident(ident("c")));
754 }
755
756 #[test]
761 fn test_pattern2_binding_block() {
762 let mut constructor = SourceConstructor::new();
763
764 constructor.begin_binding();
766 let scope = constructor.begin_scope();
767 constructor
768 .navigate(PathSegment::Ident(ident("user")))
769 .unwrap();
770 constructor.begin_eure_block();
771
772 constructor.begin_binding();
774 let inner_scope = constructor.begin_scope();
775 constructor
776 .navigate(PathSegment::Ident(ident("name")))
777 .unwrap();
778 constructor
779 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Bob")))
780 .unwrap();
781 constructor.end_scope(inner_scope).unwrap();
782 constructor.end_binding_value().unwrap();
783
784 constructor.end_eure_block().unwrap();
785 constructor.end_scope(scope).unwrap();
786 constructor.end_binding_block().unwrap();
787
788 let source_doc = constructor.finish();
789
790 let root = source_doc.root_source();
792 assert_eq!(root.bindings.len(), 1);
793
794 let binding = &root.bindings[0];
795 assert_eq!(binding.path.len(), 1);
796 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("user")));
797
798 match &binding.bind {
799 BindSource::Block(source_id) => {
800 let inner_source = source_doc.source(*source_id);
801 assert!(inner_source.value.is_none());
802 assert_eq!(inner_source.bindings.len(), 1);
803 assert_eq!(
804 inner_source.bindings[0].path[0].key,
805 SourceKey::Ident(ident("name"))
806 );
807 }
808 _ => panic!("Expected BindSource::Block"),
809 }
810 }
811
812 #[test]
817 fn test_pattern3_binding_value_block() {
818 let mut constructor = SourceConstructor::new();
819
820 constructor.begin_binding();
822 let scope = constructor.begin_scope();
823 constructor
824 .navigate(PathSegment::Ident(ident("data")))
825 .unwrap();
826 constructor.begin_eure_block();
827
828 constructor.bind_empty_array().unwrap();
830 constructor.set_block_value().unwrap();
831
832 constructor.begin_binding();
834 let inner_scope = constructor.begin_scope();
835 constructor
836 .navigate(PathSegment::Extension(ident("schema")))
837 .unwrap();
838 constructor
839 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
840 .unwrap();
841 constructor.end_scope(inner_scope).unwrap();
842 constructor.end_binding_value().unwrap();
843
844 constructor.end_eure_block().unwrap();
845 constructor.end_scope(scope).unwrap();
846 constructor.end_binding_block().unwrap();
847
848 let source_doc = constructor.finish();
849
850 let root = source_doc.root_source();
851 assert_eq!(root.bindings.len(), 1);
852
853 let binding = &root.bindings[0];
854 match &binding.bind {
855 BindSource::Block(source_id) => {
856 let inner_source = source_doc.source(*source_id);
857 assert!(inner_source.value.is_some());
859 assert_eq!(inner_source.bindings.len(), 1);
861 }
862 _ => panic!("Expected BindSource::Block"),
863 }
864 }
865
866 #[test]
871 fn test_pattern4_section_items() {
872 let mut constructor = SourceConstructor::new();
873
874 constructor.begin_section();
880 let scope = constructor.begin_scope();
881 constructor
882 .navigate(PathSegment::Ident(ident("server")))
883 .unwrap();
884 constructor.begin_section_items();
885
886 constructor.begin_binding();
888 let inner_scope1 = constructor.begin_scope();
889 constructor
890 .navigate(PathSegment::Ident(ident("host")))
891 .unwrap();
892 constructor
893 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
894 .unwrap();
895 constructor.end_scope(inner_scope1).unwrap();
896 constructor.end_binding_value().unwrap();
897
898 constructor.begin_binding();
900 let inner_scope2 = constructor.begin_scope();
901 constructor
902 .navigate(PathSegment::Ident(ident("port")))
903 .unwrap();
904 constructor
905 .bind_primitive(PrimitiveValue::Integer(8080.into()))
906 .unwrap();
907 constructor.end_scope(inner_scope2).unwrap();
908 constructor.end_binding_value().unwrap();
909
910 constructor.end_section_items().unwrap();
911 constructor.end_scope(scope).unwrap();
912
913 let source_doc = constructor.finish();
914
915 let root = source_doc.root_source();
916 assert!(root.bindings.is_empty());
917 assert_eq!(root.sections.len(), 1);
918
919 let section = &root.sections[0];
920 assert_eq!(section.path.len(), 1);
921 assert_eq!(section.path[0].key, SourceKey::Ident(ident("server")));
922
923 match §ion.body {
924 SectionBody::Items { value, bindings } => {
925 assert!(value.is_none());
926 assert_eq!(bindings.len(), 2);
927 assert_eq!(bindings[0].path[0].key, SourceKey::Ident(ident("host")));
928 assert_eq!(bindings[1].path[0].key, SourceKey::Ident(ident("port")));
929 }
930 _ => panic!("Expected SectionBody::Items"),
931 }
932 }
933
934 #[test]
939 fn test_pattern5_section_block() {
940 let mut constructor = SourceConstructor::new();
941
942 constructor.begin_section();
944 let scope = constructor.begin_scope();
945 constructor
946 .navigate(PathSegment::Ident(ident("server")))
947 .unwrap();
948 constructor.begin_eure_block();
949
950 constructor.begin_binding();
952 let inner_scope = constructor.begin_scope();
953 constructor
954 .navigate(PathSegment::Ident(ident("host")))
955 .unwrap();
956 constructor
957 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
958 .unwrap();
959 constructor.end_scope(inner_scope).unwrap();
960 constructor.end_binding_value().unwrap();
961
962 constructor.end_eure_block().unwrap();
963 constructor.end_scope(scope).unwrap();
964 constructor.end_section_block().unwrap();
965
966 let source_doc = constructor.finish();
967
968 let root = source_doc.root_source();
969 assert!(root.bindings.is_empty());
970 assert_eq!(root.sections.len(), 1);
971
972 let section = &root.sections[0];
973 match §ion.body {
974 SectionBody::Block(source_id) => {
975 let inner_source = source_doc.source(*source_id);
976 assert!(inner_source.value.is_none());
977 assert_eq!(inner_source.bindings.len(), 1);
978 }
979 _ => panic!("Expected SectionBody::Block"),
980 }
981 }
982
983 #[test]
988 fn test_pattern6_section_value_block() {
989 let mut constructor = SourceConstructor::new();
990
991 constructor.begin_section();
993 let scope = constructor.begin_scope();
994 constructor
995 .navigate(PathSegment::Ident(ident("data")))
996 .unwrap();
997 constructor.begin_eure_block();
998
999 constructor.bind_empty_array().unwrap();
1001 constructor.set_block_value().unwrap();
1002
1003 constructor.begin_binding();
1005 let inner_scope = constructor.begin_scope();
1006 constructor
1007 .navigate(PathSegment::Extension(ident("schema")))
1008 .unwrap();
1009 constructor
1010 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
1011 .unwrap();
1012 constructor.end_scope(inner_scope).unwrap();
1013 constructor.end_binding_value().unwrap();
1014
1015 constructor.end_eure_block().unwrap();
1016 constructor.end_scope(scope).unwrap();
1017 constructor.end_section_block().unwrap();
1018
1019 let source_doc = constructor.finish();
1020
1021 let root = source_doc.root_source();
1022 assert_eq!(root.sections.len(), 1);
1023
1024 let section = &root.sections[0];
1025 match §ion.body {
1026 SectionBody::Block(source_id) => {
1027 let inner_source = source_doc.source(*source_id);
1028 assert!(inner_source.value.is_some());
1030 assert_eq!(inner_source.bindings.len(), 1);
1032 }
1033 _ => panic!("Expected SectionBody::Block"),
1034 }
1035 }
1036
1037 #[test]
1042 fn test_array_index_with_key() {
1043 let mut constructor = SourceConstructor::new();
1045
1046 constructor.begin_binding();
1047 let scope = constructor.begin_scope();
1048 constructor
1049 .navigate(PathSegment::Ident(ident("items")))
1050 .unwrap();
1051 constructor
1052 .navigate(PathSegment::ArrayIndex(Some(0)))
1053 .unwrap();
1054 constructor
1055 .bind_primitive(PrimitiveValue::Text(Text::plaintext("first")))
1056 .unwrap();
1057 constructor.end_scope(scope).unwrap();
1058 constructor.end_binding_value().unwrap();
1059
1060 let source_doc = constructor.finish();
1061
1062 let root = source_doc.root_source();
1063 assert_eq!(root.bindings.len(), 1);
1064
1065 let binding = &root.bindings[0];
1066 assert_eq!(binding.path.len(), 1);
1068 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1069 assert_eq!(binding.path[0].array, Some(Some(0)));
1070 }
1071
1072 #[test]
1073 fn test_array_push_marker() {
1074 let mut constructor = SourceConstructor::new();
1076
1077 constructor.begin_binding();
1078 let scope = constructor.begin_scope();
1079 constructor
1080 .navigate(PathSegment::Ident(ident("items")))
1081 .unwrap();
1082 constructor.navigate(PathSegment::ArrayIndex(None)).unwrap();
1083 constructor
1084 .bind_primitive(PrimitiveValue::Text(Text::plaintext("new")))
1085 .unwrap();
1086 constructor.end_scope(scope).unwrap();
1087 constructor.end_binding_value().unwrap();
1088
1089 let source_doc = constructor.finish();
1090
1091 let root = source_doc.root_source();
1092 let binding = &root.bindings[0];
1093 assert_eq!(binding.path.len(), 1);
1094 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1095 assert_eq!(binding.path[0].array, Some(None));
1097 }
1098
1099 #[test]
1100 fn test_standalone_array_index_returns_error() {
1101 let mut constructor = SourceConstructor::new();
1103
1104 constructor.begin_binding();
1105 let _scope = constructor.begin_scope();
1106 let result = constructor.navigate(PathSegment::ArrayIndex(Some(0)));
1108 assert!(matches!(
1109 result,
1110 Err(InsertError {
1111 kind: InsertErrorKind::ConstructorError(ConstructorError::StandaloneArrayIndex),
1112 ..
1113 })
1114 ));
1115 }
1116
1117 #[test]
1122 fn test_end_binding_value_without_bind_returns_error() {
1123 let mut constructor = SourceConstructor::new();
1124
1125 constructor.begin_binding();
1126 let scope = constructor.begin_scope();
1127 constructor
1128 .navigate(PathSegment::Ident(ident("name")))
1129 .unwrap();
1130 constructor.end_scope(scope).unwrap();
1132 let result = constructor.end_binding_value();
1133 assert!(matches!(
1134 result,
1135 Err(InsertError {
1136 kind: InsertErrorKind::ConstructorError(
1137 ConstructorError::MissingBindBeforeEndBindingValue
1138 ),
1139 ..
1140 })
1141 ));
1142 }
1143
1144 #[test]
1145 fn test_set_block_value_without_bind_returns_error() {
1146 let mut constructor = SourceConstructor::new();
1147
1148 constructor.begin_binding();
1149 let _scope = constructor.begin_scope();
1150 constructor
1151 .navigate(PathSegment::Ident(ident("data")))
1152 .unwrap();
1153 constructor.begin_eure_block();
1154 let result = constructor.set_block_value();
1156 assert!(matches!(
1157 result,
1158 Err(InsertError {
1159 kind: InsertErrorKind::ConstructorError(
1160 ConstructorError::MissingBindBeforeSetBlockValue
1161 ),
1162 ..
1163 })
1164 ));
1165 }
1166
1167 #[test]
1168 fn test_end_binding_block_without_end_eure_block_returns_error() {
1169 let mut constructor = SourceConstructor::new();
1170
1171 constructor.begin_binding();
1172 let scope = constructor.begin_scope();
1173 constructor
1174 .navigate(PathSegment::Ident(ident("data")))
1175 .unwrap();
1176 constructor.end_scope(scope).unwrap();
1178 let result = constructor.end_binding_block();
1179 assert!(matches!(
1180 result,
1181 Err(InsertError {
1182 kind: InsertErrorKind::ConstructorError(
1183 ConstructorError::MissingEndEureBlockBeforeEndBindingBlock
1184 ),
1185 ..
1186 })
1187 ));
1188 }
1189
1190 #[test]
1195 fn test_multiple_bindings() {
1196 let mut constructor = SourceConstructor::new();
1197
1198 for (name, value) in [("a", 1), ("b", 2)] {
1200 constructor.begin_binding();
1201 let scope = constructor.begin_scope();
1202 constructor
1203 .navigate(PathSegment::Ident(ident(name)))
1204 .unwrap();
1205 constructor
1206 .bind_primitive(PrimitiveValue::Integer(value.into()))
1207 .unwrap();
1208 constructor.end_scope(scope).unwrap();
1209 constructor.end_binding_value().unwrap();
1210 }
1211
1212 let source_doc = constructor.finish();
1213
1214 let root = source_doc.root_source();
1215 assert_eq!(root.bindings.len(), 2);
1216 assert_eq!(root.bindings[0].path[0].key, SourceKey::Ident(ident("a")));
1217 assert_eq!(root.bindings[1].path[0].key, SourceKey::Ident(ident("b")));
1218 }
1219
1220 #[test]
1221 fn test_nested_blocks() {
1222 let mut constructor = SourceConstructor::new();
1223
1224 constructor.begin_binding();
1226 let scope1 = constructor.begin_scope();
1227 constructor
1228 .navigate(PathSegment::Ident(ident("outer")))
1229 .unwrap();
1230 constructor.begin_eure_block();
1231
1232 constructor.begin_binding();
1233 let scope2 = constructor.begin_scope();
1234 constructor
1235 .navigate(PathSegment::Ident(ident("inner")))
1236 .unwrap();
1237 constructor.begin_eure_block();
1238
1239 constructor.begin_binding();
1240 let scope3 = constructor.begin_scope();
1241 constructor
1242 .navigate(PathSegment::Ident(ident("value")))
1243 .unwrap();
1244 constructor
1245 .bind_primitive(PrimitiveValue::Integer(1.into()))
1246 .unwrap();
1247 constructor.end_scope(scope3).unwrap();
1248 constructor.end_binding_value().unwrap();
1249
1250 constructor.end_eure_block().unwrap();
1251 constructor.end_scope(scope2).unwrap();
1252 constructor.end_binding_block().unwrap();
1253
1254 constructor.end_eure_block().unwrap();
1255 constructor.end_scope(scope1).unwrap();
1256 constructor.end_binding_block().unwrap();
1257
1258 let source_doc = constructor.finish();
1259
1260 let root = source_doc.root_source();
1262 assert_eq!(root.bindings.len(), 1);
1263
1264 if let BindSource::Block(outer_id) = &root.bindings[0].bind {
1265 let outer = source_doc.source(*outer_id);
1266 assert_eq!(outer.bindings.len(), 1);
1267
1268 if let BindSource::Block(inner_id) = &outer.bindings[0].bind {
1269 let inner = source_doc.source(*inner_id);
1270 assert_eq!(inner.bindings.len(), 1);
1271 assert!(matches!(inner.bindings[0].bind, BindSource::Value(_)));
1272 } else {
1273 panic!("Expected inner block");
1274 }
1275 } else {
1276 panic!("Expected outer block");
1277 }
1278 }
1279
1280 #[test]
1285 fn test_trivia_before_binding() {
1286 let mut constructor = SourceConstructor::new();
1287
1288 constructor.comment(Comment::Line("This is a comment".to_string()));
1290 constructor.blank_line();
1291
1292 constructor.begin_binding();
1294 let scope = constructor.begin_scope();
1295 constructor
1296 .navigate(PathSegment::Ident(ident("name")))
1297 .unwrap();
1298 constructor
1299 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1300 .unwrap();
1301 constructor.end_scope(scope).unwrap();
1302 constructor.end_binding_value().unwrap();
1303
1304 let source_doc = constructor.finish();
1305
1306 let root = source_doc.root_source();
1307 assert_eq!(root.bindings.len(), 1);
1308
1309 let binding = &root.bindings[0];
1311 assert_eq!(binding.trivia_before.len(), 2);
1312 assert!(matches!(
1313 &binding.trivia_before[0],
1314 Trivia::Comment(Comment::Line(s)) if s == "This is a comment"
1315 ));
1316 assert!(matches!(&binding.trivia_before[1], Trivia::BlankLine));
1317 }
1318
1319 #[test]
1320 fn test_trivia_before_section() {
1321 let mut constructor = SourceConstructor::new();
1322
1323 constructor.blank_line();
1325
1326 constructor.begin_section();
1328 let scope = constructor.begin_scope();
1329 constructor
1330 .navigate(PathSegment::Ident(ident("server")))
1331 .unwrap();
1332 constructor.begin_section_items();
1333
1334 constructor.begin_binding();
1336 let inner_scope = constructor.begin_scope();
1337 constructor
1338 .navigate(PathSegment::Ident(ident("host")))
1339 .unwrap();
1340 constructor
1341 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
1342 .unwrap();
1343 constructor.end_scope(inner_scope).unwrap();
1344 constructor.end_binding_value().unwrap();
1345
1346 constructor.end_section_items().unwrap();
1347 constructor.end_scope(scope).unwrap();
1348
1349 let source_doc = constructor.finish();
1350
1351 let root = source_doc.root_source();
1352 assert_eq!(root.sections.len(), 1);
1353
1354 let section = &root.sections[0];
1356 assert_eq!(section.trivia_before.len(), 1);
1357 assert!(matches!(§ion.trivia_before[0], Trivia::BlankLine));
1358 }
1359
1360 #[test]
1361 fn test_trailing_trivia() {
1362 let mut constructor = SourceConstructor::new();
1363
1364 constructor.begin_binding();
1366 let scope = constructor.begin_scope();
1367 constructor
1368 .navigate(PathSegment::Ident(ident("name")))
1369 .unwrap();
1370 constructor
1371 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1372 .unwrap();
1373 constructor.end_scope(scope).unwrap();
1374 constructor.end_binding_value().unwrap();
1375
1376 constructor.blank_line();
1378 constructor.comment(Comment::Line("end of file".to_string()));
1379
1380 let source_doc = constructor.finish();
1381
1382 let root = source_doc.root_source();
1383 assert_eq!(root.trailing_trivia.len(), 2);
1384 assert!(matches!(&root.trailing_trivia[0], Trivia::BlankLine));
1385 assert!(matches!(
1386 &root.trailing_trivia[1],
1387 Trivia::Comment(Comment::Line(s)) if s == "end of file"
1388 ));
1389 }
1390
1391 #[test]
1392 fn test_trivia_between_bindings() {
1393 let mut constructor = SourceConstructor::new();
1394
1395 constructor.begin_binding();
1397 let scope1 = constructor.begin_scope();
1398 constructor
1399 .navigate(PathSegment::Ident(ident("a")))
1400 .unwrap();
1401 constructor
1402 .bind_primitive(PrimitiveValue::Integer(1.into()))
1403 .unwrap();
1404 constructor.end_scope(scope1).unwrap();
1405 constructor.end_binding_value().unwrap();
1406
1407 constructor.blank_line();
1409 constructor.comment(Comment::Line("Second binding".to_string()));
1410
1411 constructor.begin_binding();
1413 let scope2 = constructor.begin_scope();
1414 constructor
1415 .navigate(PathSegment::Ident(ident("b")))
1416 .unwrap();
1417 constructor
1418 .bind_primitive(PrimitiveValue::Integer(2.into()))
1419 .unwrap();
1420 constructor.end_scope(scope2).unwrap();
1421 constructor.end_binding_value().unwrap();
1422
1423 let source_doc = constructor.finish();
1424
1425 let root = source_doc.root_source();
1426 assert_eq!(root.bindings.len(), 2);
1427
1428 assert!(root.bindings[0].trivia_before.is_empty());
1430
1431 assert_eq!(root.bindings[1].trivia_before.len(), 2);
1433 assert!(matches!(
1434 &root.bindings[1].trivia_before[0],
1435 Trivia::BlankLine
1436 ));
1437 assert!(matches!(
1438 &root.bindings[1].trivia_before[1],
1439 Trivia::Comment(Comment::Line(s)) if s == "Second binding"
1440 ));
1441 }
1442}