parsanol 1.3.14-arm-linux → 1.3.16-arm-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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee82309e5f5550d8b7e874fb457082c29e441044c21f0149108947c1908fc312
4
- data.tar.gz: a58b979b3cca49c5fcc3ad04bbc592f2dc1995883500e13e1bdcab73fa3e41a9
3
+ metadata.gz: d8496db15cc90acf09d51ca06fb3fbeda98ed9a1cf010eee22177aef50d9b6e3
4
+ data.tar.gz: f11121252847374665e97bbe23881723c66314d960c7532246c3ed79f9ecd565
5
5
  SHA512:
6
- metadata.gz: d2cd46409841355d16f45d29cbe1d87fc57107bef76de6ef85c7f6cf9b154e25a0f6cb5b05f62235319b8ece92f283f6da772f834fbc629a11e867d23fd90435
7
- data.tar.gz: b44083dd31df4bde64bb04d319ef9ef605f5aca0c1f03302c284918e6779bc8c809b774d59ec92ec9acb44728a2b3acf00945dc5b9488c9f2f8627c4ff11b7c9
6
+ metadata.gz: 4d649379c1796c92079fe220dedc76fac3654805958fe956de43ee47f88099b0577621f219e51d052c35c2f0f063c919aaadfbd36789171e5dd709eac6babbba
7
+ data.tar.gz: d8e2af5697eb5d4cc745a71257d0c770d5b34dbd6e156e4da118e9516f16da348662575d8e892bb2ca466174e6abfed0c458b0658bb471c3a9b211159a4794f6
@@ -30,9 +30,29 @@ module Parsanol
30
30
  # @return [Object] the parsed result
31
31
  # @raise [Parsanol::ParseFailed] on parse failure
32
32
  def parse(source, options = {})
33
- input = normalize_input(source)
34
33
  must_consume_all = !options[:prefix]
35
34
 
35
+ # Compiled-VM fast path: String input, full-consumption semantics.
36
+ # On failure (or unsupported grammar / budget exhaustion) fall
37
+ # through to the interpreter, which also produces the exact
38
+ # cause-tree diagnostics. run_for memoizes heavy-backtracking
39
+ # grammars transparently.
40
+ if must_consume_all && source.is_a?(String) &&
41
+ (program = VM.program_for(self))
42
+ result = VM.run_for(self, program, source, true)
43
+ if result == VM::BAIL
44
+ # Internal bail: fall back to the interpreter and skip the VM
45
+ # for this grammar from now on.
46
+ VM.disable_for!(self)
47
+ elsif result.first
48
+ return finalize_result(result[1])
49
+ end
50
+ # Clean [false, nil]: the input does not parse — the interpreter
51
+ # reparse below produces the detailed cause tree.
52
+ end
53
+
54
+ input = normalize_input(source)
55
+
36
56
  # Initial parse attempt (no error collection)
37
57
  success, value = run_with_context(input, nil, must_consume_all)
38
58
  return finalize_result(value) if success
@@ -160,6 +180,11 @@ module Parsanol
160
180
  # Alias for ok (legacy compatibility)
161
181
  alias succ ok
162
182
 
183
+ # Finalizes result by flattening.
184
+ def finalize_result(value)
185
+ flatten(value)
186
+ end
187
+
163
188
  private
164
189
 
165
190
  # Converts raw input to Source if needed.
@@ -198,11 +223,6 @@ module Parsanol
198
223
 
199
224
  cause.raise
200
225
  end
201
-
202
- # Finalizes result by flattening.
203
- def finalize_result(value)
204
- flatten(value)
205
- end
206
226
  end
207
227
  end
208
228
  end
@@ -132,9 +132,11 @@ module Parsanol
132
132
  # Transform the value
133
133
  transformed = transform(value, named: true)
134
134
 
135
- # Check if value is a tagged repetition from native parser
135
+ # Check if value is a tagged repetition from native parser.
136
+ # The Rust handle path tags with Symbols, the batch decoder with
137
+ # ":repetition" Strings — accept both.
136
138
  is_tagged_repetition = value.is_a?(Array) && !value.empty? &&
