parsanol 1.3.5-aarch64-linux → 1.3.7-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +48 -48
  3. data/lib/parsanol/ast_visitor.rb +1 -1
  4. data/lib/parsanol/atoms/alternative.rb +3 -2
  5. data/lib/parsanol/atoms/base.rb +12 -6
  6. data/lib/parsanol/atoms/can_flatten.rb +8 -8
  7. data/lib/parsanol/atoms/context.rb +23 -16
  8. data/lib/parsanol/atoms/custom.rb +2 -2
  9. data/lib/parsanol/atoms/dynamic.rb +1 -1
  10. data/lib/parsanol/atoms/infix.rb +10 -5
  11. data/lib/parsanol/atoms/lookahead.rb +7 -4
  12. data/lib/parsanol/atoms/re.rb +1 -1
  13. data/lib/parsanol/atoms/repetition.rb +29 -11
  14. data/lib/parsanol/atoms/sequence.rb +3 -2
  15. data/lib/parsanol/atoms/str.rb +9 -3
  16. data/lib/parsanol/atoms.rb +20 -20
  17. data/lib/parsanol/builder_callbacks.rb +2 -2
  18. data/lib/parsanol/cause.rb +2 -2
  19. data/lib/parsanol/context.rb +2 -2
  20. data/lib/parsanol/error_reporter.rb +5 -5
  21. data/lib/parsanol/expression/treetop.rb +17 -17
  22. data/lib/parsanol/expression.rb +1 -1
  23. data/lib/parsanol/fast_mode.rb +50 -12
  24. data/lib/parsanol/first_set.rb +1 -1
  25. data/lib/parsanol/grammar_builder.rb +10 -8
  26. data/lib/parsanol/incremental_parser.rb +13 -8
  27. data/lib/parsanol/interval_tree.rb +12 -3
  28. data/lib/parsanol/lazy_result.rb +2 -2
  29. data/lib/parsanol/mermaid.rb +12 -9
  30. data/lib/parsanol/native/batch_decoder.rb +13 -9
  31. data/lib/parsanol/native/dynamic.rb +7 -6
  32. data/lib/parsanol/native/parser.rb +7 -5
  33. data/lib/parsanol/native/serializer.rb +42 -42
  34. data/lib/parsanol/native/transformer.rb +55 -28
  35. data/lib/parsanol/native/types.rb +3 -3
  36. data/lib/parsanol/native.rb +26 -20
  37. data/lib/parsanol/optimizer.rb +6 -6
  38. data/lib/parsanol/optimizers/choice_optimizer.rb +1 -1
  39. data/lib/parsanol/optimizers/cut_inserter.rb +5 -2
  40. data/lib/parsanol/optimizers/lookahead_optimizer.rb +9 -3
  41. data/lib/parsanol/optimizers/quantifier_optimizer.rb +5 -5
  42. data/lib/parsanol/optimizers/sequence_optimizer.rb +1 -1
  43. data/lib/parsanol/options/zero_copy.rb +1 -1
  44. data/lib/parsanol/options.rb +1 -1
  45. data/lib/parsanol/parallel.rb +4 -3
  46. data/lib/parsanol/parser.rb +18 -16
  47. data/lib/parsanol/parslet.rb +7 -7
  48. data/lib/parsanol/pattern/binding.rb +1 -1
  49. data/lib/parsanol/pattern.rb +4 -1
  50. data/lib/parsanol/pool.rb +3 -3
  51. data/lib/parsanol/pools/buffer_pool.rb +2 -2
  52. data/lib/parsanol/pools/position_pool.rb +2 -2
  53. data/lib/parsanol/position.rb +1 -1
  54. data/lib/parsanol/result_builder.rb +4 -4
  55. data/lib/parsanol/result_stream.rb +10 -5
  56. data/lib/parsanol/slice.rb +11 -8
  57. data/lib/parsanol/source.rb +14 -9
  58. data/lib/parsanol/source_location.rb +1 -1
  59. data/lib/parsanol/streaming_parser.rb +3 -3
  60. data/lib/parsanol/string_view.rb +4 -1
  61. data/lib/parsanol/transform.rb +2 -2
  62. data/lib/parsanol/version.rb +1 -1
  63. data/lib/parsanol/wasm_parser.rb +1 -1
  64. data/lib/parsanol.rb +37 -39
  65. data/parsanol.gemspec +30 -30
  66. metadata +1 -1
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
- require 'digest'
3
+ require "json"
4
+ require "digest"
5
5
 
