rparsec-ruby19 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/rparsec.rb +3 -0
- data/rparsec/context.rb +83 -0
- data/rparsec/error.rb +28 -0
- data/rparsec/expressions.rb +184 -0
- data/rparsec/functors.rb +274 -0
- data/rparsec/id_monad.rb +17 -0
- data/rparsec/keywords.rb +114 -0
- data/rparsec/locator.rb +40 -0
- data/rparsec/misc.rb +130 -0
- data/rparsec/monad.rb +62 -0
- data/rparsec/operators.rb +103 -0
- data/rparsec/parser.rb +894 -0
- data/rparsec/parser_monad.rb +23 -0
- data/rparsec/parsers.rb +623 -0
- data/rparsec/token.rb +43 -0
- data/test/src/expression_test.rb +124 -0
- data/test/src/full_parser_test.rb +95 -0
- data/test/src/functor_test.rb +66 -0
- data/test/src/import.rb +5 -0
- data/test/src/keyword_test.rb +28 -0
- data/test/src/operator_test.rb +21 -0
- data/test/src/parser_test.rb +53 -0
- data/test/src/perf_benchmark.rb +25 -0
- data/test/src/s_expression_test.rb +33 -0
- data/test/src/scratch.rb +41 -0
- data/test/src/simple_monad_test.rb +22 -0
- data/test/src/simple_parser_test.rb +423 -0
- data/test/src/sql.rb +268 -0
- data/test/src/sql_parser.rb +258 -0
- data/test/src/sql_test.rb +128 -0
- data/test/src/tests.rb +13 -0
- metadata +95 -0
data/rparsec.rb
ADDED
data/rparsec/context.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module RParsec
|
2
|
+
|
3
|
+
class ParseContext
|
4
|
+
attr_reader :error, :src, :index, :result
|
5
|
+
attr_writer :error, :index, :result
|
6
|
+
|
7
|
+
def initialize(src, index=0, error=nil)
|
8
|
+
@src, @index, @error = src, index, error
|
9
|
+
end
|
10
|
+
|
11
|
+
def scanner
|
12
|
+
@scanner = StringScanner.new(src) if @scanner.nil?
|
13
|
+
@scanner.pos= @index
|
14
|
+
@scanner
|
15
|
+
end
|
16
|
+
|
17
|
+
def prepare_error
|
18
|
+
@error.flatten! if @error.kind_of?(Array)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_msg
|
22
|
+
return '' if @error.nil?
|
23
|
+
return @error.msg unless @error.kind_of?(Array)
|
24
|
+
@error.map{|e|e.msg}.join(' or ')
|
25
|
+
end
|
26
|
+
|
27
|
+
def error_input
|
28
|
+
return nil if @error.nil?
|
29
|
+
err = @error
|
30
|
+
err = err.last if err.kind_of? Array
|
31
|
+
err.input
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset_error
|
35
|
+
@error = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def current
|
39
|
+
@src[@index]
|
40
|
+
end
|
41
|
+
|
42
|
+
def eof
|
43
|
+
@index >= @src.length
|
44
|
+
end
|
45
|
+
|
46
|
+
def available
|
47
|
+
@src.length - @index
|
48
|
+
end
|
49
|
+
|
50
|
+
def peek i
|
51
|
+
@src[@index+i]
|
52
|
+
end
|
53
|
+
|
54
|
+
def next
|
55
|
+
@index += 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def advance n
|
59
|
+
@index += n
|
60
|
+
end
|
61
|
+
|
62
|
+
def retn(val)
|
63
|
+
@result = val
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def failure(msg=nil)
|
68
|
+
@error = Failure.new(@index, get_current_input, msg)
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
|
72
|
+
def expecting(expected=nil)
|
73
|
+
@error = Expected.new(@index, get_current_input, expected)
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_current_input
|
78
|
+
return nil if eof
|
79
|
+
current
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end # module
|
data/rparsec/error.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rparsec/misc'
|
2
|
+
|
3
|
+
module RParsec
|
4
|
+
|
5
|
+
class ParserException < StandardError
|
6
|
+
extend DefHelper
|
7
|
+
def_readable :index
|
8
|
+
end
|
9
|
+
class Failure
|
10
|
+
def initialize(ind, input, message=nil)
|
11
|
+
@index, @input, @msg = ind, input, message
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :index, :input
|
15
|
+
attr_writer :index
|
16
|
+
|
17
|
+
def msg
|
18
|
+
return @msg.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
Precedence = 100
|
22
|
+
end
|
23
|
+
|
24
|
+
class Expected < Failure
|
25
|
+
Precedence = 100
|
26
|
+
end
|
27
|
+
|
28
|
+
end # module
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'rparsec/parser'
|
2
|
+
|
3
|
+
module RParsec
|
4
|
+
|
5
|
+
Associativities = [:prefix, :postfix, :infixn, :infixr, :infixl]
|
6
|
+
#
|
7
|
+
# This class holds information about operator precedences
|
8
|
+
# and associativities.
|
9
|
+
# prefix, postfix, infixl, infixr, infixn can be called
|
10
|
+
# to register operators.
|
11
|
+
#
|
12
|
+
class OperatorTable
|
13
|
+
#
|
14
|
+
# operators attribute is used internally. Do not access it.
|
15
|
+
#
|
16
|
+
attr_reader :operators
|
17
|
+
|
18
|
+
#
|
19
|
+
# Re-initialize the operator table. Internal use only.
|
20
|
+
#
|
21
|
+
def reinit
|
22
|
+
@operators = []
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# To create an OperatorTable instance.
|
27
|
+
# If a block is given, it is invoked to do post-instantiation.
|
28
|
+
# For example:
|
29
|
+
#
|
30
|
+
# OperatorTable.new do |tbl|
|
31
|
+
# tbl.infixl(char(?+) >> Plus, 10)
|
32
|
+
# tbl.infixl(char(?-) >> Minus, 10)
|
33
|
+
# tbl.infixl(char(?*) >> Mul, 20)
|
34
|
+
# tbl.infixl(char(?/) >> Div, 20)
|
35
|
+
# tbl.prefix(char(?-) >> Neg, 50)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def self.new
|
39
|
+
this = allocate
|
40
|
+
this.reinit
|
41
|
+
if block_given?
|
42
|
+
yield this
|
43
|
+
end
|
44
|
+
this
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Defines a prefix operator that returns a unary Proc object with a precedence associated.
|
49
|
+
# Returns self.
|
50
|
+
#
|
51
|
+
def prefix(op, precedence)
|
52
|
+
add(:prefix, op, precedence)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Defines a postfix operator that returns a unary Proc object with a precedence associated.
|
57
|
+
# Returns self.
|
58
|
+
#
|
59
|
+
def postfix(op, precedence)
|
60
|
+
add(:postfix, op, precedence)
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Defines a left associative infix operator that returns a binary Proc object with a precedence
|
65
|
+
# associated. Returns self.
|
66
|
+
#
|
67
|
+
def infixl(op, precedence)
|
68
|
+
add(:infixl, op, precedence)
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Defines a right associative infix operator that returns a binary Proc object with a precedence
|
73
|
+
# associated. Returns self.
|
74
|
+
#
|
75
|
+
def infixr(op, precedence)
|
76
|
+
add(:infixr, op, precedence)
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Defines a non-associative infix operator that returns a binary Proc object with a precedence
|
81
|
+
# associated. Returns self.
|
82
|
+
#
|
83
|
+
def infixn(op, precedence)
|
84
|
+
add(:infixn, op, precedence)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def add(*entry)
|
90
|
+
@operators << entry
|
91
|
+
self
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# This module helps build an expression parser
|
97
|
+
# using an OperatorTable instance and a parser
|
98
|
+
# that parses the term expression.
|
99
|
+
#
|
100
|
+
module Expressions
|
101
|
+
private
|
102
|
+
|
103
|
+
def self.array_to_dict arr
|
104
|
+
result = {}
|
105
|
+
arr.each_with_index do |key,i|
|
106
|
+
result [key] = i unless result.include? key
|
107
|
+
end
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
KindPrecedence = array_to_dict Associativities
|
112
|
+
|
113
|
+
public
|
114
|
+
|
115
|
+
#
|
116
|
+
# build an expression parser using the given term parser
|
117
|
+
# and operator table.
|
118
|
+
# When _delim_ is specified, patterns recognized by _delim_
|
119
|
+
# is automatically ignored.
|
120
|
+
#
|
121
|
+
def self.build(term, table, delim=nil)
|
122
|
+
# sort so that higher precedence first.
|
123
|
+
apply_operators(term, prepare_suites(table).sort, delim)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def self.apply_operators(term, entries, delim)
|
129
|
+
# apply operators stored in [[precedence,associativity],[op...]] starting from beginning.
|
130
|
+
entries.inject(term) do |result, entry|
|
131
|
+
key, ops = *entry
|
132
|
+
null, kind_index = *key
|
133
|
+
op = ops[0]
|
134
|
+
op = Parsers.sum(*ops) if ops.length>1
|
135
|
+
apply_operator(result, op, Associativities[kind_index], delim)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.apply_operator(term, op, kind, delim)
|
140
|
+
term, op = ignore_rest(term, delim), ignore_rest(op, delim)
|
141
|
+
# we could use send here,
|
142
|
+
# but explicit case stmt is more straight forward and less coupled with names.
|
143
|
+
# performance might be another benefit,
|
144
|
+
# though it is not clear whether meta-code is indeed slower than regular ones at all.
|
145
|
+
case kind
|
146
|
+
when :prefix
|
147
|
+
term.prefix(op)
|
148
|
+
when :postfix
|
149
|
+
term.postfix(op)
|
150
|
+
when :infixl
|
151
|
+
term.infixl(op)
|
152
|
+
when :infixr
|
153
|
+
term.infixr(op)
|
154
|
+
when :infixn
|
155
|
+
term.infixn(op)
|
156
|
+
else
|
157
|
+
raise ArgumentError, "unknown associativity: #{kind}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.ignore_rest(parser, delim)
|
162
|
+
return parser if delim.nil?
|
163
|
+
parser << delim
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.prepare_suites(table)
|
167
|
+
# create a hash with [precedence, associativity] as key, and op as value.
|
168
|
+
suites = {}
|
169
|
+
table.operators.each do |entry|
|
170
|
+
kind, op, precedence = *entry
|
171
|
+
key = [-precedence, KindPrecedence[kind]]
|
172
|
+
suite = suites[key]
|
173
|
+
if suite.nil?
|
174
|
+
suite = [op]
|
175
|
+
suites[key] = suite
|
176
|
+
else
|
177
|
+
suite << op
|
178
|
+
end
|
179
|
+
end
|
180
|
+
suites
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end # module
|
data/rparsec/functors.rb
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
module RParsec
|
2
|
+
|
3
|
+
#
|
4
|
+
# This module provides frequently used functors.
|
5
|
+
#
|
6
|
+
module Functors
|
7
|
+
Id = proc {|x|x}
|
8
|
+
Idn = proc {|*x|x}
|
9
|
+
Neg = proc {|x|-x}
|
10
|
+
Inc = proc {|x|x+1}
|
11
|
+
Dec = proc {|x|x-1}
|
12
|
+
Plus = proc {|x,y|x+y}
|
13
|
+
Minus = proc {|x,y|x-y}
|
14
|
+
Mul = proc {|x,y|x*y}
|
15
|
+
Div = proc {|x,y|x/y}
|
16
|
+
Mod = proc {|x,y|x%y}
|
17
|
+
Power = proc {|x,y|x**y}
|
18
|
+
Not = proc {|x,y|!x}
|
19
|
+
And = proc {|x,y|x&&y}
|
20
|
+
Or = proc {|x,y|x||y}
|
21
|
+
Xor = proc {|x,y|x^y}
|
22
|
+
BitAnd = proc {|x,y|x&y}
|
23
|
+
Union = proc {|x,y|x|y}
|
24
|
+
Match = proc {|x,y|x=~y}
|
25
|
+
Eq = proc {|x,y|x==y}
|
26
|
+
Ne = proc {|x,y|x!=y}
|
27
|
+
Lt = proc {|x,y|x<y}
|
28
|
+
Gt = proc {|x,y|x>y}
|
29
|
+
Le = proc {|x,y|x<=y}
|
30
|
+
Ge = proc {|x,y|x>=y}
|
31
|
+
Compare = proc {|x,y|x<=>y}
|
32
|
+
Call = proc {|x,y|x.call(y)}
|
33
|
+
Feed = proc {|x,y|y.call(x)}
|
34
|
+
Fst = proc {|x,_|x}
|
35
|
+
Snd = proc {|_, x|x}
|
36
|
+
At = proc {|x,y|x[y]}
|
37
|
+
To_a = proc {|x|x.to_a}
|
38
|
+
To_s = proc {|x|x.to_s}
|
39
|
+
To_i = proc {|x|x.to_i}
|
40
|
+
To_sym = proc {|x|x.to_sym}
|
41
|
+
To_f = proc {|x|x.to_f}
|
42
|
+
|
43
|
+
#
|
44
|
+
# Get a Proc, when called, always return the given value.
|
45
|
+
#
|
46
|
+
def const(v)
|
47
|
+
proc {|_|v}
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Get a Proc, when called, return the nth parameter.
|
52
|
+
#
|
53
|
+
def nth(n)
|
54
|
+
proc {|*args|args[n]}
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Create a Proc, which expects the two parameters
|
59
|
+
# in the reverse order of _block_.
|
60
|
+
#
|
61
|
+
def flip(&block)
|
62
|
+
proc {|x,y|block.call(y,x)}
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Create a Proc, when called, the parameter is
|
67
|
+
# first passed into _f2_, _f1_ is called in turn
|
68
|
+
# with the return value from _other_.
|
69
|
+
#
|
70
|
+
def compose(f1, f2)
|
71
|
+
proc {|*x|f1.call(f2.call(*x))}
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Create a Proc that's curriable.
|
76
|
+
# When curried, parameters are passed in from left to right.
|
77
|
+
# i.e. curry(closure).call(a).call(b) is quivalent to closure.call(a,b) .
|
78
|
+
# _block_ is encapsulated under the hood to perform the actual
|
79
|
+
# job when currying is done.
|
80
|
+
# arity explicitly specifies the number of parameters to curry.
|
81
|
+
#
|
82
|
+
def curry(arity, &block)
|
83
|
+
fail "cannot curry for unknown arity" if arity < 0
|
84
|
+
Functors.make_curry(arity, &block)
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Create a Proc that's curriable.
|
89
|
+
# When curried, parameters are passed in from right to left.
|
90
|
+
# i.e. reverse_curry(closure).call(a).call(b) is quivalent to closure.call(b,a) .
|
91
|
+
# _block_ is encapsulated under the hood to perform the actual
|
92
|
+
# job when currying is done.
|
93
|
+
# arity explicitly specifies the number of parameters to curry.
|
94
|
+
#
|
95
|
+
def reverse_curry(arity, &block)
|
96
|
+
fail "cannot curry for unknown arity" if arity < 0
|
97
|
+
Functors.make_reverse_curry(arity, &block)
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Uncurry a curried closure.
|
102
|
+
#
|
103
|
+
def uncurry(&block)
|
104
|
+
return block unless block.arity == 1
|
105
|
+
proc do |*args|
|
106
|
+
result = block
|
107
|
+
args.each do |a|
|
108
|
+
result = result.call(a)
|
109
|
+
end
|
110
|
+
result
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Uncurry a reverse curried closure.
|
116
|
+
#
|
117
|
+
def reverse_uncurry(&block)
|
118
|
+
return block unless block.arity == 1
|
119
|
+
proc do |*args|
|
120
|
+
result = block
|
121
|
+
args.reverse_each do |a|
|
122
|
+
result = result.call(a)
|
123
|
+
end
|
124
|
+
result
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Create a Proc, when called,
|
130
|
+
# repeatedly call _block_ for _n_ times.
|
131
|
+
# The same arguments are passed to each invocation.
|
132
|
+
#
|
133
|
+
def repeat(n, &block)
|
134
|
+
proc do |*args|
|
135
|
+
result = nil
|
136
|
+
n.times {result = block.call(*args)}
|
137
|
+
result
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Create a Proc, when called,
|
143
|
+
# repeatedly call _block_ for _n_ times.
|
144
|
+
# At each iteration, return value from the previous iteration
|
145
|
+
# is used as parameter.
|
146
|
+
#
|
147
|
+
def power(n, &block)
|
148
|
+
return const(nil) if n<=0
|
149
|
+
return block if n==1
|
150
|
+
proc do |*args|
|
151
|
+
result = block.call(*args)
|
152
|
+
(n-1).times {result = block.call(result)}
|
153
|
+
result
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
extend self
|
158
|
+
|
159
|
+
private_class_method
|
160
|
+
|
161
|
+
def self.make_curry(arity, &block)
|
162
|
+
return block if arity<=1
|
163
|
+
proc do |x|
|
164
|
+
make_curry(arity-1) do |*rest|
|
165
|
+
block.call(*rest.insert(0, x))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.make_reverse_curry(arity, &block)
|
171
|
+
return block if arity <= 1
|
172
|
+
proc do |x|
|
173
|
+
make_reverse_curry(arity-1) do |*rest|
|
174
|
+
block.call(*rest << x)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
#
|
182
|
+
# This module provides instance methods that
|
183
|
+
# manipulate closures in a functional style.
|
184
|
+
# It is typically included in Proc and Method.
|
185
|
+
#
|
186
|
+
module FunctorMixin
|
187
|
+
#
|
188
|
+
# Create a Proc, which expects the two parameters
|
189
|
+
# in the reverse order of _self_.
|
190
|
+
#
|
191
|
+
def flip
|
192
|
+
Functors.flip(&self)
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Create a Proc, when called, the parameter is
|
197
|
+
# first passed into _other_, _self_ is called in turn
|
198
|
+
# with the return value from _other_.
|
199
|
+
#
|
200
|
+
def compose(other)
|
201
|
+
Functors.compose(self, other)
|
202
|
+
end
|
203
|
+
|
204
|
+
alias << compose
|
205
|
+
|
206
|
+
#
|
207
|
+
# a >> b is equivalent to b << a
|
208
|
+
#
|
209
|
+
def >> (other)
|
210
|
+
other << self
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Create a Proc that's curriable.
|
215
|
+
# When curried, parameters are passed in from left to right.
|
216
|
+
# i.e. closure.curry.call(a).call(b) is quivalent to closure.call(a,b) .
|
217
|
+
# _self_ is encapsulated under the hood to perform the actual
|
218
|
+
# job when currying is done.
|
219
|
+
# _ary_ explicitly specifies the number of parameters to curry.
|
220
|
+
#
|
221
|
+
def curry(ary=arity)
|
222
|
+
Functors.curry(ary, &self)
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
# Create a Proc that's curriable.
|
227
|
+
# When curried, parameters are passed in from right to left.
|
228
|
+
# i.e. closure.reverse_curry.call(a).call(b) is quivalent to closure.call(b,a) .
|
229
|
+
# _self_ is encapsulated under the hood to perform the actual
|
230
|
+
# job when currying is done.
|
231
|
+
# _ary_ explicitly specifies the number of parameters to curry.
|
232
|
+
#
|
233
|
+
def reverse_curry(ary=arity)
|
234
|
+
Functors.reverse_curry(ary, &self)
|
235
|
+
end
|
236
|
+
|
237
|
+
#
|
238
|
+
# Uncurry a curried closure.
|
239
|
+
#
|
240
|
+
def uncurry
|
241
|
+
Functors.uncurry(&self)
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Uncurry a reverse curried closure.
|
246
|
+
#
|
247
|
+
def reverse_uncurry
|
248
|
+
Functors.reverse_uncurry(&self)
|
249
|
+
end
|
250
|
+
|
251
|
+
#
|
252
|
+
# Create a Proc, when called,
|
253
|
+
# repeatedly call _self_ for _n_ times.
|
254
|
+
# The same arguments are passed to each invocation.
|
255
|
+
#
|
256
|
+
def repeat(n)
|
257
|
+
Functors.repeat(n, &self)
|
258
|
+
end
|
259
|
+
#
|
260
|
+
|
261
|
+
# Create a Proc, when called,
|
262
|
+
# repeatedly call _self_ for _n_ times.
|
263
|
+
# At each iteration, return value from the previous iteration
|
264
|
+
# is used as parameter.
|
265
|
+
#
|
266
|
+
def power(n)
|
267
|
+
Functors.power(n, &self)
|
268
|
+
end
|
269
|
+
|
270
|
+
alias ** power
|
271
|
+
alias * repeat
|
272
|
+
end
|
273
|
+
|
274
|
+
end # module
|