yaparc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +16 -0
  2. data/lib/parser.rb +271 -0
  3. data/tests/test_calc.rb +129 -0
  4. data/tests/test_parser.rb +167 -0
  5. metadata +50 -0
data/README ADDED
@@ -0,0 +1,16 @@
1
+ = Synopsis
2
+
3
+ This is a yet another simple combinator parser library in ruby.
4
+
5
+ = Requirements
6
+
7
+ * Ruby (http://www.ruby-lang.org/)
8
+
9
+ = Install
10
+
11
+ $ gem install yaparc
12
+
13
+ = Usage
14
+
15
+ Please look at unit test files.
16
+
data/lib/parser.rb ADDED
@@ -0,0 +1,271 @@
1
+
2
+ module Yaparc
3
+ module Parsable
4
+ include Yaparc
5
+
6
+ IS_LOWER = lambda {|c| c >= 'a' and c <= 'z'}
7
+ IS_ALPHANUM = lambda {|c| (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9')}
8
+ IS_DIGIT = lambda {|i| i > '0' and i < '9'}
9
+ IS_SPACE = lambda {|i| i == ' '}
10
+
11
+ def self.included(mod)
12
+ mod.extend ClassMethods
13
+ end
14
+
15
+
16
+ def parse(input)
17
+ @parser.call(input)
18
+ end
19
+
20
+ def eval
21
+ tree = parse(input)
22
+ end
23
+
24
+ def define_parser
25
+ raise
26
+ end
27
+
28
+ module ClassMethods
29
+ def included(mod)
30
+ end
31
+
32
+ # def self.initialize
33
+ # @parser = @@parser
34
+ # end
35
+
36
+ def define_parser(&block)
37
+ @@parser = lambda do |input|
38
+ parser = yield
39
+ parser.parse(input)
40
+ end
41
+ end
42
+ end
43
+ end # of Parsable
44
+
45
+ class SucceedParser
46
+ include Parsable
47
+ def initialize(value)
48
+ @parser = lambda {|input| [[value, input]]}
49
+ end
50
+ end
51
+
52
+ class FailParser
53
+ include Parsable
54
+ def initialize
55
+ @parser = lambda {|input| []}
56
+ end
57
+ end
58
+
59
+ class ItemParser
60
+ include Parsable
61
+ def initialize
62
+ @parser = lambda do |input|
63
+ if input.nil? or input.empty?
64
+ []
65
+ else
66
+ [[input[0..0],input[1..input.length]]]
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ class SatisfyParser
73
+ include Parsable
74
+ def initialize(predicate)
75
+ @parser = lambda do |input|
76
+ item = ItemParser.new.parse(input)
77
+ if item == []
78
+ FailParser.new.parse(input)
79
+ else
80
+ if predicate.call(item[0][0])
81
+ SucceedParser.new(item[0][0]).parse(item[0][1])
82
+ else
83
+ FailParser.new.parse(input)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ class SeqParser
91
+ include Parsable
92
+ def initialize(*parsers, &block)
93
+ @parser = lambda do |input|
94
+ args = []
95
+ remains = parsers.inject(input) do |accumulator, parser|
96
+ result = parser.parse(accumulator)
97
+ unless result == []
98
+ args << result[0][0]
99
+ result[0][1]
100
+ else
101
+ break []
102
+ end
103
+ end
104
+ unless remains == []
105
+ retval = yield(*args)
106
+ [[retval, remains]]
107
+ else
108
+ []
109
+ end
110
+ end
111
+ end # of initialize
112
+ end # of SeqParser
113
+
114
+ class AltParser
115
+ include Parsable
116
+ def initialize(*parsers)
117
+ @parser = lambda do |input|
118
+ parsers.inject([]) do |accum, parser|
119
+ result = parser.parse(input)
120
+ if result == []
121
+ result
122
+ else
123
+ break [result[0]]
124
+ end
125
+ end
126
+ end
127
+ end # of initialize
128
+ end
129
+
130
+ class CharParser
131
+ include Parsable
132
+ def initialize(char)
133
+ equal_char = lambda {|i| i == char}
134
+ @parser = lambda do |input|
135
+ SatisfyParser.new(equal_char).parse(input)
136
+ end
137
+ end
138
+ end
139
+
140
+ class StringParser
141
+ include Parsable
142
+ def initialize(string)
143
+ @parser = lambda do |input|
144
+ result = ItemParser.new.parse(string)
145
+ if result == []
146
+ SucceedParser.new(result).parse(input)
147
+ # FailParser.new.parse(input)
148
+ else
149
+ SeqParser.new(
150
+ CharParser.new(result[0][0]),
151
+ StringParser.new(result[0][1]),
152
+ SucceedParser.new(result[0][0] + result[0][1])
153
+ ) do |char_result, string_result, succeed_result|
154
+ succeed_result
155
+ end.parse(input)
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ class ManyParser
162
+ include Parsable
163
+ def initialize(predicate)
164
+ @parser = lambda do |input|
165
+ AltParser.new(ManyOneParser.new(predicate), SucceedParser.new([])).parse(input)
166
+ end
167
+ end
168
+ end
169
+
170
+ class ManyOneParser
171
+ include Parsable
172
+ def initialize(predicate)
173
+ @parser = lambda do |input|
174
+ SeqParser.new(
175
+ SatisfyParser.new(predicate),
176
+ ManyParser.new(predicate)
177
+ ) do |v, vs|
178
+ if vs == []
179
+ v
180
+ else
181
+ v + vs.to_s
182
+ end
183
+ end.parse(input)
184
+ end
185
+ end
186
+ end
187
+
188
+
189
+ class Ident
190
+ include Parsable
191
+ def initialize
192
+ @parser = lambda do |input|
193
+ SeqParser.new(
194
+ SatisfyParser.new(IS_LOWER),
195
+ ManyParser.new(IS_ALPHANUM)
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 Nat
208
+ include Parsable
209
+ def initialize
210
+ @parser = lambda do |input|
211
+ SeqParser.new(ManyOneParser.new(IS_DIGIT)) do |vs|
212
+ if vs == []
213
+ vs
214
+ else
215
+ vs.to_i
216
+ end
217
+ end.parse(input)
218
+ end
219
+ end
220
+ end
221
+
222
+ class Space
223
+ include Parsable
224
+ def initialize
225
+ @parser = lambda do |input|
226
+ SeqParser.new(ManyParser.new(IS_SPACE)) do |vs|
227
+ []
228
+ end.parse(input)
229
+ end
230
+ end
231
+ end
232
+
233
+ class Token
234
+ include Parsable
235
+ def initialize(parser)
236
+ @parser = lambda do |input|
237
+ SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
238
+ vs
239
+ end.parse(input)
240
+ end
241
+ end
242
+ end
243
+
244
+ class Identifier
245
+ include Parsable
246
+ def initialize
247
+ @parser = lambda do |input|
248
+ Token.new(Ident.new).parse(input)
249
+ end
250
+ end
251
+ end
252
+
253
+ class Natural
254
+ include Parsable
255
+ def initialize
256
+ @parser = lambda do |input|
257
+ Token.new(Nat.new).parse(input)
258
+ end
259
+ end
260
+ end
261
+
262
+ class Symbol
263
+ include Parsable
264
+ def initialize(literal)
265
+ @parser = lambda do |input|
266
+ Token.new(StringParser.new(literal)).parse(input)
267
+ end
268
+ end
269
+ end
270
+
271
+ end
@@ -0,0 +1,129 @@
1
+ require 'lib/parser.rb'
2
+ require 'test/unit'
3
+ require 'pp'
4
+
5
+
6
+
7
+ class Expr
8
+ include Yaparc::Parsable
9
+
10
+ # define_parser do
11
+ # AltParser.new(
12
+ # SeqParser.new(Term.new,
13
+ # Symbol.new('+'),
14
+ # Expr.new) do |term, _, expr|
15
+ # ['+', term,expr]
16
+ # end,
17
+ # Term.new
18
+ # )
19
+ # end
20
+
21
+ def initialize
22
+ @parser = lambda do |input|
23
+ AltParser.new(
24
+ SeqParser.new(Term.new,
25
+ Symbol.new('+'),
26
+ Expr.new) do |term, _, expr|
27
+ ['+', term,expr]
28
+ end,
29
+ Term.new
30
+ ).parse(input)
31
+ end
32
+ end
33
+
34
+ def eval(input)
35
+ result = parse(input)
36
+ tree = result[0][0]
37
+ # p tree
38
+ eval_tree(tree)
39
+ end
40
+
41
+ def eval_tree(tree)
42
+ case tree
43
+ when Array
44
+ case tree[0]
45
+ when '+'
46
+ eval_tree(tree[1]) + eval_tree(tree[2])
47
+ when '-'
48
+ eval_tree(tree[1]) - eval_tree(tree[2])
49
+ when '*'
50
+ eval_tree(tree[1]) * eval_tree(tree[2])
51
+ when '/'
52
+ eval_tree(tree[1]) / eval_tree(tree[2])
53
+ end
54
+ else
55
+ tree
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ class Term
62
+ include Yaparc::Parsable
63
+
64
+ # define_parser do
65
+ # AltParser.new(
66
+ # SeqParser.new(Factor.new,
67
+ # Symbol.new('*'),
68
+ # Term.new) do |factor, _, term|
69
+ # ['*', factor,term]
70
+ # end,
71
+ # Factor.new
72
+ # )
73
+ # end
74
+
75
+ def initialize
76
+ @parser = lambda do |input|
77
+ AltParser.new(
78
+ SeqParser.new(Factor.new,
79
+ Symbol.new('*'),
80
+ Term.new) do |factor, _, term|
81
+ ['*', factor,term]
82
+ end,
83
+ Factor.new
84
+ ).parse(input)
85
+ end
86
+ end
87
+ end
88
+
89
+ class Factor
90
+ include Yaparc::Parsable
91
+
92
+ # define_parser do
93
+ # AltParser.new(
94
+ # SeqParser.new(Symbol.new('('),
95
+ # Expr.new,
96
+ # Symbol.new(')')) do |_,expr, _|
97
+ # expr
98
+ # end,
99
+ # Natural.new
100
+ # )
101
+ # end
102
+
103
+ def initialize
104
+ @parser = lambda do |input|
105
+ AltParser.new(
106
+ SeqParser.new(Symbol.new('('),
107
+ Expr.new,
108
+ Symbol.new(')')) do |_,expr, _|
109
+ expr
110
+ end,
111
+ Natural.new
112
+ ).parse(input)
113
+ end
114
+ end
115
+ end
116
+
117
+ class YaparcCalcTest < Test::Unit::TestCase
118
+ include ::Yaparc
119
+
120
+ def setup
121
+ end
122
+ def test_expr
123
+ parser = Expr.new
124
+ result = parser.parse("1 + 2 ")
125
+ assert_equal [[["+", 1, 2], ""]], result
126
+ assert_equal 3, parser.eval("1 + 2 ")
127
+ assert_equal 9, parser.eval("(1 + 2) * 3 ")
128
+ end
129
+ end
@@ -0,0 +1,167 @@
1
+ require 'lib/parser.rb'
2
+ require 'test/unit'
3
+ require 'pp'
4
+
5
+ class YaparcTest < Test::Unit::TestCase
6
+ include ::Yaparc
7
+
8
+
9
+ def setup
10
+
11
+ end
12
+
13
+ def teardown
14
+ end
15
+
16
+ def test_succeed_parse
17
+ parser = ::Yaparc::SucceedParser.new(1)
18
+ assert_equal [[1, "abs"]], parser.parse("abs")
19
+ end
20
+
21
+ def test_fail_parse
22
+ parser = ::Yaparc::FailParser.new
23
+ result = parser.parse("abc")
24
+ assert_equal [], result
25
+ end
26
+
27
+ def test_item_parse
28
+ parser = ::Yaparc::ItemParser.new
29
+ result = parser.parse("")
30
+ assert_equal [], result
31
+ result = parser.parse("abc")
32
+ assert_equal [["a", "bc"]], result
33
+ end
34
+
35
+ def test_seq_parse
36
+ parser = SeqParser.new(ItemParser.new, ItemParser.new) do |item1, item2|
37
+ [item1, item2]
38
+ end
39
+ result = parser.parse("abcdef")
40
+ assert_equal [[["a", "b"], "cdef"]], result
41
+
42
+ parser = SeqParser.new(ItemParser.new, ItemParser.new, ItemParser.new) do |item1, item2, item3|
43
+ [item1, item3]
44
+ end
45
+ result = parser.parse("ABCDEF")
46
+ assert_equal [[["A", "C"], "DEF"]], result
47
+
48
+ parser = SeqParser.new(ItemParser.new, ItemParser.new, ItemParser.new) do |item1, item2, item3|
49
+ [item2]
50
+ end
51
+ result = parser.parse("ABCDEF")
52
+ assert_equal [[["B"], "DEF"]], result
53
+ end
54
+
55
+ def test_alt_parse
56
+ parser = AltParser.new(ItemParser.new, SucceedParser.new('d'))
57
+ result = parser.parse("abc")
58
+ assert_equal [["a", "bc"]], result
59
+
60
+ parser = AltParser.new(FailParser.new, SucceedParser.new('d'))
61
+ result = parser.parse("abc")
62
+ assert_equal [["d", "abc"]], result
63
+
64
+ parser = AltParser.new(FailParser.new, FailParser.new)
65
+ result = parser.parse("abc")
66
+ assert_equal [], result
67
+ end
68
+
69
+ def test_satisfy_parse
70
+ is_integer = lambda do |i|
71
+ begin
72
+ Integer(i)
73
+ true
74
+ rescue
75
+ false
76
+ end
77
+ end
78
+ parser = SatisfyParser.new(is_integer)
79
+ result = parser.parse("123")
80
+ assert_equal [["1", "23"]], result
81
+
82
+ parser = SatisfyParser.new(is_integer)
83
+ result = parser.parse("abc")
84
+ assert_equal [], result
85
+
86
+ is_char = lambda do |i|
87
+ begin
88
+ String(i)
89
+ true
90
+ rescue
91
+ false
92
+ end
93
+ end
94
+ parser = SatisfyParser.new(is_char)
95
+ result = parser.parse("abc")
96
+ assert_equal [["a", "bc"]], result
97
+ end
98
+
99
+ def test_char_parse
100
+ parser = CharParser.new("a")
101
+ result = parser.parse("abc")
102
+ assert_equal [["a", "bc"]], result
103
+
104
+ parser = CharParser.new("a")
105
+ result = parser.parse("123")
106
+ assert_equal [], result
107
+ end
108
+
109
+ def test_string_parse
110
+ parser = StringParser.new("abc")
111
+ result = parser.parse("abcdef")
112
+ assert_equal [["abc", "def"]], result
113
+
114
+ parser = StringParser.new("abc")
115
+ result = parser.parse("ab1234")
116
+ assert_equal [], result
117
+ end
118
+
119
+ def test_many_parse
120
+ is_digit = lambda {|i| i > '0' and i < '9'}
121
+
122
+ parser = ManyParser.new(is_digit)
123
+ result = parser.parse("123abc")
124
+ assert_equal [["123", "abc"]], result
125
+
126
+ result = parser.parse("abcdef")
127
+ assert_equal [[[], "abcdef"]], result
128
+ end
129
+
130
+ def test_ident
131
+ parser = Ident.new
132
+ result = parser.parse("abc def")
133
+ assert_equal [["abc", " def"]], result
134
+ end
135
+
136
+ def test_nat
137
+ parser = Nat.new
138
+ result = parser.parse("123 abc")
139
+ assert_equal [[123, " abc"]], result
140
+ end
141
+
142
+ def test_space
143
+ parser = Space.new
144
+ result = parser.parse(" abc")
145
+ assert_equal [[[], "abc"]], result
146
+ end
147
+
148
+ def test_identifier
149
+ parser = Identifier.new
150
+ result = parser.parse(" abc ")
151
+ assert_equal [["abc", ""]], result
152
+ end
153
+
154
+ def test_natural
155
+ parser = Natural.new
156
+ result = parser.parse(" 1234 ")
157
+ assert_equal [[1234, ""]], result
158
+ end
159
+
160
+ def test_symbol
161
+ parser = Symbol.new('%')
162
+ result = parser.parse(" % ")
163
+ assert_equal [["%", ""]], result
164
+ end
165
+
166
+ end
167
+
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.3
3
+ specification_version: 1
4
+ name: yaparc
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-12-06 00:00:00 +09:00
8
+ summary: Yet Another Combinator Parser Library
9
+ require_paths:
10
+ - lib
11
+ email: akimichi_tatsukawa@nifty.com
12
+ homepage: http://rubyforge.org/projects/yaparc/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: parser
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Akimichi Tatsukawa
31
+ files:
32
+ - tests/test_calc.rb
33
+ - tests/test_parser.rb
34
+ - lib/parser.rb
35
+ - README
36
+ test_files:
37
+ - tests/test_calc.rb
38
+ - tests/test_parser.rb
39
+ rdoc_options: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ requirements: []
48
+
49
+ dependencies: []
50
+