yaparc 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -15,7 +15,7 @@ There are several implementations of parser combinator in ruby. This is a yet an
15
15
 
16
16
  In combinator parser, each parser is construct as a function taking input string as arguments. Larger parsers are built from smaller parsers. Although combinators are higher-order functions in ordinary functional languages, they are constructed as classes in yaparc, because Ruby has more object-oriented than functional property.
17
17
 
18
- All parsers has 'parse' method, each of which takes input string as its arguments except SatisfyParser. All of them return an array of array as their result, with the empty array [] denoting faiilure, and a singleton array [[v, xs]] indicating success, with value v and uncosumed input xs as String instance.
18
+ All parsers has 'parse' method, each of which takes input string as its arguments except SatisfyParser. Every parser returns either Result::OK or Result::Fail as their result of parsing. An instance of Result::Fail denotes faiilure, and instance of Result::OK indicates success.
19
19
 
20
20
  == Primitive Parsers
21
21
 
@@ -29,25 +29,25 @@ All parsers has 'parse' method, each of which takes input string as its argument
29
29
  The parser SucceedParser always succeeds with the result value, without consuming any of the input string.
30
30
  In the following example, SucceedParser#parse takes an input string "blah, blah, blah" and returns the singleton array [[1, "blah, blah, blah"]].
31
31
 
32
- parser = SucceedParser.new(1)
32
+ parser = Yaparc::SucceedParser.new(1)
33
33
  parser.parse("blah, blah, blah")
34
- => [[1, "blah, blah, blah"]]
34
+ => #<Yaparc::Result::OK:0xb7aaaf5c @input="blah, blah, blah", @value=1>
35
35
 
36
36
  === FailParser class
37
37
 
38
38
  The parser FailParser always fails, regardless of the contents of the input string.
39
39
 
40
- parser = FailParser.new
40
+ parser = Yaparc::FailParser.new
41
41
  parser.parse("abc")
42
- => []
42
+ => #<Yaparc::Result::Fail:0xb7aa56b0 @value=nil>
43
43
 
44
44
  === ItemParser class
45
45
 
46
46
  The parser ItemParser fails if the input string is empty, and succeeds with the first character as the result value otherwise.
47
47
 
48
- parser = ::Yaparc::ItemParser.new
48
+ parser = Yaparc::ItemParser.new
49
49
  parser.parse("abc")
50
- => [["a", "bc"]]
50
+ => #<Yaparc::Result::OK:0xb7a9fdb4 @input="bc", @value="a">
51
51
 
52
52
  === SatisfyParser class
53
53
 
@@ -61,9 +61,9 @@ The parser SatisfyParser recognizes a single input via predicate which determine
61
61
  false
62
62
  end
63
63
  end
64
- parser = SatisfyParser.new(is_integer)
64
+ parser = Yaparc::SatisfyParser.new(is_integer)
65
65
  parser.parse("123")
66
- => [["1", "23"]]
66
+ => #<Yaparc::Result::OK:0xb7a8f284 @input="23", @value="1">
67
67
 
68
68
 
69
69
  == Combining Parsers
@@ -81,15 +81,15 @@ The SeqParser corresponds to sequencing in BNF. The following parser recognizes
81
81
 
82
82
  parser = SeqParser.new(Symbol.new('+'), Natural.new)
83
83
  parser.parse("+321")
84
- => [[321,""]]
84
+ => #<Yaparc::Result::OK:0xb7a81ae4 @input="", @value=321>
85
85
 
86
86
  if a block given to SeqParser, it analyses input string to construct its logical structure.
87
87
 
88
- parser = SeqParser.new(Symbol.new('+'), Natural.new) do | plus, nat|
88
+ parser = Yaparc::SeqParser.new(Yaparc::Symbol.new('+'), Yaparc::Natural.new) do | plus, nat|
89
89
  nat
90
90
  end
91
91
  parser.parse("+1234")
92
- => [[1234,""]]
92
+ => #<Yaparc::Result::OK:0xb7a70a00 @input="", @value=1234>
93
93
 
94
94
  It produces a parse tree which expounds the semantic structure of the program.
95
95
 
@@ -98,26 +98,25 @@ It produces a parse tree which expounds the semantic structure of the program.
98
98
  The parser AltParser class is an alternation parser, which returns the result of the first parser to succeed, and failure if neither does.
99
99
 
100
100
 
