parslet 1.0.1 → 1.1.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/Gemfile +3 -4
- data/HISTORY.txt +17 -3
- data/README +3 -2
- data/Rakefile +12 -55
- data/example/email_parser.rb +9 -5
- data/example/erb.rb +44 -0
- data/example/minilisp.rb +11 -17
- data/example/parens.rb +3 -1
- data/lib/parslet/atoms/alternative.rb +7 -5
- data/lib/parslet/atoms/base.rb +90 -59
- data/lib/parslet/atoms/context.rb +48 -0
- data/lib/parslet/atoms/entity.rb +2 -2
- data/lib/parslet/atoms/lookahead.rb +17 -29
- data/lib/parslet/atoms/named.rb +10 -5
- data/lib/parslet/atoms/re.rb +16 -7
- data/lib/parslet/atoms/repetition.rb +16 -9
- data/lib/parslet/atoms/sequence.rb +15 -9
- data/lib/parslet/atoms/str.rb +17 -7
- data/lib/parslet/atoms/visitor.rb +75 -0
- data/lib/parslet/atoms.rb +13 -9
- data/lib/parslet/convenience.rb +33 -0
- data/lib/parslet/export.rb +162 -0
- data/lib/parslet/expression.rb +3 -3
- data/lib/parslet/pattern.rb +2 -2
- data/lib/parslet/rig/rspec.rb +2 -2
- data/lib/parslet/source.rb +112 -0
- data/lib/parslet.rb +1 -2
- metadata +24 -7
@@ -0,0 +1,112 @@
|
|
1
|
+
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
# Wraps the input IO to parslet. The interface defined by this class is
|
5
|
+
# smaller than what IO offers, but enhances it with a #column and #line
|
6
|
+
# method for the current position.
|
7
|
+
#
|
8
|
+
class Parslet::Source
|
9
|
+
attr_reader :line_ends
|
10
|
+
|
11
|
+
def initialize(io)
|
12
|
+
if io.respond_to? :to_str
|
13
|
+
io = StringIO.new(io)
|
14
|
+
end
|
15
|
+
|
16
|
+
@io = io
|
17
|
+
warn "Line counting will be off if the IO is not rewound." unless @io.pos==0
|
18
|
+
|
19
|
+
# Stores line endings as a simple position number. The first line always
|
20
|
+
# starts at 0; numbers beyond the biggest entry are on any line > size,
|
21
|
+
# but probably make a scan to that position neccessary.
|
22
|
+
@line_ends = []
|
23
|
+
@line_ends.extend RangeSearch
|
24
|
+
@eof_reached_once = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def read(n)
|
28
|
+
start_pos = pos
|
29
|
+
@io.read(n).tap { |buf| scan_for_line_endings(start_pos, buf) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def eof?
|
33
|
+
@io.eof?
|
34
|
+
end
|
35
|
+
|
36
|
+
def pos
|
37
|
+
@io.pos
|
38
|
+
end
|
39
|
+
|
40
|
+
# NOTE: If you seek beyond the point that you last read, you will get
|
41
|
+
# undefined behaviour. This is by design.
|
42
|
+
def pos=(new_pos)
|
43
|
+
@io.pos = new_pos
|
44
|
+
end
|
45
|
+
|
46
|
+
def line_and_column(position=nil)
|
47
|
+
pos = (position || self.pos)
|
48
|
+
eol_idx = @line_ends.lbound(pos)
|
49
|
+
|
50
|
+
if eol_idx
|
51
|
+
# eol_idx points to the offset that ends the current line.
|
52
|
+
# Let's try to find the offset that starts it:
|
53
|
+
offset = eol_idx>0 && @line_ends[eol_idx-1] || 0
|
54
|
+
return [eol_idx+1, pos-offset+1]
|
55
|
+
else
|
56
|
+
# eol_idx is nil, that means that we're beyond the last line end that
|
57
|
+
# we know about. Pretend for now that we're just on the last line.
|
58
|
+
offset = @line_ends.last || 0
|
59
|
+
return [@line_ends.size+1, pos-offset+1]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Mixin for arrays that implicitly give a number of ranges, where one range
|
64
|
+
# begins where the other one ends.
|
65
|
+
#
|
66
|
+
# Example:
|
67
|
+
#
|
68
|
+
# [10, 20, 30]
|
69
|
+
# # would describe [0, 10], (10, 20], (20, 30]
|
70
|
+
#
|
71
|
+
module RangeSearch
|
72
|
+
# Scans the array for the first number that is > than bound. Returns the
|
73
|
+
# index of that number.
|
74
|
+
#
|
75
|
+
def lbound(bound)
|
76
|
+
return nil if empty?
|
77
|
+
return nil unless last > bound
|
78
|
+
|
79
|
+
left = 0
|
80
|
+
right = size - 1
|
81
|
+
|
82
|
+
n = 10
|
83
|
+
loop do
|
84
|
+
mid = left + (right - left) / 2
|
85
|
+
|
86
|
+
if self[mid] > bound
|
87
|
+
right = mid
|
88
|
+
else
|
89
|
+
# assert: self[mid] <= bound
|
90
|
+
left = mid+1
|
91
|
+
end
|
92
|
+
|
93
|
+
if right <= left
|
94
|
+
return right
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def scan_for_line_endings(start_pos, buf)
|
103
|
+
# Scan the string for line endings; store the positions of all endings
|
104
|
+
# in @line_ends.
|
105
|
+
cur = -1
|
106
|
+
while buf && cur = buf.index("\n", cur+1)
|
107
|
+
@line_ends << (start_pos + cur+1)
|
108
|
+
end
|
109
|
+
|
110
|
+
@eof_reached_once = true
|
111
|
+
end
|
112
|
+
end
|
data/lib/parslet.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
1
|
# A simple parser generator library. Typical usage would look like this:
|
4
2
|
#
|
5
3
|
# require 'parslet'
|
@@ -229,6 +227,7 @@ module Parslet
|
|
229
227
|
autoload :Expression, 'parslet/expression'
|
230
228
|
end
|
231
229
|
|
230
|
+
require 'parslet/source'
|
232
231
|
require 'parslet/error_tree'
|
233
232
|
require 'parslet/atoms'
|
234
233
|
require 'parslet/pattern'
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 1.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Kaspar Schiess
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-02-02 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -27,10 +27,8 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
29
|
- 2
|
30
|
-
-
|
31
|
-
|
32
|
-
- 3
|
33
|
-
version: 2.1.2.3
|
30
|
+
- 0
|
31
|
+
version: "2.0"
|
34
32
|
type: :runtime
|
35
33
|
version_requirements: *id001
|
36
34
|
- !ruby/object:Gem::Dependency
|
@@ -59,6 +57,19 @@ dependencies:
|
|
59
57
|
version: "0"
|
60
58
|
type: :development
|
61
59
|
version_requirements: *id003
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: sdoc
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
type: :development
|
72
|
+
version_requirements: *id004
|
62
73
|
description:
|
63
74
|
email: kaspar.schiess@absurd.li
|
64
75
|
executables: []
|
@@ -75,6 +86,7 @@ files:
|
|
75
86
|
- README
|
76
87
|
- lib/parslet/atoms/alternative.rb
|
77
88
|
- lib/parslet/atoms/base.rb
|
89
|
+
- lib/parslet/atoms/context.rb
|
78
90
|
- lib/parslet/atoms/entity.rb
|
79
91
|
- lib/parslet/atoms/lookahead.rb
|
80
92
|
- lib/parslet/atoms/named.rb
|
@@ -82,8 +94,11 @@ files:
|
|
82
94
|
- lib/parslet/atoms/repetition.rb
|
83
95
|
- lib/parslet/atoms/sequence.rb
|
84
96
|
- lib/parslet/atoms/str.rb
|
97
|
+
- lib/parslet/atoms/visitor.rb
|
85
98
|
- lib/parslet/atoms.rb
|
99
|
+
- lib/parslet/convenience.rb
|
86
100
|
- lib/parslet/error_tree.rb
|
101
|
+
- lib/parslet/export.rb
|
87
102
|
- lib/parslet/expression/treetop.rb
|
88
103
|
- lib/parslet/expression.rb
|
89
104
|
- lib/parslet/parser.rb
|
@@ -91,11 +106,13 @@ files:
|
|
91
106
|
- lib/parslet/pattern/context.rb
|
92
107
|
- lib/parslet/pattern.rb
|
93
108
|
- lib/parslet/rig/rspec.rb
|
109
|
+
- lib/parslet/source.rb
|
94
110
|
- lib/parslet/transform.rb
|
95
111
|
- lib/parslet.rb
|
96
112
|
- example/documentation.rb
|
97
113
|
- example/email_parser.rb
|
98
114
|
- example/empty.rb
|
115
|
+
- example/erb.rb
|
99
116
|
- example/ip_address.rb
|
100
117
|
- example/minilisp.rb
|
101
118
|
- example/parens.rb
|