parslet 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|