101
- parser = AltParser.new(
102
- SeqParser.new(Symbol.new('+'), Natural.new) do | _, nat|
101
+ parser = Yaparc::AltParser.new(
102
+ Yaparc::SeqParser.new(Yaparc::Symbol.new('+'), Yaparc::Natural.new) do | _, nat|
103
103
  nat
104
104
  end,
105
- Natural.new
105
+ Yaparc::Natural.new
106
106
  )
107
107
  parser.parse("1234")
108
- => [[1234,""]]
108
+ => #<Yaparc::Result::OK:0xb7a5a610 @input="", @value=1234>
109
109
  parser.parse("-1234")
110
- => []
110
+ => #<Yaparc::Result::Fail:0xb7a57ba4 @value=nil>
111
111
 
112
112
 
113
113
  === ManyParser
114
114
 
115
115
  In ManyParser, zero or more applications of parser are admissible.
116
116
 
117
- parser = ManyParser.new(SatisfyParser.new(lambda {|i| i > '0' and i < '9'}))
117
+ parser = Yaparc::ManyParser.new(Yaparc::SatisfyParser.new(lambda {|i| i > '0' and i < '9'}))
118
118
  parser.parse("123abc")
119
- => [["123", "abc"]]
120
-
119
+ => #<Yaparc::Result::OK:0xb7a49dc4 @input="abc", @value="123">
121
120
 
122
121
  === ManyOneParser
123
122
 
@@ -145,7 +144,7 @@ There are two ways to construct parser. One is to inherit from Yaparc::ParserBas
145
144
  class StringMatch < Yaparc::ParserBase
146
145
 
147
146
  def initialize(literal)
148
- @parser = Token.new(StringParser.new(literal))
147
+ @parser = Yaparc::Token.new(Yaparc::StringParser.new(literal))
149
148
  end
150
149
  end
151
150
 
@@ -154,7 +153,7 @@ The other is to inherit from Yaparc::AbstractParser class.
154
153
  class Identifier < Yaparc::AbstractParser
155
154
  def initialize
156
155
  @parser = lambda do
157
- Token.new(Ident.new)
156
+ Yaparc::Token.new(Yaparc::Ident.new)
158
157
  end
159
158
  end
160
159
  end
data/lib/yaparc.rb CHANGED
@@ -1,10 +1,3 @@
1
- def assert_at(file,line, message = "")
2
- unless yield
3
- raise "Assertion failed !: #{file}, #{line}: #{message}"
4
- end
5
- end
6
-
7
-
8
1
  module Yaparc
9
2
  module Result
10
3
  class Base
@@ -12,7 +5,7 @@ module Yaparc
12
5
  def initialize(options = {})
13
6
  @message = options[:message] if options[:message]
14
7
  @input = options[:input] if options[:input]
15
- @value = options[:value] if options[:value]
8
+ @value = options[:value]
16
9
  end
17
10
  end
18
11
 
@@ -38,16 +31,35 @@ module Yaparc
38
31
  mod.extend ClassMethods
39
32
  end
40
33
 
41
-
42
34
  def parse(input, &block)
43
35
  result = @parser.call(input)
44
- if block_given?
45
- @tree = yield result.value
36
+
37
+ if result.respond_to? :parse
38
+ result = result.parse(input)
46
39
  else
47
- @tree = result.value
40
+ if block_given?
41
+ # @tree = yield result.value
42
+ result.value = yield result.value
43
+ @tree = result
44
+ else
45
+ @tree = result.value
46
+ # @tree = result.parse(input)
47
+ end
48
+ result
48
49
  end
49
- result
50
50
  end
51
+ # def parse(input, &block)
52
+ # result = @parser.call(input)
53
+ # if block_given?
54
+ # # @tree = yield result.value
55
+ # result.value = yield result.value
56
+ # @tree = result
57
+ # else
58
+ # # @tree = result.value
59
+ # @tree = result.parse(input)
60
+ # end
61
+ # result
62
+ # end
51
63
 
52
64
  def eval
53
65
  tree = parse(input)
@@ -63,24 +75,6 @@ module Yaparc
63
75
  yield
64
76
  end
65
77
  end
66
-
67
- # def define_parser(&block)
68
- # @@parser = lambda do |input|
69
- # parser = yield
70
- # parser.parse(input)
71
- # end
72
- # end
73
-
74
- # def cparse(input, &block)
75
- # tree = @@cparser.call.parse(input)
76
- # if block_given?
77
- # yield tree
78
- # else
79
- # tree
80
- # end
81
- # end
82
- # module_function :cparse
83
-
84
78
  end
85
79
  end # of Module Parsable
86
80
 
@@ -91,7 +85,6 @@ module Yaparc
91
85
  attr_reader :remaining
92
86
  def initialize(value, remaining = nil)
93
87
  @parser = lambda do |input|
94
- # [[value, input]]
95
88
  Result::OK.new(:value => value, :input => input)
96
89
  end
97
90
  @remaining = remaining
@@ -115,7 +108,6 @@ module Yaparc
115
108
  if input.nil? or input.empty?
116
109
  Result::Fail.new
117
110
  else
118
- # [[input[0..0],input[1..input.length]]]
119
111
  Result::OK.new(:value => input[0..0],:input => input[1..input.length])
120
112
  end
121
113
  end
@@ -125,7 +117,7 @@ module Yaparc
125
117
  class SatisfyParser
126
118
  include Parsable
127
119
  def initialize(predicate)
128
- assert_at(__FILE__,__LINE__){predicate.instance_of?(Proc)}
120
+ raise unless predicate.instance_of?(Proc)
129
121
 
130
122
  @parser = lambda do |input|
131
123
  case result = ItemParser.new.parse(input)
@@ -153,8 +145,6 @@ module Yaparc
153
145
  end
154
146
  end
155
147
 
156
-
157
-
158
148
  class SeqParser
159
149
  include Parsable
160
150
  def initialize(*parsers, &block)
@@ -167,6 +157,7 @@ module Yaparc
167
157
  break Result::Fail.new
168
158
  else
169
159
  args << result.value
160
+ # args << result.parse(input)
170
161
  result
171
162
  end
172
163
  end
@@ -195,7 +186,6 @@ module Yaparc
195
186
  @parser = lambda do |input|
196
187
  initial_result = Result::OK.new(:input => input)
197
188
  final_result = Result::Fail.new
198
- # final_result = Error.new
199
189
  parsers.each do |parser|
200
190
  case result = parser.parse(initial_result.input)
201
191
  when Result::Fail
@@ -275,12 +265,13 @@ module Yaparc
275
265
  include Parsable
276
266
  def initialize(parser, identity = "")
277
267
  @parser = lambda do |input|
278
- AltParser.new(ManyOneParser.new(parser, identity), SucceedParser.new(identity)).parse(input)
268
+ # AltParser.new(ManyOneParser.new(parser, identity), SucceedParser.new(identity)).parse(input)
269
+ AltParser.new(ManyOneParser.new(parser, identity), SucceedParser.new(identity))
279
270
  end
280
271
  end
281
272
 
282
273
  def parse(input)
283
- @parser.call(input)
274
+ @parser.call(input).parse(input)
284
275
  end
285
276
  end
286
277
 
@@ -319,7 +310,6 @@ module Yaparc
319
310
  end
320
311
  end
321
312
 
322
-
323
313
  class ZeroOneParser < ParserBase
324
314
  def initialize(parser)
325
315
  @parser = AltParser.new(parser, SucceedParser.new([])) # Is it OK?
@@ -361,7 +351,6 @@ module Yaparc
361
351
  class Token < ParserBase
362
352
 
363
353
  def initialize(parser, prefix = Space.new, postfix = Space.new)
364
- # @parser = SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
365
354
  @parser = SeqParser.new(prefix, parser, postfix) do |_, vs, _|
366
355
  vs
367
356
  end
data/tests/test_calc.rb CHANGED
@@ -1,126 +1,90 @@
1
1
  require 'lib/yaparc.rb'
2
2
  require 'test/unit'
3
- require 'pp'
4
3
 
4
+ module Calc
5
5
 
6
- class Expr < Yaparc::AbstractParser
6
+ class Expr < Yaparc::AbstractParser
7
7
 
8
- def initialize
9
- @parser = lambda do
10
- Yaparc::AltParser.new(
11
- Yaparc::SeqParser.new(Term.new,
12
- Yaparc::Symbol.new('+'),
13
- Expr.new) do |term, _, expr|
14
- ['+', term,expr]
15
- end,
16
- Term.new
17
- )
8
+ def initialize
9
+ @parser = lambda do
10
+ Yaparc::AltParser.new(
11
+ Yaparc::SeqParser.new(Term.new,
12
+ Yaparc::Symbol.new('+'),
13
+ Expr.new) do |term, _, expr|
14
+ ['+', term,expr]
15
+ end,
16
+ Term.new
17
+ )
18
+ end
18
19
  end
19
- end
20
20
 
21
- # define_parser do
22
- # Yaparc::AltParser.new(
23
- # Yaparc::SeqParser.new(Term.new,
24
- # Yaparc::Symbol.new('+'),
25
- # Expr.new) do |term, _, expr|
26
- # ['+', term,expr]
27
- # end,
28
- # Term.new
29
- # )
30
- # end
31
-
32
-
33
- def evaluate(input)
34
- result = parse(input)
35
- tree = result.value
36
- eval_tree(tree)
37
- end
21
+ def evaluate(input)
22
+ result = parse(input)
23
+ tree = result.value
24
+ eval_tree(tree)
25
+ end
38
26
 
39
- def eval_tree(tree)
40
- case tree
41
- when Array
42
- case tree[0]
43
- when '+'
44
- eval_tree(tree[1]) + eval_tree(tree[2])
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])
27
+ def eval_tree(tree)
28
+ case tree
29
+ when Array
30
+ case tree[0]
31
+ when '+'
32
+ eval_tree(tree[1]) + eval_tree(tree[2])
33
+ when '-'
34
+ eval_tree(tree[1]) - eval_tree(tree[2])
35
+ when '*'
36
+ eval_tree(tree[1]) * eval_tree(tree[2])
37
+ when '/'
38
+ eval_tree(tree[1]) / eval_tree(tree[2])
39
+ end
40
+ else
41
+ tree
51
42
  end
