parsanol 1.3.80-arm-linux → 1.3.81-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: '082b8651b4be9f5cfa8579ddd021a01b76e72a00f8a5ee108f2674c1c8990bfd'
4
- data.tar.gz: b5f94c8e10d8156c10873e9d5eebad3f4395307ed3f13b4df9bab939333e6a82
3
+ metadata.gz: 01fb11b456bec79f8f4bd6b6db018ef771260440414f75ef02f4e1520ec2caf2
4
+ data.tar.gz: 75e011ecd46597e4c008cbb3fd2c7e3d2bda46ba4cd716c1613a351a28d99fb8
5
5
  SHA512:
6
- metadata.gz: 1c9b597c365b5c7bd2d79aca132450dd8a93b03129a26a95403195b1b68722938b26baec0e4929f772f8a917daacada8cdbf11a5daf62ef3d5b2e52142bade4f
7
- data.tar.gz: fe3d1efcd398ac36c28dd230d07593b96293ce827725d12972a8f7e7abe9b21ebcab653356d3c0794c2fabd9bc156dbabb1b931c2dfd06d0646d2b6770fa8d14
6
+ metadata.gz: 602203c6a4b11eef7c4af0613212091742b1c2f4d9a0250ee27dc7e6d67a891a77c318a70feb7f38b168d64dfd6843ace2123687cc8a17713b0dd9fcb8c8bc43
7
+ data.tar.gz: 49afc1a994a7aeb1b3231446890bc729da4c6a76f520fa448c872437f45861fb4e912a1dfbf8476e13c37e4723dc21b3675e1e4dc8156851d645905006e0c1dd
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.2/parsanol_native.so
3
- size: 33857428 bytes
4
- sha256: 555fffa50043f91efe6d1003cf97ba60224c83b0118205bff2033615de4bf54d
3
+ size: 33956544 bytes
4
+ sha256: 5f8d55c4f6ab0f5bba8ea501b6ab13b16df2bfa1b63b823152d70bb86b95daaf
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.3/parsanol_native.so
3
- size: 34042676 bytes
4
- sha256: 63a27cccdad9628f8dba74a5efdf1d6993ad7b5ad69a434746608ca1df28dd9c
3
+ size: 34141808 bytes
4
+ sha256: c9ec101532d77f531c2b73fd93c48add52fcd2fc0a06e4047b9e1deb9dc5c4d6
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.4/parsanol_native.so
3
- size: 34036828 bytes
4
- sha256: a7917405bf0af8cbff7095c8391970d47165543ec62fcc25518a3bd017e03397
3
+ size: 34135964 bytes
4
+ sha256: 42f14ef394d8a41ed832e9a9f61fbc0868056062d94df7ea62403290c5581c31
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/4.0/parsanol_native.so
3
- size: 34046564 bytes
4
- sha256: 3eb609a621681ded3508cdbb5fe6fb0ebea27419febfb58243b56625d041db51
3
+ size: 34145720 bytes
4
+ sha256: 953c7f621b8c343ab150a9dada110ad29b94d571cc621d0be94c8235419bd2b1
Binary file
@@ -205,6 +205,19 @@ module Parsanol
205
205
  [:constant, atom.value.inspect]
206
206
  when ::Parsanol::Atoms::Lookbehind
207
207
  [:lookbehind, atom.count, atom.pattern, atom.positive]
208
+ # Subclass first: TriviaCapture < Trivia < Ignored (the same
209
+ # dispatch discipline as the serializer's).
210
+ when ::Parsanol::Atoms::TriviaCapture
211
+ # The capturer table differentiates capture-carrying
212
+ # grammars from plain-trivia ones — without it the grammar
213
+ # cache serves one variant's wire to every other and the
214
+ # wrong marker table reaches the engine (parsanol-ruby#180).
215
+ [:trivia_capture, atom.capturers.to_a.sort,
216
+ atom_structure(atom.wrapped_atom, visited)]
217
+ when ::Parsanol::Atoms::Trivia
218
+ [:trivia, atom_structure(atom.wrapped_atom, visited)]
219
+ when ::Parsanol::Atoms::Ignored
220
+ [:ignored, atom_structure(atom.wrapped_atom, visited)]
208
221
  else
209
222
  [:unknown, atom.class.name]
210
223
  end
@@ -65,24 +65,26 @@ module Parsanol
65
65
  def parse(entry_name, input, mode: :native)
66
66
  case mode
67
67
  when :native
68
- if Native.available? && !envelope["dynamic"]
69
- # Fast lane (parsanol-ruby#162): the per-instance atom
70
- # tree rides the DSL serialization/registration caches
68
+ if Native.available?
69
+ # Fast lane (parsanol-ruby#162): Native.parse with the
70
+ # per-instance root atom registers the grammar once
71
71
  # (GRAMMAR_CACHE / HANDLE_CACHE keyed on the stable root
