1use 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 matches!(root_node.content, NodeValue::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 !matches!(node.content, NodeValue::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) -> Result<(), InsertError> {
148 let node = self.current_node_mut();
149 if !matches!(node.content, NodeValue::Hole) {
150 return Err(InsertError {
151 kind: InsertErrorKind::BindingTargetHasValue,
152 path: EurePath::from_iter(self.current_path().iter().cloned()),
153 });
154 }
155 Ok(())
157 }
158
159 pub fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertError> {
161 let node = self.current_node_mut();
162 if !matches!(node.content, NodeValue::Hole) {
163 return Err(InsertError {
164 kind: InsertErrorKind::BindingTargetHasValue,
165 path: EurePath::from_iter(self.current_path().iter().cloned()),
166 });
167 }
168 node.content = NodeValue::Primitive(value);
169 Ok(())
170 }
171
172 pub fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), InsertError> {
177 self.bind_primitive(value.into())
178 }
179
180 pub fn bind_empty_map(&mut self) -> Result<(), InsertError> {
182 let node = self.current_node_mut();
183 if !matches!(node.content, NodeValue::Hole) {
184 return Err(InsertError {
185 kind: InsertErrorKind::BindingTargetHasValue,
186 path: EurePath::from_iter(self.current_path().iter().cloned()),
187 });
188 }
189 node.content = NodeValue::Map(Default::default());
190 Ok(())
191 }
192
193 pub fn bind_empty_array(&mut self) -> Result<(), InsertError> {
195 let node = self.current_node_mut();
196 if !matches!(node.content, NodeValue::Hole) {
197 return Err(InsertError {
198 kind: InsertErrorKind::BindingTargetHasValue,
199 path: EurePath::from_iter(self.current_path().iter().cloned()),
200 });
201 }
202 node.content = NodeValue::Array(Default::default());
203 Ok(())
204 }
205
206 pub fn bind_empty_tuple(&mut self) -> Result<(), InsertError> {
208 let node = self.current_node_mut();
209 if !matches!(node.content, NodeValue::Hole) {
210 return Err(InsertError {
211 kind: InsertErrorKind::BindingTargetHasValue,
212 path: EurePath::from_iter(self.current_path().iter().cloned()),
213 });
214 }
215 node.content = NodeValue::Tuple(Default::default());
216 Ok(())
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::identifier::IdentifierParser;
224
225 fn create_identifier(s: &str) -> Identifier {
226 let parser = IdentifierParser::init();
227 parser.parse(s).unwrap()
228 }
229
230 #[test]
231 fn test_new_initializes_at_root() {
232 let constructor = DocumentConstructor::new();
233 let root_id = constructor.document().get_root_id();
234
235 assert_eq!(constructor.current_node_id(), root_id);
236 assert_eq!(constructor.current_path(), &[]);
237 }
238
239 #[test]
240 fn test_current_node_returns_root_initially() {
241 let constructor = DocumentConstructor::new();
242
243 let node = constructor.current_node();
244 assert!(matches!(node.content, NodeValue::Hole));
245 }
246
247 #[test]
248 fn test_navigate_single_ident() {
249 let mut constructor = DocumentConstructor::new();
250
251 let identifier = create_identifier("field");
252 let segment = PathSegment::Ident(identifier.clone());
253
254 let node_id = constructor
255 .navigate(segment.clone())
256 .expect("Failed to navigate");
257
258 assert_eq!(constructor.current_node_id(), node_id);
259 assert_eq!(constructor.current_path(), &[segment]);
260 }
261
262 #[test]
263 fn test_navigate_multiple_times() {
264 let mut constructor = DocumentConstructor::new();
265
266 let id1 = create_identifier("field1");
267 let id2 = create_identifier("field2");
268
269 constructor
270 .navigate(PathSegment::Ident(id1.clone()))
271 .expect("Failed to navigate first");
272
273 let node_id2 = constructor
274 .navigate(PathSegment::Extension(id2.clone()))
275 .expect("Failed to navigate second");
276
277 assert_eq!(constructor.current_node_id(), node_id2);
278 assert_eq!(
279 constructor.current_path(),
280 &[PathSegment::Ident(id1), PathSegment::Extension(id2)]
281 );
282 }
283
284 #[test]
285 fn test_navigate_error_propagates() {
286 let mut constructor = DocumentConstructor::new();
288 let identifier = create_identifier("field");
290 constructor
291 .navigate(PathSegment::Ident(identifier))
292 .expect("Failed to navigate");
293 let node_id = constructor.current_node_id();
295 constructor.document_mut().node_mut(node_id).content =
296 NodeValue::Primitive(PrimitiveValue::Null);
297
298 let result = constructor.navigate(PathSegment::TupleIndex(0));
299
300 assert_eq!(
301 result.map_err(|e| e.kind),
302 Err(InsertErrorKind::ExpectedTuple)
303 );
304 }
305
306 #[test]
307 fn test_scope_success() {
308 let mut constructor = DocumentConstructor::new();
309 let root_id = constructor.document().get_root_id();
310
311 let identifier = create_identifier("field");
312 let token = constructor.begin_scope();
313 let _node_id = constructor
314 .navigate(PathSegment::Ident(identifier.clone()))
315 .expect("Failed to navigate");
316
317 let result = constructor.end_scope(token);
319 assert_eq!(result, Ok(()));
320
321 assert_eq!(constructor.current_node_id(), root_id);
323 assert_eq!(constructor.current_path(), &[]);
324 }
325
326 #[test]
327 fn test_scope_lifo_enforcement() {
328 let mut constructor = DocumentConstructor::new();
329
330 let id1 = create_identifier("field1");
331 let id2 = create_identifier("field2");
332
333 let token1 = constructor.begin_scope();
334 constructor
335 .navigate(PathSegment::Ident(id1))
336 .expect("Failed to navigate");
337
338 let token2 = constructor.begin_scope();
339 constructor
340 .navigate(PathSegment::Extension(id2))
341 .expect("Failed to navigate");
342
343 let result = constructor.end_scope(token1);
345 assert_eq!(result, Err(ScopeError::NotMostRecentScope));
346
347 constructor
349 .end_scope(token2)
350 .expect("Failed to end scope 2");
351 constructor
352 .end_scope(token1)
353 .expect("Failed to end scope 1");
354 }
355
356 #[test]
357 fn test_scope_with_multiple_navigations() {
358 let mut constructor = DocumentConstructor::new();
359 let root_id = constructor.document().get_root_id();
360
361 let id1 = create_identifier("level1");
362 let id2 = create_identifier("level2");
363 let id3 = create_identifier("level3");
364
365 let token = constructor.begin_scope();
366
367 let node_id1 = constructor
369 .navigate(PathSegment::Ident(id1.clone()))
370 .expect("Failed to navigate level1");
371
372 let node_id2 = constructor
373 .navigate(PathSegment::Extension(id2.clone()))
374 .expect("Failed to navigate level2");
375
376 let node_id3 = constructor
377 .navigate(PathSegment::Extension(id3.clone()))
378 .expect("Failed to navigate level3");
379
380 assert_eq!(constructor.current_node_id(), node_id3);
382 assert_eq!(
383 constructor.current_path(),
384 &[
385 PathSegment::Ident(id1.clone()),
386 PathSegment::Extension(id2.clone()),
387 PathSegment::Extension(id3)
388 ]
389 );
390
391 constructor.end_scope(token).expect("Failed to end scope");
393 assert_eq!(constructor.current_node_id(), root_id);
394 assert_eq!(constructor.current_path(), &[]);
395
396 let _ = constructor.document().node(node_id1);
398 let _ = constructor.document().node(node_id2);
399 let _ = constructor.document().node(node_id3);
400 }
401
402 #[test]
403 fn test_nested_scopes() {
404 let mut constructor = DocumentConstructor::new();
405 let root_id = constructor.document().get_root_id();
406
407 let id1 = create_identifier("a");
408 let id2 = create_identifier("b");
409 let id3 = create_identifier("c");
410
411 let token_outer = constructor.begin_scope();
413 let node_a = constructor
414 .navigate(PathSegment::Ident(id1.clone()))
415 .expect("Failed to navigate a");
416
417 let token_inner = constructor.begin_scope();
419 let _node_b = constructor
420 .navigate(PathSegment::Extension(id2.clone()))
421 .expect("Failed to navigate b");
422 let _node_c = constructor
423 .navigate(PathSegment::Extension(id3.clone()))
424 .expect("Failed to navigate c");
425
426 constructor
428 .end_scope(token_inner)
429 .expect("Failed to end inner scope");
430 assert_eq!(constructor.current_node_id(), node_a);
431 assert_eq!(constructor.current_path(), &[PathSegment::Ident(id1)]);
432
433 constructor
435 .end_scope(token_outer)
436 .expect("Failed to end outer scope");
437 assert_eq!(constructor.current_node_id(), root_id);
438 assert_eq!(constructor.current_path(), &[]);
439 }
440
441 #[test]
442 fn test_require_hole_success() {
443 let mut constructor = DocumentConstructor::new();
444
445 let identifier = create_identifier("field");
446 constructor
447 .navigate(PathSegment::Ident(identifier))
448 .expect("Failed to navigate");
449
450 let result = constructor.require_hole();
452 assert_eq!(result, Ok(()));
453 }
454
455 #[test]
456 fn test_require_hole_fails_when_bound() {
457 let mut constructor = DocumentConstructor::new();
458
459 let identifier = create_identifier("field");
460 let node_id = constructor
461 .navigate(PathSegment::Ident(identifier))
462 .expect("Failed to navigate");
463
464 constructor.document_mut().node_mut(node_id).content =
466 NodeValue::Primitive(PrimitiveValue::Bool(true));
467
468 let result = constructor.require_hole();
470 assert_eq!(
471 result.unwrap_err().kind,
472 InsertErrorKind::BindingTargetHasValue
473 );
474 }
475
476 #[test]
477 fn test_bind_primitive_success() {
478 let mut constructor = DocumentConstructor::new();
479 let identifier = create_identifier("field");
480
481 let node_id = constructor
483 .navigate(PathSegment::Ident(identifier))
484 .expect("Failed to navigate");
485
486 let result = constructor.bind_primitive(PrimitiveValue::Bool(true));
488 assert_eq!(result, Ok(()));
489
490 let node = constructor.document().node(node_id);
492 assert!(matches!(
493 node.content,
494 NodeValue::Primitive(PrimitiveValue::Bool(true))
495 ));
496 }
497
498 #[test]
499 fn test_bind_primitive_already_bound() {
500 let mut constructor = DocumentConstructor::new();
501 let identifier = create_identifier("field");
502
503 let node_id = constructor
505 .navigate(PathSegment::Ident(identifier.clone()))
506 .expect("Failed to navigate");
507
508 constructor.document_mut().node_mut(node_id).content =
510 NodeValue::Primitive(PrimitiveValue::Null);
511
512 let result = constructor.bind_primitive(PrimitiveValue::Bool(false));
514
515 assert_eq!(
516 result.unwrap_err().kind,
517 InsertErrorKind::BindingTargetHasValue
518 );
519
520 let node = constructor.document().node(node_id);
522 assert!(matches!(
523 node.content,
524 NodeValue::Primitive(PrimitiveValue::Null)
525 ));
526 }
527
528 #[test]
529 fn test_finish_replaces_uninitialized_root_with_null() {
530 let constructor = DocumentConstructor::new();
531
532 let root_id = constructor.document().get_root_id();
534 assert!(matches!(
535 constructor.document().node(root_id).content,
536 NodeValue::Hole
537 ));
538
539 let document = constructor.finish();
541 let root_node = document.node(document.get_root_id());
542 assert_eq!(root_node.content, NodeValue::Map(Default::default()));
543 }
544
545 #[test]
546 fn test_finish_preserves_initialized_root() {
547 let mut constructor = DocumentConstructor::new();
548
549 constructor
551 .bind_primitive(PrimitiveValue::Bool(true))
552 .expect("Failed to bind");
553
554 let document = constructor.finish();
556 let root_node = document.node(document.get_root_id());
557 assert!(matches!(
558 root_node.content,
559 NodeValue::Primitive(PrimitiveValue::Bool(true))
560 ));
561 }
562
563 #[test]
564 fn test_typical_binding_pattern() {
565 let mut constructor = DocumentConstructor::new();
567
568 let id_a = create_identifier("a");
569 let id_b = create_identifier("b");
570 let id_c = create_identifier("c");
571
572 let token = constructor.begin_scope();
573 constructor
574 .navigate(PathSegment::Ident(id_a.clone()))
575 .unwrap();
576 constructor
577 .navigate(PathSegment::Extension(id_b.clone()))
578 .unwrap();
579 let node_c = constructor
580 .navigate(PathSegment::Extension(id_c.clone()))
581 .unwrap();
582 constructor.require_hole().unwrap();
583 constructor
584 .bind_primitive(PrimitiveValue::Bool(true))
585 .unwrap();
586 constructor.end_scope(token).unwrap();
587
588 let node = constructor.document().node(node_c);
590 assert!(matches!(
591 node.content,
592 NodeValue::Primitive(PrimitiveValue::Bool(true))
593 ));
594 }
595}