52
- else
53
- tree
54
43
  end
55
44
  end
56
- end
57
45
 
58
- class Term < Yaparc::AbstractParser
59
-
60
- def initialize
61
- @parser = lambda do
62
- Yaparc::AltParser.new(
63
- Yaparc::SeqParser.new(Factor.new,
64
- Yaparc::Symbol.new('*'),
65
- Term.new) do |factor, _, term|
66
- ['*', factor,term]
67
- end,
68
- Factor.new
69
- )
46
+ class Term < Yaparc::AbstractParser
47
+
48
+ def initialize
49
+ @parser = lambda do
50
+ Yaparc::AltParser.new(
51
+ Yaparc::SeqParser.new(Factor.new,
52
+ Yaparc::Symbol.new('*'),
53
+ Term.new) do |factor, _, term|
54
+ ['*', factor,term]
55
+ end,
56
+ Factor.new
57
+ )
58
+ end
70
59
  end
71
60
  end
72
61
 
73
- # define_parser do
74
- # Yaparc::AltParser.new(
75
- # Yaparc::SeqParser.new(Factor.new,
76
- # Yaparc::Symbol.new('*'),
77
- # Term.new) do |factor, _, term|
78
- # ['*', factor,term]
79
- # end,
80
- # Factor.new
81
- # )
82
- # end
83
- end
84
-
85
- class Factor < Yaparc::AbstractParser
86
-
87
-
88
- def initialize
89
- @parser = lambda do
90
- Yaparc::AltParser.new(
91
- Yaparc::SeqParser.new(
92
- Yaparc::Symbol.new('('),
93
- Expr.new,
94
- Yaparc::Symbol.new(')')
95
- ) do |_,expr, _|
96
- expr
97
- end,
98
- Yaparc::Natural.new
99
- )
62
+ class Factor < Yaparc::AbstractParser
63
+
64
+
65
+ def initialize
66
+ @parser = lambda do
67
+ Yaparc::AltParser.new(
68
+ Yaparc::SeqParser.new(
69
+ Yaparc::Symbol.new('('),
70
+ Expr.new,
71
+ Yaparc::Symbol.new(')')
72
+ ) do |_,expr, _|
73
+ expr
74
+ end,
75
+ Yaparc::Natural.new
76
+ )
77
+ end
100
78
  end
101
79
  end
