parsanol 1.3.74 → 1.3.75

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: f6eac7cb7780cfacc7d2a1989e6cea0ee26edc13f3e2d133cefc4f363a8f3e2e
4
- data.tar.gz: 6629c13a4cdbf3fea6378028ae736e49a547688443769278e9583bf508462087
3
+ metadata.gz: ca6a45b629235f8dc4976c046341a91d159a699f2784c564b08f73f31ed7cb49
4
+ data.tar.gz: f0fcbe3350657d533a298e67384eb54861fd5289a4ec049d98425d6db689012b
5
5
  SHA512:
6
- metadata.gz: f5f374af54ca2375e94cd04d9771088b10b383ec046731ff57f2d36da85961d29ba6c2c6af2063e88836980a5bb0c1c4d8fbaaa98af98112e4cbf9b5da4dec39
7
- data.tar.gz: 6f6f2ee120b8a45fe28a403504cd198225ae4833d4e8925758cc16160a0f64f4c2b005b622fec7bd0ad3ded616f402550edf0fa4893c0858434cbe825d0b48c3
6
+ metadata.gz: 720729fb5363a237a40bf29ca97c21d977c45a0b3f30c58025abc32b940edfbc2ee8bcbe791697180d9272ea21370df0b59469a984b0cc815177f0989ca2e044
7
+ data.tar.gz: 66a5dd4694fd3ee9d8791e2fa94b68c6103762b2cd2f43322b508eb6dbee2d7bf1cb4c345403de1eecbfa9ce50ed5f5161441f9f6f2f958a550bdf6e7c893c05
data/Cargo.lock CHANGED
@@ -307,9 +307,9 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
307
307
 
308
308
  [[package]]
309
309
  name = "parsanol"
310
- version = "0.14.0"
310
+ version = "0.15.0"
311
311
  source = "registry+https://github.com/rust-lang/crates.io-index"