72
- # atom), so an artifact parses at compiled speed after
73
- # the first call. The old path re-serialized the whole
74
- # grammar JSON and re-registered it per parse (~8x).
75
- # Dynamic artifacts carry ruby-tier atoms their wire
76
- # cannot express — they keep the interpreter.
77
- begin
78
- return root_atom(entry_name).parse(input, mode: :native)
79
- rescue Parsanol::ParseFailed
80
- # The atom-tree native path reports the root position; the
81
- # wire-registration path carries the deepest-failure
82
- # diagnostics (parsanol-ruby#171). Failures pay the
83
- # serialization once; successes keep the fast lane.
84
- return Native.parse(JSON.generate(entry(entry_name).fetch("grammar")), input)
85
- end
72
+ # atom) and every parse after the first runs the native
73
+ # engine by handle — the same path a DSL parser's
74
+ # mode: :native takes. Atoms::Base#parse must NOT carry
75
+ # this lane: it ignores :mode, so it would silently run
76
+ # the pure-Ruby VM and its interpreter fallback (the
77
+ # 5-7x real-document gap in #162, and the root-position
78
+ # diagnostics in #171 before the wire fallback).
79
+ #
80
+ # Dynamic-flagged artifacts parse natively too (rs#204):
81
+ # the state atoms (StateSet/StateMatch/StateSwitch)
82
+ # evaluate in the engine, riding the capture store's
83
+ # rollback discipline. Reaching a CustomRef aborts the
84
+ # native pass outright — Native.parse's error path then
85
+ # re-runs the interpreter, so customs stay Ruby-tier with
86
+ # identical trees.
87
+ return Native.parse(root_atom(entry_name), input)
86
88
  end
87
89
 
88
90
  root_atom(entry_name).parse(input)
@@ -52,7 +52,12 @@ module Parsanol
52
52
  define_method(:root) do
53
53
  atom = __send__(rule_name)
54
54
  skip_name = self.class.skip_rule_name
55
- skip_name ? Parsanol::Skip.inject(self, atom, skip_name)[0] : atom
55
+ if skip_name
56
+ Parsanol::Skip.inject(self, atom, skip_name,
57
+ captures: self.class.skip_captures)[0]
58
+ else
59
+ atom
60
+ end
56
61
  end
57
62
  end
58
63
 
@@ -63,6 +68,13 @@ module Parsanol
63
68
  # everything it references) builds without injection; it must be
64
69
  # non-nullable. Order-independent with +root+.
65
70
  #
71
+ # +capture:+ (parsanol-ruby#180) declares trivia capturers — a
72
+ # map of rule name to kind label. Units of the skip rule
73
+ # matching a capturer's leading literal attach to the next
74
+ # Named capture under +comments:+ (the PARG
75
+ # `skip = trivia capture: comments` shape) instead of being
76
+ # discarded; whitespace-shaped units never record.
77
+ #
66
78
  # @example
67
79
  # class MyParser < Parsanol::Parser
68
80
  # rule(:spaces) { match(/[ \t]/).repeat(1) }
@@ -72,8 +84,14 @@ module Parsanol
72
84
  # root :doc
73
85
  # end
74
86
  #
75
- def skip(rule_name)
87
+ # @example capturing comments
88
+ # rule(:trivia) { spaces | line_comment }
89
+ # rule(:line_comment) { str("//") >> match(/[^\n]/).repeat }
90
+ # skip :trivia, capture: { line_comment: :line_comment }
91
+ #
92
+ def skip(rule_name, capture: nil)
76
93
  @skip_rule_name = rule_name
94
+ @skip_captures = capture
77
95
  nil
78
96
  end
79
97
 
@@ -82,6 +100,12 @@ module Parsanol
82
100
  def skip_rule_name
83
101
  @skip_rule_name
84
102
  end
103
+
104
+ # The declared capturer map ({rule => kind label}), or nil —
105
+ # see {.skip}.
106
+ def skip_captures
107
+ @skip_captures
108
+ end
85
109
  end
86
110
 
87
111
  # Delegates matching to the root rule.
data/lib/parsanol/skip.rb CHANGED
@@ -13,7 +13,14 @@ module Parsanol
13
13
  # methods. Returns [injected_root, skip_atom] with the wrapper
14
14
  # built and the lint applied, or raises GrammarError for a
15
15
  # nullable skip.