102
-
103
- # define_parser do
104
- # AltParser.new(
105
- # Yaparc::SeqParser.new(
106
- # Yaparc::Symbol.new('('),
107
- # Expr.new,
108
- # Yaparc::Symbol.new(')')
109
- # ) do |_,expr, _|
110
- # expr
111
- # end,
112
- # Natural.new
113
- # )
114
- # end
115
- end
116
-
80
+ end # of Calc
117
81
 
118
82
  class YaparcCalcTest < Test::Unit::TestCase
119
83
  include ::Yaparc
120
84
 
121
85
  def setup
122
- @expr = Expr.new
123
- @factor = Factor.new
86
+ @expr = Calc::Expr.new
87
+ @factor = Calc::Factor.new
124
88
  end
125
89
 
126
90
  def test_expr
@@ -145,17 +109,4 @@ class YaparcCalcTest < Test::Unit::TestCase
145
109
  assert_equal 312, result.value
146
110
  assert_equal "", result.input
147
111
  end
148
-
149
- # def test_cexpr
150
- # result = @expr.cparse("1 + 2 ")
151
- # assert_equal [[["+", 1, 2], ""]], result
152
- # end
153
-
154
- # def test_expr_define_parser
155
- # parser = Expr.new
156
- # result = Expr.parse("1 + 2 ")
157
- # assert_equal [[["+", 1, 2], ""]], result
158
- # # assert_equal 3, parser.evaluate("1 + 2 ")
159
- # # assert_equal 9, parser.evaluate("(1 + 2) * 3 ")
160
- # end
161
112
  end
data/tests/test_parser.rb CHANGED
@@ -25,28 +25,12 @@ class YaparcTest < Test::Unit::TestCase
25
25
  assert_equal 1, result.value
26
26
  end
27
27
 
28
- # def test_succeed_parse
29
- # parser = ::Yaparc::SucceedParser.new(1)
30
- # assert_equal [[1, "abs"]], parser.parse("abs")
31
- # assert_equal [[1, "abs"]], parser.tree
32
- # result = parser.parse("abs") do |result|
33
- # result[0][0]
34
- # end
35
- # assert_equal 1, result
36
- # end
37
-
38
28
  def test_fail_parse
39
29
  parser = ::Yaparc::FailParser.new
40
30
  result = parser.parse("abc")
41
31
  assert_instance_of Result::Fail, result
42
32
  end
43
33
 
44
- # def test_fail_parse
45
- # parser = ::Yaparc::FailParser.new
46
- # result = parser.parse("abc")
47
- # assert_equal [], result
48
- # end
49
-
50
34
  def test_item_parse
51
35
  parser = ::Yaparc::ItemParser.new
52
36
  result = parser.parse("")
@@ -56,14 +40,6 @@ class YaparcTest < Test::Unit::TestCase
56
40
  assert_equal "bc", result.input
57
41
  end
58
42
 
59
- # def test_item_parse
60
- # parser = ::Yaparc::ItemParser.new
61
- # result = parser.parse("")
62
- # assert_equal [], result
63
- # result = parser.parse("abc")
64
- # assert_equal [["a", "bc"]], result
65
- # end
66
-
67
43
  def test_satisfy_parse
68
44
  is_integer = lambda do |i|
69
45
  begin
@@ -96,37 +72,6 @@ class YaparcTest < Test::Unit::TestCase
96
72
  assert_equal "bc", result.input
97
73
  end
98
74
 
99
- # def test_satisfy_parse
100
- # is_integer = lambda do |i|
101
- # begin
102
- # Integer(i)
103
- # true
104
- # rescue
105
- # false
106
- # end
107
- # end
108
- # parser = SatisfyParser.new(is_integer)
109
- # result = parser.parse("123")
110
- # assert_equal [["1", "23"]], result
111
-
112
- # parser = SatisfyParser.new(is_integer)
113
- # result = parser.parse("abc")
114
- # assert_equal [], result
115
-
116
- # is_char = lambda do |i|
117
- # begin
118
- # String(i)
119
- # true
120
- # rescue
121
- # false
122
- # end
123
- # end
124
- # parser = SatisfyParser.new(is_char)
125
- # result = parser.parse("abc")
126
- # assert_equal [["a", "bc"]], result
127
- # end
128
-
129
-
130
75
  def test_seq_parse
131
76
  parser = SeqParser.new(ItemParser.new, ItemParser.new) do |item1, item2|
132
77
  [item1, item2]
@@ -150,26 +95,6 @@ class YaparcTest < Test::Unit::TestCase
150
95
  assert_equal "DEF", result.input
151
96
  end
152
97
 
153
- # def test_seq_parse
154
- # parser = SeqParser.new(ItemParser.new, ItemParser.new) do |item1, item2|
155
- # [item1, item2]
156
- # end
157
- # result = parser.parse("abcdef")
158
- # assert_equal [[["a", "b"], "cdef"]], result
159
-
160
- # parser = SeqParser.new(ItemParser.new, ItemParser.new, ItemParser.new) do |item1, item2, item3|
161
- # [item1, item3]
162
- # end
163
- # result = parser.parse("ABCDEF")
164
- # assert_equal [[["A", "C"], "DEF"]], result
165
-
166
- # parser = SeqParser.new(ItemParser.new, ItemParser.new, ItemParser.new) do |item1, item2, item3|
167
- # [item2]
168
- # end
169
- # result = parser.parse("ABCDEF")
170
- # assert_equal [[["B"], "DEF"]], result
171
- # end
172
-
173
98
  def test_seq_parse_without_block
174
99
  parser = SeqParser.new(ItemParser.new, ItemParser.new)
175
100
  result = parser.parse("abcdef")
@@ -177,12 +102,6 @@ class YaparcTest < Test::Unit::TestCase
177
102
  assert_equal "cdef", result.input
178
103
  end
179
104
 