6
- require 'parsanol/native/types'
7
- require 'parsanol/native/parser'
8
- require 'parsanol/native/serializer'
9
- require 'parsanol/native/batch_decoder'
6
+ require "parsanol/native/types"
7
+ require "parsanol/native/parser"
8
+ require "parsanol/native/serializer"
9
+ require "parsanol/native/batch_decoder"
10
10
 
11
11
  module Parsanol
12
12
  module Native
13
- VERSION = '0.1.0'
13
+ VERSION = "0.1.0"
14
14
 
15
15
  class << self
16
16
  # Check if native extension is available
@@ -53,7 +53,8 @@ module Parsanol
53
53
  # The batch format doesn't preserve :repetition/:sequence tags, so we use
54
54
  # the direct FFI path. Apply the Ruby transformer to handle tags correctly.
55
55
  raw_ast = _parse_raw(grammar_json, input)
56
- BatchDecoder.decode_and_flatten(raw_ast, input, Parsanol::Slice, grammar_atom)
56
+ BatchDecoder.decode_and_flatten(raw_ast, input, Parsanol::Slice,
57
+ grammar_atom)
57
58
  end
58
59
 
59
60
  # Parse and return RAW AST without transformation.
@@ -76,11 +77,11 @@ module Parsanol
76
77
  raise LoadError, "Native parser not available" unless available?
77
78
 
78
79
  # Handle both grammar atoms and pre-serialized JSON strings
79
- if grammar.is_a?(String)
80
- grammar_json = grammar
81
- else
82
- grammar_json = Parser.serialize_grammar(grammar)
83
- end
80
+ grammar_json = if grammar.is_a?(String)
81
+ grammar
82
+ else
83
+ Parser.serialize_grammar(grammar)
84
+ end
84
85
 
85
86
  # Use batch_raw format for raw AST (no transformation)
86
87
  slice_class = Parsanol::Slice
@@ -112,11 +113,6 @@ module Parsanol
112
113
  BatchDecoder.decode(batch_data, input, slice_class)
113
114
  end
114
115
 
115
- # Get the Slice class
116
- private def get_slice_class
117
- Parsanol::Slice
118
- end
119
-
120
116
  # Serialize a Ruby grammar to JSON (cached).
121
117
  #
122
118
  # @param root_atom [Parsanol::Atoms::Base] Root atom of the grammar
@@ -139,6 +135,7 @@ module Parsanol
139
135
  # @return [nil]
140
136
  def clear_grammar_cache
141
137
  raise LoadError, "Native parser not available" unless available?
138
+
142
139
  _clear_grammar_cache
143
140
  end
144
141
 
@@ -147,6 +144,7 @@ module Parsanol
147
144
  # @return [Integer] Number of cached grammars
148
145
  def grammar_cache_size
149
146
  raise LoadError, "Native parser not available" unless available?
147
+
150
148
  _grammar_cache_size
151
149
  end
152
150
 
@@ -155,6 +153,7 @@ module Parsanol
155
153
  # @return [Integer] Maximum cache capacity
156
154
  def grammar_cache_capacity
157
155
  raise LoadError, "Native parser not available" unless available?
156
+
158
157
  _grammar_cache_capacity
159
158
  end
160
159
 
@@ -167,17 +166,24 @@ module Parsanol
167
166
  end
168
167
  stats
169
168
  end
169
+
170
+ private
171
+
172
+ # Get the Slice class
173
+ def get_slice_class
174
+ Parsanol::Slice
175
+ end
170
176
  end
171
177
  end
172
178
  end
173
179
 
174
180
  # Attempt to load native extension
175
181
  begin
176
- ruby_version = RUBY_VERSION.split('.').take(2).join('.')
182
+ ruby_version = RUBY_VERSION.split(".").take(2).join(".")
177
183
  require "parsanol/#{ruby_version}/parsanol_native"
178
184
  rescue LoadError
179
185
  begin