137
- value.first.is_a?(String) && value.first == REPETITION_TAG
139
+ [REPETITION_SYM, REPETITION_TAG].include?(value.first)
138
140
 
139
141
  # Check RAW value for repetition pattern BEFORE transformation
140
142
  # Array with items that all have the parent key
@@ -203,13 +205,12 @@ module Parsanol
203
205
  # Empty array from repetition stays as empty array
204
206
  if transformed.empty?
205
207
  { sym_key => EMPTY_ARRAY }
206
- # Check if items already have the same key (avoid double-wrapping)
207
- elsif transformed.all? do |item|
208
- item.is_a?(Hash) && item.key?(sym_key)
209
- end
208
+ # Hash items already carry their own capture names — a
209
+ # repetition of named captures keeps them as-is (parslet
210
+ # semantics); only unnamed items get the parent name per item.
211
+ elsif transformed.all?(Hash)
210
212
  { sym_key => transformed }
211
213
  else
212
- # Wrap each item with the name
213
214
  { sym_key => transformed.map { |item| { sym_key => item } } }
214
215
  end
215
216
  elsif transformed.is_a?(::Parsanol::Slice) && transformed.empty?
@@ -38,14 +38,14 @@ module Parsanol
38
38
  def parse(grammar, input)
39
39
  raise LoadError, "Native parser not available" unless available?
40
40
 
41
- raw_ast =
42
- if grammar.is_a?(String)
43
- parse_json_grammar(grammar, input)
44
- else
45
- parse_atom_grammar(grammar, input)
46
- end
47
-
48
- BatchDecoder.decode_and_flatten(raw_ast, input, Parsanol::Slice)
41
+ # Both sub-methods return the final decoded tree; on native failure
42
+ # they fall back to the pure-Ruby parser, whose result is already
43
+ # final and must not be transformed again.
44
+ if grammar.is_a?(String)
45
+ parse_json_grammar(grammar, input)
46
+ else
47
+ parse_atom_grammar(grammar, input)
48
+ end
49
49
  end
50
50
 
51
51
  # Memory-bounded parsing without packrat cache.
@@ -65,12 +65,14 @@ module Parsanol
65
65
  Parser.serialize_grammar(grammar)
66
66
  end
67
67
 
68
+ # Decode here, not around the fallback: raise_native_parse_error
69
+ # returns the Ruby parser's already-final tree on success.
68
70
  begin
69
- raw_ast = _parse_fresh_raw(grammar_json, input)
71
+ BatchDecoder.decode_and_flatten(_parse_fresh_raw(grammar_json, input),
72
+ input, Parsanol::Slice)
70
73
  rescue RuntimeError => e
71
74
  raise_native_parse_error(e, grammar, input)
72
75
  end
73
- BatchDecoder.decode_and_flatten(raw_ast, input, Parsanol::Slice)
74
76
  end
75
77
 
76
78
  # Parse and return RAW AST without transformation.
@@ -192,7 +194,20 @@ module Parsanol
192
194
  # pre-serialized JSON grammars the native message is wrapped in a
193
195
  # Parsanol::ParseFailed directly.
194
196
  def raise_native_parse_error(error, grammar, input)
195
- return grammar.parse(input) if grammar.respond_to?(:parse)
197
+ if grammar.respond_to?(:parse)
198
+ # One interpreter pass with the error reporter attached covers
199
+ # both jobs: a success means the native backend could not
200
+ # express the grammar (recover the tree), a failure raises the
201
+ # parslet-compatible cause tree. The native backend has
202
+ # already failed, so a separate plain attempt first would be a
203
+ # wasted parse.
204
+ reporter = Parsanol::ErrorReporter::Tree.new
205
+ source = Parsanol::Source.new(input)
206
+ success, value = grammar.run_with_context(source, reporter, true)
207
+ return grammar.finalize_result(value) if success
208
+
209
+ value.raise
210
+ end
196
211
 