180
- # def test_seq_parse_without_block
181
- # parser = SeqParser.new(ItemParser.new, ItemParser.new)
182
- # result = parser.parse("abcdef")
183
- # assert_equal [["b", "cdef"]], result
184
- # end
185
-
186
105
  def test_alt_parse
187
106
  parser = AltParser.new(ItemParser.new, SucceedParser.new('d'))
188
107
  result = parser.parse("abc")
@@ -199,30 +118,20 @@ class YaparcTest < Test::Unit::TestCase
199
118
  assert_instance_of Result::Fail, result
200
119
  end
201
120
 
202
-
203
- # def test_alt_parse
204
- # parser = AltParser.new(ItemParser.new, SucceedParser.new('d'))
205
- # result = parser.parse("abc")
206
- # assert_equal [["a", "bc"]], result
207
-
208
- # parser = AltParser.new(FailParser.new, SucceedParser.new('d'))
209
- # result = parser.parse("abc")
210
- # assert_equal [["d", "abc"]], result
211
-
212
- # parser = AltParser.new(FailParser.new, FailParser.new)
213
- # result = parser.parse("abc")
214
- # assert_equal [], result
215
- # end
216
-
217
121
  def test_apply_parse
218
122
  is_digit = lambda {|i| i >= '0' and i <= '9'}
219
123
  parser = ApplyParser.new(SatisfyParser.new(is_digit)) do |digit|
220
124
  digit.to_i - '0'.to_i
221
125
  end
222
-
223
126
  result = parser.parse('7')
224
127
  assert_equal 7, result.value
225
128
  assert_equal "", result.input
129
+
130
+ parser = Yaparc::ApplyParser.new(Yaparc::RegexParser.new(/\d+/)) do |match|
131
+ Integer(match)
132
+ end
133
+ result = parser.parse('7')
134
+ assert_equal 7, result.value
226
135
  end
227
136
 
228
137
  def test_char_parse
@@ -236,16 +145,6 @@ class YaparcTest < Test::Unit::TestCase
236
145
  assert_instance_of Result::Fail, result
237
146
  end
238
147
 
239
- # def test_char_parse
240
- # parser = CharParser.new("a")
241
- # result = parser.parse("abc")
242
- # assert_equal [["a", "bc"]], result
243
-
244
- # parser = CharParser.new("a")
245
- # result = parser.parse("123")
246
- # assert_equal [], result
247
- # end
248
-
249
148
  def test_string_parse
250
149
  parser = StringParser.new("abc")
251
150
  result = parser.parse("abcdef")
@@ -257,16 +156,6 @@ class YaparcTest < Test::Unit::TestCase
257
156
  assert_instance_of Result::Fail, result
258
157
  end
259
158
 
260
- # def test_string_parse
261
- # parser = StringParser.new("abc")
262
- # result = parser.parse("abcdef")
263
- # assert_equal [["abc", "def"]], result
264
-
265
- # parser = StringParser.new("abc")
266
- # result = parser.parse("ab1234")
267
- # assert_equal [], result
268
- # end
269
-
270
159
  def test_regex_parse
271
160
  parser = RegexParser.new(/[a-z]/)
272
161
  result = parser.parse("abcdef")
@@ -277,17 +166,13 @@ class YaparcTest < Test::Unit::TestCase
277
166
  result = parser.parse("1234ab")
278
167
  assert_equal "1234", result.value
279
168
  assert_equal "ab", result.input
280
- end
281
-
282
- # def test_regex_parse
283
- # parser = RegexParser.new(/[a-z]/)
284
- # result = parser.parse("abcdef")
285
- # assert_equal [["a", "bcdef"]], result
286
169
 
287
- # parser = RegexParser.new(/[0-9]+/)
288
- # result = parser.parse("1234ab")
289
- # assert_equal [["1234", "ab"]], result
290
- # end
170
+ parser = RegexParser.new(/[0-9]+/)
171
+ result = parser.parse("1234ab") do |match|
172
+ Integer(match)
173
+ end
174
+ assert_equal 1234, result.value
175
+ end
291
176
 
292
177
  def test_zero_one_parse
293
178
  parser = ZeroOneParser.new(StringParser.new("abc"))
@@ -300,15 +185,6 @@ class YaparcTest < Test::Unit::TestCase
300
185
  assert_equal "123", result.input
301
186
  end
302
187
 
303
- # def test_zero_one_parse
304
- # parser = ZeroOneParser.new(StringParser.new("abc"))
305
- # result = parser.parse("abc ")
306
- # assert_equal [["abc", " "]], result
307
- # parser = ZeroOneParser.new(StringParser.new("abc"))
308
- # result = parser.parse("123")
309
- # assert_equal [[[], "123"]], result
310
- # end
311
-
312
188
  def test_many_parse
313
189
  is_digit = SatisfyParser.new(lambda {|i| i >= '0' and i <= '9'})
314
190
  parser = ManyParser.new(is_digit)
@@ -321,17 +197,6 @@ class YaparcTest < Test::Unit::TestCase
321
197
  assert_equal "abcdef", result.input
322
198
  end
323
199
 
324
- # def test_many_parse
325
- # is_digit = SatisfyParser.new(lambda {|i| i >= '0' and i <= '9'})
326
- # parser = ManyParser.new(is_digit)
327
- # result = parser.parse("123abc")
328
- # assert_equal [["123", "abc"]], result
329
-
330
- # result = parser.parse("abcdef")
331
- # assert_equal [[[], "abcdef"]], result
332
- # end
333
-
334
-
335
200
  def test_ident
336
201
  parser = Ident.new
337
202
  result = parser.parse("abc def")
@@ -339,12 +204,6 @@ class YaparcTest < Test::Unit::TestCase
339
204
  assert_equal " def", result.input