312
- checksum = "25d42f7d6475885046f668bdabb6f2f8c13807148811b9d1b618fd00ec07a858"
312
+ checksum = "01c2f6b018d28cdf676aa117f37747b227476b3f5fad5b577b51abb01609e6b5"
313
313
  dependencies = [
314
314
  "ahash",
315
315
  "getrandom 0.3.4",
@@ -326,9 +326,9 @@ dependencies = [
326
326
 
327
327
  [[package]]
328
328
  name = "parsanol-derive"
329
- version = "0.14.0"
329
+ version = "0.15.0"
330
330
  source = "registry+https://github.com/rust-lang/crates.io-index"
331
- checksum = "8ebddcf7d0b843657a5699f3cdeb7805bc934fcb8df24c6ab460d4dd345562d1"
331
+ checksum = "0aff970b9bcf36471356270512814045b011f30bb93f46382529ee94b3d8e11a"
332
332
  dependencies = [
333
333
  "proc-macro2",
334
334
  "quote",
@@ -12,5 +12,5 @@ crate-type = ["cdylib"]
12
12
  doc = false
13
13
 
14
14
  [dependencies]
15
- # 0.14.0 carries the TriviaCapture atom (native capture parity)
16
- parsanol = { version = "0.14.0" }
15
+ # 0.15.0 carries the Constant and Lookbehind atoms
16
+ parsanol = { version = "0.15.0" }
@@ -29,9 +29,9 @@ magnus = { version = "0.9" }
29
29
 
30
30
  # parsanol parser library (crates.io; 0.12 carries the rs#174 native
31
31
  # backtracking fix: dynamic-dependent memoization + outcome cache)
32
- # parsanol parser library (crates.io; 0.14.0 carries the TriviaCapture
33
- # atom: native trivia-capture parity, rs#172/#152)
34
- parsanol = { version = "0.14.0", features = ["ruby"] }
32
+ # parsanol parser library (crates.io; 0.15.0 carries the Constant and
33
+ # Lookbehind atoms: the coradoc-markdown native gap, rs#137 follow-up)
34
+ parsanol = { version = "0.15.0", features = ["ruby"] }
35
35
 
36
36
  # Logging
37
37
  log = "0.4"
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parsanol
4
+ module Atoms
5
+ # Matches empty and yields a constant value (coradoc-markdown
6
+ # Output parity, rs#137 follow-up): the native wire carries the
7
+ # value as wire data, so constant-yielding grammar shapes parse
8
+ # on both engines with identical trees.
9
+ class Constant < Base
10
+ attr_reader :value
11
+
12
+ def initialize(value)
13
+ super()
14
+ @value = value
15
+ end
16
+
17
+ def try(_source, _context, _consume_all)
18
+ [true, @value]
19
+ end
20
+
21
+ def to_s_inner(_prec)
22
+ "constant(#{@value.inspect})"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parsanol
4
+ module Atoms
5
+ # Inspects the byte window behind the current position: the
6
+ # previous +count+ bytes must equal +pattern+ (positive) or
7
+ # differ (negative). Consumes nothing, yields nil — the
8
+ # precedes?/does_not_precede? guard shape (coradoc-markdown
9
+ # parity, rs#137 follow-up).
10
+ class Lookbehind < Base
11
+ attr_reader :count, :pattern, :positive
12
+
13
+ def initialize(count, pattern, positive: true)
14
+ super()
15
+ @count = count
16
+ @pattern = pattern
17
+ @positive = positive
18
+ end
19
+
20
+ def try(source, _context, _consume_all)
21
+ start = source.bytepos
22
+ behind = start >= @count ? source.input.byteslice(start - @count, @count) : nil
23
+ matched = !behind.nil? && behind == @pattern.b
24
+ [matched == @positive, nil]
25
+ end
26
+
27
+ def to_s_inner(_prec)
28
+ "lookbehind(#{@count}, #{@pattern.inspect}, #{@positive ? '+' : '-'})"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -30,6 +30,8 @@ module Parsanol
30
30
  require "parsanol/atoms/trivia"
31
31
  require "parsanol/atoms/named"
32
32
  require "parsanol/atoms/lookahead"
33
+ require "parsanol/atoms/constant"
34
+ require "parsanol/atoms/lookbehind"
33
35
  require "parsanol/atoms/cut"
34
36
  require "parsanol/atoms/alternative"
35
37
  require "parsanol/atoms/sequence"
@@ -191,6 +191,13 @@ module Parsanol
191
191
  when ::Parsanol::Atoms::Lookahead
192
192
  [:lookahead, atom.positive,
193
193
  atom_structure(atom.bound_parslet, visited)]
194
+ when ::Parsanol::Atoms::Constant
195
+ # The value differentiates otherwise-identical constant
196
+ # atoms — without it every Constant hashes alike and the
197
+ # grammar cache serves the first wire forever.
198
+ [:constant, atom.value.inspect]
199
+ when ::Parsanol::Atoms::Lookbehind
200
+ [:lookbehind, atom.count, atom.pattern, atom.positive]
194
201
  else
195
202
  [:unknown, atom.class.name]
196
203
  end
@@ -18,6 +18,10 @@ module Parsanol
18
18
  def initialize
19
19
  @atoms = []
20
20
  @atom_cache = {} # object_id => atom_id for deduplication
21
+ # Strong retention: cache keys are object_ids; without holding the
22
+ # atoms, the GC can free one and a later allocation reuses its id,
23
+ # aliasing to a stale wire atom (the #138 recycled-id class).
24
+ @retained_atoms = []
21
25
  end
22
26
 
23
27
  # Main serialization method
@@ -94,6 +98,20 @@ module Parsanol
94
98
  # reject skip-carrying artifacts loudly (unknown
95
99
  # variant), which is the declared gate.
96
100
  serialize_trivia(atom)
101
+ when Parsanol::Atoms::Constant
102
+ # rs#137 follow-up: coradoc-markdown's Output
103
+ # atoms — empty match yielding a wire constant.
104
+ { "Constant" => { "value" => serialize_constant_value(atom.value) } }
105
+ when Parsanol::Atoms::Lookbehind
106
+ # rs#137 follow-up: the precedes?/does_not_precede?
107
+ # guards — inspect the bytes behind the position.
108
+ {
109
+ "Lookbehind" => {
110
+ "count" => atom.count,
111
+ "pattern" => atom.pattern,
112
+ "positive" => atom.positive,
113
+ },
114
+ }
97
115
  when Parsanol::Atoms::Ignored
98
116
  serialize_ignored(atom)
99
117
  else
@@ -104,6 +122,7 @@ module Parsanol
104
122
  # Now reserve an atom_id and cache
105
123
  atom_id = @atoms.size
106
124
  @atom_cache[cache_key] = atom_id
125
+ @retained_atoms << atom
107
126
  @atoms << serialized
108
127
 
109
128
  atom_id
@@ -179,6 +198,7 @@ module Parsanol
179
198
  # This prevents infinite recursion when a rule references itself
180
199
  atom_id = @atoms.size
181
200
  @atom_cache[cache_key] = atom_id
201
+ @retained_atoms << atom
182
202
 
183
203
  # Add a placeholder that will be replaced
184
204
  @atoms << nil
@@ -292,6 +312,22 @@ module Parsanol
292
312
  "parse this grammar with mode: :ruby"
293
313
  end
294
314
 
315
+ def serialize_constant_value(value)
316
+ case value
317
+ when nil then "Nil" # unit variant serializes as the bare tag
318
+ when true, false then { "Bool" => value }
319
+ when Integer then { "Int" => value }
320
+ when String then { "Str" => value }
321
+ when Array then { "Array" => value.map { |v| serialize_constant_value(v) } }
322
+ when Hash
323
+ { "Hash" => value.map { |k, v| [k.to_s, serialize_constant_value(v)] } }
324
+ else
325
+ raise UnsupportedGrammar,
326
+ "constant atoms carry nil/bool/int/string/array/hash values " \
327
+ "(got #{value.class}); restructure the grammar for native parsing"
328
+ end
329
+ end
330
+
295
331
  def serialize_trivia_capture(atom)
296
332
  inner_id = serialize_atom(atom.wrapped_atom)
297
333
  {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.74"
4
+ VERSION = "1.3.75"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parsanol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.74
4
+ version: 1.3.75
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -55,6 +55,7 @@ files:
55
55
  - lib/parsanol/atoms/base.rb
56
56
  - lib/parsanol/atoms/can_flatten.rb
57
57
  - lib/parsanol/atoms/capture.rb
58
+ - lib/parsanol/atoms/constant.rb
58
59
  - lib/parsanol/atoms/context.rb
59
60
  - lib/parsanol/atoms/context_optimized.rb
60
61
  - lib/parsanol/atoms/custom.rb
@@ -65,6 +66,7 @@ files:
65
66
  - lib/parsanol/atoms/ignored.rb
66
67
  - lib/parsanol/atoms/infix.rb
67
68
  - lib/parsanol/atoms/lookahead.rb
69
+ - lib/parsanol/atoms/lookbehind.rb
68
70
  - lib/parsanol/atoms/named.rb
69
71
  - lib/parsanol/atoms/re.rb
70
72
  - lib/parsanol/atoms/repetition.rb