parslet 1.7.1 → 1.8.0
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/HISTORY.txt +14 -0
- data/lib/parslet.rb +18 -9
- data/lib/parslet/accelerator.rb +1 -0
- data/lib/parslet/atoms.rb +1 -0
- data/lib/parslet/atoms/base.rb +2 -2
- data/lib/parslet/atoms/can_flatten.rb +1 -1
- data/lib/parslet/atoms/dsl.rb +11 -0
- data/lib/parslet/atoms/entity.rb +1 -0
- data/lib/parslet/atoms/ignored.rb +26 -0
- data/lib/parslet/atoms/infix.rb +5 -4
- data/lib/parslet/atoms/lookahead.rb +1 -1
- data/lib/parslet/cause.rb +2 -2
- data/lib/parslet/context.rb +2 -16
- data/lib/parslet/convenience.rb +2 -2
- data/lib/parslet/error_reporter/deepest.rb +1 -1
- data/lib/parslet/parser.rb +2 -1
- data/lib/parslet/pattern.rb +4 -5
- data/lib/parslet/rig/rspec.rb +5 -12
- data/lib/parslet/slice.rb +1 -1
- data/lib/parslet/source/line_cache.rb +1 -0
- data/lib/parslet/transform.rb +11 -3
- data/parslet.gemspec +2 -4
- data/spec/acceptance/examples_spec.rb +2 -2
- data/spec/acceptance/infix_parser_spec.rb +9 -0
- data/spec/parslet/atoms/ignored_spec.rb +15 -0
- data/spec/parslet/atoms_spec.rb +3 -3
- data/spec/parslet/transform/context_spec.rb +37 -16
- data/spec/parslet/transform_spec.rb +23 -5
- data/spec/spec_helper.rb +3 -1
- metadata +7 -25
- data/example/ignore.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 930ed2d329af700f3465739d6db3e2897ef64fbc
|
4
|
+
data.tar.gz: ea14cb80ebd03f9b6b9e55aa461021ffaa79a622
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0872f8510339d1dfd97c4060ac4298115f2270765b192804e7722e27f93c90df38b915af6cc867792ecfca3137fd8291b4d7ac854b20849884dd9214185d837f
|
7
|
+
data.tar.gz: 76bb599af2b8df83c53dccbc4bd49652b1a49c3046c9e5bd6f37dd8e30dfe66db07142eb66032886cf0dd78b55bb3763840962d6c41b956e8394e3ca2bd7fcf4
|
data/HISTORY.txt
CHANGED
@@ -1,7 +1,21 @@
|
|
1
|
+
|
1
2
|
= 2.0 / ?? (future release changes, like a reminder to self)
|
2
3
|
|
3
4
|
- prsnt? and absnt? are now finally banned into oblivion. Wasting vocals for
|
4
5
|
the win.
|
6
|
+
|
7
|
+
= 1.8 / 3Apr2017
|
8
|
+
|
9
|
+
+ The `ignored` atom that allows to ignore a part of the matched text.
|
10
|
+
`str('foo').ignore` will match 'foo', but not yield any parse output.
|
11
|
+
Thanks to chrismwendt (Chris Wendt).
|
12
|
+
+ Infix expression parser (arithmetics, anyone?) now supports custom reducers
|
13
|
+
in block form. Thanks to chrismwendt (Chris Wendt).
|
14
|
+
! Small patches to memory footprint (Christophe Bliard).
|
15
|
+
- blankslate dependency removed. You should be good - but if things break,
|
16
|
+
please let us know (Nikita Shilnikov).
|
17
|
+
! Parslet now has `parse_failure_cause`, replaces the earlier `cause`.
|
18
|
+
! Fixes all these interpreter warnings on modern rubies.
|
5
19
|
|
6
20
|
= 1.7 / 12Mar2015
|
7
21
|
|
data/lib/parslet.rb
CHANGED
@@ -55,13 +55,13 @@ module Parslet
|
|
55
55
|
|
56
56
|
# Raised when the parse failed to match. It contains the message that should
|
57
57
|
# be presented to the user. More details can be extracted from the
|
58
|
-
# exceptions #
|
58
|
+
# exceptions #parse_failure_cause member: It contains an instance of {Parslet::Cause} that
|
59
59
|
# stores all the details of your failed parse in a tree structure.
|
60
60
|
#
|
61
61
|
# begin
|
62
62
|
# parslet.parse(str)
|
63
63
|
# rescue Parslet::ParseFailed => failure
|
64
|
-
# puts failure.
|
64
|
+
# puts failure.parse_failure_cause.ascii_tree
|
65
65
|
# end
|
66
66
|
#
|
67
67
|
# Alternatively, you can just require 'parslet/convenience' and call the
|
@@ -72,15 +72,15 @@ module Parslet
|
|
72
72
|
# parslet.parse_with_debug(str)
|
73
73
|
#
|
74
74
|
class ParseFailed < StandardError
|
75
|
-
def initialize(message,
|
75
|
+
def initialize(message, parse_failure_cause=nil)
|
76
76
|
super(message)
|
77
|
-
@
|
77
|
+
@parse_failure_cause = parse_failure_cause
|
78
78
|
end
|
79
79
|
|
80
80
|
# Why the parse failed.
|
81
81
|
#
|
82
82
|
# @return [Parslet::Cause]
|
83
|
-
attr_reader :
|
83
|
+
attr_reader :parse_failure_cause
|
84
84
|
end
|
85
85
|
|
86
86
|
module ClassMethods
|
@@ -100,6 +100,7 @@ module Parslet
|
|
100
100
|
# end
|
101
101
|
#
|
102
102
|
def rule(name, opts={}, &definition)
|
103
|
+
undef_method name if method_defined? name
|
103
104
|
define_method(name) do
|
104
105
|
@rules ||= {} # <name, rule> memoization
|
105
106
|
return @rules[name] if @rules.has_key?(name)
|
@@ -217,18 +218,26 @@ module Parslet
|
|
217
218
|
# associativity is chosen, it would be interpreted as '1 + (2 + 3)'. Note
|
218
219
|
# that the hash trees output reflect that choice as well.
|
219
220
|
#
|
220
|
-
#
|
221
|
+
# An optional block can be provided in order to manipulate the generated tree.
|
222
|
+
# The block will be called on each operator and passed 3 arguments: the left
|
223
|
+
# operand, the operator, and the right operand.
|
224
|
+
#
|
225
|
+
# Examples:
|
221
226
|
# infix_expression(integer, [add_op, 1, :left])
|
222
227
|
# # would parse things like '1 + 2'
|
223
228
|
#
|
229
|
+
# infix_expression(integer, [add_op, 1, :left]) { |l,o,r| { :plus => [l, r] } }
|
230
|
+
# # would parse '1 + 2 + 3' as:
|
231
|
+
# # { :plus => [1, { :plus => [2, 3] }] }
|
232
|
+
#
|
224
233
|
# @param element [Parslet::Atoms::Base] elements that take the NUMBER position
|
225
234
|
# in the expression
|
226
235
|
# @param operations [Array<(Parslet::Atoms::Base, Integer, {:left, :right})>]
|
227
236
|
#
|
228
237
|
# @see Parslet::Atoms::Infix
|
229
238
|
#
|
230
|
-
def infix_expression(element, *operations)
|
231
|
-
Parslet::Atoms::Infix.new(element, operations)
|
239
|
+
def infix_expression(element, *operations, &reducer)
|
240
|
+
Parslet::Atoms::Infix.new(element, operations, &reducer)
|
232
241
|
end
|
233
242
|
module_function :infix_expression
|
234
243
|
|
@@ -299,4 +308,4 @@ require 'parslet/pattern/binding'
|
|
299
308
|
require 'parslet/transform'
|
300
309
|
require 'parslet/parser'
|
301
310
|
require 'parslet/error_reporter'
|
302
|
-
require 'parslet/scope'
|
311
|
+
require 'parslet/scope'
|
data/lib/parslet/accelerator.rb
CHANGED
data/lib/parslet/atoms.rb
CHANGED
@@ -19,6 +19,7 @@ module Parslet::Atoms
|
|
19
19
|
require 'parslet/atoms/context'
|
20
20
|
require 'parslet/atoms/dsl'
|
21
21
|
require 'parslet/atoms/base'
|
22
|
+
require 'parslet/atoms/ignored'
|
22
23
|
require 'parslet/atoms/named'
|
23
24
|
require 'parslet/atoms/lookahead'
|
24
25
|
require 'parslet/atoms/alternative'
|
data/lib/parslet/atoms/base.rb
CHANGED
@@ -83,7 +83,7 @@ class Parslet::Atoms::Base
|
|
83
83
|
def apply(source, context, consume_all=false)
|
84
84
|
old_pos = source.bytepos
|
85
85
|
|
86
|
-
success,
|
86
|
+
success, _ = result = context.try_with_cache(self, source, consume_all)
|
87
87
|
|
88
88
|
if success
|
89
89
|
# Notify context
|
@@ -137,7 +137,7 @@ class Parslet::Atoms::Base
|
|
137
137
|
end
|
138
138
|
precedence BASE
|
139
139
|
def to_s(outer_prec=OUTER)
|
140
|
-
str =
|
140
|
+
str = label || to_s_inner(precedence)
|
141
141
|
if outer_prec < precedence
|
142
142
|
"(#{str})"
|
143
143
|
else
|
@@ -120,7 +120,7 @@ module Parslet::Atoms
|
|
120
120
|
return [] if named && list.empty?
|
121
121
|
|
122
122
|
# If there are only strings, concatenate them and return that.
|
123
|
-
foldl(list) { |s,e| s+e }
|
123
|
+
foldl(list.compact) { |s,e| s+e }
|
124
124
|
end
|
125
125
|
|
126
126
|
# That annoying warning 'Duplicate subtrees while merging result' comes
|
data/lib/parslet/atoms/dsl.rb
CHANGED
@@ -35,6 +35,17 @@ module Parslet::Atoms::DSL
|
|
35
35
|
Parslet::Atoms::Repetition.new(self, 0, 1, :maybe)
|
36
36
|
end
|
37
37
|
|
38
|
+
# Returns a new parslet atom that will not show up in the output. This
|
39
|
+
# is synonymous to calling #repeat(0,1). Generated tree value will always be
|
40
|
+
# nil.
|
41
|
+
#
|
42
|
+
# Example:
|
43
|
+
# str('foo').ignore
|
44
|
+
#
|
45
|
+
def ignore
|
46
|
+
Parslet::Atoms::Ignored.new(self)
|
47
|
+
end
|
48
|
+
|
38
49
|
# Chains two parslet atoms together as a sequence.
|
39
50
|
#
|
40
51
|
# Example:
|
data/lib/parslet/atoms/entity.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Ignores the result of a match.
|
2
|
+
#
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# str('foo') # will return 'foo',
|
6
|
+
# str('foo').ignore # will return nil
|
7
|
+
#
|
8
|
+
class Parslet::Atoms::Ignored < Parslet::Atoms::Base
|
9
|
+
attr_reader :parslet
|
10
|
+
def initialize(parslet)
|
11
|
+
super()
|
12
|
+
|
13
|
+
@parslet = parslet
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply(source, context, consume_all)
|
17
|
+
success, _ = result = parslet.apply(source, context, consume_all)
|
18
|
+
|
19
|
+
return result unless success
|
20
|
+
succ(nil)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s_inner(prec)
|
24
|
+
"ignored(#{parslet.to_s(prec)})"
|
25
|
+
end
|
26
|
+
end
|
data/lib/parslet/atoms/infix.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
class Parslet::Atoms::Infix < Parslet::Atoms::Base
|
2
|
-
attr_reader :element, :operations
|
2
|
+
attr_reader :element, :operations, :reducer
|
3
3
|
|
4
|
-
def initialize(element, operations)
|
4
|
+
def initialize(element, operations, &reducer)
|
5
5
|
super()
|
6
6
|
|
7
7
|
@element = element
|
8
8
|
@operations = operations
|
9
|
+
@reducer = reducer || lambda { |left, op, right| {l: left, o: op, r: right} }
|
9
10
|
end
|
10
11
|
|
11
12
|
def try(source, context, consume_all)
|
@@ -31,9 +32,9 @@ class Parslet::Atoms::Infix < Parslet::Atoms::Base
|
|
31
32
|
|
32
33
|
if right.kind_of? Array
|
33
34
|
# Subexpression -> Subhash
|
34
|
-
left =
|
35
|
+
left = reducer.call(left, op, produce_tree(right))
|
35
36
|
else
|
36
|
-
left =
|
37
|
+
left = reducer.call(left, op, right)
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
@@ -25,7 +25,7 @@ class Parslet::Atoms::Lookahead < Parslet::Atoms::Base
|
|
25
25
|
rewind_pos = source.bytepos
|
26
26
|
error_pos = source.pos
|
27
27
|
|
28
|
-
success,
|
28
|
+
success, _ = bound_parslet.apply(source, context, consume_all)
|
29
29
|
|
30
30
|
if positive
|
31
31
|
return succ(nil) if success
|
data/lib/parslet/cause.rb
CHANGED
@@ -5,8 +5,8 @@ module Parslet
|
|
5
5
|
#
|
6
6
|
class Cause
|
7
7
|
def initialize(message, source, pos, children)
|
8
|
-
@message, @source, @pos, @children =
|
9
|
-
message, source, pos, children
|
8
|
+
@message, @source, @pos, @children, @context =
|
9
|
+
message, source, pos, children, nil
|
10
10
|
end
|
11
11
|
|
12
12
|
# @return [String, Array] A string or an array of message pieces that
|
data/lib/parslet/context.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'blankslate'
|
2
|
-
|
3
1
|
# Provides a context for tree transformations to run in. The context allows
|
4
2
|
# accessing each of the bindings in the bindings hash as local method.
|
5
3
|
#
|
@@ -11,24 +9,12 @@ require 'blankslate'
|
|
11
9
|
# end
|
12
10
|
#
|
13
11
|
# @api private
|
14
|
-
class Parslet::Context
|
15
|
-
reveal :methods
|
16
|
-
reveal :respond_to?
|
17
|
-
reveal :inspect
|
18
|
-
reveal :to_s
|
19
|
-
reveal :instance_variable_set
|
20
|
-
|
12
|
+
class Parslet::Context
|
21
13
|
include Parslet
|
22
|
-
|
23
|
-
def meta_def(name, &body)
|
24
|
-
metaclass = class << self; self; end
|
25
14
|
|
26
|
-
metaclass.send(:define_method, name, &body)
|
27
|
-
end
|
28
|
-
|
29
15
|
def initialize(bindings)
|
30
16
|
bindings.each do |key, value|
|
31
|
-
|
17
|
+
singleton_class.send(:define_method, key) { value }
|
32
18
|
instance_variable_set("@#{key}", value)
|
33
19
|
end
|
34
20
|
end
|
data/lib/parslet/convenience.rb
CHANGED
@@ -5,7 +5,7 @@ class Parslet::Atoms::Base
|
|
5
5
|
# begin
|
6
6
|
# tree = parser.parse('something')
|
7
7
|
# rescue Parslet::ParseFailed => error
|
8
|
-
# puts parser.
|
8
|
+
# puts parser.parse_failure_cause.ascii_tree
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
# into a convenient method.
|
@@ -27,7 +27,7 @@ class Parslet::Atoms::Base
|
|
27
27
|
def parse_with_debug str, opts={}
|
28
28
|
parse str, opts
|
29
29
|
rescue Parslet::ParseFailed => error
|
30
|
-
puts error.
|
30
|
+
puts error.parse_failure_cause.ascii_tree
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
@@ -64,7 +64,7 @@ module Parslet
|
|
64
64
|
# current deepest error that was saved as a reference.
|
65
65
|
#
|
66
66
|
def deepest(cause)
|
67
|
-
|
67
|
+
_, leaf = deepest_child(cause)
|
68
68
|
|
69
69
|
if !deepest_cause || leaf.pos >= deepest_cause.pos
|
70
70
|
# This error reaches deeper into the input, save it as reference.
|
data/lib/parslet/parser.rb
CHANGED
@@ -51,6 +51,7 @@ class Parslet::Parser < Parslet::Atoms::Base
|
|
51
51
|
# end
|
52
52
|
#
|
53
53
|
def root(name)
|
54
|
+
undef_method :root if method_defined? :root
|
54
55
|
define_method(:root) do
|
55
56
|
self.send(name)
|
56
57
|
end
|
@@ -64,4 +65,4 @@ class Parslet::Parser < Parslet::Atoms::Base
|
|
64
65
|
def to_s_inner(prec)
|
65
66
|
root.to_s(prec)
|
66
67
|
end
|
67
|
-
end
|
68
|
+
end
|
data/lib/parslet/pattern.rb
CHANGED
@@ -48,11 +48,10 @@ class Parslet::Pattern
|
|
48
48
|
#
|
49
49
|
def element_match(tree, exp, bindings)
|
50
50
|
# p [:elm, tree, exp]
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
return element_match_ary_single(tree, exp, bindings)
|
51
|
+
if tree.is_a?(Hash) && exp.is_a?(Hash)
|
52
|
+
return element_match_hash(tree, exp, bindings)
|
53
|
+
elsif tree.is_a?(Array) && exp.is_a?(Array)
|
54
|
+
return element_match_ary_single(tree, exp, bindings)
|
56
55
|
else
|
57
56
|
# If elements match exactly, then that is good enough in all cases
|
58
57
|
return true if exp === tree
|
data/lib/parslet/rig/rspec.rb
CHANGED
@@ -2,13 +2,6 @@ RSpec::Matchers.define(:parse) do |input, opts|
|
|
2
2
|
as = block = nil
|
3
3
|
result = trace = nil
|
4
4
|
|
5
|
-
unless self.respond_to? :failure_message # if RSpec 2.x
|
6
|
-
class << self
|
7
|
-
alias_method :failure_message, :failure_message_for_should
|
8
|
-
alias_method :failure_message_when_negated, :failure_message_for_should_not
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
5
|
match do |parser|
|
13
6
|
begin
|
14
7
|
result = parser.parse(input)
|
@@ -16,12 +9,12 @@ RSpec::Matchers.define(:parse) do |input, opts|
|
|
16
9
|
block.call(result) :
|
17
10
|
(as == result || as.nil?)
|
18
11
|
rescue Parslet::ParseFailed => ex
|
19
|
-
trace = ex.
|
12
|
+
trace = ex.parse_failure_cause.ascii_tree if opts && opts[:trace]
|
20
13
|
false
|
21
14
|
end
|
22
15
|
end
|
23
16
|
|
24
|
-
failure_message do |is|
|
17
|
+
public_send(respond_to?(:failure_message) ? :failure_message : :failure_message_for_should) do |is|
|
25
18
|
if block
|
26
19
|
"expected output of parsing #{input.inspect}" <<
|
27
20
|
" with #{is.inspect} to meet block conditions, but it didn't"
|
@@ -37,7 +30,7 @@ RSpec::Matchers.define(:parse) do |input, opts|
|
|
37
30
|
end
|
38
31
|
end
|
39
32
|
|
40
|
-
failure_message_when_negated do |is|
|
33
|
+
public_send(respond_to?(:failure_message_when_negated) ? :failure_message_when_negated : :failure_message_for_should_not) do |is|
|
41
34
|
if block
|
42
35
|
"expected output of parsing #{input.inspect} with #{is.inspect} not to meet block conditions, but it did"
|
43
36
|
else
|
@@ -52,8 +45,8 @@ RSpec::Matchers.define(:parse) do |input, opts|
|
|
52
45
|
|
53
46
|
# NOTE: This has a nodoc tag since the rdoc parser puts this into
|
54
47
|
# Object, a thing I would never allow.
|
55
|
-
chain :as do |expected_output=nil, &
|
48
|
+
chain :as do |expected_output=nil, &my_block|
|
56
49
|
as = expected_output
|
57
|
-
block =
|
50
|
+
block = my_block
|
58
51
|
end
|
59
52
|
end
|
data/lib/parslet/slice.rb
CHANGED
data/lib/parslet/transform.rb
CHANGED
@@ -131,7 +131,7 @@ class Parslet::Transform
|
|
131
131
|
# Allows accessing the class' rules
|
132
132
|
#
|
133
133
|
def rules
|
134
|
-
@__transform_rules
|
134
|
+
@__transform_rules ||= []
|
135
135
|
end
|
136
136
|
|
137
137
|
def inherited(subclass)
|
@@ -140,7 +140,8 @@ class Parslet::Transform
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
def initialize(&block)
|
143
|
+
def initialize(raise_on_unmatch: false, &block)
|
144
|
+
@raise_on_unmatch = raise_on_unmatch
|
144
145
|
@rules = []
|
145
146
|
|
146
147
|
if block
|
@@ -236,7 +237,14 @@ class Parslet::Transform
|
|
236
237
|
end
|
237
238
|
|
238
239
|
# No rule matched - element is not transformed
|
239
|
-
|
240
|
+
if @raise_on_unmatch && elt.is_a?(Hash)
|
241
|
+
elt_types = elt.map do |key, value|
|
242
|
+
[ key, value.class ]
|
243
|
+
end.to_h
|
244
|
+
raise NotImplementedError, "Failed to match `#{elt_types.inspect}`"
|
245
|
+
else
|
246
|
+
return elt
|
247
|
+
end
|
240
248
|
end
|
241
249
|
|
242
250
|
# @api private
|
data/parslet.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'parslet'
|
5
|
-
s.version = '1.
|
5
|
+
s.version = '1.8.0'
|
6
6
|
|
7
7
|
s.authors = ['Kaspar Schiess']
|
8
8
|
s.email = 'kaspar.schiess@absurd.li'
|
@@ -12,7 +12,5 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.license = 'MIT'
|
13
13
|
s.rdoc_options = ['--main', 'README']
|
14
14
|
s.require_paths = ['lib']
|
15
|
-
s.summary = 'Parser construction library with great error reporting in Ruby.'
|
16
|
-
|
17
|
-
s.add_dependency 'blankslate', '>= 2.0', '<= 4.0'
|
15
|
+
s.summary = 'Parser construction library with great error reporting in Ruby.'
|
18
16
|
end
|
@@ -12,7 +12,7 @@ describe "Regression on" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "runs successfully" do
|
15
|
-
|
15
|
+
_, stdout, stderr = Open3.popen3("ruby #{example}")
|
16
16
|
|
17
17
|
handle_map = {
|
18
18
|
stdout => :out,
|
@@ -21,7 +21,7 @@ describe "Regression on" do
|
|
21
21
|
expectation_found = handle_map.any? do |io, ext|
|
22
22
|
name = product_path(example, ext)
|
23
23
|
|
24
|
-
if File.
|
24
|
+
if File.exist?(name)
|
25
25
|
io.read.strip.should == File.read(name).strip
|
26
26
|
true
|
27
27
|
end
|
@@ -109,4 +109,13 @@ Don't know what to do with "%" at line 1 char 2.
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
|
+
describe "providing a reducer block" do
|
113
|
+
class InfixExpressionReducerParser < Parslet::Parser
|
114
|
+
rule(:top) { infix_expression(str('a'), [str('-'), 1, :right]) { |l,o,r| {:and=>[l,r]} } }
|
115
|
+
end
|
116
|
+
|
117
|
+
it "applies the reducer" do
|
118
|
+
InfixExpressionReducerParser.new.top.parse("a-a-a").should == {:and=>["a", {:and=>["a", "a"]}]}
|
119
|
+
end
|
120
|
+
end
|
112
121
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Parslet::Atoms::Ignored do
|
4
|
+
include Parslet
|
5
|
+
|
6
|
+
describe "ignore" do
|
7
|
+
it "ignores parts of the input" do
|
8
|
+
str('a').ignore.parse('a').should == nil
|
9
|
+
(str('a') >> str('b').ignore >> str('c')).parse('abc').should == 'ac'
|
10
|
+
(str('a') >> str('b').as(:name).ignore >> str('c')).parse('abc').should == 'ac'
|
11
|
+
(str('a') >> str('b').maybe.ignore >> str('c')).parse('abc').should == 'ac'
|
12
|
+
(str('a') >> str('b').maybe.ignore >> str('c')).parse('ac').should == 'ac'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/parslet/atoms_spec.rb
CHANGED
@@ -225,7 +225,7 @@ describe Parslet do
|
|
225
225
|
|
226
226
|
it "should not loop infinitely" do
|
227
227
|
lambda {
|
228
|
-
timeout(1) { parslet.parse('bar') }
|
228
|
+
Timeout.timeout(1) { parslet.parse('bar') }
|
229
229
|
}.should raise_error(Parslet::ParseFailed)
|
230
230
|
end
|
231
231
|
end
|
@@ -398,7 +398,7 @@ describe Parslet do
|
|
398
398
|
end
|
399
399
|
|
400
400
|
describe "combinations thereof (regression)" do
|
401
|
-
|
401
|
+
[
|
402
402
|
[(str('a').repeat >> str('b').repeat), 'aaabbb']
|
403
403
|
].each do |(parslet, input)|
|
404
404
|
describe "#{parslet.inspect} applied to #{input.inspect}" do
|
@@ -408,7 +408,7 @@ describe Parslet do
|
|
408
408
|
end
|
409
409
|
end
|
410
410
|
|
411
|
-
|
411
|
+
[
|
412
412
|
[str('a'), "'a'" ],
|
413
413
|
[(str('a') | str('b')).maybe, "('a' / 'b')?" ],
|
414
414
|
[(str('a') >> str('b')).maybe, "('a' 'b')?" ],
|
@@ -9,22 +9,6 @@ describe Parslet::Context do
|
|
9
9
|
context(:a => 'value').instance_eval { a }.
|
10
10
|
should == 'value'
|
11
11
|
end
|
12
|
-
describe 'when a method in BlankSlate is inherited from the environment somehow' do
|
13
|
-
before(:each) { BlankSlate.send(:define_method, :a) { 'c' } }
|
14
|
-
after(:each) { BlankSlate.send(:undef_method, :a) }
|
15
|
-
|
16
|
-
it "masks what is already on blank slate" do
|
17
|
-
context(:a => 'b').instance_eval { a }.
|
18
|
-
should == 'b'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
it "should not reveal define_singleton_method for all users of blankslate, just for us" do
|
22
|
-
expect {
|
23
|
-
BlankSlate.new.instance_eval {
|
24
|
-
define_singleton_method(:foo) { 'foo' }
|
25
|
-
}
|
26
|
-
}.to raise_error(NoMethodError)
|
27
|
-
end
|
28
12
|
it "one contexts variables aren't the next ones" do
|
29
13
|
ca = context(:a => 'b')
|
30
14
|
cb = context(:b => 'c')
|
@@ -32,4 +16,41 @@ describe Parslet::Context do
|
|
32
16
|
ca.methods.should_not include(:b)
|
33
17
|
cb.methods.should_not include(:a)
|
34
18
|
end
|
19
|
+
|
20
|
+
describe 'works as a Ruby object should' do
|
21
|
+
let(:obj) { context(a: 1) }
|
22
|
+
|
23
|
+
it 'responds_to? :a' do
|
24
|
+
assert obj.respond_to?(:a)
|
25
|
+
end
|
26
|
+
it 'includes :a in #methods' do
|
27
|
+
obj.methods.assert.include?(:a)
|
28
|
+
end
|
29
|
+
it 'allows inspection' do
|
30
|
+
obj.inspect.assert.match(/@a=1/)
|
31
|
+
end
|
32
|
+
it 'allows conversion to string' do
|
33
|
+
obj.to_s.assert.match(/Parslet::Context:0x/)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the context is enhanced' do
|
37
|
+
before(:each) do
|
38
|
+
class << obj
|
39
|
+
def foo
|
40
|
+
'foo'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'responds_to correctly' do
|
46
|
+
assert obj.respond_to?(:foo)
|
47
|
+
end
|
48
|
+
it 'includes :foo also in methods' do
|
49
|
+
obj.methods.assert.include?(:foo)
|
50
|
+
end
|
51
|
+
it 'allows calling #foo' do
|
52
|
+
obj.foo.assert == 'foo'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
35
56
|
end
|
@@ -6,10 +6,6 @@ describe Parslet::Transform do
|
|
6
6
|
include Parslet
|
7
7
|
|
8
8
|
let(:transform) { Parslet::Transform.new }
|
9
|
-
attr_reader :transform
|
10
|
-
before(:each) do
|
11
|
-
@transform = Parslet::Transform.new
|
12
|
-
end
|
13
9
|
|
14
10
|
class A < Struct.new(:elt); end
|
15
11
|
class B < Struct.new(:elt); end
|
@@ -77,6 +73,26 @@ describe Parslet::Transform do
|
|
77
73
|
transform.apply(:a => 'a').should == A.new('a')
|
78
74
|
end
|
79
75
|
|
76
|
+
context "optionally raise when no match found" do
|
77
|
+
class BumbleBee < Parslet::Transform
|
78
|
+
def initialize(&block)
|
79
|
+
super(raise_on_unmatch: true, &block)
|
80
|
+
end
|
81
|
+
rule(:a => simple(:x)) { A.new(x) }
|
82
|
+
end
|
83
|
+
let(:transform) { BumbleBee.new }
|
84
|
+
|
85
|
+
it "should evaluate rules" do
|
86
|
+
transform.apply(:a => 'a').should == A.new('a')
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should raise when no rules are matched" do
|
90
|
+
lambda {
|
91
|
+
transform.apply(:z => 'z')
|
92
|
+
}.should raise_error(NotImplementedError, /Failed to match/)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
80
96
|
context "with inheritance" do
|
81
97
|
class OptimusPrimeJunior < OptimusPrime
|
82
98
|
rule(:b => simple(:x)) { B.new(x.upcase) }
|
@@ -137,7 +153,9 @@ describe Parslet::Transform do
|
|
137
153
|
it "should execute in its own context" do
|
138
154
|
@bar = 'test'
|
139
155
|
transform.call_on_match(bindings, proc do
|
140
|
-
@bar
|
156
|
+
if instance_variable_defined?("@bar")
|
157
|
+
instance_variable_get("@bar").should_not == 'test'
|
158
|
+
end
|
141
159
|
end)
|
142
160
|
end
|
143
161
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,8 @@ require 'parslet/rig/rspec'
|
|
5
5
|
require 'parslet/atoms/visitor'
|
6
6
|
require 'parslet/export'
|
7
7
|
|
8
|
+
require 'ae'
|
9
|
+
|
8
10
|
RSpec.configure do |config|
|
9
11
|
config.mock_with :flexmock
|
10
12
|
|
@@ -29,7 +31,7 @@ def catch_failed_parse
|
|
29
31
|
yield
|
30
32
|
rescue Parslet::ParseFailed => exception
|
31
33
|
end
|
32
|
-
exception.
|
34
|
+
exception.parse_failure_cause
|
33
35
|
end
|
34
36
|
|
35
37
|
def slet name, &block
|
metadata
CHANGED
@@ -1,35 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parslet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kaspar Schiess
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: blankslate
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '2.0'
|
20
|
-
- - "<="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '4.0'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '2.0'
|
30
|
-
- - "<="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '4.0'
|
11
|
+
date: 2017-04-03 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
33
13
|
description:
|
34
14
|
email: kaspar.schiess@absurd.li
|
35
15
|
executables: []
|
@@ -51,7 +31,6 @@ files:
|
|
51
31
|
- example/email_parser.rb
|
52
32
|
- example/empty.rb
|
53
33
|
- example/erb.rb
|
54
|
-
- example/ignore.rb
|
55
34
|
- example/ip_address.rb
|
56
35
|
- example/json.rb
|
57
36
|
- example/local.rb
|
@@ -111,6 +90,7 @@ files:
|
|
111
90
|
- lib/parslet/atoms/dsl.rb
|
112
91
|
- lib/parslet/atoms/dynamic.rb
|
113
92
|
- lib/parslet/atoms/entity.rb
|
93
|
+
- lib/parslet/atoms/ignored.rb
|
114
94
|
- lib/parslet/atoms/infix.rb
|
115
95
|
- lib/parslet/atoms/lookahead.rb
|
116
96
|
- lib/parslet/atoms/named.rb
|
@@ -154,6 +134,7 @@ files:
|
|
154
134
|
- spec/parslet/atoms/combinations_spec.rb
|
155
135
|
- spec/parslet/atoms/dsl_spec.rb
|
156
136
|
- spec/parslet/atoms/entity_spec.rb
|
137
|
+
- spec/parslet/atoms/ignored_spec.rb
|
157
138
|
- spec/parslet/atoms/infix_spec.rb
|
158
139
|
- spec/parslet/atoms/lookahead_spec.rb
|
159
140
|
- spec/parslet/atoms/named_spec.rb
|
@@ -206,8 +187,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
187
|
version: '0'
|
207
188
|
requirements: []
|
208
189
|
rubyforge_project:
|
209
|
-
rubygems_version: 2.4
|
190
|
+
rubygems_version: 2.6.4
|
210
191
|
signing_key:
|
211
192
|
specification_version: 4
|
212
193
|
summary: Parser construction library with great error reporting in Ruby.
|
213
194
|
test_files: []
|
195
|
+
has_rdoc:
|
data/example/ignore.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# A small example on how to make parslet ignore parts of the parse tree.
|
2
|
-
|
3
|
-
$:.unshift File.dirname(__FILE__) + "/../lib"
|
4
|
-
require 'parslet'
|
5
|
-
|
6
|
-
class IgnoreParslet < Parslet::Atoms::Base
|
7
|
-
def initialize(parslet)
|
8
|
-
@parslet = parslet
|
9
|
-
end
|
10
|
-
def to_s_inner(prec)
|
11
|
-
@parslet.to_s(prec)
|
12
|
-
end
|
13
|
-
def try(source, context, consume_all)
|
14
|
-
success, value = result = @parslet.try(source, context, consume_all)
|
15
|
-
|
16
|
-
return succ(nil) if success
|
17
|
-
return result
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
module IgnoreDSL
|
22
|
-
def ignore
|
23
|
-
IgnoreParslet.new(self)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class Parslet::Atoms::Base
|
28
|
-
include IgnoreDSL
|
29
|
-
end
|
30
|
-
|
31
|
-
include Parslet
|
32
|
-
p (str('a') >> str('b').ignore >> str('c')).
|
33
|
-
parse('abc')
|