rparsec2 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5de30f07e3855c6c2168832879138e3341ce79a20272ddf2c92857f47414e1ea
4
+ data.tar.gz: 74c1ad503c94fe4a75a788d1384161b6f1b34a7e017a0740a0025d24f8a8518f
5
+ SHA512:
6
+ metadata.gz: 26932d06bc2b3ec459ea0b3e22d091ebd1470d277bdac373b075821c97b82b4ab5936bdf4944150f21016cd9632f0a84d0428417f68446c31e33447734035e74
7
+ data.tar.gz: e776214089f74d14ce7f61d4fde624ca245127d7edf89ca87033fe96b2132ab25b74f4d36a8927a6c0c24145c0722b911334f7e1eb32f08064ed7e6b448fd33f
@@ -0,0 +1,86 @@
1
+ require 'strscan'
2
+
3
+ module RParsec
4
+
5
+ class ParseContext
6
+ attr_reader :error, :src, :index, :result
7
+ attr_writer :error, :index, :result
8
+
9
+ def initialize(src, index=0, error=nil)
10
+ @src, @index, @error = src, index, error
11
+ @scanner = nil
12
+ end
13
+
14
+ def scanner
15
+ @scanner = StringScanner.new(src) if @scanner.nil?
16
+ @scanner.pos= @index
17
+ @scanner
18
+ end
19
+
20
+ def prepare_error
21
+ @error.flatten! if @error.kind_of?(Array)
22
+ end
23
+
24
+ def to_msg
25
+ return '' if @error.nil?
26
+ return @error.msg unless @error.kind_of?(Array)
27
+ @error.map{|e|e.msg}.join(' or ')
28
+ end
29
+
30
+ def error_input
31
+ return nil if @error.nil?
32
+ err = @error
33
+ err = err.last if err.kind_of? Array
34
+ err.input
35
+ end
36
+
37
+ def reset_error
38
+ @error = nil
39
+ end
40
+
41
+ def current
42
+ @src[@index]
43
+ end
44
+
45
+ def eof
46
+ @index >= @src.length
47
+ end
48
+
49
+ def available
50
+ @src.length - @index
51
+ end
52
+
53
+ def peek i
54
+ @src[@index+i]
55
+ end
56
+
57
+ def next
58
+ @index += 1
59
+ end
60
+
61
+ def advance n
62
+ @index += n
63
+ end
64
+
65
+ def retn(val)
66
+ @result = val
67
+ true
68
+ end
69
+
70
+ def failure(msg=nil)
71
+ @error = Failure.new(@index, get_current_input, msg)
72
+ return false
73
+ end
74
+
75
+ def expecting(expected=nil)
76
+ @error = Expected.new(@index, get_current_input, expected)
77
+ return false
78
+ end
79
+
80
+ def get_current_input
81
+ return nil if eof
82
+ current
83
+ end
84
+ end
85
+
86
+ end # module
@@ -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,186 @@
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
+ class << self
102
+ private
103
+
104
+ def array_to_dict arr
105
+ result = {}
106
+ arr.each_with_index do |key, i|
107
+ result[key] = i unless result.include? key
108
+ end
109
+ result
110
+ end
111
+ end
112
+
113
+ KindPrecedence = array_to_dict Associativities
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
+ class << self
127
+ private
128
+
129
+ def apply_operators(term, entries, delim)
130
+ # apply operators stored in [[precedence,associativity],[op...]] starting from beginning.
131
+ entries.inject(term) do |result, entry|
132
+ key, ops = *entry
133
+ _, kind_index = *key
134
+ op = ops[0]
135
+ op = Parsers.sum(*ops) if ops.length > 1
136
+ apply_operator(result, op, Associativities[kind_index], delim)
137
+ end
138
+ end
139
+
140
+ def apply_operator(term, op, kind, delim)
141
+ term, op = ignore_rest(term, delim), ignore_rest(op, delim)
142
+ # we could use send here,
143
+ # but explicit case stmt is more straight forward and less coupled with names.
144
+ # performance might be another benefit,
145
+ # though it is not clear whether meta-code is indeed slower than regular ones at all.
146
+ case kind
147
+ when :prefix
148
+ term.prefix(op)
149
+ when :postfix
150
+ term.postfix(op)
151
+ when :infixl
152
+ term.infixl(op)
153
+ when :infixr
154
+ term.infixr(op)
155
+ when :infixn
156
+ term.infixn(op)
157
+ else
158
+ raise ArgumentError, "unknown associativity: #{kind}"
159
+ end
160
+ end
161
+
162
+ def ignore_rest(parser, delim)
163
+ return parser if delim.nil?
164
+ parser << delim
165
+ end
166
+
167
+ def prepare_suites(table)
168
+ # create a hash with [precedence, associativity] as key, and op as value.
169
+ suites = {}
170
+ table.operators.each do |entry|
171
+ kind, op, precedence = *entry
172
+ key = [-precedence, KindPrecedence[kind]]
173
+ suite = suites[key]
174
+ if suite.nil?
175
+ suite = [op]
176
+ suites[key] = suite
177
+ else
178
+ suite << op
179
+ end
180
+ end
181
+ suites
182
+ end
183
+ end
184
+ end
185
+
186
+ end # module
@@ -0,0 +1,282 @@
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
+ Succ = proc { |x| x.succ }
12
+ Dec = proc { |x| x - 1 }
13
+ Plus = proc { |x, y| x + y }
14
+ Minus = proc { |x, y| x - y }
15
+ Mul = proc { |x, y| x * y }
16
+ Div = proc { |x, y| x / y }
17
+ Mod = proc { |x, y| x % y }
18
+ Power = proc { |x, y| x**y }
19
+ Not = proc { |x, _y| !x }
20
+ And = proc { |x, y| x && y }
21
+ Or = proc { |x, y| x || y }
22
+ Xor = proc { |x, y| x ^ y }
23
+ BitAnd = proc { |x, y| x & y }
24
+ Union = proc { |x, y| x | y }
25
+ Match = proc { |x, y| x =~ y }
26
+ Eq = proc { |x, y| x == y }
27
+ Ne = proc { |x, y| x != y }
28
+ Lt = proc { |x, y| x < y }
29
+ Gt = proc { |x, y| x > y }
30
+ Le = proc { |x, y| x <= y }
31
+ Ge = proc { |x, y| x >= y }
32
+ Compare = proc { |x, y| x <=> y }
33
+ Call = proc { |x, y| x.call(y) }
34
+ Feed = proc { |x, y| y.call(x) }
35
+ Fst = proc { |x, _| x }
36
+ Snd = proc { |_, x| x }
37
+ At = proc { |x, y| x[y] }
38
+ To_a = proc { |x| x.to_a }
39
+ To_s = proc { |x| x.to_s }
40
+ To_i = proc { |x| x.to_i }
41
+ To_sym = proc { |x| x.to_sym }
42
+ To_f = proc { |x| x.to_f }
43
+
44
+ #
45
+ # Get a Proc, when called, always return the given value.
46
+ #
47
+ def const(v)
48
+ proc { |_| v }
49
+ end
50
+
51
+ #
52
+ # Get a Proc, when called, return the nth parameter.
53
+ #
54
+ def nth(n)
55
+ proc { |*args| args[n] }
56
+ end
57
+
58
+ #
59
+ # Create a Proc, which expects the two parameters
60
+ # in the reverse order of _block_.
61
+ #
62
+ def flip(&block)
63
+ proc { |x, y| block.call(y, x) }
64
+ end
65
+
66
+ #
67
+ # Create a Proc, when called, the parameter is
68
+ # first passed into _f2_, _f1_ is called in turn
69
+ # with the return value from _other_.
70
+ #
71
+ def compose(f1, f2)
72
+ proc { |*x| f1.call(f2.call(*x)) }
73
+ end
74
+
75
+ #
76
+ # Create a Proc that's curriable.
77
+ # When curried, parameters are passed in from left to right.
78
+ # i.e. curry(closure).call(a).call(b) is quivalent to closure.call(a,b) .
79
+ # _block_ is encapsulated under the hood to perform the actual
80
+ # job when currying is done.
81
+ # arity explicitly specifies the number of parameters to curry.
82
+ #
83
+ def curry(arity, &block)
84
+ fail "cannot curry for unknown arity" if arity < 0
85
+ Functors.make_curry(arity, &block)
86
+ end
87
+
88
+ #
89
+ # Create a Proc that's curriable.
90
+ # When curried, parameters are passed in from right to left.
91
+ # i.e. reverse_curry(closure).call(a).call(b) is quivalent to closure.call(b,a) .
92
+ # _block_ is encapsulated under the hood to perform the actual
93
+ # job when currying is done.
94
+ # arity explicitly specifies the number of parameters to curry.
95
+ #
96
+ def reverse_curry(arity, &block)
97
+ fail "cannot curry for unknown arity" if arity < 0
98
+ Functors.make_reverse_curry(arity, &block)
99
+ end
100
+
101
+ #
102
+ # Uncurry a curried closure.
103
+ #
104
+ def uncurry(&block)
105
+ return block unless block.arity == 1
106
+ proc do |*args|
107
+ result = block
108
+ args.each do |a|
109
+ result = result.call(a)
110
+ end
111
+ result
112
+ end
113
+ end
114
+
115
+ #
116
+ # Uncurry a reverse curried closure.
117
+ #
118
+ def reverse_uncurry(&block)
119
+ return block unless block.arity == 1
120
+ proc do |*args|
121
+ result = block
122
+ args.reverse_each do |a|
123
+ result = result.call(a)
124
+ end
125
+ result
126
+ end
127
+ end
128
+
129
+ #
130
+ # Create a Proc, when called,
131
+ # repeatedly call _block_ for _n_ times.
132
+ # The same arguments are passed to each invocation.
133
+ #
134
+ def repeat(n, &block)
135
+ proc do |*args|
136
+ result = nil
137
+ n.times { result = block.call(*args) }
138
+ result
139
+ end
140
+ end
141
+
142
+ #
143
+ # Create a Proc, when called,
144
+ # repeatedly call _block_ for _n_ times.
145
+ # At each iteration, return value from the previous iteration
146
+ # is used as parameter.
147
+ #
148
+ def power(n, &block)
149
+ return const(nil) if n <= 0
150
+ return block if n == 1
151
+ proc do |*args|
152
+ result = block.call(*args)
153
+ (n - 1).times { result = block.call(result) }
154
+ result
155
+ end
156
+ end
157
+
158
+ extend self
159
+
160
+ def self.make_curry(arity, &block)
161
+ return block if arity <= 1
162
+ proc do |x|
163
+ make_curry(arity - 1) do |*rest|
164
+ block.call(*rest.insert(0, x))
165
+ end
166
+ end
167
+ end
168
+
169
+ def self.make_reverse_curry(arity, &block)
170
+ return block if arity <= 1
171
+ proc do |x|
172
+ make_reverse_curry(arity - 1) do |*rest|
173
+ block.call(*rest << x)
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ #
180
+ # This module provides instance methods that
181
+ # manipulate closures in a functional style.
182
+ # It is typically included in Proc and Method.
183
+ #
184
+ module FunctorMixin
185
+ #
186
+ # Create a Proc, which expects the two parameters
187
+ # in the reverse order of _self_.
188
+ #
189
+ def flip
190
+ Functors.flip(&self)
191
+ end
192
+
193
+ #
194
+ # Create a Proc, when called, the parameter is
195
+ # first passed into _other_, _self_ is called in turn
196
+ # with the return value from _other_.
197
+ #
198
+ def compose(other)
199
+ Functors.compose(self, other)
200
+ end
201
+
202
+ alias << compose
203
+
204
+ #
205
+ # a >> b is equivalent to b << a
206
+ #
207
+ def >>(other)
208
+ other << self
209
+ end
210
+
211
+ #
212
+ # Create a Proc that's curriable.
213
+ # When curried, parameters are passed in from left to right.
214
+ # i.e. closure.curry.call(a).call(b) is quivalent to closure.call(a,b) .
215
+ # _self_ is encapsulated under the hood to perform the actual
216
+ # job when currying is done.
217
+ # _ary_ explicitly specifies the number of parameters to curry.
218
+ #
219
+ # *IMPORTANT*
220
+ # Proc and Method have built-in curry.
221
+ # but the arity always return -1.
222
+ # So, curry.reverse_curry does not work as expected.
223
+ # You need to use the "using FunctorMixin"
224
+ # See the "functor_test.rb"
225
+ [Proc, Method].each do |klass|
226
+ refine klass do
227
+ def curry(ary = arity)
228
+ Functors.curry(ary, &self)
229
+ end
230
+ end
231
+ end
232
+
233
+ #
234
+ # Create a Proc that's curriable.
235
+ # When curried, parameters are passed in from right to left.
236
+ # i.e. closure.reverse_curry.call(a).call(b) is quivalent to closure.call(b,a) .
237
+ # _self_ is encapsulated under the hood to perform the actual
238
+ # job when currying is done.
239
+ # _ary_ explicitly specifies the number of parameters to curry.
240
+ #
241
+ def reverse_curry(ary = arity)
242
+ Functors.reverse_curry(ary, &self)
243
+ end
244
+
245
+ #
246
+ # Uncurry a curried closure.
247
+ #
248
+ def uncurry
249
+ Functors.uncurry(&self)
250
+ end
251
+
252
+ #
253
+ # Uncurry a reverse curried closure.
254
+ #
255
+ def reverse_uncurry
256
+ Functors.reverse_uncurry(&self)
257
+ end
258
+
259
+ #
260
+ # Create a Proc, when called,
261
+ # repeatedly call _self_ for _n_ times.
262
+ # The same arguments are passed to each invocation.
263
+ #
264
+ def repeat(n)
265
+ Functors.repeat(n, &self)
266
+ end
267
+ #
268
+
269
+ # Create a Proc, when called,
270
+ # repeatedly call _self_ for _n_ times.
271
+ # At each iteration, return value from the previous iteration
272
+ # is used as parameter.
273
+ #
274
+ def power(n)
275
+ Functors.power(n, &self)
276
+ end
277
+
278
+ alias ** power
279
+ alias * repeat
280
+ end
281
+
282
+ end # module
@@ -0,0 +1,17 @@
1
+ module RParsec
2
+
3
+ class IdMonad
4
+ def value v
5
+ v
6
+ end
7
+
8
+ def bind prev
9
+ yield prev
10
+ end
11
+
12
+ def mplus a, _b
13
+ a
14
+ end
15
+ end
16
+
17
+ end # module
@@ -0,0 +1,114 @@
1
+ require 'rparsec/parser'
2
+
3
+ module RParsec
4
+
5
+ #
6
+ # This class helps building lexers and parsers for keywords.
7
+ #
8
+ class Keywords
9
+ extend Parsers
10
+
11
+ private_class_method :new
12
+
13
+ #
14
+ # The symbol used to identify a keyword token
15
+ #
16
+ attr_reader :keyword_symbol
17
+
18
+ #
19
+ # The lexer that parses all the keywords represented
20
+ #
21
+ attr_reader :lexer
22
+
23
+ #
24
+ # Do we lex case sensitively?
25
+ #
26
+ def case_sensitive?
27
+ @case_sensitive
28
+ end
29
+
30
+ #
31
+ # To create an instance that lexes the given keywords
32
+ # case sensitively.
33
+ # _default_lexer_ is used to lex a token first, the token text is then compared with
34
+ # the given keywords. If it matches any of the keyword, a keyword token is generated instead
35
+ # using _keyword_symbol_.
36
+ # The _block_ parameter, if present, is used to convert the token text to another object
37
+ # when the token is recognized during grammar parsing phase.
38
+ #
39
+ def self.case_sensitive(words, default_lexer = word.token(:word), keyword_symbol = :keyword, &block)
40
+ new(words, true, default_lexer, keyword_symbol, &block)
41
+ end
42
+
43
+ #
44
+ # To create an instance that lexes the given keywords
45
+ # case insensitively.
46
+ # _default_lexer_ is used to lex a token first, the token text is then compared with
47
+ # the given keywords. If it matches any of the keyword, a keyword token is generated instead
48
+ # using _keyword_symbol_.
49
+ # The _block_ parameter, if present, is used to convert the token text to another object
50
+ # when the token is recognized during parsing phase.
51
+ #
52
+ def self.case_insensitive(words, default_lexer = word.token(:word), keyword_symbol = :keyword, &block)
53
+ new(words, false, default_lexer, keyword_symbol, &block)
54
+ end
55
+
56
+ # scanner has to return a string
57
+ def initialize(words, case_sensitive, default_lexer, keyword_symbol, &block)
58
+ @default_lexer, @case_sensitive, @keyword_symbol = default_lexer, case_sensitive, keyword_symbol
59
+ # this guarantees that we have copy of the words array and all the word strings.
60
+ words = copy_words(words, case_sensitive)
61
+ @name_map = {}
62
+ @symbol_map = {}
63
+ word_map = {}
64
+ words.each do |w|
65
+ symbol = "#{keyword_symbol}:#{w}".to_sym
66
+ word_map[w] = symbol
67
+ parser = Parsers.token(symbol, &block)
68
+ @symbol_map["#{w}".to_sym] = parser
69
+ @name_map[w] = parser
70
+ end
71
+ @lexer = make_lexer(default_lexer, word_map)
72
+ end
73
+
74
+ #
75
+ # Get the parser that recognizes the token of the given keyword during the parsing phase.
76
+ #
77
+ def parser(key)
78
+ result = nil
79
+ if key.kind_of? String
80
+ name = canonical_name(key)
81
+ result = @name_map[name]
82
+ else
83
+ result = @symbol_map[key]
84
+ end
85
+ raise ArgumentError, "parser not found for #{key}" if result.nil?
86
+ result
87
+ end
88
+
89
+ alias [] parser
90
+
91
+ private
92
+
93
+ def make_lexer(default_lexer, word_map)
94
+ default_lexer.map do |tok|
95
+ text, ind = tok.text, tok.index
96
+ key = canonical_name(text)
97
+ my_symbol = word_map[key]
98
+ case when my_symbol.nil? then tok
99
+ else Token.new(my_symbol, text, ind) end
100
+ end
101
+ end
102
+
103
+ def canonical_name(name)
104
+ case when @case_sensitive then name else name.downcase end
105
+ end
106
+
107
+ def copy_words(words, case_sensitive)
108
+ words.map do |w|
109
+ case when case_sensitive then w.dup else w.downcase end
110
+ end
111
+ end
112
+ end
113
+
114
+ end # module