parslet 1.3.0 → 1.4.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.
- data/HISTORY.txt +38 -1
- data/README +33 -21
- data/example/deepest_errors.rb +131 -0
- data/example/email_parser.rb +2 -6
- data/example/ignore.rb +2 -2
- data/example/json.rb +0 -3
- data/example/modularity.rb +47 -0
- data/example/nested_errors.rb +132 -0
- data/example/output/deepest_errors.out +54 -0
- data/example/output/modularity.out +0 -0
- data/example/output/nested_errors.out +54 -0
- data/lib/parslet.rb +65 -51
- data/lib/parslet/atoms.rb +1 -1
- data/lib/parslet/atoms/alternative.rb +11 -12
- data/lib/parslet/atoms/base.rb +57 -99
- data/lib/parslet/atoms/can_flatten.rb +9 -4
- data/lib/parslet/atoms/context.rb +26 -4
- data/lib/parslet/atoms/entity.rb +5 -10
- data/lib/parslet/atoms/lookahead.rb +11 -7
- data/lib/parslet/atoms/named.rb +8 -12
- data/lib/parslet/atoms/re.rb +10 -9
- data/lib/parslet/atoms/repetition.rb +23 -24
- data/lib/parslet/atoms/sequence.rb +10 -16
- data/lib/parslet/atoms/str.rb +11 -13
- data/lib/parslet/cause.rb +45 -13
- data/lib/parslet/convenience.rb +6 -6
- data/lib/parslet/error_reporter.rb +7 -0
- data/lib/parslet/error_reporter/deepest.rb +95 -0
- data/lib/parslet/error_reporter/tree.rb +57 -0
- data/lib/parslet/export.rb +4 -4
- data/lib/parslet/expression.rb +0 -2
- data/lib/parslet/expression/treetop.rb +2 -2
- data/lib/parslet/parser.rb +2 -6
- data/lib/parslet/pattern.rb +15 -4
- data/lib/parslet/pattern/binding.rb +3 -3
- data/lib/parslet/rig/rspec.rb +2 -2
- data/lib/parslet/slice.rb +0 -6
- data/lib/parslet/source.rb +40 -59
- data/lib/parslet/source/line_cache.rb +2 -2
- data/lib/parslet/transform.rb +13 -7
- data/lib/parslet/transform/context.rb +1 -1
- metadata +69 -26
- data/example/ignore_whitespace.rb +0 -66
- data/lib/parslet/bytecode.rb +0 -6
- data/lib/parslet/bytecode/compiler.rb +0 -138
- data/lib/parslet/bytecode/instructions.rb +0 -358
- data/lib/parslet/bytecode/vm.rb +0 -209
- data/lib/parslet/error_tree.rb +0 -50
@@ -3,7 +3,7 @@
|
|
3
3
|
class Parslet::Source
|
4
4
|
# A cache for line start positions.
|
5
5
|
#
|
6
|
-
class LineCache
|
6
|
+
class LineCache
|
7
7
|
def initialize
|
8
8
|
# Stores line endings as a simple position number. The first line always
|
9
9
|
# starts at 0; numbers beyond the biggest entry are on any line > size,
|
@@ -59,7 +59,7 @@ class Parslet::Source
|
|
59
59
|
# [10, 20, 30]
|
60
60
|
# # would describe [0, 10], (10, 20], (20, 30]
|
61
61
|
#
|
62
|
-
module RangeSearch
|
62
|
+
module RangeSearch
|
63
63
|
def find_mid(left, right)
|
64
64
|
# NOTE: Jonathan Hinkle reported that when mathn is required, just
|
65
65
|
# dividing and relying on the integer truncation is not enough.
|
data/lib/parslet/transform.rb
CHANGED
@@ -131,12 +131,12 @@ class Parslet::Transform
|
|
131
131
|
|
132
132
|
# Allows accessing the class' rules
|
133
133
|
#
|
134
|
-
def rules
|
134
|
+
def rules
|
135
135
|
@__transform_rules || []
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
|
-
def initialize(&block)
|
139
|
+
def initialize(&block)
|
140
140
|
@rules = []
|
141
141
|
|
142
142
|
if block
|
@@ -183,7 +183,6 @@ class Parslet::Transform
|
|
183
183
|
# arity 1 variant of the block. Alternatively, you can inject a context object
|
184
184
|
# and call methods on it (think :ctx => self).
|
185
185
|
#
|
186
|
-
# Example:
|
187
186
|
# # the local variable a is simulated
|
188
187
|
# t.call_on_match(:a => :b) { a }
|
189
188
|
# # no change of environment here
|
@@ -203,11 +202,13 @@ class Parslet::Transform
|
|
203
202
|
# Allow easy access to all rules, the ones defined in the instance and the
|
204
203
|
# ones predefined in a subclass definition.
|
205
204
|
#
|
206
|
-
def rules
|
205
|
+
def rules
|
207
206
|
self.class.rules + @rules
|
208
207
|
end
|
209
208
|
|
210
|
-
|
209
|
+
# @api private
|
210
|
+
#
|
211
|
+
def transform_elt(elt, context)
|
211
212
|
rules.each do |pattern, block|
|
212
213
|
if bindings=pattern.match(elt, context)
|
213
214
|
# Produces transformed value
|
@@ -218,13 +219,18 @@ class Parslet::Transform
|
|
218
219
|
# No rule matched - element is not transformed
|
219
220
|
return elt
|
220
221
|
end
|
221
|
-
|
222
|
+
|
223
|
+
# @api private
|
224
|
+
#
|
225
|
+
def recurse_hash(hsh, ctx)
|
222
226
|
hsh.inject({}) do |new_hsh, (k,v)|
|
223
227
|
new_hsh[k] = apply(v, ctx)
|
224
228
|
new_hsh
|
225
229
|
end
|
226
230
|
end
|
227
|
-
|
231
|
+
# @api private
|
232
|
+
#
|
233
|
+
def recurse_array(ary, ctx)
|
228
234
|
ary.map { |elt| apply(elt, ctx) }
|
229
235
|
end
|
230
236
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parslet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: blankslate
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '2.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rspec
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: flexmock
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rdoc
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: sdoc
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ! '>='
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: '0'
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: guard
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,10 +101,15 @@ dependencies:
|
|
76
101
|
version: '0'
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: guard-rspec
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ! '>='
|
@@ -87,10 +117,15 @@ dependencies:
|
|
87
117
|
version: '0'
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: growl
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ! '>='
|
@@ -98,7 +133,12 @@ dependencies:
|
|
98
133
|
version: '0'
|
99
134
|
type: :development
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
102
142
|
description:
|
103
143
|
email: kaspar.schiess@absurd.li
|
104
144
|
executables: []
|
@@ -124,13 +164,11 @@ files:
|
|
124
164
|
- lib/parslet/atoms/str.rb
|
125
165
|
- lib/parslet/atoms/visitor.rb
|
126
166
|
- lib/parslet/atoms.rb
|
127
|
-
- lib/parslet/bytecode/compiler.rb
|
128
|
-
- lib/parslet/bytecode/instructions.rb
|
129
|
-
- lib/parslet/bytecode/vm.rb
|
130
|
-
- lib/parslet/bytecode.rb
|
131
167
|
- lib/parslet/cause.rb
|
132
168
|
- lib/parslet/convenience.rb
|
133
|
-
- lib/parslet/
|
169
|
+
- lib/parslet/error_reporter/deepest.rb
|
170
|
+
- lib/parslet/error_reporter/tree.rb
|
171
|
+
- lib/parslet/error_reporter.rb
|
134
172
|
- lib/parslet/export.rb
|
135
173
|
- lib/parslet/expression/treetop.rb
|
136
174
|
- lib/parslet/expression.rb
|
@@ -146,19 +184,22 @@ files:
|
|
146
184
|
- lib/parslet.rb
|
147
185
|
- example/boolean_algebra.rb
|
148
186
|
- example/comments.rb
|
187
|
+
- example/deepest_errors.rb
|
149
188
|
- example/documentation.rb
|
150
189
|
- example/email_parser.rb
|
151
190
|
- example/empty.rb
|
152
191
|
- example/erb.rb
|
153
192
|
- example/ignore.rb
|
154
|
-
- example/ignore_whitespace.rb
|
155
193
|
- example/ip_address.rb
|
156
194
|
- example/json.rb
|
157
195
|
- example/local.rb
|
158
196
|
- example/mathn.rb
|
159
197
|
- example/minilisp.rb
|
198
|
+
- example/modularity.rb
|
199
|
+
- example/nested_errors.rb
|
160
200
|
- example/output/boolean_algebra.out
|
161
201
|
- example/output/comments.out
|
202
|
+
- example/output/deepest_errors.out
|
162
203
|
- example/output/documentation.err
|
163
204
|
- example/output/documentation.out
|
164
205
|
- example/output/email_parser.out
|
@@ -171,6 +212,8 @@ files:
|
|
171
212
|
- example/output/local.out
|
172
213
|
- example/output/mathn.out
|
173
214
|
- example/output/minilisp.out
|
215
|
+
- example/output/modularity.out
|
216
|
+
- example/output/nested_errors.out
|
174
217
|
- example/output/parens.out
|
175
218
|
- example/output/readme.out
|
176
219
|
- example/output/seasons.out
|
@@ -201,7 +244,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
201
244
|
version: '0'
|
202
245
|
segments:
|
203
246
|
- 0
|
204
|
-
hash:
|
247
|
+
hash: 1524575203779308108
|
205
248
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
206
249
|
none: false
|
207
250
|
requirements:
|
@@ -210,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
210
253
|
version: '0'
|
211
254
|
requirements: []
|
212
255
|
rubyforge_project:
|
213
|
-
rubygems_version: 1.8.
|
256
|
+
rubygems_version: 1.8.24
|
214
257
|
signing_key:
|
215
258
|
specification_version: 3
|
216
259
|
summary: Parser construction library with great error reporting in Ruby.
|
@@ -1,66 +0,0 @@
|
|
1
|
-
# An example on how to ignore whitespace. Use the composition, luke.
|
2
|
-
|
3
|
-
$:.unshift File.dirname(__FILE__) + "/../lib"
|
4
|
-
|
5
|
-
require 'pp'
|
6
|
-
require 'parslet'
|
7
|
-
require 'parslet/convenience'
|
8
|
-
|
9
|
-
class AParser < Parslet::Parser
|
10
|
-
root :as
|
11
|
-
|
12
|
-
rule(:as) { a.repeat }
|
13
|
-
rule(:a) { str('a').as(:a) }
|
14
|
-
end
|
15
|
-
|
16
|
-
class WsIgnoreSource
|
17
|
-
def initialize(string)
|
18
|
-
@io = StringIO.new(string)
|
19
|
-
@early_eof = nil
|
20
|
-
end
|
21
|
-
|
22
|
-
def pos
|
23
|
-
@io.pos
|
24
|
-
end
|
25
|
-
|
26
|
-
def pos=(n)
|
27
|
-
@io.pos = n
|
28
|
-
end
|
29
|
-
|
30
|
-
def gets(buf, n)
|
31
|
-
return nil if eof?
|
32
|
-
|
33
|
-
return read(n).tap {
|
34
|
-
@early_eof = pos unless can_read?
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
def eof?
|
39
|
-
@io.eof? || # the underlying source is EOF
|
40
|
-
@early_eof && pos >= @early_eof # we have no non-ws chars left
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# Reads n chars from @io.
|
46
|
-
def read(n)
|
47
|
-
b = ''
|
48
|
-
while b.size < n && !@io.eof?
|
49
|
-
c = @io.gets(nil, 1)
|
50
|
-
b << c unless c == ' '
|
51
|
-
end
|
52
|
-
b
|
53
|
-
end
|
54
|
-
|
55
|
-
# True if there are any chars left in @io.
|
56
|
-
def can_read?
|
57
|
-
old_pos = @io.pos
|
58
|
-
read(1).size == 1
|
59
|
-
rescue => ex
|
60
|
-
return false
|
61
|
-
ensure
|
62
|
-
@io.pos = old_pos
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
pp AParser.new.parse_with_debug(WsIgnoreSource.new('a a a a '))
|
data/lib/parslet/bytecode.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'parslet/atoms/visitor'
|
2
|
-
|
3
|
-
module Parslet::Bytecode
|
4
|
-
class Compiler
|
5
|
-
def initialize
|
6
|
-
@buffer = []
|
7
|
-
@blocks = Hash.new
|
8
|
-
end
|
9
|
-
|
10
|
-
class Address
|
11
|
-
attr_reader :address
|
12
|
-
def initialize(address=nil)
|
13
|
-
@address = address
|
14
|
-
end
|
15
|
-
def resolve(vm)
|
16
|
-
@address = vm.buffer_pointer
|
17
|
-
end
|
18
|
-
def inspect
|
19
|
-
"@#{@address}"
|
20
|
-
end
|
21
|
-
def to_s
|
22
|
-
"@#{address}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
class Block
|
26
|
-
def initialize(name, block, compiler)
|
27
|
-
@name = name
|
28
|
-
@block = block
|
29
|
-
@compiler = compiler
|
30
|
-
end
|
31
|
-
def address
|
32
|
-
return @address if @address
|
33
|
-
|
34
|
-
# Actual compilation:
|
35
|
-
|
36
|
-
# TODO raise not implemented if the block returns nil (see Entity)
|
37
|
-
@address = @compiler.current_address
|
38
|
-
atom.accept(@compiler)
|
39
|
-
@compiler.add Return.new
|
40
|
-
|
41
|
-
return @address
|
42
|
-
end
|
43
|
-
def atom
|
44
|
-
@atom ||= @block.call
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def compile(atom)
|
49
|
-
atom.accept(self)
|
50
|
-
add Stop.new
|
51
|
-
@buffer
|
52
|
-
end
|
53
|
-
def add(instruction)
|
54
|
-
@buffer << instruction
|
55
|
-
end
|
56
|
-
|
57
|
-
def fwd_address
|
58
|
-
Address.new
|
59
|
-
end
|
60
|
-
def current_address
|
61
|
-
Address.new(buffer_pointer)
|
62
|
-
end
|
63
|
-
def buffer_pointer
|
64
|
-
@buffer.size
|
65
|
-
end
|
66
|
-
|
67
|
-
def visit_str(str)
|
68
|
-
add Match.new(str)
|
69
|
-
end
|
70
|
-
def visit_re(match)
|
71
|
-
add Re.new(match, 1)
|
72
|
-
end
|
73
|
-
def visit_sequence(parslets)
|
74
|
-
emit_block do
|
75
|
-
sequence = Parslet::Atoms::Sequence.new(*parslets)
|
76
|
-
error_msg = "Failed to match sequence (#{sequence.inspect})"
|
77
|
-
|
78
|
-
end_adr = fwd_address
|
79
|
-
parslets.each_with_index do |atom, idx|
|
80
|
-
atom.accept(self)
|
81
|
-
add CheckSequence.new(idx, end_adr, error_msg)
|
82
|
-
end
|
83
|
-
|
84
|
-
add PackSequence.new(parslets.size)
|
85
|
-
|
86
|
-
end_adr.resolve(self)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
def visit_alternative(alternatives)
|
90
|
-
emit_block do
|
91
|
-
adr_end = fwd_address
|
92
|
-
|
93
|
-
add EnterFrame.new
|
94
|
-
add PushPos.new
|
95
|
-
alternatives.each_with_index do |alternative, idx|
|
96
|
-
alternative.accept(self)
|
97
|
-
add BranchOnSuccess.new(adr_end, idx)
|
98
|
-
end
|
99
|
-
add Fail.new(["Expected one of ", alternatives.inspect], alternatives.size)
|
100
|
-
|
101
|
-
adr_end.resolve(self)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
def visit_repetition(tag, min, max, parslet)
|
105
|
-
add SetupRepeat.new(tag)
|
106
|
-
start = current_address
|
107
|
-
parslet.accept(self)
|
108
|
-
add Repeat.new(min, max, start, parslet)
|
109
|
-
end
|
110
|
-
def visit_named(name, parslet)
|
111
|
-
parslet.accept(self)
|
112
|
-
add Box.new(name)
|
113
|
-
end
|
114
|
-
def visit_lookahead(positive, parslet)
|
115
|
-
add PushPos.new
|
116
|
-
parslet.accept(self)
|
117
|
-
add CheckAndReset.new(positive, parslet)
|
118
|
-
end
|
119
|
-
def visit_entity(name, block)
|
120
|
-
@blocks[name] ||= Block.new(name, block, self)
|
121
|
-
add CallBlock.new(@blocks[name])
|
122
|
-
end
|
123
|
-
def visit_parser(root)
|
124
|
-
root.accept(self)
|
125
|
-
end
|
126
|
-
|
127
|
-
def emit_block
|
128
|
-
end_adr = fwd_address
|
129
|
-
cache_adr = current_address
|
130
|
-
add CheckCache.new(end_adr)
|
131
|
-
|
132
|
-
yield
|
133
|
-
|
134
|
-
add StoreResult.new(cache_adr)
|
135
|
-
end_adr.resolve(self)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|