eure_document/document/interpreter_sink.rs
1//! Interpreter sink trait for document construction.
2//!
3//! This module defines the abstract interface for document construction,
4//! matching the semantics of spec Section 8 (Document Interpretation).
5//!
6//! # Architecture
7//!
8//! The [`InterpreterSink`] trait provides:
9//! - Core actions from spec Section 8 (scope, navigation, binding)
10//! - Source layout markers with default no-op implementations
11//!
12//! # Implementations
13//!
14//! - [`DocumentConstructor`](super::constructor::DocumentConstructor): Low-level, uses default no-ops
15//! - [`SourceConstructor`](super::source_constructor::SourceConstructor): Overrides to track layout
16
17use crate::document::NodeId;
18use crate::path::PathSegment;
19use crate::prelude_internal::*;
20use crate::source::Comment;
21
22/// Core trait for document construction (spec section 8 semantics).
23///
24/// The 5 primitive actions from the spec:
25/// - `begin_scope()` / `end_scope()` -> scope management
26/// - `navigate(segment)` -> tree navigation
27/// - `assert_unbound()` -> `require_hole()`
28/// - `bind(value)` -> `bind_*()` methods
29///
30/// # Example
31///
32/// ```ignore
33/// // Equivalent to: a.b = true
34/// let scope = sink.begin_scope();
35/// sink.navigate(PathSegment::Ident("a".parse()?))?;
36/// sink.navigate(PathSegment::Ident("b".parse()?))?;
37/// sink.require_hole()?;
38/// sink.bind_primitive(PrimitiveValue::Bool(true))?;
39/// sink.end_scope(scope)?;
40/// ```
41pub trait InterpreterSink {
42 /// The error type for operations.
43 type Error;
44 /// The scope handle type returned by `begin_scope`.
45 type Scope;
46
47 // === Scope Management ===
48
49 /// Begin a new scope. Returns a handle that must be passed to `end_scope`.
50 /// Scopes must be ended in LIFO order (most recent first).
51 fn begin_scope(&mut self) -> Self::Scope;
52
53 /// End a scope, restoring the sink to the state when `begin_scope` was called.
54 fn end_scope(&mut self, scope: Self::Scope) -> Result<(), Self::Error>;
55
56 // === Navigation ===
57
58 /// Navigate to a child node by path segment.
59 /// Creates the node if it doesn't exist.
60 fn navigate(&mut self, segment: PathSegment) -> Result<NodeId, Self::Error>;
61
62 // === Validation ===
63
64 /// Assert that the current node is unbound (a hole).
65 /// Use this before binding a value to ensure the node hasn't already been assigned.
66 fn require_hole(&self) -> Result<(), Self::Error>;
67
68 // === Binding ===
69
70 /// Bind a primitive value to the current node.
71 fn bind_primitive(&mut self, value: PrimitiveValue) -> Result<(), Self::Error>;
72
73 /// Bind a hole (with optional label) to the current node.
74 fn bind_hole(&mut self, label: Option<Identifier>) -> Result<(), Self::Error>;
75
76 /// Bind an empty map to the current node.
77 fn bind_empty_map(&mut self) -> Result<(), Self::Error>;
78
79 /// Bind an empty array to the current node.
80 fn bind_empty_array(&mut self) -> Result<(), Self::Error>;
81
82 /// Bind an empty tuple to the current node.
83 fn bind_empty_tuple(&mut self) -> Result<(), Self::Error>;
84
85 /// Bind a value using `Into<PrimitiveValue>`.
86 /// Convenience method for use with the `eure!` macro.
87 fn bind_from(&mut self, value: impl Into<PrimitiveValue>) -> Result<(), Self::Error> {
88 self.bind_primitive(value.into())
89 }
90
91 // === Access ===
92
93 /// Get the current node ID.
94 fn current_node_id(&self) -> NodeId;
95
96 /// Get the current path from root.
97 fn current_path(&self) -> &[PathSegment];
98
99 /// Get a reference to the document being built.
100 fn document(&self) -> &EureDocument;
101
102 /// Get a mutable reference to the document being built.
103 fn document_mut(&mut self) -> &mut EureDocument;
104
105 // =========================================================================
106 // Source Layout Markers (default no-op implementations)
107 //
108 // These methods track source structure for round-trip formatting.
109 // Override in SourceConstructor; DocumentConstructor uses the default no-ops.
110 //
111 // The 6 source patterns:
112 // #1: path = value -> begin_binding, end_binding_value
113 // #2: path { eure } -> begin_binding, begin_eure_block, ..., end_eure_block, end_binding_block
114 // #3: path { = value eure } -> begin_binding, begin_eure_block, set_block_value, ..., end_eure_block, end_binding_block
115 // #4: @ path (items) -> begin_section, begin_section_items, ..., end_section_items
116 // #5: @ path { eure } -> begin_section, begin_eure_block, ..., end_eure_block, end_section_block
117 // #6: @ path { = value eure }-> begin_section, begin_eure_block, set_block_value, ..., end_eure_block, end_section_block
118 // =========================================================================
119
120 // === EureSource block management ===
121
122 /// Enter a new EureSource block (for `{ eure }` patterns).
123 /// Pushes a new EureSource onto the builder stack.
124 /// Default: no-op.
125 fn begin_eure_block(&mut self) {}
126
127 /// Set the value binding for current EureSource (for `{ = value ... }` patterns).
128 /// Called after `bind_*` to record the value node.
129 /// Returns error if called without a preceding bind operation.
130 /// Default: no-op (returns Ok).
131 fn set_block_value(&mut self) -> Result<(), Self::Error> {
132 Ok(())
133 }
134
135 /// End current EureSource block.
136 /// Pops from the builder stack.
137 /// Returns error if the builder stack is in an invalid state.
138 /// Default: no-op (returns Ok).
139 fn end_eure_block(&mut self) -> Result<(), Self::Error> {
140 Ok(())
141 }
142
143 // === Binding patterns (#1-#3) ===
144
145 /// Start a binding statement (`path ...`).
146 /// Default: no-op.
147 fn begin_binding(&mut self) {}
148
149 /// End binding #1: `path = value`.
150 /// Adds BindingSource with BindSource::Value to current EureSource.
151 /// Returns error if called without a preceding bind operation.
152 /// Default: no-op (returns Ok).
153 fn end_binding_value(&mut self) -> Result<(), Self::Error> {
154 Ok(())
155 }
156
157 /// End binding #2/#3: `path { eure }`.
158 /// Adds BindingSource with BindSource::Block to current EureSource.
159 /// The block's EureSource was built between begin_eure_block/end_eure_block.
160 /// Returns error if called without a preceding end_eure_block.
161 /// Default: no-op (returns Ok).
162 fn end_binding_block(&mut self) -> Result<(), Self::Error> {
163 Ok(())
164 }
165
166 // === Section patterns (#4-#6) ===
167
168 /// Start a section header (`@ path ...`).
169 /// Default: no-op.
170 fn begin_section(&mut self) {}
171
172 /// Begin section #4: `@ section` (items follow).
173 /// Begins collecting items into SectionBody::Items.
174 /// Default: no-op.
175 fn begin_section_items(&mut self) {}
176
177 /// End section #4: finalize section with items body.
178 /// Adds SectionSource with SectionBody::Items to current EureSource.
179 /// Returns error if the builder stack is in an invalid state.
180 /// Default: no-op (returns Ok).
181 fn end_section_items(&mut self) -> Result<(), Self::Error> {
182 Ok(())
183 }
184
185 /// End section #5/#6: `@ section { eure }`.
186 /// Adds SectionSource with SectionBody::Block to current EureSource.
187 /// The block's EureSource was built between begin_eure_block/end_eure_block.
188 /// Returns error if called without a preceding end_eure_block.
189 /// Default: no-op (returns Ok).
190 fn end_section_block(&mut self) -> Result<(), Self::Error> {
191 Ok(())
192 }
193
194 // === Other ===
195
196 /// Add a comment to the layout.
197 /// Default: no-op.
198 fn comment(&mut self, _comment: Comment) {}
199
200 /// Add a blank line to the layout.
201 /// Default: no-op.
202 fn blank_line(&mut self) {}
203}