Skip to main content

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}