340
205
  end
341
206
 
342
- # def test_ident
343
- # parser = Ident.new
344
- # result = parser.parse("abc def")
345
- # assert_equal [["abc", " def"]], result
346
- # end
347
-
348
207
  def test_nat
349
208
  parser = Nat.new
350
209
  result = parser.parse("123 abc")
@@ -352,13 +211,6 @@ class YaparcTest < Test::Unit::TestCase
352
211
  assert_equal " abc", result.input
353
212
  end
354
213
 
355
-
356
- # def test_nat
357
- # parser = Nat.new
358
- # result = parser.parse("123 abc")
359
- # assert_equal [[123, " abc"]], result
360
- # end
361
-
362
214
  def test_nat_ident
363
215
  parser = SeqParser.new(Nat.new, Ident.new) do |nat, ident|
364
216
  [nat,ident]
@@ -368,14 +220,6 @@ class YaparcTest < Test::Unit::TestCase
368
220
  assert_equal "", result.input
369
221
  end
370
222
 
371
- # def test_nat_ident
372
- # parser = SeqParser.new(Nat.new, Ident.new) do |nat, ident|
373
- # [nat,ident]
374
- # end
375
- # result = parser.parse("123abc")
376
- # assert_equal [[[123, "abc"], ""]], result
377
- # end
378
-
379
223
  def test_space
380
224
  parser = Space.new
381
225
  result = parser.parse(" abc")
@@ -383,12 +227,6 @@ class YaparcTest < Test::Unit::TestCase
383
227
  assert_equal "abc", result.input
384
228
  end
385
229
 
386
- # def test_space
387
- # parser = Space.new
388
- # result = parser.parse(" abc")
389
- # assert_equal [[[], "abc"]], result
390
- # end
391
-
392
230
  def test_identifier
393
231
  parser = Identifier.new
394
232
  result = parser.parse(" abc ")
@@ -403,18 +241,6 @@ class YaparcTest < Test::Unit::TestCase
403
241
  assert_equal "", result.input
404
242
  end
405
243
 
406
- # def test_identifier
407
- # parser = Identifier.new
408
- # result = parser.parse(" abc ")
409
- # assert_equal [["abc", ""]], result
410
-
411
- # parser_with_keyword = Identifier.new("abc","efg")
412
- # result = parser_with_keyword.parse("abc")
413
- # assert_equal [], result
414
- # result = parser_with_keyword.parse(" xyz")
415
- # assert_equal [["xyz", ""]], result
416
- # end
417
-
418
244
  def test_natural
419
245
  parser = Natural.new
420
246
  result = parser.parse(" 1234 ")
@@ -422,55 +248,11 @@ class YaparcTest < Test::Unit::TestCase
422
248
  assert_equal "", result.input
423
249
  end
424
250
 
425
- # def test_natural
426
- # parser = Natural.new
427
- # result = parser.parse(" 1234 ")
428
- # assert_equal [[1234, ""]], result
429
- # end
430
-
431
251
  def test_symbol
432
252
  parser = Symbol.new('%')
433
253
  result = parser.parse(" % ")
434
254
  assert_equal "%", result.value
435
255
  assert_equal "", result.input
436
256
  end
437
-
438
- # def test_symbol
439
- # parser = Symbol.new('%')
440
- # result = parser.parse(" % ")
441
- # assert_equal [["%", ""]], result
442
- # end
443
-
444
- # def test_define_parser
445
- # parser = Symbol.new('%')
446
- # result = parser.parse(" % ")
447
- # assert_equal [["%", ""]], result
448
- # end
449
-
450
- # def test_combination
451
- # parser = AltParser.new(
452
- # SeqParser.new(Symbol.new('+'),
453
- # Natural.new) do | _, nat|
454
- # nat
455
- # end,
456
- # Natural.new
457
- # )
458
- # result = parser.parse("+123")
459
- # assert_equal [[123, ""]], result
460
- # result = parser.parse(" 123 ")
461
- # assert_equal [[123, ""]], result
462
- # parser = AltParser.new(
463
- # SeqParser.new(
464
- # Symbol.new('('),
465
- # Natural.new,
466
- # Symbol.new(')')
467
- # ) do |_,expr, _|
468
- # expr
469
- # end,
470
- # Natural.new
471
- # )
472
- # result = parser.parse("( 123 )")
473
- # assert_equal [[123, ""]], result
474
- # end
475
257
  end
476
258
 
