Class: Expressir::Express::StreamingBuilder
- Inherits:
-
Object
- Object
- Expressir::Express::StreamingBuilder
- Includes:
- Parsanol::BuilderCallbacks
- Defined in:
- lib/expressir/express/streaming_builder.rb
Overview
Streaming builder that receives parse events from Parsanol native parser.
This builder implements the Parsanol::BuilderCallbacks interface and reconstructs the AST from streaming events, then uses the existing Builder to convert to Model objects.
The key insight is that when a value starts (HASH_START, ARRAY_START), we must FIRST add it to the parent with the pending key, THEN push it to the stack so nested values are added to the correct container.
Instance Attribute Summary collapse
-
#include_source ⇒ Boolean
readonly
Whether to include source in model elements.
-
#source ⇒ String?
Original source code for position tracking.
Instance Method Summary collapse
-
#finish ⇒ Model::Repository?
Called when parsing is complete.
-
#initialize(source: nil, include_source: nil) ⇒ StreamingBuilder
constructor
Initialize the streaming builder.
-
#on_array_element(index) ⇒ Object
Called when an array element is about to be parsed.
-
#on_array_end(_size) ⇒ Object
Called when finishing parsing an array.
-
#on_array_start(_size = nil) ⇒ Object
Called when starting to parse an array.
-
#on_bool(value) ⇒ Object
Called when a boolean value is matched.
-
#on_error(message) ⇒ Object
Called when parsing fails.
-
#on_float(value) ⇒ Object
Called when a float value is matched.
-
#on_hash_end(_size) ⇒ Object
Called when finishing parsing a hash/object.
-
#on_hash_key(key) ⇒ Object
Called when a hash key is encountered.
-
#on_hash_start(_size = nil) ⇒ Object
Called when starting to parse a hash/object.
-
#on_hash_value(key) ⇒ Object
Called when a hash value is about to be parsed.
-
#on_int(value) ⇒ Object
Called when an integer value is matched.
-
#on_named_end(name) ⇒ Object
Called when finishing parsing a named rule.
-
#on_named_start(name) ⇒ Object
Called when starting to parse a named rule.
-
#on_nil ⇒ Object
Called when a nil/null value is matched.
-
#on_start(input) ⇒ Object
Called when parsing starts.
-
#on_string(value, _offset, _length) ⇒ Object
Called when a string value is matched.
-
#on_success ⇒ Object
Called when parsing succeeds.
Constructor Details
#initialize(source: nil, include_source: nil) ⇒ StreamingBuilder
Initialize the streaming builder
31 32 33 34 35 36 37 |
# File 'lib/expressir/express/streaming_builder.rb', line 31 def initialize(source: nil, include_source: nil) @source = source @include_source = include_source @stack = [] # Stack of containers (Hash or Array) @pending_key = nil @final_ast = nil end |
Instance Attribute Details
#include_source ⇒ Boolean (readonly)
Returns Whether to include source in model elements.
25 26 27 |
# File 'lib/expressir/express/streaming_builder.rb', line 25 def include_source @include_source end |
#source ⇒ String?
Returns Original source code for position tracking.
22 23 24 |
# File 'lib/expressir/express/streaming_builder.rb', line 22 def source @source end |
Instance Method Details
#finish ⇒ Model::Repository?
Called when parsing is complete. Returns the built Repository.
198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/expressir/express/streaming_builder.rb', line 198 def finish return nil unless @final_ast # Convert Parsanol native AST format to Builder-compatible format # Parsanol native: {"key" => [{:a => ...}, {:b => ...}]} (Array of single-key hashes) # Builder: {:key => {:a => ..., :b => ...}} (Hash with multiple keys) converted_ast = convert_ast_format(@final_ast) # Pass to the existing Builder Builder.build_with_remarks(converted_ast, source: @source, include_source: @include_source) end |
#on_array_element(index) ⇒ Object
Called when an array element is about to be parsed
162 163 164 |
# File 'lib/expressir/express/streaming_builder.rb', line 162 def on_array_element(index) # Element processed - no action needed end |
#on_array_end(_size) ⇒ Object
Called when finishing parsing an array
169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/expressir/express/streaming_builder.rb', line 169 def on_array_end(_size) return if @stack.empty? finished_array = @stack.pop if @stack.empty? # Top-level array, save as final AST @final_ast = finished_array end # If there's a parent, the array was already added in on_array_start end |
#on_array_start(_size = nil) ⇒ Object
Called when starting to parse an array
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/expressir/express/streaming_builder.rb', line 145 def on_array_start(_size = nil) new_array = [] # First add this array to the parent (if any) with the pending key if @stack.any? add_value_to_current_container(new_array) end # Then push to stack @stack.push(new_array) # Clear pending key - we're starting a new array context @pending_key = nil end |
#on_bool(value) ⇒ Object
Called when a boolean value is matched
84 85 86 |
# File 'lib/expressir/express/streaming_builder.rb', line 84 def on_bool(value) add_value_to_current_container(value) end |
#on_error(message) ⇒ Object
Called when parsing fails
54 55 56 |
# File 'lib/expressir/express/streaming_builder.rb', line 54 def on_error() raise Error::SchemaParseFailure.new("(streaming)", ) end |
#on_float(value) ⇒ Object
Called when a float value is matched
77 78 79 |
# File 'lib/expressir/express/streaming_builder.rb', line 77 def on_float(value) add_value_to_current_container(value) end |
#on_hash_end(_size) ⇒ Object
Called when finishing parsing a hash/object
130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/expressir/express/streaming_builder.rb', line 130 def on_hash_end(_size) return if @stack.empty? finished_hash = @stack.pop if @stack.empty? # This is the top-level hash, save it as final AST @final_ast = finished_hash end # If there's a parent, the hash was already added in on_hash_start end |
#on_hash_key(key) ⇒ Object
Called when a hash key is encountered
113 114 115 116 117 |
# File 'lib/expressir/express/streaming_builder.rb', line 113 def on_hash_key(key) # Convert string key to symbol to match existing parser AST format puts "DEBUG on_hash_key: #{key.inspect} (#{key.class})" if ENV["DEBUG_STREAMING"] @pending_key = key.to_sym end |
#on_hash_start(_size = nil) ⇒ Object
Called when starting to parse a hash/object
96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/expressir/express/streaming_builder.rb', line 96 def on_hash_start(_size = nil) new_hash = {} # First add this hash to the parent (if any) with the pending key if @stack.any? add_value_to_current_container(new_hash) end # Then push to stack so nested values go into this hash @stack.push(new_hash) # Clear pending key - we're starting a new hash context @pending_key = nil end |
#on_hash_value(key) ⇒ Object
Called when a hash value is about to be parsed
122 123 124 125 |
# File 'lib/expressir/express/streaming_builder.rb', line 122 def on_hash_value(key) puts "DEBUG on_hash_value: #{key.inspect} (#{key.class})" if ENV["DEBUG_STREAMING"] @pending_key = nil end |
#on_int(value) ⇒ Object
Called when an integer value is matched
70 71 72 |
# File 'lib/expressir/express/streaming_builder.rb', line 70 def on_int(value) add_value_to_current_container(value) end |
#on_named_end(name) ⇒ Object
Called when finishing parsing a named rule
191 192 193 |
# File 'lib/expressir/express/streaming_builder.rb', line 191 def on_named_end(name) # Named captures are handled via hash wrapping - no action needed end |
#on_named_start(name) ⇒ Object
Called when starting to parse a named rule
184 185 186 |
# File 'lib/expressir/express/streaming_builder.rb', line 184 def on_named_start(name) # Named captures are handled via hash wrapping - no action needed end |
#on_nil ⇒ Object
Called when a nil/null value is matched
89 90 91 |
# File 'lib/expressir/express/streaming_builder.rb', line 89 def on_nil add_value_to_current_container(nil) end |
#on_start(input) ⇒ Object
Called when parsing starts
42 43 44 |
# File 'lib/expressir/express/streaming_builder.rb', line 42 def on_start(input) @on_start ||= input end |
#on_string(value, _offset, _length) ⇒ Object
Called when a string value is matched
63 64 65 |
# File 'lib/expressir/express/streaming_builder.rb', line 63 def on_string(value, _offset, _length) add_value_to_current_container(value) end |
#on_success ⇒ Object
Called when parsing succeeds
47 48 49 |
# File 'lib/expressir/express/streaming_builder.rb', line 47 def on_success # Parsing completed end |