1use crate::document::constructor::{DocumentConstructor, Scope as InnerScope};
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
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56enum PendingPathContext {
57 Binding,
58 Section,
59}
60
61pub struct SourceConstructor {
98 inner: DocumentConstructor,
100
101 sources: Vec<EureSource>,
103
104 builder_stack: Vec<BuilderContext>,
106
107 pending_path: Vec<SourcePathSegment>,
109
110 pending_trivia: Vec<Trivia>,
112
113 last_bound_node: Option<NodeId>,
115
116 last_block_id: Option<SourceId>,
118
119 skip_path_restore_for_next_scope: bool,
122
123 suspended_path_tracking: usize,
125
126 pending_path_context: Option<PendingPathContext>,
128}
129
130#[derive(Debug, Clone)]
136pub struct Scope {
137 inner: InnerScope,
138 pending_path: SourcePath,
139 restore_pending_path: bool,
140}
141
142impl Default for SourceConstructor {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl SourceConstructor {
149 #[must_use]
151 pub fn new() -> Self {
152 let sources = vec![EureSource::default()];
154
155 Self {
156 inner: DocumentConstructor::new(),
157 sources,
158 builder_stack: vec![BuilderContext::EureBlock {
159 source_id: SourceId(0),
160 saved_path: Vec::new(),
161 saved_trivia: Vec::new(),
162 }],
163 pending_path: Vec::new(),
164 pending_trivia: Vec::new(),
165 last_bound_node: None,
166 last_block_id: None,
167 skip_path_restore_for_next_scope: false,
168 suspended_path_tracking: 0,
169 pending_path_context: None,
170 }
171 }
172
173 #[must_use]
175 pub fn finish(mut self) -> SourceDocument {
176 if !self.pending_trivia.is_empty() {
178 self.sources[0].trailing_trivia = std::mem::take(&mut self.pending_trivia);
179 }
180 SourceDocument::new(self.inner.finish(), self.sources)
181 }
182
183 fn current_source_mut(&mut self) -> &mut EureSource {
187 for ctx in self.builder_stack.iter().rev() {
188 if let BuilderContext::EureBlock { source_id, .. } = ctx {
189 return &mut self.sources[source_id.0];
190 }
191 }
192 &mut self.sources[0]
194 }
195
196 pub fn begin_scope(&mut self) -> Scope {
205 InterpreterSink::begin_scope(self)
206 }
207
208 pub fn end_scope(&mut self, scope: Scope) -> Result<(), InsertError> {
210 InterpreterSink::end_scope(self, scope)
211 }
212
213 pub fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, InsertError> {
215 InterpreterSink::navigate(self, segment)
216 }
217
218 pub fn navigate_partial_map_entry(
220 &mut self,
221 key: crate::value::PartialObjectKey,
222 ) -> Result<NodeId, InsertError> {
223 self.pending_path.push(SourcePathSegment {
224 key: Self::partial_object_key_to_source_key(&key),
225 array: None,
226 });
227 self.inner.navigate_partial_map_entry(key)
228 }
229
230 pub fn require_hole(&self) -> Result<(), InsertError> {
232 InterpreterSink::require_hole(self)
233 }
234
235 pub fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertError> {
237 InterpreterSink::bind_primitive(self, value)
238 }
239
240 pub fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), InsertError> {
242 InterpreterSink::bind_hole(self, label)
243 }
244
245 pub fn bind_empty_map(&mut self) -> Result<(), InsertError> {
247 InterpreterSink::bind_empty_map(self)
248 }
249
250 pub fn bind_empty_partial_map(&mut self) -> Result<(), InsertError> {
252 self.last_bound_node = Some(self.inner.current_node_id());
253 self.inner.bind_empty_partial_map()
254 }
255
256 pub fn bind_empty_array(&mut self) -> Result<(), InsertError> {
258 InterpreterSink::bind_empty_array(self)
259 }
260
261 pub fn bind_empty_tuple(&mut self) -> Result<(), InsertError> {
263 InterpreterSink::bind_empty_tuple(self)
264 }
265
266 pub fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), InsertError> {
268 InterpreterSink::bind_from(self, value)
269 }
270
271 pub fn current_node_id(&self) -> NodeId {
273 InterpreterSink::current_node_id(self)
274 }
275
276 pub fn current_path(&self) -> &[PathSegment] {
278 InterpreterSink::current_path(self)
279 }
280
281 pub fn current_node(&self) -> &crate::document::node::Node {
283 self.inner.current_node()
284 }
285
286 pub fn current_node_mut(&mut self) -> &mut crate::document::node::Node {
288 self.inner.current_node_mut()
289 }
290
291 pub fn set_last_bound_node(&mut self, node_id: NodeId) {
293 self.last_bound_node = Some(node_id);
294 }
295
296 pub fn clone_pending_path(&self) -> SourcePath {
298 self.pending_path.clone()
299 }
300
301 pub fn set_pending_path(&mut self, path: SourcePath) {
303 self.pending_path = path;
304 }
305
306 pub fn suspend_path_tracking(&mut self) {
308 self.suspended_path_tracking += 1;
309 }
310
311 pub fn resume_path_tracking(&mut self) {
313 self.suspended_path_tracking = self.suspended_path_tracking.saturating_sub(1);
314 }
315
316 pub fn document(&self) -> &EureDocument {
318 InterpreterSink::document(self)
319 }
320
321 pub fn document_mut(&mut self) -> &mut EureDocument {
323 InterpreterSink::document_mut(self)
324 }
325
326 pub fn begin_eure_block(&mut self) {
332 InterpreterSink::begin_eure_block(self)
333 }
334
335 pub fn set_block_value(&mut self) -> Result<(), InsertError> {
337 InterpreterSink::set_block_value(self)
338 }
339
340 pub fn end_eure_block(&mut self) -> Result<(), InsertError> {
342 InterpreterSink::end_eure_block(self)
343 }
344
345 pub fn begin_binding(&mut self) {
347 InterpreterSink::begin_binding(self)
348 }
349
350 pub fn end_binding_value(&mut self) -> Result<(), InsertError> {
352 InterpreterSink::end_binding_value(self)
353 }
354
355 pub fn end_binding_block(&mut self) -> Result<(), InsertError> {
357 InterpreterSink::end_binding_block(self)
358 }
359
360 pub fn begin_section(&mut self) {
362 InterpreterSink::begin_section(self)
363 }
364
365 pub fn begin_section_items(&mut self) {
367 InterpreterSink::begin_section_items(self)
368 }
369
370 pub fn end_section_items(&mut self) -> Result<(), InsertError> {
372 InterpreterSink::end_section_items(self)
373 }
374
375 pub fn end_section_block(&mut self) -> Result<(), InsertError> {
377 InterpreterSink::end_section_block(self)
378 }
379
380 pub fn comment(&mut self, comment: Comment) {
382 InterpreterSink::comment(self, comment)
383 }
384
385 pub fn blank_line(&mut self) {
387 InterpreterSink::blank_line(self)
388 }
389
390 pub fn add_trivia(&mut self, trivia: Trivia) {
392 self.pending_trivia.push(trivia);
393 }
394
395 fn path_segment_to_source(segment: &PathSegment) -> SourcePathSegment {
401 match segment {
402 PathSegment::Ident(id) => SourcePathSegment::ident(id.clone()),
403 PathSegment::Extension(id) => SourcePathSegment::extension(id.clone()),
404 PathSegment::PartialValue(key) => SourcePathSegment {
405 key: Self::partial_object_key_to_source_key(key),
406 array: None,
407 },
408 PathSegment::HoleKey(label) => SourcePathSegment {
409 key: SourceKey::hole(label.clone()),
410 array: None,
411 },
412 PathSegment::Value(key) => SourcePathSegment {
413 key: Self::object_key_to_source_key(key),
414 array: None,
415 },
416 PathSegment::TupleIndex(idx) => SourcePathSegment {
417 key: SourceKey::TupleIndex(*idx),
418 array: None,
419 },
420 PathSegment::ArrayIndex(_) => {
421 unreachable!(
424 "ArrayIndex should be merged with previous segment, not converted directly"
425 )
426 }
427 }
428 }
429
430 fn partial_object_key_to_source_key(key: &crate::value::PartialObjectKey) -> SourceKey {
431 match key {
432 crate::value::PartialObjectKey::String(s) => {
433 if let Ok(id) = s.parse::<Identifier>() {
434 SourceKey::Ident(id)
435 } else {
436 SourceKey::quoted(s.clone())
437 }
438 }
439 crate::value::PartialObjectKey::Number(n) => {
440 if let Ok(n64) = i64::try_from(n) {
441 SourceKey::Integer(n64)
442 } else {
443 SourceKey::quoted(n.to_string())
444 }
445 }
446 crate::value::PartialObjectKey::Hole(label) => SourceKey::hole(label.clone()),
447 crate::value::PartialObjectKey::Tuple(keys) => SourceKey::Tuple(
448 keys.iter()
449 .map(Self::partial_object_key_to_source_key)
450 .collect(),
451 ),
452 }
453 }
454
455 fn object_key_to_source_key(key: &ObjectKey) -> SourceKey {
457 match key {
458 ObjectKey::String(s) => {
459 if let Ok(id) = s.parse::<Identifier>() {
461 SourceKey::Ident(id)
462 } else {
463 SourceKey::quoted(s.clone())
464 }
465 }
466 ObjectKey::Number(n) => {
467 if let Ok(n64) = i64::try_from(n) {
469 SourceKey::Integer(n64)
470 } else {
471 SourceKey::quoted(n.to_string())
472 }
473 }
474 ObjectKey::Tuple(keys) => {
475 SourceKey::Tuple(keys.iter().map(Self::object_key_to_source_key).collect())
476 }
477 }
478 }
479
480 fn push_binding(&mut self, mut binding: BindingSource) {
482 binding.trivia_before = std::mem::take(&mut self.pending_trivia);
484
485 match self.builder_stack.last_mut() {
486 Some(BuilderContext::SectionItems { bindings, .. }) => {
487 bindings.push(binding);
488 }
489 Some(BuilderContext::EureBlock { source_id, .. }) => {
490 self.sources[source_id.0].bindings.push(binding);
491 }
492 None => {
493 self.sources[0].bindings.push(binding);
495 }
496 }
497 }
498
499 fn push_section(&mut self, mut section: SectionSource, trivia: Vec<Trivia>) {
501 section.trivia_before = trivia;
503 self.current_source_mut().sections.push(section);
504 }
505}
506
507impl InterpreterSink for SourceConstructor {
508 type Error = InsertError;
509 type Scope = Scope;
510
511 fn begin_scope(&mut self) -> Self::Scope {
512 let restore_pending_path = !self.skip_path_restore_for_next_scope;
513 self.skip_path_restore_for_next_scope = false;
514 Scope {
515 inner: self.inner.begin_scope(),
516 pending_path: self.pending_path.clone(),
517 restore_pending_path,
518 }
519 }
520
521 fn end_scope(&mut self, scope: Self::Scope) -> Result<(), Self::Error> {
522 if scope.restore_pending_path {
523 self.pending_path = scope.pending_path;
524 }
525 InterpreterSink::end_scope(&mut self.inner, scope.inner)
526 }
527
528 fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, Self::Error> {
529 if self.suspended_path_tracking == 0 {
530 if let PathSegment::ArrayIndex(idx) = &segment {
532 if let Some(last) = self.pending_path.last_mut() {
533 last.array = Some(*idx);
534 } else {
535 let in_section_items = matches!(
536 self.builder_stack.last(),
537 Some(BuilderContext::SectionItems { .. })
538 );
539 let in_section_header =
540 self.pending_path_context == Some(PendingPathContext::Section);
541 if in_section_items || in_section_header {
542 self.pending_path.push(SourcePathSegment::root_array(*idx));
543 } else {
544 return Err(InsertError {
545 kind: ConstructorError::StandaloneArrayIndex.into(),
546 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
547 });
548 }
549 }
550 } else {
551 let source_segment = Self::path_segment_to_source(&segment);
552 self.pending_path.push(source_segment);
553 }
554 }
555
556 InterpreterSink::navigate(&mut self.inner, segment)
557 }
558
559 fn require_hole(&self) -> Result<(), Self::Error> {
560 self.inner.require_hole()
561 }
562
563 fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), Self::Error> {
564 self.last_bound_node = Some(self.inner.current_node_id());
565 InterpreterSink::bind_primitive(&mut self.inner, value)
566 }
567
568 fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), Self::Error> {
569 self.last_bound_node = Some(self.inner.current_node_id());
570 InterpreterSink::bind_hole(&mut self.inner, label)
571 }
572
573 fn bind_empty_map(&mut self) -> Result<(), Self::Error> {
574 self.last_bound_node = Some(self.inner.current_node_id());
575 InterpreterSink::bind_empty_map(&mut self.inner)
576 }
577
578 fn bind_empty_array(&mut self) -> Result<(), Self::Error> {
579 self.last_bound_node = Some(self.inner.current_node_id());
580 InterpreterSink::bind_empty_array(&mut self.inner)
581 }
582
583 fn bind_empty_tuple(&mut self) -> Result<(), Self::Error> {
584 self.last_bound_node = Some(self.inner.current_node_id());
585 InterpreterSink::bind_empty_tuple(&mut self.inner)
586 }
587
588 fn current_node_id(&self) -> NodeId {
589 self.inner.current_node_id()
590 }
591
592 fn current_path(&self) -> &[PathSegment] {
593 self.inner.current_path()
594 }
595
596 fn document(&self) -> &EureDocument {
597 self.inner.document()
598 }
599
600 fn document_mut(&mut self) -> &mut EureDocument {
601 self.inner.document_mut()
602 }
603
604 fn begin_eure_block(&mut self) {
609 let source_id = SourceId(self.sources.len());
611 self.sources.push(EureSource::default());
612
613 let saved_path = std::mem::take(&mut self.pending_path);
615 let saved_trivia = std::mem::take(&mut self.pending_trivia);
616
617 self.builder_stack.push(BuilderContext::EureBlock {
619 source_id,
620 saved_path,
621 saved_trivia,
622 });
623 }
624
625 fn set_block_value(&mut self) -> Result<(), Self::Error> {
626 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
628 kind: ConstructorError::MissingBindBeforeSetBlockValue.into(),
629 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
630 })?;
631 self.current_source_mut().value = Some(node_id);
632 Ok(())
633 }
634
635 fn end_eure_block(&mut self) -> Result<(), Self::Error> {
636 if !self.pending_trivia.is_empty() {
638 let source_id = match self.builder_stack.last() {
639 Some(BuilderContext::EureBlock { source_id, .. }) => *source_id,
640 _ => {
641 return Err(InsertError {
642 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
643 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
644 });
645 }
646 };
647 self.sources[source_id.0].trailing_trivia = std::mem::take(&mut self.pending_trivia);
648 }
649
650 match self.builder_stack.pop() {
652 Some(BuilderContext::EureBlock {
653 source_id,
654 saved_path,
655 saved_trivia,
656 }) => {
657 self.last_block_id = Some(source_id);
658 self.pending_path = saved_path;
660 self.pending_trivia = saved_trivia;
661 Ok(())
662 }
663 _ => Err(InsertError {
664 kind: ConstructorError::InvalidBuilderStackForEndEureBlock.into(),
665 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
666 }),
667 }
668 }
669
670 fn begin_binding(&mut self) {
671 self.pending_path.clear();
672 self.pending_path_context = Some(PendingPathContext::Binding);
673 self.skip_path_restore_for_next_scope = true;
674 }
675
676 fn end_binding_value(&mut self) -> Result<(), Self::Error> {
677 let path = std::mem::take(&mut self.pending_path);
679 let node_id = self.last_bound_node.take().ok_or_else(|| InsertError {
680 kind: ConstructorError::MissingBindBeforeEndBindingValue.into(),
681 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
682 })?;
683
684 let binding = BindingSource::value(path, node_id);
685 self.push_binding(binding);
686 self.pending_path_context = None;
687 Ok(())
688 }
689
690 fn end_binding_block(&mut self) -> Result<(), Self::Error> {
691 let path = std::mem::take(&mut self.pending_path);
693 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
694 kind: ConstructorError::MissingEndEureBlockBeforeEndBindingBlock.into(),
695 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
696 })?;
697
698 let binding = BindingSource::block(path, source_id);
699 self.push_binding(binding);
700 self.pending_path_context = None;
701 Ok(())
702 }
703
704 fn begin_section(&mut self) {
705 self.pending_path.clear();
706 self.pending_path_context = Some(PendingPathContext::Section);
707 self.skip_path_restore_for_next_scope = true;
708 }
709
710 fn begin_section_items(&mut self) {
711 let path = std::mem::take(&mut self.pending_path);
713 let trivia_before = std::mem::take(&mut self.pending_trivia);
714
715 let value = self.last_bound_node.take();
717
718 self.builder_stack.push(BuilderContext::SectionItems {
719 trivia_before,
720 path,
721 value,
722 bindings: Vec::new(),
723 });
724 self.pending_path_context = None;
725 }
726
727 fn end_section_items(&mut self) -> Result<(), Self::Error> {
728 match self.builder_stack.pop() {
730 Some(BuilderContext::SectionItems {
731 trivia_before,
732 path,
733 value,
734 bindings,
735 }) => {
736 let section = SectionSource::items(path, value, bindings);
737 self.push_section(section, trivia_before);
738 Ok(())
739 }
740 _ => Err(InsertError {
741 kind: ConstructorError::InvalidBuilderStackForEndSectionItems.into(),
742 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
743 }),
744 }
745 }
746
747 fn end_section_block(&mut self) -> Result<(), Self::Error> {
748 let path = std::mem::take(&mut self.pending_path);
750 let trivia_before = std::mem::take(&mut self.pending_trivia);
751 let source_id = self.last_block_id.take().ok_or_else(|| InsertError {
752 kind: ConstructorError::MissingEndEureBlockBeforeEndSectionBlock.into(),
753 path: EurePath::from_iter(self.inner.current_path().iter().cloned()),
754 })?;
755
756 let section = SectionSource::block(path, source_id);
757 self.push_section(section, trivia_before);
758 self.pending_path_context = None;
759 Ok(())
760 }
761
762 fn comment(&mut self, comment: Comment) {
763 self.pending_trivia.push(Trivia::Comment(comment));
764 }
765
766 fn blank_line(&mut self) {
767 self.pending_trivia.push(Trivia::BlankLine);
768 }
769}
770
771#[cfg(test)]
772mod tests {
773 use super::*;
774 use crate::document::InsertErrorKind;
775 use crate::path::ArrayIndexKind;
776 use crate::source::{BindSource, SectionBody};
777
778 fn ident(s: &str) -> Identifier {
779 s.parse().unwrap()
780 }
781
782 #[test]
787 fn test_pattern1_simple_binding() {
788 let mut constructor = SourceConstructor::new();
789
790 constructor.begin_binding();
792 let scope = constructor.begin_scope();
793 constructor
794 .navigate(PathSegment::Ident(ident("name")))
795 .unwrap();
796 constructor
797 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
798 .unwrap();
799 constructor.end_scope(scope).unwrap();
800 constructor.end_binding_value().unwrap();
801
802 let source_doc = constructor.finish();
803
804 let root = source_doc.root_source();
806 assert_eq!(root.bindings.len(), 1);
807 assert!(root.sections.is_empty());
808 assert!(root.value.is_none());
809
810 let binding = &root.bindings[0];
811 assert_eq!(binding.path.len(), 1);
812 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("name")));
813 match &binding.bind {
814 BindSource::Value(node_id) => {
815 assert!(node_id.0 > 0); }
817 _ => panic!("Expected BindSource::Value"),
818 }
819 }
820
821 #[test]
822 fn test_pattern1_nested_path() {
823 let mut constructor = SourceConstructor::new();
824
825 constructor.begin_binding();
827 let scope = constructor.begin_scope();
828 constructor
829 .navigate(PathSegment::Ident(ident("a")))
830 .unwrap();
831 constructor
832 .navigate(PathSegment::Ident(ident("b")))
833 .unwrap();
834 constructor
835 .navigate(PathSegment::Ident(ident("c")))
836 .unwrap();
837 constructor
838 .bind_primitive(PrimitiveValue::Integer(42.into()))
839 .unwrap();
840 constructor.end_scope(scope).unwrap();
841 constructor.end_binding_value().unwrap();
842
843 let source_doc = constructor.finish();
844
845 let root = source_doc.root_source();
846 assert_eq!(root.bindings.len(), 1);
847
848 let binding = &root.bindings[0];
849 assert_eq!(binding.path.len(), 3);
850 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("a")));
851 assert_eq!(binding.path[1].key, SourceKey::Ident(ident("b")));
852 assert_eq!(binding.path[2].key, SourceKey::Ident(ident("c")));
853 }
854
855 #[test]
860 fn test_pattern2_binding_block() {
861 let mut constructor = SourceConstructor::new();
862
863 constructor.begin_binding();
865 let scope = constructor.begin_scope();
866 constructor
867 .navigate(PathSegment::Ident(ident("user")))
868 .unwrap();
869 constructor.begin_eure_block();
870
871 constructor.begin_binding();
873 let inner_scope = constructor.begin_scope();
874 constructor
875 .navigate(PathSegment::Ident(ident("name")))
876 .unwrap();
877 constructor
878 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Bob")))
879 .unwrap();
880 constructor.end_scope(inner_scope).unwrap();
881 constructor.end_binding_value().unwrap();
882
883 constructor.end_eure_block().unwrap();
884 constructor.end_scope(scope).unwrap();
885 constructor.end_binding_block().unwrap();
886
887 let source_doc = constructor.finish();
888
889 let root = source_doc.root_source();
891 assert_eq!(root.bindings.len(), 1);
892
893 let binding = &root.bindings[0];
894 assert_eq!(binding.path.len(), 1);
895 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("user")));
896
897 match &binding.bind {
898 BindSource::Block(source_id) => {
899 let inner_source = source_doc.source(*source_id);
900 assert!(inner_source.value.is_none());
901 assert_eq!(inner_source.bindings.len(), 1);
902 assert_eq!(
903 inner_source.bindings[0].path[0].key,
904 SourceKey::Ident(ident("name"))
905 );
906 }
907 _ => panic!("Expected BindSource::Block"),
908 }
909 }
910
911 #[test]
916 fn test_pattern3_binding_value_block() {
917 let mut constructor = SourceConstructor::new();
918
919 constructor.begin_binding();
921 let scope = constructor.begin_scope();
922 constructor
923 .navigate(PathSegment::Ident(ident("data")))
924 .unwrap();
925 constructor.begin_eure_block();
926
927 constructor.bind_empty_array().unwrap();
929 constructor.set_block_value().unwrap();
930
931 constructor.begin_binding();
933 let inner_scope = constructor.begin_scope();
934 constructor
935 .navigate(PathSegment::Extension(ident("schema")))
936 .unwrap();
937 constructor
938 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
939 .unwrap();
940 constructor.end_scope(inner_scope).unwrap();
941 constructor.end_binding_value().unwrap();
942
943 constructor.end_eure_block().unwrap();
944 constructor.end_scope(scope).unwrap();
945 constructor.end_binding_block().unwrap();
946
947 let source_doc = constructor.finish();
948
949 let root = source_doc.root_source();
950 assert_eq!(root.bindings.len(), 1);
951
952 let binding = &root.bindings[0];
953 match &binding.bind {
954 BindSource::Block(source_id) => {
955 let inner_source = source_doc.source(*source_id);
956 assert!(inner_source.value.is_some());
958 assert_eq!(inner_source.bindings.len(), 1);
960 }
961 _ => panic!("Expected BindSource::Block"),
962 }
963 }
964
965 #[test]
970 fn test_pattern4_section_items() {
971 let mut constructor = SourceConstructor::new();
972
973 constructor.begin_section();
979 let scope = constructor.begin_scope();
980 constructor
981 .navigate(PathSegment::Ident(ident("server")))
982 .unwrap();
983 constructor.begin_section_items();
984
985 constructor.begin_binding();
987 let inner_scope1 = constructor.begin_scope();
988 constructor
989 .navigate(PathSegment::Ident(ident("host")))
990 .unwrap();
991 constructor
992 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
993 .unwrap();
994 constructor.end_scope(inner_scope1).unwrap();
995 constructor.end_binding_value().unwrap();
996
997 constructor.begin_binding();
999 let inner_scope2 = constructor.begin_scope();
1000 constructor
1001 .navigate(PathSegment::Ident(ident("port")))
1002 .unwrap();
1003 constructor
1004 .bind_primitive(PrimitiveValue::Integer(8080.into()))
1005 .unwrap();
1006 constructor.end_scope(inner_scope2).unwrap();
1007 constructor.end_binding_value().unwrap();
1008
1009 constructor.end_section_items().unwrap();
1010 constructor.end_scope(scope).unwrap();
1011
1012 let source_doc = constructor.finish();
1013
1014 let root = source_doc.root_source();
1015 assert!(root.bindings.is_empty());
1016 assert_eq!(root.sections.len(), 1);
1017
1018 let section = &root.sections[0];
1019 assert_eq!(section.path.len(), 1);
1020 assert_eq!(section.path[0].key, SourceKey::Ident(ident("server")));
1021
1022 match §ion.body {
1023 SectionBody::Items { value, bindings } => {
1024 assert!(value.is_none());
1025 assert_eq!(bindings.len(), 2);
1026 assert_eq!(bindings[0].path[0].key, SourceKey::Ident(ident("host")));
1027 assert_eq!(bindings[1].path[0].key, SourceKey::Ident(ident("port")));
1028 }
1029 _ => panic!("Expected SectionBody::Items"),
1030 }
1031 }
1032
1033 #[test]
1034 fn test_pattern4_root_array_section_items() {
1035 let mut constructor = SourceConstructor::new();
1036
1037 constructor.begin_section();
1042 let scope = constructor.begin_scope();
1043 constructor
1044 .navigate(PathSegment::ArrayIndex(ArrayIndexKind::Push))
1045 .unwrap();
1046 constructor.begin_section_items();
1047
1048 constructor.begin_binding();
1049 let inner_scope = constructor.begin_scope();
1050 constructor
1051 .navigate(PathSegment::Ident(ident("a")))
1052 .unwrap();
1053 constructor
1054 .bind_primitive(PrimitiveValue::Integer(1.into()))
1055 .unwrap();
1056 constructor.end_scope(inner_scope).unwrap();
1057 constructor.end_binding_value().unwrap();
1058
1059 constructor.end_section_items().unwrap();
1060 constructor.end_scope(scope).unwrap();
1061
1062 let source_doc = constructor.finish();
1063 let root = source_doc.root_source();
1064 assert_eq!(root.sections.len(), 1);
1065
1066 let section = &root.sections[0];
1067 assert_eq!(section.path.len(), 1);
1068 assert_eq!(section.path[0].key, SourceKey::Root);
1069 assert_eq!(section.path[0].array, Some(ArrayIndexKind::Push));
1070 }
1071
1072 #[test]
1077 fn test_pattern5_section_block() {
1078 let mut constructor = SourceConstructor::new();
1079
1080 constructor.begin_section();
1082 let scope = constructor.begin_scope();
1083 constructor
1084 .navigate(PathSegment::Ident(ident("server")))
1085 .unwrap();
1086 constructor.begin_eure_block();
1087
1088 constructor.begin_binding();
1090 let inner_scope = constructor.begin_scope();
1091 constructor
1092 .navigate(PathSegment::Ident(ident("host")))
1093 .unwrap();
1094 constructor
1095 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
1096 .unwrap();
1097 constructor.end_scope(inner_scope).unwrap();
1098 constructor.end_binding_value().unwrap();
1099
1100 constructor.end_eure_block().unwrap();
1101 constructor.end_scope(scope).unwrap();
1102 constructor.end_section_block().unwrap();
1103
1104 let source_doc = constructor.finish();
1105
1106 let root = source_doc.root_source();
1107 assert!(root.bindings.is_empty());
1108 assert_eq!(root.sections.len(), 1);
1109
1110 let section = &root.sections[0];
1111 match §ion.body {
1112 SectionBody::Block(source_id) => {
1113 let inner_source = source_doc.source(*source_id);
1114 assert!(inner_source.value.is_none());
1115 assert_eq!(inner_source.bindings.len(), 1);
1116 }
1117 _ => panic!("Expected SectionBody::Block"),
1118 }
1119 }
1120
1121 #[test]
1126 fn test_pattern6_section_value_block() {
1127 let mut constructor = SourceConstructor::new();
1128
1129 constructor.begin_section();
1131 let scope = constructor.begin_scope();
1132 constructor
1133 .navigate(PathSegment::Ident(ident("data")))
1134 .unwrap();
1135 constructor.begin_eure_block();
1136
1137 constructor.bind_empty_array().unwrap();
1139 constructor.set_block_value().unwrap();
1140
1141 constructor.begin_binding();
1143 let inner_scope = constructor.begin_scope();
1144 constructor
1145 .navigate(PathSegment::Extension(ident("schema")))
1146 .unwrap();
1147 constructor
1148 .bind_primitive(PrimitiveValue::Text(Text::plaintext("array")))
1149 .unwrap();
1150 constructor.end_scope(inner_scope).unwrap();
1151 constructor.end_binding_value().unwrap();
1152
1153 constructor.end_eure_block().unwrap();
1154 constructor.end_scope(scope).unwrap();
1155 constructor.end_section_block().unwrap();
1156
1157 let source_doc = constructor.finish();
1158
1159 let root = source_doc.root_source();
1160 assert_eq!(root.sections.len(), 1);
1161
1162 let section = &root.sections[0];
1163 match §ion.body {
1164 SectionBody::Block(source_id) => {
1165 let inner_source = source_doc.source(*source_id);
1166 assert!(inner_source.value.is_some());
1168 assert_eq!(inner_source.bindings.len(), 1);
1170 }
1171 _ => panic!("Expected SectionBody::Block"),
1172 }
1173 }
1174
1175 #[test]
1180 fn test_array_index_with_key() {
1181 let mut constructor = SourceConstructor::new();
1183
1184 constructor.begin_binding();
1185 let scope = constructor.begin_scope();
1186 constructor
1187 .navigate(PathSegment::Ident(ident("items")))
1188 .unwrap();
1189 constructor
1190 .navigate(PathSegment::ArrayIndex(ArrayIndexKind::Specific(0)))
1191 .unwrap();
1192 constructor
1193 .bind_primitive(PrimitiveValue::Text(Text::plaintext("first")))
1194 .unwrap();
1195 constructor.end_scope(scope).unwrap();
1196 constructor.end_binding_value().unwrap();
1197
1198 let source_doc = constructor.finish();
1199
1200 let root = source_doc.root_source();
1201 assert_eq!(root.bindings.len(), 1);
1202
1203 let binding = &root.bindings[0];
1204 assert_eq!(binding.path.len(), 1);
1206 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1207 assert_eq!(binding.path[0].array, Some(ArrayIndexKind::Specific(0)));
1208 }
1209
1210 #[test]
1211 fn test_array_push_marker() {
1212 let mut constructor = SourceConstructor::new();
1214
1215 constructor.begin_binding();
1216 let scope = constructor.begin_scope();
1217 constructor
1218 .navigate(PathSegment::Ident(ident("items")))
1219 .unwrap();
1220 constructor
1221 .navigate(PathSegment::ArrayIndex(ArrayIndexKind::Push))
1222 .unwrap();
1223 constructor
1224 .bind_primitive(PrimitiveValue::Text(Text::plaintext("new")))
1225 .unwrap();
1226 constructor.end_scope(scope).unwrap();
1227 constructor.end_binding_value().unwrap();
1228
1229 let source_doc = constructor.finish();
1230
1231 let root = source_doc.root_source();
1232 let binding = &root.bindings[0];
1233 assert_eq!(binding.path.len(), 1);
1234 assert_eq!(binding.path[0].key, SourceKey::Ident(ident("items")));
1235 assert_eq!(binding.path[0].array, Some(ArrayIndexKind::Push));
1237 }
1238
1239 #[test]
1240 fn test_standalone_array_index_returns_error() {
1241 let mut constructor = SourceConstructor::new();
1243
1244 constructor.begin_binding();
1245 let _scope = constructor.begin_scope();
1246 let result = constructor.navigate(PathSegment::ArrayIndex(ArrayIndexKind::Specific(0)));
1248 assert!(matches!(
1249 result,
1250 Err(InsertError {
1251 kind: InsertErrorKind::ConstructorError(ConstructorError::StandaloneArrayIndex),
1252 ..
1253 })
1254 ));
1255 }
1256
1257 #[test]
1262 fn test_end_binding_value_without_bind_returns_error() {
1263 let mut constructor = SourceConstructor::new();
1264
1265 constructor.begin_binding();
1266 let scope = constructor.begin_scope();
1267 constructor
1268 .navigate(PathSegment::Ident(ident("name")))
1269 .unwrap();
1270 constructor.end_scope(scope).unwrap();
1272 let result = constructor.end_binding_value();
1273 assert!(matches!(
1274 result,
1275 Err(InsertError {
1276 kind: InsertErrorKind::ConstructorError(
1277 ConstructorError::MissingBindBeforeEndBindingValue
1278 ),
1279 ..
1280 })
1281 ));
1282 }
1283
1284 #[test]
1285 fn test_set_block_value_without_bind_returns_error() {
1286 let mut constructor = SourceConstructor::new();
1287
1288 constructor.begin_binding();
1289 let _scope = constructor.begin_scope();
1290 constructor
1291 .navigate(PathSegment::Ident(ident("data")))
1292 .unwrap();
1293 constructor.begin_eure_block();
1294 let result = constructor.set_block_value();
1296 assert!(matches!(
1297 result,
1298 Err(InsertError {
1299 kind: InsertErrorKind::ConstructorError(
1300 ConstructorError::MissingBindBeforeSetBlockValue
1301 ),
1302 ..
1303 })
1304 ));
1305 }
1306
1307 #[test]
1308 fn test_end_binding_block_without_end_eure_block_returns_error() {
1309 let mut constructor = SourceConstructor::new();
1310
1311 constructor.begin_binding();
1312 let scope = constructor.begin_scope();
1313 constructor
1314 .navigate(PathSegment::Ident(ident("data")))
1315 .unwrap();
1316 constructor.end_scope(scope).unwrap();
1318 let result = constructor.end_binding_block();
1319 assert!(matches!(
1320 result,
1321 Err(InsertError {
1322 kind: InsertErrorKind::ConstructorError(
1323 ConstructorError::MissingEndEureBlockBeforeEndBindingBlock
1324 ),
1325 ..
1326 })
1327 ));
1328 }
1329
1330 #[test]
1335 fn test_multiple_bindings() {
1336 let mut constructor = SourceConstructor::new();
1337
1338 for (name, value) in [("a", 1), ("b", 2)] {
1340 constructor.begin_binding();
1341 let scope = constructor.begin_scope();
1342 constructor
1343 .navigate(PathSegment::Ident(ident(name)))
1344 .unwrap();
1345 constructor
1346 .bind_primitive(PrimitiveValue::Integer(value.into()))
1347 .unwrap();
1348 constructor.end_scope(scope).unwrap();
1349 constructor.end_binding_value().unwrap();
1350 }
1351
1352 let source_doc = constructor.finish();
1353
1354 let root = source_doc.root_source();
1355 assert_eq!(root.bindings.len(), 2);
1356 assert_eq!(root.bindings[0].path[0].key, SourceKey::Ident(ident("a")));
1357 assert_eq!(root.bindings[1].path[0].key, SourceKey::Ident(ident("b")));
1358 }
1359
1360 #[test]
1361 fn test_nested_blocks() {
1362 let mut constructor = SourceConstructor::new();
1363
1364 constructor.begin_binding();
1366 let scope1 = constructor.begin_scope();
1367 constructor
1368 .navigate(PathSegment::Ident(ident("outer")))
1369 .unwrap();
1370 constructor.begin_eure_block();
1371
1372 constructor.begin_binding();
1373 let scope2 = constructor.begin_scope();
1374 constructor
1375 .navigate(PathSegment::Ident(ident("inner")))
1376 .unwrap();
1377 constructor.begin_eure_block();
1378
1379 constructor.begin_binding();
1380 let scope3 = constructor.begin_scope();
1381 constructor
1382 .navigate(PathSegment::Ident(ident("value")))
1383 .unwrap();
1384 constructor
1385 .bind_primitive(PrimitiveValue::Integer(1.into()))
1386 .unwrap();
1387 constructor.end_scope(scope3).unwrap();
1388 constructor.end_binding_value().unwrap();
1389
1390 constructor.end_eure_block().unwrap();
1391 constructor.end_scope(scope2).unwrap();
1392 constructor.end_binding_block().unwrap();
1393
1394 constructor.end_eure_block().unwrap();
1395 constructor.end_scope(scope1).unwrap();
1396 constructor.end_binding_block().unwrap();
1397
1398 let source_doc = constructor.finish();
1399
1400 let root = source_doc.root_source();
1402 assert_eq!(root.bindings.len(), 1);
1403
1404 if let BindSource::Block(outer_id) = &root.bindings[0].bind {
1405 let outer = source_doc.source(*outer_id);
1406 assert_eq!(outer.bindings.len(), 1);
1407
1408 if let BindSource::Block(inner_id) = &outer.bindings[0].bind {
1409 let inner = source_doc.source(*inner_id);
1410 assert_eq!(inner.bindings.len(), 1);
1411 assert!(matches!(inner.bindings[0].bind, BindSource::Value(_)));
1412 } else {
1413 panic!("Expected inner block");
1414 }
1415 } else {
1416 panic!("Expected outer block");
1417 }
1418 }
1419
1420 #[test]
1425 fn test_trivia_before_binding() {
1426 let mut constructor = SourceConstructor::new();
1427
1428 constructor.comment(Comment::Line("This is a comment".to_string()));
1430 constructor.blank_line();
1431
1432 constructor.begin_binding();
1434 let scope = constructor.begin_scope();
1435 constructor
1436 .navigate(PathSegment::Ident(ident("name")))
1437 .unwrap();
1438 constructor
1439 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1440 .unwrap();
1441 constructor.end_scope(scope).unwrap();
1442 constructor.end_binding_value().unwrap();
1443
1444 let source_doc = constructor.finish();
1445
1446 let root = source_doc.root_source();
1447 assert_eq!(root.bindings.len(), 1);
1448
1449 let binding = &root.bindings[0];
1451 assert_eq!(binding.trivia_before.len(), 2);
1452 assert!(matches!(
1453 &binding.trivia_before[0],
1454 Trivia::Comment(Comment::Line(s)) if s == "This is a comment"
1455 ));
1456 assert!(matches!(&binding.trivia_before[1], Trivia::BlankLine));
1457 }
1458
1459 #[test]
1460 fn test_trivia_before_section() {
1461 let mut constructor = SourceConstructor::new();
1462
1463 constructor.blank_line();
1465
1466 constructor.begin_section();
1468 let scope = constructor.begin_scope();
1469 constructor
1470 .navigate(PathSegment::Ident(ident("server")))
1471 .unwrap();
1472 constructor.begin_section_items();
1473
1474 constructor.begin_binding();
1476 let inner_scope = constructor.begin_scope();
1477 constructor
1478 .navigate(PathSegment::Ident(ident("host")))
1479 .unwrap();
1480 constructor
1481 .bind_primitive(PrimitiveValue::Text(Text::plaintext("localhost")))
1482 .unwrap();
1483 constructor.end_scope(inner_scope).unwrap();
1484 constructor.end_binding_value().unwrap();
1485
1486 constructor.end_section_items().unwrap();
1487 constructor.end_scope(scope).unwrap();
1488
1489 let source_doc = constructor.finish();
1490
1491 let root = source_doc.root_source();
1492 assert_eq!(root.sections.len(), 1);
1493
1494 let section = &root.sections[0];
1496 assert_eq!(section.trivia_before.len(), 1);
1497 assert!(matches!(§ion.trivia_before[0], Trivia::BlankLine));
1498 }
1499
1500 #[test]
1501 fn test_trailing_trivia() {
1502 let mut constructor = SourceConstructor::new();
1503
1504 constructor.begin_binding();
1506 let scope = constructor.begin_scope();
1507 constructor
1508 .navigate(PathSegment::Ident(ident("name")))
1509 .unwrap();
1510 constructor
1511 .bind_primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
1512 .unwrap();
1513 constructor.end_scope(scope).unwrap();
1514 constructor.end_binding_value().unwrap();
1515
1516 constructor.blank_line();
1518 constructor.comment(Comment::Line("end of file".to_string()));
1519
1520 let source_doc = constructor.finish();
1521
1522 let root = source_doc.root_source();
1523 assert_eq!(root.trailing_trivia.len(), 2);
1524 assert!(matches!(&root.trailing_trivia[0], Trivia::BlankLine));
1525 assert!(matches!(
1526 &root.trailing_trivia[1],
1527 Trivia::Comment(Comment::Line(s)) if s == "end of file"
1528 ));
1529 }
1530
1531 #[test]
1532 fn test_trivia_between_bindings() {
1533 let mut constructor = SourceConstructor::new();
1534
1535 constructor.begin_binding();
1537 let scope1 = constructor.begin_scope();
1538 constructor
1539 .navigate(PathSegment::Ident(ident("a")))
1540 .unwrap();
1541 constructor
1542 .bind_primitive(PrimitiveValue::Integer(1.into()))
1543 .unwrap();
1544 constructor.end_scope(scope1).unwrap();
1545 constructor.end_binding_value().unwrap();
1546
1547 constructor.blank_line();
1549 constructor.comment(Comment::Line("Second binding".to_string()));
1550
1551 constructor.begin_binding();
1553 let scope2 = constructor.begin_scope();
1554 constructor
1555 .navigate(PathSegment::Ident(ident("b")))
1556 .unwrap();
1557 constructor
1558 .bind_primitive(PrimitiveValue::Integer(2.into()))
1559 .unwrap();
1560 constructor.end_scope(scope2).unwrap();
1561 constructor.end_binding_value().unwrap();
1562
1563 let source_doc = constructor.finish();
1564
1565 let root = source_doc.root_source();
1566 assert_eq!(root.bindings.len(), 2);
1567
1568 assert!(root.bindings[0].trivia_before.is_empty());
1570
1571 assert_eq!(root.bindings[1].trivia_before.len(), 2);
1573 assert!(matches!(
1574 &root.bindings[1].trivia_before[0],
1575 Trivia::BlankLine
1576 ));
1577 assert!(matches!(
1578 &root.bindings[1].trivia_before[1],
1579 Trivia::Comment(Comment::Line(s)) if s == "Second binding"
1580 ));
1581 }
1582}