180
- require 'parsanol/parsanol_native'
186
+ require "parsanol/parsanol_native"
181
187
  rescue LoadError
182
188
  # Native extension not built yet
183
189
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'ast_visitor'
4
- require_relative 'optimizers/quantifier_optimizer'
5
- require_relative 'optimizers/sequence_optimizer'
6
- require_relative 'optimizers/choice_optimizer'
7
- require_relative 'optimizers/lookahead_optimizer'
8
- require_relative 'optimizers/cut_inserter'
3
+ require_relative "ast_visitor"
4
+ require_relative "optimizers/quantifier_optimizer"
5
+ require_relative "optimizers/sequence_optimizer"
6
+ require_relative "optimizers/choice_optimizer"
7
+ require_relative "optimizers/lookahead_optimizer"
8
+ require_relative "optimizers/cut_inserter"
9
9
 
10
10
  # Grammar-level optimizations for Parslet parsers
11
11
  # These optimizations transform the parser AST to reduce runtime overhead
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../ast_visitor'
3
+ require_relative "../ast_visitor"
4
4
 
5
5
  module Parsanol
6
6
  module Optimizers
@@ -84,7 +84,7 @@ module Parsanol
84
84
  Parsanol::Atoms::Repetition.new(
85
85
  optimized_parslet,
86
86
  rep.min,
87
- rep.max
87
+ rep.max,
88
88
  )
89
89
  end
90
90
 
@@ -101,7 +101,10 @@ module Parsanol
101
101
  # For sequences, find the longest safe prefix
102
102
  if parslet.is_a?(Parsanol::Atoms::Sequence)
103
103
  prefix_parslets = find_deterministic_prefix(parslet)
104
- return build_cut_sequence(parslet, prefix_parslets) if prefix_parslets && !prefix_parslets.empty?
104
+ if prefix_parslets && !prefix_parslets.empty?
105
+ return build_cut_sequence(parslet,
106
+ prefix_parslets)
107
+ end
105
108
  end
106
109
 
107
110
  # For other atoms, cut the whole thing if safe
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../ast_visitor'
3
+ require_relative "../ast_visitor"
4
4
 
5
5
  module Parsanol
6
6
  module Optimizers
@@ -26,13 +26,19 @@ module Parsanol
26
26
  inner_positive = inner.positive
27
27
 
28
28
  # !(!x) => &x (double negation)
29
- return Parsanol::Atoms::Lookahead.new(inner.bound_parslet, true) if !outer_positive && !inner_positive
29
+ if !outer_positive && !inner_positive
30
+ return Parsanol::Atoms::Lookahead.new(inner.bound_parslet,
31
+ true)
32
+ end
30
33
 
31
34
  # &(&x) => &x (idempotent)
32
35
  return inner if outer_positive && inner_positive
33
36
 
34
37
  # !(&x) => !x (negative of positive)
35
- return Parsanol::Atoms::Lookahead.new(inner.bound_parslet, false) if !outer_positive && inner_positive
38
+ if !outer_positive && inner_positive
39
+ return Parsanol::Atoms::Lookahead.new(inner.bound_parslet,
40
+ false)
41
+ end
36
42
 
37
43
  # &(!x) => !x (positive of negative)
38
44
  return inner if outer_positive && !inner_positive
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../ast_visitor'
3
+ require_relative "../ast_visitor"
4
4
 
5
5
  module Parsanol
6
6
  module Optimizers
@@ -26,19 +26,19 @@ module Parsanol
26
26
  if inner.is_a?(Parsanol::Atoms::Repetition)
27
27
  # repeat(0,1).repeat(0,1) => repeat(0,1) (idempotent)
28
28
  if parslet.min.zero? && parslet.max == 1 &&
29
- inner.min.zero? && inner.max == 1
29
+ inner.min.zero? && inner.max == 1
30
30
  return inner
31
31
  end
32
32
 
33
33
  # repeat(n,n).repeat(m,m) => repeat(n*m,n*m) for exact counts
34
34
  if parslet.min == parslet.max && inner.min == inner.max &&
35
- parslet.max && inner.max
35
+ parslet.max && inner.max
36
36
  new_count = parslet.min * inner.min
