parsanol 1.3.30 → 1.3.32
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 +4 -4
- data/Cargo.lock +4 -4
- data/README.adoc +18 -0
- data/ext/parsanol_native/extconf.rb +12 -0
- data/lib/parsanol/version.rb +1 -1
- data/lib/parsanol.rb +50 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41651c6d4901c45b1b2d8973eb221d28ea31412a832a88a6c24e6e765bd7617e
|
|
4
|
+
data.tar.gz: 92260b260487280d55c561e49ef9342ce2a752bd12ead9dd3cedca190f260946
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d47ce37751cc457c2e0f878fed50c3b0d337cf663843f821b1aeb792325371862f951f4b3b324983408def926959bd7487ff0c3879b3603a93f8c5fc8a806d94
|
|
7
|
+
data.tar.gz: bd256709d110df1092d60ef05939c9d8a2d3fe6db6714987eb60ad67ce47407c1f9b37701245f5745e940d712cdbff766ae3f7dfe11bc72764f0e1f08fdcf3c4
|
data/Cargo.lock
CHANGED
|
@@ -252,8 +252,8 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
|
252
252
|
|
|
253
253
|
[[package]]
|
|
254
254
|
name = "parsanol"
|
|
255
|
-
version = "0.5.
|
|
256
|
-
source = "git+https://github.com/parsanol/parsanol-rs?branch=main#
|
|
255
|
+
version = "0.5.3"
|
|
256
|
+
source = "git+https://github.com/parsanol/parsanol-rs?branch=main#3a441c45ce089cae40ed69260bf00c4ed6de635a"
|
|
257
257
|
dependencies = [
|
|
258
258
|
"ahash",
|
|
259
259
|
"getrandom 0.3.4",
|
|
@@ -269,8 +269,8 @@ dependencies = [
|
|
|
269
269
|
|
|
270
270
|
[[package]]
|
|
271
271
|
name = "parsanol-derive"
|
|
272
|
-
version = "0.5.
|
|
273
|
-
source = "git+https://github.com/parsanol/parsanol-rs?branch=main#
|
|
272
|
+
version = "0.5.3"
|
|
273
|
+
source = "git+https://github.com/parsanol/parsanol-rs?branch=main#3a441c45ce089cae40ed69260bf00c4ed6de635a"
|
|
274
274
|
dependencies = [
|
|
275
275
|
"proc-macro2",
|
|
276
276
|
"quote",
|
data/README.adoc
CHANGED
|
@@ -156,6 +156,24 @@ Run your own benchmarks with:
|
|
|
156
156
|
bundle exec ruby examples/benchmark_examples.rb
|
|
157
157
|
----
|
|
158
158
|
|
|
159
|
+
[[engine-posture]]
|
|
160
|
+
==== Engine roles
|
|
161
|
+
|
|
162
|
+
Parsanol ships two engines with one semantic contract (identical parse
|
|
163
|
+
trees and error messages):
|
|
164
|
+
|
|
165
|
+
* **Native (default)** — the Rust extension. It handles every parsing
|
|
166
|
+
mode, including error cause trees, `prefix:` and `reporter:`, with no
|
|
167
|
+
Ruby fallback during parsing. Prebuilt platform gems cover the common
|
|
168
|
+
triples; `bundle exec rake compile` builds it locally otherwise.
|
|
169
|
+
* **Ruby (`mode: :ruby`)** — the pure-Ruby engine. Its role is
|
|
170
|
+
portability (no prebuilt gem, no Rust toolchain, non-MRI rubies) and
|
|
171
|
+
serving as the semantic reference implementation for differential
|
|
172
|
+
testing against Parslet.
|
|
173
|
+
|
|
174
|
+
When both are available, the native engine is always used unless
|
|
175
|
+
`mode: :ruby` is requested explicitly.
|
|
176
|
+
|
|
159
177
|
[[slice-support]]
|
|
160
178
|
=== Slice Support
|
|
161
179
|
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "mkmf"
|
|
4
|
+
|
|
5
|
+
# The Rust extension only builds against MRI's C API. Other engines
|
|
6
|
+
# (TruffleRuby, JRuby) resolve the ruby-platform gem and must install
|
|
7
|
+
# cleanly on the pure-Ruby backend instead of failing the whole install
|
|
8
|
+
# (parsanol-ruby#23). An explicit opt-out works on MRI too.
|
|
9
|
+
if RUBY_ENGINE != "ruby" || ENV["PARSANOL_NATIVE"] == "0"
|
|
10
|
+
File.write("Makefile", dummy_makefile("").to_s)
|
|
11
|
+
warn "parsanol: skipping the Rust extension on #{RUBY_ENGINE} " \
|
|
12
|
+
"(pure-Ruby backend will be used)"
|
|
13
|
+
exit 0
|
|
14
|
+
end
|
|
15
|
+
|
|
4
16
|
require "rb_sys/mkmf"
|
|
5
17
|
|
|
6
18
|
create_rust_makefile("parsanol/parsanol_native") do |r|
|
data/lib/parsanol/version.rb
CHANGED
data/lib/parsanol.rb
CHANGED
|
@@ -129,10 +129,60 @@ module Parsanol
|
|
|
129
129
|
def match(pattern = nil)
|
|
130
130
|
return CharacterClassBuilder.new unless pattern
|
|
131
131
|
|
|
132
|
+
match_quantifier_warning(pattern)
|
|
132
133
|
Atoms::Re.new(pattern)
|
|
133
134
|
end
|
|
134
135
|
module_function :match
|
|
135
136
|
|
|
137
|
+
# `match` consumes exactly one character (Parslet parity), so a regex
|
|
138
|
+
# quantifier is silently truncated: match(/[0-9]+/) matches a single
|
|
139
|
+
# digit. Warn once per offending pattern — the intended spelling is
|
|
140
|
+
# `match("[0-9]").repeat(1)`.
|
|
141
|
+
# Deliberately mutable: it accumulates warned patterns per process.
|
|
142
|
+
QUANTIFIER_WARNED = {} # rubocop:disable Style/MutableConstant
|
|
143
|
+
private_constant :QUANTIFIER_WARNED
|
|
144
|
+
|
|
145
|
+
def match_quantifier_warning(pattern)
|
|
146
|
+
return if QUANTIFIER_WARNED.key?(pattern)
|
|
147
|
+
return unless pattern.is_a?(String)
|
|
148
|
+
return unless quantified_pattern?(pattern)
|
|
149
|
+
|
|
150
|
+
QUANTIFIER_WARNED[pattern] = true
|
|
151
|
+
warn "Parsanol: match(#{pattern.inspect}) matches exactly one character " \
|
|
152
|
+
"(Parslet parity); the quantifier is ignored. " \
|
|
153
|
+
"Use match(...).repeat(1) to match repeatedly."
|
|
154
|
+
end
|
|
155
|
+
module_function :match_quantifier_warning
|
|
156
|
+
|
|
157
|
+
# True when the pattern carries a top-level quantifier (+, *, ?, or
|
|
158
|
+
# {n,m}) outside a character class.
|
|
159
|
+
def quantified_pattern?(pattern)
|
|
160
|
+
in_class = false
|
|
161
|
+
escaped = false
|
|
162
|
+
previous = nil
|
|
163
|
+
|
|
164
|
+
pattern.each_char.with_index do |ch, idx|
|
|
165
|
+
if escaped
|
|
166
|
+
escaped = false
|
|
167
|
+
elsif ch == "\\"
|
|
168
|
+
escaped = true
|
|
169
|
+
elsif in_class
|
|
170
|
+
in_class = false if ch == "]"
|
|
171
|
+
elsif ch == "["
|
|
172
|
+
in_class = true
|
|
173
|
+
elsif %w[+ * ?].include?(ch) || (ch == "{" && idx + 1 < pattern.length && pattern[idx + 1] =~ /\d/)
|
|
174
|
+
# A leading quantifier applies to nothing and cannot truncate a
|
|
175
|
+
# character match; any other quantifier does.
|
|
176
|
+
return true if idx.positive? && !previous.nil? && previous != "("
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
previous = ch
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
false
|
|
183
|
+
end
|
|
184
|
+
module_function :quantified_pattern?
|
|
185
|
+
|
|
136
186
|
# Creates a literal string matcher.
|
|
137
187
|
#
|
|
138
188
|
# @param literal [String] the string to match
|