197
212
  source = Parsanol::Source.new(input)
198
213
  cause = Parsanol::Cause.new(error.message, source, source.bytepos)
@@ -201,7 +216,8 @@ module Parsanol
201
216
 
202
217
  # Pre-serialized JSON grammar path (library authors with cached JSON).
203
218
  def parse_json_grammar(grammar_json, input)
204
- _parse_raw(grammar_json, input)
219
+ BatchDecoder.decode_and_flatten(_parse_raw(grammar_json, input),
220
+ input, Parsanol::Slice)
205
221
  rescue RuntimeError => e
206
222
  raise_native_parse_error(e, grammar_json, input)
207
223
  end
@@ -212,12 +228,16 @@ module Parsanol
212
228
  handle = Parser.grammar_handle(grammar)
213
229
 
214
230
  begin
215
- _parse_handle(handle, input)
231
+ BatchDecoder.decode_and_flatten(_parse_handle(handle, input),
232
+ input, Parsanol::Slice)
216
233
  rescue ArgumentError
217
234
  # Handle dropped Rust-side (e.g. cache cleared): re-register once.
218
235
  Parser.invalidate_handle(handle)
219
236
  begin
220
- _parse_handle(Parser.grammar_handle(grammar), input)
237
+ BatchDecoder.decode_and_flatten(
238
+ _parse_handle(Parser.grammar_handle(grammar), input),
239
+ input, Parsanol::Slice
240
+ )
221
241
  rescue RuntimeError => e
222
242
  raise_native_parse_error(e, grammar, input)
223
243
  end
@@ -109,32 +109,36 @@ module Parsanol
109
109
  # result[:name].to_s # => "hello"
110
110
  #
111
111
  def parse(input, mode_or_opts = {}, **kwargs)
112
- if mode_or_opts.is_a?(Hash) && !kwargs.key?(:mode)
113
- # Legacy API: parse(input, options={})
114
- merged = mode_or_opts.merge(kwargs)
115
- if Parsanol::Native.available? && !merged.key?(:prefix) &&
116
- !merged.key?(:reporter)
117
- # Native backend by default; falls back to pure Ruby inside
118
- # parse_native when the extension is missing.
119
- parse_native(input, merged)
112
+ opts =
113
+ if mode_or_opts.is_a?(Hash)
114
+ mode_or_opts.merge(kwargs)
115
+ elsif mode_or_opts.nil?
116
+ kwargs
120
117
  else
121
- super(input, merged)
118
+ # New API: parse(input, :mode, **options)
119
+ kwargs[:mode] = mode_or_opts
120
+ kwargs
122
121
  end
122
+ # parse(input, {mode: :ruby, ...}) is the same call shape a subclass
123
+ # forwarding options via super produces; :mode must be honored
124
+ # wherever it appears, or those callers silently get the native path.
125
+ mode = opts.delete(:mode) ||
126
+ (if Parsanol::Native.available? && !opts.key?(:prefix) &&
127
+ !opts.key?(:reporter)
128
+ :native
129
+ else
130
+ :ruby
131
+ end)
132
+ case mode
133
+ when :ruby
134
+ super(input, opts)
135
+ when :native
136
+ parse_native(input, opts)
137
+ when :json
138
+ parse_json(input, opts)
123
139
  else
124
- # New API: parse(input, mode:, **options)
125
- mode = kwargs.delete(:mode) ||
126
- (Parsanol::Native.available? ? :native : :ruby)
127
- case mode
128
- when :ruby
129
- super(input, kwargs)
130
- when :native
131
- parse_native(input, kwargs)
132
- when :json
133
- parse_json(input, kwargs)
134
- else
135
- raise ArgumentError,
136
- "Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
137
- end
140
+ raise ArgumentError,
141
+ "Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
138
142
  end
139
143
  end
140
144
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.14"
4
+ VERSION = "1.3.16"
5
5
  end