16
- def self.inject(parser_instance, root_atom, skip_rule_name)
16
+ #
17
+ # +captures+ (parsanol-ruby#180) maps capturer rule names to kind
18
+ # labels (`skip :trivia, capture: { line_comment: :line }`); the
19
+ # injected wrapper becomes a TriviaCapture whose units matching a
20
+ # capturer's leading literal attach to the next Named capture
21
+ # under `comments:` — the PARG `skip = trivia capture: comments`
22
+ # shape. Whitespace-shaped units never record.
23
+ def self.inject(parser_instance, root_atom, skip_rule_name, captures: nil)
17
24
  skip_atom = parser_instance.__send__(skip_rule_name)
18
25
  skip_atom = skip_atom.parslet while skip_atom.is_a?(Atoms::Entity)
19
26
 
@@ -23,10 +30,62 @@ module Parsanol
23
30
  "empty loops forever at injection points"
24
31
  end
25
32
 
26
- injector = Injector.new(skip_atom)
33
+ markers = capturer_markers(parser_instance, captures)
34
+ injector = Injector.new(skip_atom, markers)
27
35
  [injector.inject(root_atom, entry: true), skip_atom]
28
36
  end
29
37
 
38
+ # Derives each capturer's leading literal (the leftmost Str the
39
+ # rule can start with) and keys the marker table by it — the same
40
+ # derivation the PARG compiler applies to its skip declaration. A
41
+ # declared capturer without a derivable, non-blank literal is a
42
+ # declaration error: its units could never be told apart from
43
+ # whitespace-shaped trivia and it would silently record nothing.
44
+ def self.capturer_markers(parser_instance, captures)
45
+ return nil if captures.nil? || captures.empty?
46
+
47
+ captures.each_with_object({}) do |(rule_name, kind), markers|
48
+ atom = parser_instance.__send__(rule_name)
49
+ atom = atom.parslet while atom.is_a?(Atoms::Entity)
50
+ literal = leading_literal(atom)
51
+ if literal.nil? || literal.strip.empty?
52
+ raise GrammarError,
53
+ "skip capturer #{rule_name.inspect} has no leading " \
54
+ "literal: its units cannot be told apart from " \
55
+ "whitespace-shaped trivia"
56
+ end
57
+ markers[literal] = kind || rule_name
58
+ end
59
+ end
60
+
61
+ # The leftmost literal the atom can start with, or nil when the
62
+ # shape is not literal-led (alternatives with disagreeing
63
+ # branches, regexes, lookaheads).
64
+ def self.leading_literal(atom)
65
+ case atom
66
+ when Atoms::Str then atom.str
67
+ when Atoms::Sequence
68
+ atom.parslets.each do |child|
69
+ literal = leading_literal(child)
70
+ return literal if literal
71
+ end
72
+ nil
73
+ when Atoms::Alternative
74
+ first = nil
75
+ atom.alternatives.each do |branch|
76
+ literal = leading_literal(branch)
77
+ return nil if literal.nil? || (first && literal != first)
78
+
79
+ first ||= literal
80
+ end
81
+ first
82
+ when Atoms::Repetition
83
+ atom.min&.positive? ? leading_literal(atom.parslet) : nil
84
+ when Atoms::Named, Atoms::Capture, Atoms::Ignored, Atoms::Trivia
85
+ leading_literal(atom.parslet)
86
+ end
87
+ end
88
+
30
89
  # The injection walk. Mirrors the PARG compiler's semantics:
31
90
  # sequences interleave the wrapper before every child, alternatives
32
91
  # and repetitions descend, named captures descend (spans stay
@@ -34,8 +93,9 @@ module Parsanol
34
93
  # transparency), bare terminals gain a leading wrapper, and the
35
94
  # entry root takes leading and trailing wrappers.
36
95
  class Injector
37
- def initialize(skip_atom)
96
+ def initialize(skip_atom, markers = nil)
38
97
  @skip_atom = skip_atom
98
+ @markers = markers
39
99
  @wrapper_ids = {}.compare_by_identity
40
100
  end
41
101
 
@@ -50,7 +110,13 @@ module Parsanol
50
110
 
51
111
  def maybe
52
112
  @maybe ||= begin
53
- wrapper = Atoms::Trivia.new(Atoms::Repetition.new(@skip_atom, 0, 1))
113
+ inner = Atoms::Repetition.new(@skip_atom, 0, 1)
114
+ wrapper =
115
+ if @markers
116
+ Atoms::TriviaCapture.new(inner, @markers)
117
+ else
118
+ Atoms::Trivia.new(inner)
119
+ end
54
120
  @wrapper_ids[wrapper] = true
55
121
  wrapper
56
122
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.80"
4
+ VERSION = "1.3.81"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parsanol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.80
4
+ version: 1.3.81
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-07 00:00:00.000000000 Z
11
+ date: 2026-10-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A small Ruby library for constructing parsers in the PEG (Parsing Expression
14
14
  Grammar) fashion. Parsanol provides Parslet-compatible API with additional features