yaparc 0.0.1 → 0.0.3

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/README CHANGED
@@ -12,5 +12,12 @@ This is a yet another simple combinator parser library in ruby.
12
12
 
13
13
  = Usage
14
14
 
15
+ require 'rubygems'
16
+ require_gem 'yaparc'
17
+
18
+
19
+
15
20
  Please look at unit test files.
16
21
 
22
+
23
+
data/lib/parser.rb CHANGED
@@ -2,7 +2,9 @@
2
2
  module Yaparc
3
3
  module Parsable
4
4
  include Yaparc
5
-
5
+
6
+ attr_accessor :tree
7
+
6
8
  IS_LOWER = lambda {|c| c >= 'a' and c <= 'z'}
7
9
  IS_ALPHANUM = lambda {|c| (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9')}
8
10
  IS_DIGIT = lambda {|i| i > '0' and i < '9'}
@@ -13,8 +15,13 @@ module Yaparc
13
15
  end
14
16
 
15
17
 
16
- def parse(input)
17
- @parser.call(input)
18
+ def parse(input, &block)
19
+ tree = @parser.call(input)
20
+ if block_given?
21
+ @tree = yield tree
22
+ else
23
+ @tree = tree
24
+ end
18
25
  end
19
26
 
20
27
  def eval
@@ -143,8 +150,7 @@ module Yaparc
143
150
  @parser = lambda do |input|
144
151
  result = ItemParser.new.parse(string)
145
152
  if result == []
146
- SucceedParser.new(result).parse(input)
147
- # FailParser.new.parse(input)
153
+ SucceedParser.new(result).parse(input) # FailParser.new.parse(input)
148
154
  else
149
155
  SeqParser.new(
150
156
  CharParser.new(result[0][0]),
@@ -158,6 +164,19 @@ module Yaparc
158
164
  end
159
165
  end
160
166
 
167
+ class RegexParser
168
+ include Parsable
169
+ def initialize(regex)
170
+ @parser = lambda do |input|
171
+ if match = Regexp.new(regex).match(input)
172
+ [[match[0],match.post_match]]
173
+ else
174
+ []
175
+ end
176
+ end
177
+ end
178
+ end
179
+
161
180
  class ManyParser
162
181
  include Parsable
163
182
  def initialize(predicate)
@@ -185,6 +204,15 @@ module Yaparc
185
204
  end
186
205
  end
187
206
 
207
+ class ZeroOneParser
208
+ include Parsable
209
+ def initialize(parser)
210
+ @parser = lambda do |input|
211
+ AltParser.new(parser,
212
+ SucceedParser.new([])).parse(input)
213
+ end
214
+ end
215
+ end
188
216
 
189
217
  class Ident
190
218
  include Parsable
data/lib/parser_cps.rb ADDED
@@ -0,0 +1,319 @@
1
+
2
+ module Yaparc
3
+ module Parsable
4
+ include Yaparc
5
+
6
+ attr_accessor :tree
7
+
8
+ IS_LOWER = lambda {|c| c >= 'a' and c <= 'z'}
9
+ IS_ALPHANUM = lambda {|c| (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9')}
10
+ IS_DIGIT = lambda {|i| i > '0' and i < '9'}
11
+ IS_SPACE = lambda {|i| i == ' '}
12
+
13
+ # def self.included(mod)
14
+ # mod.extend ClassMethods
15
+ # end
16
+
17
+ def parse(input, cont, &block)
18
+ tree = @parser.call(input, cont)
19
+ if block_given?
20
+ @tree = yield tree
21
+ else
22
+ @tree = tree
23
+ end
24
+ cont.apply(input)
25
+ end
26
+ end # of Parsable
27
+
28
+ module Continuation
29
+ class Base
30
+ def apply(input)
31
+ @proc.call(input)
32
+ end
33
+ # def apply(arg, input = '')
34
+ # @proc.call(input,val)
35
+ # end
36
+ end
37
+
38
+ class StopCont < Base
39
+ def initialize
40
+ # @proc = lambda do |input|
41
+ # lambda{|input, val|
42
+ # [[val,input]]
43
+ # }
44
+ # end
45
+ @proc = lambda do |val, input|
46
+ [[val,input]]
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+
53
+ class ItemHeadCont < Base
54
+ def initialize(input, cont)
55
+ @proc = lambda do |val, input|
56
+ [[val,input]]
57
+ end
58
+ end
59
+ end
60
+
61
+ class ItemTailCont < Base
62
+ def initialize(cont)
63
+ @proc = lambda do |val, input|
64
+ [[val,input]]
65
+ end
66
+ end
67
+ end
68
+ end # of Continuation
69
+
70
+ module Parser
71
+ class SucceedParser
72
+ include Parsable
73
+ def initialize(val)
74
+ @parser = lambda do |input, cont|
75
+ cont.apply(val)
76
+ end
77
+ end
78
+ end
79
+
80
+ class FailParser
81
+ include Parsable
82
+ def initialize
83
+ @parser = lambda do |input|
84
+ []
85
+ end
86
+ end
87
+ end
88
+
89
+ class ItemParser
90
+ include Parsable
91
+ def initialize(cont)
92
+ @parser = lambda do |input|
93
+ if input.nil? or input.empty?
94
+ FailParser.new(StopCont.new)
95
+ else
96
+ # head = input[0..0]
97
+ # tail = input[1..input.length]
98
+ ItemHeadCont.new(input,ItemTailCont.new(cont)).apply(input)
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ class SatisfyParser
105
+ include Parsable
106
+ def initialize(predicate)
107
+ @parser = lambda do |input|
108
+ item = ItemParser.new.parse(input)
109
+ if item == []
110
+ FailParser.new.parse(input)
111
+ else
112
+ if predicate.call(item[0][0])
113
+ SucceedParser.new(item[0][0]).parse(item[0][1])
114
+ else
115
+ FailParser.new.parse(input)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ class SeqParser
123
+ include Parsable
124
+ def initialize(first, second, &block)
125
+ @parser = lambda do |input, cont|
126
+ SeqCont.new(first, second, cont).apply(input)
127
+ end
128
+ end # of initialize
129
+
130
+ class SeqCont < Continuation::Base
131
+ def initialize(first, second, cont)
132
+ @proc = lambda do |input|
133
+ first.parse(input, second.parse(input, cont))
134
+ end
135
+ end
136
+ end
137
+ end # of SeqParser
138
+
139
+
140
+
141
+ class AltParser
142
+ include Parsable
143
+ def initialize(left, right)
144
+ @parser = lambda do |input, cont|
145
+ AltCont.new(left, right, cont).apply(input)
146
+ end
147
+ end
148
+ class AltCont < Continuation::Base
149
+ def initialize(left, right, cont)
150
+ @proc = lambda do |input|
151
+ left.parse(input, cont) or right.parse(input, cont)
152
+ end
153
+ end
154
+ end
155
+ end # of AltParser
156
+
157
+ class CharParser
158
+ include Parsable
159
+ def initialize(char)
160
+ equal_char = lambda {|i| i == char}
161
+ @parser = lambda do |input|
162
+ SatisfyParser.new(equal_char).parse(input)
163
+ end
164
+ end
165
+ end
166
+
167
+ class StringParser
168
+ include Parsable
169
+ def initialize(string)
170
+ @parser = lambda do |input|
171
+ result = ItemParser.new.parse(string)
172
+ if result == []
173
+ SucceedParser.new(result).parse(input) # FailParser.new.parse(input)
174
+ else
175
+ SeqParser.new(
176
+ CharParser.new(result[0][0]),
177
+ StringParser.new(result[0][1]),
178
+ SucceedParser.new(result[0][0] + result[0][1])
179
+ ) do |char_result, string_result, succeed_result|
180
+ succeed_result
181
+ end.parse(input)
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ class RegexParser
188
+ include Parsable
189
+ def initialize(regex)
190
+ @parser = lambda do |input|
191
+ if match = Regexp.new(regex).match(input)
192
+ [[match[0],match.post_match]]
193
+ else
194
+ []
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ class ManyParser
201
+ include Parsable
202
+ def initialize(predicate)
203
+ @parser = lambda do |input|
204
+ AltParser.new(ManyOneParser.new(predicate), SucceedParser.new([])).parse(input)
205
+ end
206
+ end
207
+ end
208
+
209
+ class ManyOneParser
210
+ include Parsable
211
+ def initialize(predicate)
212
+ @parser = lambda do |input|
213
+ SeqParser.new(
214
+ SatisfyParser.new(predicate),
215
+ ManyParser.new(predicate)
216
+ ) do |v, vs|
217
+ if vs == []
218
+ v
219
+ else
220
+ v + vs.to_s
221
+ end
222
+ end.parse(input)
223
+ end
224
+ end
225
+ end
226
+
227
+ class ZeroOneParser
228
+ include Parsable
229
+ def initialize(parser)
230
+ @parser = lambda do |input|
231
+ AltParser.new(parser,
232
+ SucceedParser.new([])).parse(input)
233
+ end
234
+ end
235
+ end
236
+
237
+ class Ident
238
+ include Parsable
239
+ def initialize
240
+ @parser = lambda do |input|
241
+ SeqParser.new(
242
+ SatisfyParser.new(IS_LOWER),
243
+ ManyParser.new(IS_ALPHANUM)
244
+ ) do |v, vs|
245
+ if vs == []
246
+ v
247
+ else
248
+ v + vs.to_s
249
+ end
250
+ end.parse(input)
251
+ end
252
+ end
253
+ end
254
+
255
+ class Nat
256
+ include Parsable
257
+ def initialize
258
+ @parser = lambda do |input|
259
+ SeqParser.new(ManyOneParser.new(IS_DIGIT)) do |vs|
260
+ if vs == []
261
+ vs
262
+ else
263
+ vs.to_i
264
+ end
265
+ end.parse(input)
266
+ end
267
+ end
268
+ end
269
+
270
+ class Space
271
+ include Parsable
272
+ def initialize
273
+ @parser = lambda do |input|
274
+ SeqParser.new(ManyParser.new(IS_SPACE)) do |vs|
275
+ []
276
+ end.parse(input)
277
+ end
278
+ end
279
+ end
280
+
281
+ class Token
282
+ include Parsable
283
+ def initialize(parser)
284
+ @parser = lambda do |input|
285
+ SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
286
+ vs
287
+ end.parse(input)
288
+ end
289
+ end
290
+ end
291
+
292
+ class Identifier
293
+ include Parsable
294
+ def initialize
295
+ @parser = lambda do |input|
296
+ Token.new(Ident.new).parse(input)
297
+ end
298
+ end
299
+ end
300
+
301
+ class Natural
302
+ include Parsable
303
+ def initialize
304
+ @parser = lambda do |input|
305
+ Token.new(Nat.new).parse(input)
306
+ end
307
+ end
308
+ end
309
+
310
+ class Symbol
311
+ include Parsable
312
+ def initialize(literal)
313
+ @parser = lambda do |input|
314
+ Token.new(StringParser.new(literal)).parse(input)
315
+ end
316
+ end
317
+ end
318
+ end # of Parser
319
+ end # Yaparc
data/lib/yaparc.rb ADDED
@@ -0,0 +1,299 @@
1
+
2
+ module Yaparc
3
+ module Parsable
4
+ include Yaparc
5
+
6
+ attr_accessor :tree
7
+
8
+ IS_LOWER = lambda {|c| c >= 'a' and c <= 'z'}
9
+ IS_ALPHANUM = lambda {|c| (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9')}
10
+ IS_DIGIT = lambda {|i| i > '0' and i < '9'}
11
+ IS_SPACE = lambda {|i| i == ' '}
12
+
13
+ def self.included(mod)
14
+ mod.extend ClassMethods
15
+ end
16
+
17
+
18
+ def parse(input, &block)
19
+ tree = @parser.call(input)
20
+ if block_given?
21
+ @tree = yield tree
22
+ else
23
+ @tree = tree
24
+ end
25
+ end
26
+
27
+ def eval
28
+ tree = parse(input)
29
+ end
30
+
31
+ def define_parser
32
+ raise
33
+ end
34
+
35
+ module ClassMethods
36
+ def included(mod)
37
+ end
38
+
39
+ # def self.initialize
40
+ # @parser = @@parser
41
+ # end
42
+
43
+ def define_parser(&block)
44
+ @@parser = lambda do |input|
45
+ parser = yield
46
+ parser.parse(input)
47
+ end
48
+ end
49
+ end
50
+ end # of Parsable
51
+
52
+ class SucceedParser
53
+ include Parsable
54
+ def initialize(value)
55
+ @parser = lambda {|input| [[value, input]]}
56
+ end
57
+ end
58
+
59
+ class FailParser
60
+ include Parsable
61
+ def initialize
62
+ @parser = lambda {|input| []}
63
+ end
64
+ end
65
+
66
+ class ItemParser
67
+ include Parsable
68
+ def initialize
69
+ @parser = lambda do |input|
70
+ if input.nil? or input.empty?
71
+ []
72
+ else
73
+ [[input[0..0],input[1..input.length]]]
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ class SatisfyParser
80
+ include Parsable
81
+ def initialize(predicate)
82
+ @parser = lambda do |input|
83
+ item = ItemParser.new.parse(input)
84
+ if item == []
85
+ FailParser.new.parse(input)
86
+ else
87
+ if predicate.call(item[0][0])
88
+ SucceedParser.new(item[0][0]).parse(item[0][1])
89
+ else
90
+ FailParser.new.parse(input)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ class SeqParser
98
+ include Parsable
99
+ def initialize(*parsers, &block)
100
+ @parser = lambda do |input|
101
+ args = []
102
+ remains = parsers.inject(input) do |accumulator, parser|
103
+ result = parser.parse(accumulator)
104
+ unless result == []
105
+ args << result[0][0]
106
+ result[0][1]
107
+ else
108
+ break []
109
+ end
110
+ end
111
+ unless remains == []
112
+ retval = yield(*args)
113
+ [[retval, remains]]
114
+ else
115
+ []
116
+ end
117
+ end
118
+ end # of initialize
119
+ end # of SeqParser
120
+
121
+ class AltParser
122
+ include Parsable
123
+ def initialize(*parsers)
124
+ @parser = lambda do |input|
125
+ parsers.inject([]) do |accum, parser|
126
+ result = parser.parse(input)
127
+ if result == []
128
+ result
129
+ else
130
+ break [result[0]]
131
+ end
132
+ end
133
+ end
134
+ end # of initialize
135
+ end
136
+
137
+ class CharParser
138
+ include Parsable
139
+ def initialize(char)
140
+ equal_char = lambda {|i| i == char}
141
+ @parser = lambda do |input|
142
+ SatisfyParser.new(equal_char).parse(input)
143
+ end
144
+ end
145
+ end
146
+
147
+ class StringParser
148
+ include Parsable
149
+ def initialize(string)
150
+ @parser = lambda do |input|
151
+ result = ItemParser.new.parse(string)
152
+ if result == []
153
+ SucceedParser.new(result).parse(input) # FailParser.new.parse(input)
154
+ else
155
+ SeqParser.new(
156
+ CharParser.new(result[0][0]),
157
+ StringParser.new(result[0][1]),
158
+ SucceedParser.new(result[0][0] + result[0][1])
159
+ ) do |char_result, string_result, succeed_result|
160
+ succeed_result
161
+ end.parse(input)
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ class RegexParser
168
+ include Parsable
169
+ def initialize(regex)
170
+ @parser = lambda do |input|
171
+ if match = Regexp.new(regex).match(input)
172
+ [[match[0],match.post_match]]
173
+ else
174
+ []
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ class ManyParser
181
+ include Parsable
182
+ def initialize(predicate)
183
+ @parser = lambda do |input|
184
+ AltParser.new(ManyOneParser.new(predicate), SucceedParser.new([])).parse(input)
185
+ end
186
+ end
187
+ end
188
+
189
+ class ManyOneParser
190
+ include Parsable
191
+ def initialize(predicate)
192
+ @parser = lambda do |input|
193
+ SeqParser.new(
194
+ SatisfyParser.new(predicate),
195
+ ManyParser.new(predicate)
196
+ ) do |v, vs|
197
+ if vs == []
198
+ v
199
+ else
200
+ v + vs.to_s
201
+ end
202
+ end.parse(input)
203
+ end
204
+ end
205
+ end
206
+
207
+ class ZeroOneParser
208
+ include Parsable
209
+ def initialize(parser)
210
+ @parser = lambda do |input|
211
+ AltParser.new(parser,
212
+ SucceedParser.new([])).parse(input)
213
+ end
214
+ end
215
+ end
216
+
217
+ class Ident
218
+ include Parsable
219
+ def initialize
220
+ @parser = lambda do |input|
221
+ SeqParser.new(
222
+ SatisfyParser.new(IS_LOWER),
223
+ ManyParser.new(IS_ALPHANUM)
224
+ ) do |v, vs|
225
+ if vs == []
226
+ v
227
+ else
228
+ v + vs.to_s
229
+ end
230
+ end.parse(input)
231
+ end
232
+ end
233
+ end
234
+
235
+ class Nat
236
+ include Parsable
237
+ def initialize
238
+ @parser = lambda do |input|
239
+ SeqParser.new(ManyOneParser.new(IS_DIGIT)) do |vs|
240
+ if vs == []
241
+ vs
242
+ else
243
+ vs.to_i
244
+ end
245
+ end.parse(input)
246
+ end
247
+ end
248
+ end
249
+
250
+ class Space
251
+ include Parsable
252
+ def initialize
253
+ @parser = lambda do |input|
254
+ SeqParser.new(ManyParser.new(IS_SPACE)) do |vs|
255
+ []
256
+ end.parse(input)
257
+ end
258
+ end
259
+ end
260
+
261
+ class Token
262
+ include Parsable
263
+ def initialize(parser)
264
+ @parser = lambda do |input|
265
+ SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
266
+ vs
267
+ end.parse(input)
268
+ end
269
+ end
270
+ end
271
+
272
+ class Identifier
273
+ include Parsable
274
+ def initialize
275
+ @parser = lambda do |input|
276
+ Token.new(Ident.new).parse(input)
277
+ end
278
+ end
279
+ end
280
+
281
+ class Natural
282
+ include Parsable
283
+ def initialize
284
+ @parser = lambda do |input|
285
+ Token.new(Nat.new).parse(input)
286
+ end
287
+ end
288
+ end
289
+
290
+ class Symbol
291
+ include Parsable
292
+ def initialize(literal)
293
+ @parser = lambda do |input|
294
+ Token.new(StringParser.new(literal)).parse(input)
295
+ end
296
+ end
297
+ end
298
+
299
+ end
data/tests/test_parser.rb CHANGED
@@ -16,6 +16,11 @@ class YaparcTest < Test::Unit::TestCase
16
16
  def test_succeed_parse
17
17
  parser = ::Yaparc::SucceedParser.new(1)
18
18
  assert_equal [[1, "abs"]], parser.parse("abs")
19
+ assert_equal [[1, "abs"]], parser.tree
20
+ result = parser.parse("abs") do |result|
21
+ result[0][0]
22
+ end
23
+ assert_equal 1, result
19
24
  end
20
25
 
21
26
  def test_fail_parse
@@ -116,6 +121,16 @@ class YaparcTest < Test::Unit::TestCase
116
121
  assert_equal [], result
117
122
  end
118
123
 
124
+ def test_regex_parse
125
+ parser = RegexParser.new(/[a-z]/)
126
+ result = parser.parse("abcdef")
127
+ assert_equal [["a", "bcdef"]], result
128
+
129
+ parser = RegexParser.new(/[0-9]+/)
130
+ result = parser.parse("1234ab")
131
+ assert_equal [["1234", "ab"]], result
132
+ end
133
+
119
134
  def test_many_parse
120
135
  is_digit = lambda {|i| i > '0' and i < '9'}
121
136
 
@@ -127,6 +142,15 @@ class YaparcTest < Test::Unit::TestCase
127
142
  assert_equal [[[], "abcdef"]], result
128
143
  end
129
144
 
145
+ def test_zero_one_parse
146
+ parser = ZeroOneParser.new(StringParser.new("abc"))
147
+ result = parser.parse("abc ")
148
+ assert_equal [["abc", " "]], result
149
+ parser = ZeroOneParser.new(StringParser.new("abc"))
150
+ result = parser.parse("123")
151
+ assert_equal [[[], "123"]], result
152
+ end
153
+
130
154
  def test_ident
131
155
  parser = Ident.new
132
156
  result = parser.parse("abc def")
@@ -0,0 +1,38 @@
1
+ require 'lib/parser_cps.rb'
2
+ require 'test/unit'
3
+ require 'pp'
4
+
5
+ class YaparcTest < Test::Unit::TestCase
6
+ include ::Yaparc
7
+
8
+
9
+ def setup
10
+ @stop = Continuation::StopCont.new
11
+ end
12
+
13
+
14
+ def test_succeed_parse
15
+ parser = ::Yaparc::Parser::SucceedParser.new(1)
16
+ assert_equal [[1, "abs"]], parser.parse("abs", @stop)
17
+ # assert_equal [[1, "abs"]], parser.tree
18
+ # result = parser.parse("abs") do |result|
19
+ # result[0][0]
20
+ # end
21
+ # assert_equal 1, result
22
+ end
23
+
24
+ # def test_fail_parse
25
+ # parser = ::Yaparc::Parser::FailParser.new(@stop)
26
+ # result = parser.parse("abc")
27
+ # assert_equal [], result
28
+ # end
29
+
30
+ # def test_item_parse
31
+ # parser = ::Yaparc::Parser::ItemParser.new(@stop)
32
+ # result = parser.parse("")
33
+ # assert_equal [], result
34
+ # result = parser.parse("abc")
35
+ # assert_equal [["a", "bc"]], result
36
+ # end
37
+ end
38
+
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.3
3
3
  specification_version: 1
4
4
  name: yaparc
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.1
7
- date: 2007-12-06 00:00:00 +09:00
6
+ version: 0.0.3
7
+ date: 2007-12-14 00:00:00 +09:00
8
8
  summary: Yet Another Combinator Parser Library
9
9
  require_paths:
10
10
  - lib
@@ -12,7 +12,7 @@ email: akimichi_tatsukawa@nifty.com
12
12
  homepage: http://rubyforge.org/projects/yaparc/
13
13
  rubyforge_project:
14
14
  description:
15
- autorequire: parser
15
+ autorequire: yaparc
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
@@ -29,13 +29,17 @@ post_install_message:
29
29
  authors:
30
30
  - Akimichi Tatsukawa
31
31
  files:
32
- - tests/test_calc.rb
32
+ - tests/test_parser_cps.rb
33
33
  - tests/test_parser.rb
34
+ - tests/test_calc.rb
35
+ - lib/parser_cps.rb
36
+ - lib/yaparc.rb
34
37
  - lib/parser.rb
35
38
  - README
36
39
  test_files:
37
- - tests/test_calc.rb
40
+ - tests/test_parser_cps.rb
38
41
  - tests/test_parser.rb
42
+ - tests/test_calc.rb
39
43
  rdoc_options: []
40
44
 
41
45
  extra_rdoc_files: