yaparc 0.0.1 → 0.0.3

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