37
37
  return Parsanol::Atoms::Repetition.new(
38
38
  inner.parslet,
39
39
  new_count,
40
40
  new_count,
41
- parslet.result_tag
41
+ parslet.result_tag,
42
42
  )
43
43
  end
44
44
  end
@@ -51,7 +51,7 @@ module Parsanol
51
51
  inner,
52
52
  parslet.min,
53
53
  parslet.max,
54
- parslet.result_tag
54
+ parslet.result_tag,
55
55
  )
56
56
  end
57
57
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../ast_visitor'
3
+ require_relative "../ast_visitor"
4
4
 
5
5
  module Parsanol
6
6
  module Optimizers
@@ -119,7 +119,7 @@ module Parsanol
119
119
  # @param type_map [Hash] Override type mapping for this parse
120
120
  # @return [Object] Direct Ruby object
121
121
  def parse_with_types(input, type_map)
122
- raise LoadError, 'ZeroCopy mode requires native extension.' unless Parsanol::Native.available?
122
+ raise LoadError, "ZeroCopy mode requires native extension." unless Parsanol::Native.available?
123
123
 
124
124
  grammar_json = Parsanol::Native.serialize_grammar(root)
125
125
  Parsanol::Native.parse_to_objects(grammar_json, input, type_map)
@@ -18,4 +18,4 @@
18
18
  # For standard parsing, use the Parse Modes API instead:
19
19
  # parser.parse(input, mode: :native) # or :ruby, :json
20
20
 
21
- require 'parsanol/options/zero_copy'
21
+ require "parsanol/options/zero_copy"
@@ -86,7 +86,7 @@ module Parsanol
86
86
  Parsanol::Native.parse_batch_parallel(
87
87
  grammar_json,
88
88
  inputs,
89
- num_threads: config.num_threads
89
+ num_threads: config.num_threads,
90
90
  )
91
91
  end
92
92
 
@@ -98,7 +98,8 @@ module Parsanol
98
98
  # @param config [Config] Parallel configuration (optional)
99
99
  # @return [Array<Object>] Array of transformed results
100
100
  #
101
- def parse_batch_with_transform(grammar_json, inputs, transform, config: Config.new)
101
+ def parse_batch_with_transform(grammar_json, inputs, transform,
102
+ config: Config.new)
102
103
  results = parse_batch(grammar_json, inputs, config: config)
103
104
  results.map { |result| transform.apply(result) }
104
105
  end
@@ -107,7 +108,7 @@ module Parsanol
107
108
  #
108
109
  # @return [Integer] Number of available cores
109
110
  def available_cores
110
- require 'etc'
111
+ require "etc"
111
112
  Etc.nprocessors
112
113
  rescue StandardError
113
114
  1
@@ -110,13 +110,23 @@ module Parsanol
110
110
  #
111
111
  def parse(input, mode_or_opts = {}, **kwargs)
112
112
  if mode_or_opts.is_a?(Hash) && !kwargs.key?(:mode)
113
- # Legacy API: parse(input, options={}) or parse(input, mode: :ruby)
113
+ # Legacy API: parse(input, options={})
114
114
  merged = mode_or_opts.merge(kwargs)
115
115
  super(input, merged)
116
116
  else
117
117
  # New API: parse(input, mode:, **options)
118
118
  mode = kwargs.delete(:mode) || :ruby
119
- dispatch_parse(mode, input, kwargs)
119
+ case mode
120
+ when :ruby
121
+ super(input, kwargs)
122
+ when :native
123
+ parse_native(input, kwargs)
124
+ when :json
125
+ parse_json(input, kwargs)
126
+ else
127
+ raise ArgumentError,
128
+ "Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
129
+ end
120
130
  end
121
131
  end
122
132
 
@@ -175,26 +185,19 @@ module Parsanol
175
185
  def dispatch_parse(mode, input, opts)
176
186
  case mode
177
187
  when :ruby
178
- parse_ruby(input, opts)
188
+ # Call base class parse directly (send needed since parse is defined in parent)
189
+ Parsanol::Atoms::Base.instance_method(:parse).bind_call(self, input,
190
+ opts)
179
191
  when :native
180
192
  parse_native(input, opts)
181
193
  when :json
182
194
  parse_json(input, opts)
183
195
  else
184
- raise ArgumentError, "Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
196
+ raise ArgumentError,
197
+ "Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
185
198
  end
186
199
  end
187
200
 
188
- # Pure Ruby parsing (delegates to Base implementation).
189
- #
190
- # @param input [String] input to parse
191
- # @param opts [Hash] parsing options
192
- # @return [Object] parse result
193
- #
194
- def parse_ruby(input, opts)
195
- super
196
- end
197
-
198
201
  # Native extension parsing with Ruby fallback.
199
202
  # Returns results with Slice objects containing position info.
200
203
  #
@@ -204,10 +207,9 @@ module Parsanol
204
207
  #
205
208
  def parse_native(input, opts)
206
209
  if Parsanol::Native.available?
207
- # Parse with lazy line/column support
208
210
  Parsanol::Native.parse(root, input)
209
211
  else
210
- parse_ruby(input, opts)
212
+ super
211
213
  end
212
214
  end
213
215
 
@@ -35,7 +35,7 @@
35
35
  # class MyParser < Parsanol::Parslet::Parser
36
36
  # include Parsanol::Parslet
37
37
 
38
- require 'parsanol'
38
+ require "parsanol"
39
39
 
40
40
  module Parsanol
41
41
  module Parslet
@@ -90,16 +90,16 @@ module Parsanol
90
90
  Parsanol.any
91
91
  end
92
92
 
93
- def scope(&block)
94
- Parsanol.scope(&block)
93
+ def scope(&)
94
+ Parsanol.scope(&)
95
95
  end
96
96
 
97
- def dynamic(&block)
98
- Parsanol.dynamic(&block)
97
+ def dynamic(&)
98
+ Parsanol.dynamic(&)
99
99
  end
100
100
 
101
- def infix_expression(element, *operations, &reducer)
102
- Parsanol.infix_expression(element, *operations, &reducer)
101
+ def infix_expression(element, *operations, &)
102
+ Parsanol.infix_expression(element, *operations, &)
103
103
  end
104
104
 
105
105
  # Parses a treetop-style expression string and returns the corresponding atom.
@@ -44,7 +44,7 @@ module Parsanol
44
44
  return class_match[1].downcase if class_match
45
45
 
46
46
  # Fallback for unexpected class names
47
- 'subtree'
47
+ "subtree"
48
48
  end
49
49
  end
50
50
  end
@@ -51,7 +51,10 @@ module Parsanol
51
51
  #
52
52
  def match(subtree, bindings = nil)
53
53
  current_bindings = bindings ? bindings.dup : {}
54
- check_match(subtree, @pattern_def, current_bindings) ? current_bindings : nil
54
+ if check_match(subtree, @pattern_def,
55
+ current_bindings)
56
+ current_bindings
57
+ end
55
58
  end
56
59
 
57
60
  private
data/lib/parsanol/pool.rb CHANGED
@@ -67,7 +67,7 @@ module Parsanol
67
67
  created: 0,
68
68
  reused: 0,
69
69
  released: 0,
70
- discarded: 0
70
+ discarded: 0,
71
71
  }
72
72
 
73
73
  # Pre-allocate objects for efficiency if requested
@@ -154,7 +154,7 @@ module Parsanol
154
154
  reused: @stats[:reused],
155
155
  released: @stats[:released],
156
156
  discarded: @stats[:discarded],
157
- utilization: utilization.round(2)
157
+ utilization: utilization.round(2),
158
158
  }
159
159
  end
160
160
 
@@ -174,7 +174,7 @@ module Parsanol
174
174
  created: 0,
175
175
  reused: 0,
176
176
  released: 0,
177
- discarded: 0
177
+ discarded: 0,
178
178
  }
179
179
  end
180
180
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../buffer'
3
+ require_relative "../buffer"
4
4
 
5
5
  module Parsanol
6
6
  module Pools
@@ -124,7 +124,7 @@ module Parsanol
124
124
  reused: stats[:reused],
125
125
  released: stats[:released],
126
126
  discarded: stats[:discarded],
127
- utilization: utilization.round(2)
127
+ utilization: utilization.round(2),
128
128
  }
129
129
  end
130
130
  result