data/tests/test_sql.rb ADDED
@@ -0,0 +1,324 @@
1
+ require 'lib/yaparc.rb'
2
+ require 'test/unit'
3
+
4
+ ### c.f. http://www11.plala.or.jp/sotsuken/db/sql.html
5
+ ###
6
+ ### query_body := select_expression from_expression where_expression
7
+ ### select_expression := 'select' term_sequence
8
+ ### term_sequence := term[,term_sequence]*
9
+ ### from_expression := 'from' path_expression[, path_expression]*
10
+ ### path_expression := '/' term [path_expression]*
11
+ ### where_expression :=
12
+ ### | search_cond
13
+ ### search_cond := term op term
14
+ ### | ( NOT search_cond )
15
+ ### | ( search_cond AND search_cond )
16
+ ### | ( search_cond OR search_cond )
17
+ ### | EXISTS ( query_body )
18
+ ### | term op ANY ( query_body )
19
+ ### | term op ALL ( query_body )
20
+ ### | term IN ( query_body )
21
+ ### term := any_characters
22
+ ### op := <> | = | < | > | <= | >=
23
+
24
+ module SQL
25
+ ### query_body := select_expression from_expression where_expression
26
+ class QueryBody
27
+ include Yaparc::Parsable
28
+
29
+ def initialize
30
+ @parser = lambda do
31
+ Yaparc::SeqParser.new(SelectExpression.new,
32
+ FromExpression.new,
33
+ WhereExpression.new) do |select, from, where|
34
+ {:select => select, :from => from, :where => where }
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ ### select_expression := 'select' term_sequence
41
+ class SelectExpression
42
+ include Yaparc::Parsable
43
+
44
+ def initialize
45
+ @parser = lambda do
46
+ Yaparc::SeqParser.new(
47
+ Yaparc::Symbol.new('select'),
48
+ TermSequence.new) do |_,terms|
49
+ terms
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ ### term_sequence := term[,term_sequence]*
56
+ class TermSequence
57
+ include Yaparc::Parsable
58
+
59
+ def initialize
60
+ @parser = lambda do
61
+ Yaparc::SeqParser.new(
62
+ Term.new,
63
+ Yaparc::ManyParser.new(
64
+ Yaparc::SeqParser.new(
65
+ Yaparc::Symbol.new(','),
66
+ TermSequence.new) do |_, terms|
67
+ terms
68
+ end,
69
+ []
70
+ )
71
+ ) do |term,terms|
72
+ [term] + terms
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ ### from_expression := 'from' path_expression[, path_expression]*
79
+ class FromExpression
80
+ include Yaparc::Parsable
81
+
82
+ def initialize
83
+ @parser = lambda do
84
+ Yaparc::SeqParser.new(
85
+ Yaparc::Symbol.new('from'),
86
+ PathExpression.new,
87
+ Yaparc::ManyParser.new(
88
+ Yaparc::SeqParser.new(
89
+ Yaparc::Symbol.new(','),
90
+ PathExpression.new) do |_, path|
91
+ [path]
92
+ end,
93
+ []
94
+ )
95
+ ) do |_,path,paths|
96
+ path + paths
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+
103
+ ### path_expression := '/' term [path_expression]*
104
+ class PathExpression
105
+ include Yaparc::Parsable
106
+
107
+ def initialize
108
+ @parser = lambda do
109
+ Yaparc::SeqParser.new(
110
+ Yaparc::Symbol.new('/'),
111
+ Term.new,
112
+ Yaparc::ManyParser.new(
113
+ PathExpression.new do |path|
114
+ path
115
+ end,
116
+ []
117
+ )
118
+ ) do |_,term, paths|
119
+ [term] + paths
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ ### where_expression :=
126
+ ### | search_cond
127
+ class WhereExpression
128
+ include Yaparc::Parsable
129
+
130
+ def initialize
131
+ @parser = lambda do
132
+ Yaparc::ManyParser.new(SearchCond.new)
133
+ end
134
+ end
135
+ end
136
+
137
+ ### term := any_characters
138
+ class Term
139
+ include Yaparc::Parsable
140
+
141
+ def initialize
142
+ @parser = lambda do
143
+ Yaparc::Identifier.new
144
+ end
145
+ end
146
+ end
147
+
148
+ ### search_cond := term op term
149
+ ### | ( NOT search_cond )
150
+ ### | ( search_cond AND search_cond )
151
+ ### | ( search_cond OR search_cond )
152
+ ### | EXISTS ( query_body )
153
+ ### | term op ANY ( query_body )
154
+ ### | term op ALL ( query_body )
155
+ ### | term IN ( query_body )
156
+
157
+ class SearchCond
158
+ include Yaparc::Parsable
159
+
160
+ def initialize
161
+ @parser = lambda do
162
+ Yaparc::AltParser.new(
163
+ Yaparc::SeqParser.new(Term.new,
164
+ Op.new,
165
+ Term.new) do |term1, op, term2|
166
+ {:operator => op, :args => [term1, term2]}
167
+ end,
168
+ Yaparc::SeqParser.new(Yaparc::Symbol.new('('),
169
+ Yaparc::Symbol.new('NOT'),
170
+ SearchCond.new,
171
+ Yaparc::Symbol.new(')')) do |_, _, cond, _|
172
+ {:logic => :not, :conditions => [cond]}
173
+ end,
174
+ Yaparc::SeqParser.new(Yaparc::Symbol.new('('),
175
+ SearchCond.new,
176
+ Yaparc::Symbol.new('AND'),
177
+ SearchCond.new,
178
+ Yaparc::Symbol.new(')')) do |_, cond1, _,cond2,_|
179
+ {:logic => :and, :conditions => [cond1, cond2]}
180
+ end,
181
+ Yaparc::SeqParser.new(Yaparc::Symbol.new('('),
182
+ SearchCond.new,
183
+ Yaparc::Symbol.new('OR'),
184
+ SearchCond.new,
185
+ Yaparc::Symbol.new(')')) do |_, cond1, _,cond2,_|
186
+ {:logic => :or, :conditions => [cond1,cond2]}
187
+ end,
188
+ Yaparc::SeqParser.new(Yaparc::Symbol.new('EXISTS'),
189
+ Yaparc::Symbol.new('('),
190
+ QueryBody.new,
191
+ Yaparc::Symbol.new(')')) do |_, _, body,_|
192
+ {:logic => :exits, :condition => body}
193
+ end,
194
+ # term op ANY ( query_body )
195
+ Yaparc::SeqParser.new(Term.new,
196
+ Op.new,
197
+ Yaparc::Symbol.new('ANY'),
198
+ Yaparc::Symbol.new('('),
199
+ QueryBody.new,
200
+ Yaparc::Symbol.new(')')) do |term, op, _, _, body,_|
201
+ {:operator => op,
202
+ :term1 => term,
203
+ :term2 => {:logic => :any, :condition => body}
204
+ }
205
+ end,
206
+ # term op ALL ( query_body )
207
+ Yaparc::SeqParser.new(Term.new,
208
+ Op.new,
209
+ Yaparc::Symbol.new('ALL'),
210
+ Yaparc::Symbol.new('('),
211
+ QueryBody.new,
212
+ Yaparc::Symbol.new(')')) do |term, op, _, _, body,_|
213
+ {:operator => op,
214
+ :term1 => term,
215
+ :term2 => {:logic => :ALL, :condition => body}
216
+ }
217
+ end,
218
+ # term IN ( query_body )
219
+ Yaparc::SeqParser.new(Term.new,
220
+ Op.new,
221
+ Yaparc::Symbol.new('IN'),
222
+ Yaparc::Symbol.new('('),
223
+ QueryBody.new,
224
+ Yaparc::Symbol.new(')')) do |term, op, _, _, body,_|
225
+ {:operator => op,
226
+ :term1 => term,
227
+ :term2 => {:logic => :IN, :condition => body}
228
+ }
229
+ end)
230
+ end
231
+ end
232
+ end
233
+
234
+ ### op := <> | = | < | > | <= | >=
235
+ class Op
236
+ include Yaparc::Parsable
237
+
238
+ def initialize
239
+ @parser = lambda do
240
+ Yaparc::AltParser.new(
241
+ Yaparc::ApplyParser.new(Yaparc::Symbol.new('<>')) {|_| :not},
242
+ Yaparc::ApplyParser.new(Yaparc::Symbol.new('<=')) {|_| :lesser_eq },
243
+ Yaparc::ApplyParser.new(Yaparc::Symbol.new('>=')) {|_| :greater_eq },
244
+ Yaparc::ApplyParser.new(Yaparc::Symbol.new('<')) {|_| :lesser},
245
+ Yaparc::ApplyParser.new(Yaparc::Symbol.new('>')) {|_| :greater })
246
+ end
247
+ end
248
+ end
249
+ end # of SQL
250
+
251
+
252
+ class YaparcQueryTest < Test::Unit::TestCase
253
+ include ::Yaparc
254
+
255
+ # def setup
256
+ # @expr = Expr.new
257
+ # @factor = Factor.new
258
+ # end
259
+
260
+ def test_op
261
+ op = SQL::Op.new
262
+ result = op.parse("<")
263
+ assert_instance_of Result::OK, result
264
+ assert_equal :lesser, result.value
265
+ result = op.parse("<=")
266
+ assert_instance_of Result::OK, result
267
+ assert_equal :lesser_eq, result.value
268
+ end
269
+
270
+ def test_term
271
+ term = SQL::Term.new
272
+ result = term.parse("abc")
273
+ assert_instance_of Result::OK, result
274
+ assert_equal "abc", result.value
275
+ end
276
+
277
+ def test_path_expression
278
+ path = SQL::PathExpression.new
279
+ result = path.parse("/xyz")
280
+ assert_instance_of Result::OK, result
281
+ assert_equal ["xyz"], result.value
282
+ result = path.parse("/abc/def")
283
+ assert_instance_of Result::OK, result
284
+ assert_equal ["abc", "def"], result.value
285
+ end
286
+
287
+ def test_from_expression
288
+ path = SQL::FromExpression.new
289
+ result = path.parse("from /xyz")
290
+ assert_instance_of Result::OK, result
291
+ assert_equal ["xyz"], result.value
292
+ result = path.parse("from /abc/def")
293
+ assert_instance_of Result::OK, result
294
+ assert_equal ["abc", "def"], result.value
295
+ end
296
+
297
+ def test_search_cond
298
+ search = SQL::SearchCond.new
299
+ result = search.parse("abc <> xyz")
300
+ assert_instance_of Result::OK, result
301
+ assert_equal Hash[:operator=> :not, :args=>["abc", "xyz"]], result.value
302
+
303
+ result = search.parse("(NOT abc <> xyz)")
304
+ assert_instance_of Result::OK, result
305
+ assert_equal Hash[:logic=>:not, :conditions=>[{:operator=>:not, :args=>["abc", "xyz"]}]], result.value
306
+ result = search.parse("(abc <> xyz AND abc > xyz)")
307
+ assert_instance_of Result::OK, result
308
+ assert_equal Hash[
309
+ :logic=>:and, :conditions=> [{:operator=>:not, :args=>["abc", "xyz"]},
310
+ {:operator=>:greater, :args=>["abc", "xyz"]}]
311
+ ], result.value
312
+ end
313
+
314
+ def test_query_body
315
+ query = SQL::QueryBody.new
316
+ result = query.parse("select abc from /xyz")
317
+ assert_instance_of Result::OK, result
318
+ assert_equal Hash[:from=>["xyz"], :where=>"", :select=>["abc"]], result.value
319
+ result = query.parse("select abc from /xyz/fgh")
320
+ assert_instance_of Result::OK, result
321
+ assert_equal Hash[:from=>["xyz","fgh"], :where=>"", :select=>["abc"]], result.value
322
+ end
323
+
324
+ end
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.1.0
7
- date: 2008-01-16 00:00:00 +09:00
6
+ version: 0.1.3
7
+ date: 2008-01-20 00:00:00 +09:00
8
8
  summary: Yet Another Combinator Parser Library
9
9
  require_paths:
10
10
  - lib
@@ -31,11 +31,13 @@ authors:
31
31
  files:
32
32
  - tests/test_parser.rb
33
33
  - tests/test_calc.rb
34
+ - tests/test_sql.rb
34
35
  - lib/yaparc.rb
35
36
  - README
36
37
  test_files:
37
38
  - tests/test_parser.rb
38
39
  - tests/test_calc.rb
40
+ - tests/test_sql.rb
39
41
  rdoc_options: []
40
42
 
41
43
  extra_rdoc_files: