eure_document/document/
constructor.rs1use crate::prelude_internal::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Scope {
8 id: usize,
9 stack_depth: usize,
10 path_depth: usize,
11}
12
13#[derive(Debug, PartialEq, thiserror::Error, Clone)]
14pub enum ScopeError {
15 #[error("Cannot end scope at root")]
16 CannotEndAtRoot,
17 #[error("Scope must be ended in LIFO order (most recent first)")]
18 NotMostRecentScope,
19}
20
21pub struct DocumentConstructor {
22 document: EureDocument,
23 path: Vec<PathSegment>,
25 stack: Vec<NodeId>,
27 scope_counter: usize,
29 outstanding_scopes: Vec<usize>,
31}
32
33impl Default for DocumentConstructor {
34 fn default() -> Self {
35 let document = EureDocument::default();
36 let root = document.get_root_id();
37 Self {
38 document,
39 path: vec![],
40 stack: vec![root],
41 scope_counter: 0,
42 outstanding_scopes: vec![],
43 }
44 }
45}
46
47impl DocumentConstructor {
48 pub fn new() -> Self {
49 Self::default()
50 }
51
52 pub fn current_node_id(&self) -> NodeId {
53 *self.stack.last().expect("Stack should never be empty")
54 }
55
56 pub fn current_node(&self) -> &Node {
57 self.document.node(self.current_node_id())
58 }
59
60 pub fn current_node_mut(&mut self) -> &mut Node {
61 self.document.node_mut(self.current_node_id())
62 }
63
64 pub fn current_path(&self) -> &[PathSegment] {
65 &self.path
66 }
67
68 pub fn document(&self) -> &EureDocument {
69 &self.document
70 }
71
72 pub fn document_mut(&mut self) -> &mut EureDocument {
73 &mut self.document
74 }
75
76 pub fn finish(mut self) -> EureDocument {
77 let root_id = self.document.get_root_id();
79 let root_node = self.document.node_mut(root_id);
80 if root_node.content.is_hole() {
81 root_node.content = NodeValue::Map(Default::default());
82 }
83 self.document
84 }
85}
86
87impl DocumentConstructor {
88 pub fn begin_scope(&mut self) -> Scope {
91 let id = self.scope_counter;
92 self.scope_counter += 1;
93 self.outstanding_scopes.push(id);
94 Scope {
95 id,
96 stack_depth: self.stack.len(),
97 path_depth: self.path.len(),
98 }
99 }
100
101 pub fn end_scope(&mut self, scope: Scope) -> Result<(), ScopeError> {
104 if self.outstanding_scopes.last() != Some(&scope.id) {
106 return Err(ScopeError::NotMostRecentScope);
107 }
108 if scope.stack_depth < 1 {
109 return Err(ScopeError::CannotEndAtRoot);
110 }
111 self.outstanding_scopes.pop();
112 self.stack.truncate(scope.stack_depth);
113 self.path.truncate(scope.path_depth);
114 Ok(())
115 }
116
117 pub fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, InsertError> {
120 let current = self.current_node_id();
121 let node_mut = self
122 .document
123 .resolve_child_by_segment(segment.clone(), current)
124 .map_err(|e| InsertError {
125 kind: e,
126 path: EurePath::from_iter(self.path.iter().cloned()),
127 })?;
128 let node_id = node_mut.node_id;
129 self.stack.push(node_id);
130 self.path.push(segment);
131 Ok(node_id)
132 }
133
134 pub fn require_hole(&self) -> Result<(), InsertError> {
137 let node = self.current_node();
138 if !node.content.is_hole() {
139 return Err(InsertError {
140 kind: InsertErrorKind::BindingTargetHasValue,
141 path: EurePath::from_iter(self.path.iter().cloned()),
142 });
143 }
144 Ok(())
145 }
146
147 pub fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), InsertError> {
149 let node = self.current_node_mut();
150 if !node.content.is_hole() {
151 return Err(InsertError {
152 kind: InsertErrorKind::BindingTargetHasValue,
153 path: EurePath::from_iter(self.current_path().iter().cloned()),
154 });
155 }
156 node.content = NodeValue::Hole(label);
157 Ok(())
158 }
159
160 pub fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertError> {
162 let node = self.current_node_mut();
163 if !node.content.is_hole() {
164 return Err(InsertError {
165 kind: InsertErrorKind::BindingTargetHasValue,
166 path: EurePath::from_iter(self.current_path().iter().cloned()),
167 });
168 }
169 node.content = NodeValue::Primitive(value);
170 Ok(())
171 }
172
173 pub fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), InsertError> {
178 self.bind_primitive(value.into())
179 }
180
181 pub fn bind_empty_map(&mut self) -> Result<(), InsertError> {
183 let node = self.current_node_mut();
184 if !node.content.is_hole() {
185 return Err(InsertError {
186 kind: InsertErrorKind::BindingTargetHasValue,
187 path: EurePath::from_iter(self.current_path().iter().cloned()),
188 });
189 }
190 node.content = NodeValue::Map(Default::default());
191 Ok(())
192 }
193
194 pub fn bind_empty_array(&mut self) -> Result<(), InsertError> {
196 let node = self.current_node_mut();
197 if !node.content.is_hole() {
198 return Err(InsertError {
199 kind: InsertErrorKind::BindingTargetHasValue,
200 path: EurePath::from_iter(self.current_path().iter().cloned()),
201 });
202 }
203 node.content = NodeValue::Array(Default::default());
204 Ok(())
205 }
206
207 pub fn bind_empty_tuple(&mut self) -> Result<(), InsertError> {
209 let node = self.current_node_mut();
210 if !node.content.is_hole() {
211 return Err(InsertError {
212 kind: InsertErrorKind::BindingTargetHasValue,
213 path: EurePath::from_iter(self.current_path().iter().cloned()),
214 });
215 }
216 node.content = NodeValue::Tuple(Default::default());
217 Ok(())
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224 use crate::identifier::IdentifierParser;
225
226 fn create_identifier(s: &str) -> Identifier {
227 let parser = IdentifierParser::init();
228 parser.parse(s).unwrap()
229 }
230
231 #[test]
232 fn test_new_initializes_at_root() {
233 let constructor = DocumentConstructor::new();
234 let root_id = constructor.document().get_root_id();
235
236 assert_eq!(constructor.current_node_id(), root_id);
237 assert_eq!(constructor.current_path(), &[]);
238 }
239
240 #[test]
241 fn test_current_node_returns_root_initially() {
242 let constructor = DocumentConstructor::new();
243
244 let node = constructor.current_node();
245 assert!(node.content.is_hole());
246 }
247
248 #[test]
249 fn test_navigate_single_ident() {
250 let mut constructor = DocumentConstructor::new();
251
252 let identifier = create_identifier("field");
253 let segment = PathSegment::Ident(identifier.clone());
254
255 let node_id = constructor
256 .navigate(segment.clone())
257 .expect("Failed to navigate");
258
259 assert_eq!(constructor.current_node_id(), node_id);
260 assert_eq!(constructor.current_path(), &[segment]);
261 }
262
263 #[test]
264 fn test_navigate_multiple_times() {
265 let mut constructor = DocumentConstructor::new();
266
267 let id1 = create_identifier("field1");
268 let id2 = create_identifier("field2");
269
270 constructor
271 .navigate(PathSegment::Ident(id1.clone()))
272 .expect("Failed to navigate first");
273
274 let node_id2 = constructor
275 .navigate(PathSegment::Extension(id2.clone()))
276 .expect("Failed to navigate second");
277
278 assert_eq!(constructor.current_node_id(), node_id2);
279 assert_eq!(
280 constructor.current_path(),
281 &[PathSegment::Ident(id1), PathSegment::Extension(id2)]
282 );
283 }
284
285 #[test]
286 fn test_navigate_error_propagates() {
287 let mut constructor = DocumentConstructor::new();
289 let identifier = create_identifier("field");
291 constructor
292 .navigate(PathSegment::Ident(identifier))
293 .expect("Failed to navigate");
294 let node_id = constructor.current_node_id();
296 constructor.document_mut().node_mut(node_id).content =
297 NodeValue::Primitive(PrimitiveValue::Null);
298
299 let result = constructor.navigate(PathSegment::TupleIndex(0));
300
301 assert_eq!(
302 result.map_err(|e| e.kind),
303 Err(InsertErrorKind::ExpectedTuple)
304 );
305 }
306
307 #[test]
308 fn test_scope_success() {
309 let mut constructor = DocumentConstructor::new();
310 let root_id = constructor.document().get_root_id();
311
312 let identifier = create_identifier("field");
313 let token = constructor.begin_scope();
314 let _node_id = constructor
315 .navigate(PathSegment::Ident(identifier.clone()))
316 .expect("Failed to navigate");
317
318 let result = constructor.end_scope(token);
320 assert_eq!(result, Ok(()));
321
322 assert_eq!(constructor.current_node_id(), root_id);
324 assert_eq!(constructor.current_path(), &[]);
325 }
326
327 #[test]
328 fn test_scope_lifo_enforcement() {
329 let mut constructor = DocumentConstructor::new();
330
331 let id1 = create_identifier("field1");
332 let id2 = create_identifier("field2");
333
334 let token1 = constructor.begin_scope();
335 constructor
336 .navigate(PathSegment::Ident(id1))
337 .expect("Failed to navigate");
338
339 let token2 = constructor.begin_scope();
340 constructor
341 .navigate(PathSegment::Extension(id2))
342 .expect("Failed to navigate");
343
344 let result = constructor.end_scope(token1);
346 assert_eq!(result, Err(ScopeError::NotMostRecentScope));
347
348 constructor
350 .end_scope(token2)
351 .expect("Failed to end scope 2");
352 constructor
353 .end_scope(token1)
354 .expect("Failed to end scope 1");
355 }
356
357 #[test]
358 fn test_scope_with_multiple_navigations() {
359 let mut constructor = DocumentConstructor::new();
360 let root_id = constructor.document().get_root_id();
361
362 let id1 = create_identifier("level1");
363 let id2 = create_identifier("level2");
364 let id3 = create_identifier("level3");
365
366 let token = constructor.begin_scope();
367
368 let node_id1 = constructor
370 .navigate(PathSegment::Ident(id1.clone()))
371 .expect("Failed to navigate level1");
372
373 let node_id2 = constructor
374 .navigate(PathSegment::Extension(id2.clone()))
375 .expect("Failed to navigate level2");
376
377 let node_id3 = constructor
378 .navigate(PathSegment::Extension(id3.clone()))
379 .expect("Failed to navigate level3");
380
381 assert_eq!(constructor.current_node_id(), node_id3);
383 assert_eq!(
384 constructor.current_path(),
385 &[
386 PathSegment::Ident(id1.clone()),
387 PathSegment::Extension(id2.clone()),
388 PathSegment::Extension(id3)
389 ]
390 );
391
392 constructor.end_scope(token).expect("Failed to end scope");
394 assert_eq!(constructor.current_node_id(), root_id);
395 assert_eq!(constructor.current_path(), &[]);
396
397 let _ = constructor.document().node(node_id1);
399 let _ = constructor.document().node(node_id2);
400 let _ = constructor.document().node(node_id3);
401 }
402
403 #[test]
404 fn test_nested_scopes() {
405 let mut constructor = DocumentConstructor::new();
406 let root_id = constructor.document().get_root_id();
407
408 let id1 = create_identifier("a");
409 let id2 = create_identifier("b");
410 let id3 = create_identifier("c");
411
412 let token_outer = constructor.begin_scope();
414 let node_a = constructor
415 .navigate(PathSegment::Ident(id1.clone()))
416 .expect("Failed to navigate a");
417
418 let token_inner = constructor.begin_scope();
420 let _node_b = constructor
421 .navigate(PathSegment::Extension(id2.clone()))
422 .expect("Failed to navigate b");
423 let _node_c = constructor
424 .navigate(PathSegment::Extension(id3.clone()))
425 .expect("Failed to navigate c");
426
427 constructor
429 .end_scope(token_inner)
430 .expect("Failed to end inner scope");
431 assert_eq!(constructor.current_node_id(), node_a);
432 assert_eq!(constructor.current_path(), &[PathSegment::Ident(id1)]);
433
434 constructor
436 .end_scope(token_outer)
437 .expect("Failed to end outer scope");
438 assert_eq!(constructor.current_node_id(), root_id);
439 assert_eq!(constructor.current_path(), &[]);
440 }
441
442 #[test]
443 fn test_require_hole_success() {
444 let mut constructor = DocumentConstructor::new();
445
446 let identifier = create_identifier("field");
447 constructor
448 .navigate(PathSegment::Ident(identifier))
449 .expect("Failed to navigate");
450
451 let result = constructor.require_hole();
453 assert_eq!(result, Ok(()));
454 }
455
456 #[test]
457 fn test_require_hole_fails_when_bound() {
458 let mut constructor = DocumentConstructor::new();
459
460 let identifier = create_identifier("field");
461 let node_id = constructor
462 .navigate(PathSegment::Ident(identifier))
463 .expect("Failed to navigate");
464
465 constructor.document_mut().node_mut(node_id).content =
467 NodeValue::Primitive(PrimitiveValue::Bool(true));
468
469 let result = constructor.require_hole();
471 assert_eq!(
472 result.unwrap_err().kind,
473 InsertErrorKind::BindingTargetHasValue
474 );
475 }
476
477 #[test]
478 fn test_bind_primitive_success() {
479 let mut constructor = DocumentConstructor::new();
480 let identifier = create_identifier("field");
481
482 let node_id = constructor
484 .navigate(PathSegment::Ident(identifier))
485 .expect("Failed to navigate");
486
487 let result = constructor.bind_primitive(PrimitiveValue::Bool(true));
489 assert_eq!(result, Ok(()));
490
491 let node = constructor.document().node(node_id);
493 assert!(matches!(
494 node.content,
495 NodeValue::Primitive(PrimitiveValue::Bool(true))
496 ));
497 }
498
499 #[test]
500 fn test_bind_primitive_already_bound() {
501 let mut constructor = DocumentConstructor::new();
502 let identifier = create_identifier("field");
503
504 let node_id = constructor
506 .navigate(PathSegment::Ident(identifier.clone()))
507 .expect("Failed to navigate");
508
509 constructor.document_mut().node_mut(node_id).content =
511 NodeValue::Primitive(PrimitiveValue::Null);
512
513 let result = constructor.bind_primitive(PrimitiveValue::Bool(false));
515
516 assert_eq!(
517 result.unwrap_err().kind,
518 InsertErrorKind::BindingTargetHasValue
519 );
520
521 let node = constructor.document().node(node_id);
523 assert!(matches!(
524 node.content,
525 NodeValue::Primitive(PrimitiveValue::Null)
526 ));
527 }
528
529 #[test]
530 fn test_finish_replaces_uninitialized_root_with_null() {
531 let constructor = DocumentConstructor::new();
532
533 let root_id = constructor.document().get_root_id();
535 assert!(constructor.document().node(root_id).content.is_hole());
536
537 let document = constructor.finish();
539 let root_node = document.node(document.get_root_id());
540 assert_eq!(root_node.content, NodeValue::Map(Default::default()));
541 }
542
543 #[test]
544 fn test_finish_preserves_initialized_root() {
545 let mut constructor = DocumentConstructor::new();
546
547 constructor
549 .bind_primitive(PrimitiveValue::Bool(true))
550 .expect("Failed to bind");
551
552 let document = constructor.finish();
554 let root_node = document.node(document.get_root_id());
555 assert!(matches!(
556 root_node.content,
557 NodeValue::Primitive(PrimitiveValue::Bool(true))
558 ));
559 }
560
561 #[test]
562 fn test_typical_binding_pattern() {
563 let mut constructor = DocumentConstructor::new();
565
566 let id_a = create_identifier("a");
567 let id_b = create_identifier("b");
568 let id_c = create_identifier("c");
569
570 let token = constructor.begin_scope();
571 constructor
572 .navigate(PathSegment::Ident(id_a.clone()))
573 .unwrap();
574 constructor
575 .navigate(PathSegment::Extension(id_b.clone()))
576 .unwrap();
577 let node_c = constructor
578 .navigate(PathSegment::Extension(id_c.clone()))
579 .unwrap();
580 constructor.require_hole().unwrap();
581 constructor
582 .bind_primitive(PrimitiveValue::Bool(true))
583 .unwrap();
584 constructor.end_scope(token).unwrap();
585
586 let node = constructor.document().node(node_c);
588 assert!(matches!(
589 node.content,
590 NodeValue::Primitive(PrimitiveValue::Bool(true))
591 ));
592 }
593}