@@ -48,7 +48,7 @@ module Parsanol
48
48
  if @available.empty?
49
49
  @stats[:created] += 1
50
50
  # Create Position with default values since it requires arguments
51
- Parsanol::Position.new('', 0, 0)
51
+ Parsanol::Position.new("", 0, 0)
52
52
  else
53
53
  @stats[:reused] += 1
54
54
  @available.pop
@@ -81,7 +81,7 @@ module Parsanol
81
81
  end
82
82
 
83
83
  # Reset position state with default values before returning to pool
84
- pos.reset!('', 0, 0)
84
+ pos.reset!("", 0, 0)
85
85
 
86
86
  @stats[:released] += 1
87
87
  @available.push(pos)
@@ -45,7 +45,7 @@ module Parsanol
45
45
 
46
46
  def calculate_charpos
47
47
  # Calculate it based on platform
48
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'opal'
48
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "opal"
49
49
  # In Opal, convert byte position to character position.
50
50
  # We need to calculate how many characters occupy the first @bytepos bytes.
51
51
  `
@@ -27,14 +27,14 @@ module Parsanol
27
27
  # @param options [Hash] Builder options
28
28
  # @return [ResultBuilder] Appropriate builder instance
29
29
  #
30
- def self.for(type, context, **options)
30
+ def self.for(type, context, **)
31
31
  case type
32
32
  when :repetition
33
- RepetitionBuilder.new(context, **options)
33
+ RepetitionBuilder.new(context, **)
34
34
  when :sequence
35
- SequenceBuilder.new(context, **options)
35
+ SequenceBuilder.new(context, **)
36
36
  when :hash
37
- HashBuilder.new(context, **options)
37
+ HashBuilder.new(context, **)
38
38
  else
39
39
  raise ArgumentError, "Unknown builder type: #{type}"
40
40
  end
@@ -86,10 +86,10 @@ module Parsanol
86
86
  # enum = stream.each # Returns Enumerator
87
87
  # enum.next # Get next node
88
88
  #
89
- def each(&block)
89
+ def each(&)
90
90
  return enum_for(:each) unless block_given?
91
91
 
92
- traverse(@tree, &block)
92
+ traverse(@tree, &)
93
93
  self
94
94
  end
95
95
 
@@ -206,7 +206,10 @@ module Parsanol
206
206
  # @return [Enumerator]
207
207
  #
208
208
  def depth_traverse(node, current_depth, target_depth, &block)
209
- return enum_for(:depth_traverse, node, current_depth, target_depth) unless block_given?
209
+ unless block
210
+ return enum_for(:depth_traverse, node, current_depth,
211
+ target_depth)
212
+ end
210
213
 
211
214
  # Check if we're at target depth
212
215
  return [node].to_enum if current_depth == target_depth && yield(node)
@@ -217,13 +220,15 @@ module Parsanol
217
220
  case node
218
221
  when Array
219
222
  node.each do |item|
220
- depth_traverse(item, current_depth + 1, target_depth, &block).each do |result|
223
+ depth_traverse(item, current_depth + 1, target_depth,
224
+ &block).each do |result|
221
225
  results << result
222
226
  end
223
227
  end
224
228
  when Hash
225
229
  node.each_value do |value|
226
- depth_traverse(value, current_depth + 1, target_depth, &block).each do |result|
230
+ depth_traverse(value, current_depth + 1, target_depth,
231
+ &block).each do |result|
227
232
  results << result
228
233
  end
229
234
  end
@@ -12,14 +12,14 @@ module Parsanol
12
12
 
13
13
  attr_reader :content, :input
14
14
 
15
- def initialize(byte_offset = 0, string_content = '', input = nil)
15
+ def initialize(byte_offset = 0, string_content = "", input = nil)
16
16
  @byte_position = byte_offset
17
17
  @content = string_content
18
18
  @input = input
19
19
  @line_and_column = nil
20
20
  end
21
21
 
22
- def reset!(new_offset = 0, new_content = '', new_input = nil)
22
+ def reset!(new_offset = 0, new_content = "", new_input = nil)
23
23
  @byte_position = new_offset
24
24
  @content = new_content
25
25
  @input = new_input
@@ -44,6 +44,7 @@ module Parsanol
44
44
  def ==(other)
45
45
  return content == other if other.is_a?(String)
46
46
  return content == other.content if other.is_a?(Parsanol::Slice)
47
+
47
48
  content == other
48
49
  end
49
50
 
@@ -72,7 +73,8 @@ module Parsanol
72
73
 
73
74
  # Lazy line/column — computed once and cached.
74
75
  def line_and_column
75
- raise ArgumentError, 'Line/column requires input' unless @input
76
+ raise ArgumentError, "Line/column requires input" unless @input
77
+
76
78
  @line_and_column ||= compute_line_and_column
77
79
  end
78
80
 
@@ -109,11 +111,11 @@ module Parsanol
109
111
  end
110
112
 
111
113
  def as_json(_options = {})
112
- result = { 'value' => content, 'offset' => offset, 'length' => length }
114
+ result = { "value" => content, "offset" => offset, "length" => length }
113
115
  if @input
114
116
  line, column = line_and_column
115
- result['line'] = line
116
- result['column'] = column
117
+ result["line"] = line
118
+ result["column"] = column
117
119
  end
118
120
  result
119
121
  end
@@ -123,7 +125,8 @@ module Parsanol
123
125
  line, column = line_and_column
124
126
  end_line, end_column = line_and_column_at(offset + length)
125
127
  start_pos = SourcePosition.new(offset: offset, line: line, column: column)
126
- end_pos = SourcePosition.new(offset: offset + length, line: end_line, column: end_column)
128
+ end_pos = SourcePosition.new(offset: offset + length, line: end_line,
129
+ column: end_column)
127
130
  SourceSpan.new(start_pos: start_pos, end_pos: end_pos)
128
131
  end
129
132
 
@@ -142,7 +145,7 @@ module Parsanol
142
145
  @input.line_and_column(pos)
143
146
  else
144
147
  # String input
145
- prefix = @input.byteslice(0, pos) || ''
148
+ prefix = @input.byteslice(0, pos) || ""
146
149
  line = 1 + prefix.count("\n")
147
150
  last_nl = prefix.rindex("\n")
148
151
  column = last_nl ? pos - last_nl : pos + 1
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'stringio'
4
- require 'strscan'
3
+ require "stringio"
4
+ require "strscan"
5
5
 
6
- require 'parsanol/position'
7
- require 'parsanol/source/line_cache'
8
- require 'parsanol/pools/slice_pool'
9
- require 'parsanol/pools/position_pool'
6
+ require "parsanol/position"
7
+ require "parsanol/source/line_cache"
8
+ require "parsanol/pools/slice_pool"
9
+ require "parsanol/pools/position_pool"
10
10
 
11
11
  module Parsanol
12
12
  # Encapsulates input source for parsing operations. Provides position tracking,
@@ -33,14 +33,19 @@ module Parsanol
33
33
  # @raise [ArgumentError] if input doesn't respond to to_str
34
34
  #
35
35
  def initialize(input)
36
- raise ArgumentError, 'Source requires a string-like object (responds to to_str)' unless input.respond_to?(:to_str)
36
+ unless input.respond_to?(:to_str)
37
+ raise ArgumentError,
38
+ "Source requires a string-like object (responds to to_str)"
39
+ end
37
40
 
38
41
  # Core scanner for input traversal
39
42
  @scanner = StringScanner.new(input)
40
43
  @raw_string = input.to_str
41
44
 
42
45
  # Regex cache: maps count n to /(.|$){n}/m pattern
43
- @regex_cache = Hash.new { |h, count| h[count] = Regexp.new("(.|$){#{count}}", Regexp::MULTILINE) }
46
+ @regex_cache = Hash.new do |h, count|
47
+ h[count] = Regexp.new("(.|$){#{count}}", Regexp::MULTILINE)
48
+ end
44
49
 
45
50
  # Line ending cache for position-to-line/column mapping
46
51
  @line_data = LineCache.new
@@ -173,7 +178,7 @@ module Parsanol
173
178
  @position_pool.acquire_with(
174
179
  string: @raw_string,
175
180
  bytepos: effective,
176
- charpos: char_pos
181
+ charpos: char_pos,
177
182
  )
178
183
  end
179
184
  end