neg 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/TODO.txt CHANGED
@@ -2,13 +2,14 @@
2
2
  [o] unconsumed input!
3
3
  [o] ^ 0, 1, [ min, max ]
4
4
  [o] switch from ^ to * (how * is related to +)
5
+ [o] _ (any)
6
+ [o] chars
5
7
  [ ] lookahead present/absent
6
8
  ~ x --> present
7
9
  ! x --> absent
8
- [ ] any
9
- [ ] chars
10
10
  [ ] blankslate
11
-
11
+ [ ] drop UnconsumedInput, replace with regular [ false, ... ] output
12
+ [ ] x * '?' / x * '+' / x * '*' as shortcuts
12
13
 
13
14
  `x` + [.]
14
15
  `x` + [a-z]
data/lib/neg/parser.rb CHANGED
@@ -29,9 +29,13 @@ require 'neg/input'
29
29
  module Neg
30
30
 
31
31
  class UnconsumedInputError < StandardError; end
32
+ class ParseError < StandardError; end
32
33
 
33
34
  class Parser
34
35
 
36
+ def self.`(s) ; StringParser.new(s); end
37
+ def self._(c=nil) ; CharacterParser.new(c); end
38
+
35
39
  def self.method_missing(m, *args)
36
40
 
37
41
  return super if args.any?
@@ -53,21 +57,11 @@ module Neg
53
57
 
54
58
  raise UnconsumedInputError.new(
55
59
  "remaining: #{i.remains.inspect}"
56
- ) if result[1] && ( ! i.eoi?)
60
+ ) if result[2] && ( ! i.eoi?)
57
61
 
58
62
  result
59
63
  end
60
64
 
61
- def self.`(s)
62
-
63
- StringParser.new(s)
64
- end
65
-
66
- def self._(c=nil)
67
-
68
- CharacterParser.new(c)
69
- end
70
-
71
65
  def self.to_s
72
66
 
73
67
  s = [ "#{name}:" ]
@@ -96,36 +90,23 @@ module Neg
96
90
 
97
91
  class SubParser
98
92
 
99
- def +(pa)
100
-
101
- SequenceParser.new(self, pa)
102
- end
103
-
104
- def |(pa)
105
-
106
- AlternativeParser.new(self, pa)
107
- end
108
-
109
- def [](name)
110
-
111
- NonTerminalParser.new(name.to_s, self)
112
- end
113
-
114
- def *(range)
115
-
116
- RepetitionParser.new(self, range)
117
- end
93
+ def +(pa) ; SequenceParser.new(self, pa); end
94
+ def |(pa) ; AlternativeParser.new(self, pa); end
95
+ def [](name) ; NonTerminalParser.new(name.to_s, self); end
96
+ def *(range) ; RepetitionParser.new(self, range); end
97
+ def ~ ; LookaheadParser.new(self, true); end
98
+ def -@ ; LookaheadParser.new(self, false); end
118
99
 
119
100
  def parse(input_or_string)
120
101
 
121
102
  input = Neg::Input(input_or_string)
122
103
  start = input.position
123
104
 
124
- success, result = do_parse(input)
105
+ success, result, children = do_parse(input)
125
106
 
126
107
  input.rewind(start) unless success
127
108
 
128
- [ nil, success, start, result ]
109
+ [ nil, start, success, result, children ]
129
110
  end
130
111
  end
131
112
 
@@ -142,9 +123,34 @@ module Neg
142
123
  @child = pa
143
124
  end
144
125
 
126
+ # def reduce(children_results)
127
+ #
128
+ # children_results.collect { |cr|
129
+ # if cr[0] && cr[0] != :digit
130
+ # false
131
+ # elsif cr[2]
132
+ # cr[3] ? cr[3] : reduce(cr[4])
133
+ # else
134
+ # nil
135
+ # end
136
+ # }.flatten.compact
137
+ # end
138
+
145
139
  def do_parse(i)
146
140
 
147
- @child.do_parse(i)
141
+ raise ParseError.new("\"#{@name}\" is missing") if @child.nil?
142
+
143
+ r = @child.do_parse(i)
144
+
145
+ return r
146
+
147
+ # return r if r[0] == false
148
+ #
149
+ # report = reduce(r[2])
150
+ #
151
+ # return r if report.include?(false)
152
+ #
153
+ # [ true, report.join, [] ]
148
154
  end
149
155
 
150
156
  def parse(input_or_string)
@@ -189,15 +195,15 @@ module Neg
189
195
 
190
196
  loop do
191
197
  r = @child.parse(i)
192
- break if ! r[1] && rs.size >= @min && (@max.nil? || rs.size <= @max)
198
+ break if ! r[2] && rs.size >= @min && (@max.nil? || rs.size <= @max)
193
199
  rs << r
194
- break if ! r[1]
200
+ break if ! r[2]
195
201
  break if rs.size == @max
196
202
  end
197
203
 
198
- success = (rs.empty? || rs.last[1]) && (rs.size >= @min)
204
+ success = (rs.empty? || rs.last[2]) && (rs.size >= @min)
199
205
 
200
- [ success, rs ]
206
+ [ success, nil, rs ]
201
207
  end
202
208
 
203
209
  def to_s(parent=nil)
@@ -216,9 +222,9 @@ module Neg
216
222
  def do_parse(i)
217
223
 
218
224
  if (s = i.read(@s.length)) == @s
219
- [ true, @s ]
225
+ [ true, @s, [] ]
220
226
  else
221
- [ false, "expected #{@s.inspect}, got #{s.inspect}" ]
227
+ [ false, "expected #{@s.inspect}, got #{s.inspect}", [] ]
222
228
  end
223
229
  end
224
230
 
@@ -239,9 +245,9 @@ module Neg
239
245
  def do_parse(i)
240
246
 
241
247
  if (s = i.read(1)).match(@r)
242
- [ true, s ]
248
+ [ true, s, [] ]
243
249
  else
244
- [ false, "#{s.inspect} doesn't match #{@c.inspect}" ]
250
+ [ false, "#{s.inspect} doesn't match #{@c.inspect}", [] ]
245
251
  end
246
252
  end
247
253
 
@@ -275,10 +281,10 @@ module Neg
275
281
  @children.each do |c|
276
282
 
277
283
  results << c.parse(i)
278
- break unless results.last[1]
284
+ break unless results.last[2]
279
285
  end
280
286
 
281
- [ results.last[1], results ]
287
+ [ results.last[2], nil, results ]
282
288
  end
283
289
 
284
290
  def to_s(parent=nil)
@@ -298,14 +304,14 @@ module Neg
298
304
 
299
305
  def do_parse(i)
300
306
 
301
- result = []
307
+ results = []
302
308
 
303
309
  @children.each { |c|
304
- result << c.parse(i)
305
- break if result.last[1]
310
+ results << c.parse(i)
311
+ break if results.last[2]
306
312
  }
307
313
 
308
- [ result.last[1], result ]
314
+ [ results.last[2], nil, results ]
309
315
  end
310
316
 
311
317
  def to_s(parent=nil)
@@ -313,6 +319,41 @@ module Neg
313
319
  "(#{@children.collect { |c| c.to_s(self) }.join(' | ')})"
314
320
  end
315
321
  end
322
+
323
+ class LookaheadParser < SubParser
324
+
325
+ def initialize(child, presence)
326
+
327
+ @child = child
328
+ @presence = presence
329
+ end
330
+
331
+ def do_parse(i)
332
+
333
+ start = i.position
334
+
335
+ r = @child.parse(i)
336
+ i.rewind(start)
337
+
338
+ success = r[2]
339
+ success = ! success if ! @presence
340
+
341
+ result = if success
342
+ nil
343
+ else
344
+ [
345
+ @child.to_s(nil), 'is not', @presence ? 'present' : 'absent'
346
+ ].join(' ')
347
+ end
348
+
349
+ [ success, result, [ r ] ]
350
+ end
351
+
352
+ def to_s(parent=nil)
353
+
354
+ "#{@presence ? '~' : '-'}#{@child.to_s(self)}"
355
+ end
356
+ end
316
357
  end
317
358
  end
318
359
 
data/lib/neg/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
 
26
26
  module Neg
27
27
 
28
- VERSION = '0.2.0'
28
+ VERSION = '0.3.0'
29
29
  end
30
30
 
@@ -11,24 +11,24 @@ describe Neg::Parser::AlternativeParser do
11
11
  it 'parses' do
12
12
 
13
13
  AltParser.parse('x').should ==
14
- [ :text, true, [ 0, 1, 1 ], [
15
- [ nil, true, [ 0, 1, 1 ], 'x' ] ] ]
14
+ [ :text, [ 0, 1, 1 ], true, nil, [
15
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ] ] ]
16
16
  end
17
17
 
18
18
  it 'parses (2nd alternative succeeds)' do
19
19
 
20
20
  AltParser.parse('y').should ==
21
- [ :text, true, [ 0, 1, 1 ], [
22
- [ nil, false, [ 0, 1, 1 ], 'expected "x", got "y"' ],
23
- [ nil, true, [ 0, 1, 1 ], 'y' ] ] ]
21
+ [ :text, [ 0, 1, 1 ], true, nil, [
22
+ [ nil, [ 0, 1, 1 ], false, 'expected "x", got "y"', [] ],
23
+ [ nil, [ 0, 1, 1 ], true, 'y', [] ] ] ]
24
24
  end
25
25
 
26
26
  it 'fails gracefully' do
27
27
 
28
28
  AltParser.parse('z').should ==
29
- [ :text, false, [ 0, 1, 1 ], [
30
- [ nil, false, [ 0, 1, 1 ], 'expected "x", got "z"' ],
31
- [ nil, false, [ 0, 1, 1 ], 'expected "y", got "z"' ] ] ]
29
+ [ :text, [ 0, 1, 1 ], false, nil, [
30
+ [ nil, [ 0, 1, 1 ], false, 'expected "x", got "z"', [] ],
31
+ [ nil, [ 0, 1, 1 ], false, 'expected "y", got "z"', [] ] ] ]
32
32
  end
33
33
 
34
34
  it 'goes beyond two elements' do
@@ -16,20 +16,22 @@ describe Neg::Parser::CharacterParser do
16
16
 
17
17
  parser.parse('xy').should ==
18
18
  [ :text,
19
- true,
20
19
  [ 0, 1, 1 ],
21
- [ [ nil, true, [ 0, 1, 1 ], "x" ],
22
- [ nil, true, [ 1, 1, 2 ], "y" ] ] ]
20
+ true,
21
+ nil,
22
+ [ [ nil, [ 0, 1, 1 ], true, "x", [] ],
23
+ [ nil, [ 1, 1, 2 ], true, "y", [] ] ] ]
23
24
  end
24
25
 
25
26
  it 'fails gracefully' do
26
27
 
27
28
  parser.parse('x').should ==
28
29
  [ :text,
29
- false,
30
30
  [ 0, 1, 1],
31
- [ [ nil, true, [ 0, 1, 1 ], "x" ],
32
- [ nil, false, [ 1, 1, 2 ], "\"\" doesn't match nil" ] ] ]
31
+ false,
32
+ nil,
33
+ [ [ nil, [ 0, 1, 1 ], true, "x", [] ],
34
+ [ nil, [ 1, 1, 2 ], false, "\"\" doesn't match nil", [] ] ] ]
33
35
  end
34
36
 
35
37
  it 'is rendered correctly via #to_s' do
@@ -54,19 +56,43 @@ describe Neg::Parser::CharacterParser do
54
56
 
55
57
  parser.parse('tel:0-99').should ==
56
58
  [ :text,
57
- true,
58
59
  [ 0, 1, 1 ],
59
- [ [ nil, true, [ 0, 1, 1 ], "tel:" ],
60
+ true,
61
+ nil,
62
+ [ [ nil, [ 0, 1, 1 ], true, "tel:", [] ],
60
63
  [ nil,
64
+ [ 4, 1, 5 ],
61
65
  true,
66
+ nil,
67
+ [ [ nil, [ 4, 1, 5 ], true, "0", [] ],
68
+ [ nil, [ 5, 1, 6 ], true, "-", [] ],
69
+ [ nil, [ 6, 1, 7 ], true, "9", [] ],
70
+ [ nil, [ 7, 1, 8 ], true, "9", [] ] ] ] ] ]
71
+ end
72
+
73
+ it 'fails gracefully' do
74
+
75
+ parser.parse('tel:a-bc').should ==
76
+ [ :text,
77
+ [ 0, 1, 1 ],
78
+ false,
79
+ nil,
80
+ [ [ nil, [ 0, 1, 1 ], true, "tel:", [] ],
81
+ [ nil,
62
82
  [ 4, 1, 5 ],
63
- [ [ nil, true, [ 4, 1, 5 ], "0" ],
64
- [ nil, true, [ 5, 1, 6 ], "-" ],
65
- [ nil, true, [ 6, 1, 7 ], "9" ],
66
- [ nil, true, [ 7, 1, 8 ], "9" ] ] ] ] ]
83
+ false,
84
+ nil,
85
+ [ [ nil, [ 4, 1, 5 ], false, "\"a\" doesn't match \"0-9-\"", [] ] ] ] ] ]
67
86
  end
68
87
 
69
- it 'fails gracefully'
88
+ it 'is rendered correctly via #to_s' do
89
+
90
+ parser.to_s.strip.should == %q{
91
+ :
92
+ text == (`tel:` + _("0-9-") * 1)
93
+ root: text
94
+ }.strip
95
+ end
70
96
  end
71
97
  end
72
98
 
@@ -0,0 +1,126 @@
1
+
2
+ require 'spec_helper'
3
+
4
+
5
+ describe Neg::Parser::LookaheadParser do
6
+
7
+ context '~x (presence)' do
8
+
9
+ let(:parser) {
10
+ Class.new(Neg::Parser) do
11
+ root == x + z
12
+ x == `x` + ~`z`
13
+ z == `z`
14
+ end
15
+ }
16
+
17
+ it 'parses' do
18
+
19
+ parser.parse('xz').should ==
20
+ [ :root,
21
+ [ 0, 1, 1 ],
22
+ true,
23
+ nil,
24
+ [ [ :x,
25
+ [ 0, 1, 1 ],
26
+ true,
27
+ nil,
28
+ [ [ nil, [ 0, 1, 1 ], true, "x", [] ],
29
+ [ nil, [ 1, 1, 2 ], true, nil, [
30
+ [ nil, [ 1, 1, 2 ], true, "z", [] ] ] ] ] ],
31
+ [ :z, [ 1, 1, 2 ], true, "z", [] ] ] ]
32
+ end
33
+
34
+ it 'fails gracefully' do
35
+
36
+ parser.parse('xx').should ==
37
+ [:root,
38
+ [0, 1, 1],
39
+ false,
40
+ nil,
41
+ [[:x,
42
+ [0, 1, 1],
43
+ false,
44
+ nil,
45
+ [[nil, [0, 1, 1], true, "x", []],
46
+ [nil,
47
+ [1, 1, 2],
48
+ false,
49
+ "`z` is not present",
50
+ [[nil, [1, 1, 2], false, "expected \"z\", got \"x\"", []]]]]]]]
51
+ end
52
+
53
+ it 'is rendered correctly via #to_s' do
54
+
55
+ parser.to_s.strip.should == %q{
56
+ :
57
+ root == (x + z)
58
+ x == (`x` + ~`z`)
59
+ z == `z`
60
+ root: root
61
+ }.strip
62
+ end
63
+ end
64
+
65
+ context '-x (absence)' do
66
+
67
+ let(:parser) {
68
+ Class.new(Neg::Parser) do
69
+ root == x + z
70
+ x == `x` + -`y`
71
+ z == `z`
72
+ end
73
+ }
74
+
75
+ it 'parses' do
76
+
77
+ parser.parse('xz').should ==
78
+ [ :root,
79
+ [ 0, 1, 1 ],
80
+ true,
81
+ nil,
82
+ [ [ :x,
83
+ [ 0, 1, 1 ],
84
+ true,
85
+ nil,
86
+ [ [ nil, [ 0, 1, 1 ], true, "x", [] ],
87
+ [ nil,
88
+ [ 1, 1, 2 ],
89
+ true,
90
+ nil,
91
+ [ [ nil, [ 1, 1, 2 ], false, "expected \"y\", got \"z\"", [] ] ] ] ] ],
92
+ [ :z, [ 1, 1, 2 ], true, "z", [] ] ] ]
93
+ end
94
+
95
+ it 'fails gracefully' do
96
+
97
+ parser.parse('xy').should ==
98
+ [:root,
99
+ [0, 1, 1],
100
+ false,
101
+ nil,
102
+ [[:x,
103
+ [0, 1, 1],
104
+ false,
105
+ nil,
106
+ [[nil, [0, 1, 1], true, "x", []],
107
+ [nil,
108
+ [1, 1, 2],
109
+ false,
110
+ "`y` is not absent",
111
+ [[nil, [1, 1, 2], true, "y", []]]]]]]]
112
+ end
113
+
114
+ it 'is rendered correctly via #to_s' do
115
+
116
+ parser.to_s.strip.should == %q{
117
+ :
118
+ root == (x + z)
119
+ x == (`x` + -`y`)
120
+ z == `z`
121
+ root: root
122
+ }.strip
123
+ end
124
+ end
125
+ end
126
+
@@ -14,10 +14,10 @@ describe Neg::Parser::NonTerminalParser do
14
14
  z == `zz` | `z`
15
15
  end
16
16
 
17
- parser.parse('x')[1].should == true
18
- parser.parse('z')[1].should == true
19
- parser.parse('zz')[1].should == true
20
- parser.parse('y')[1].should == false
17
+ parser.parse('x')[2].should == true
18
+ parser.parse('z')[2].should == true
19
+ parser.parse('zz')[2].should == true
20
+ parser.parse('y')[2].should == false
21
21
  end
22
22
 
23
23
  it 'sets its name in the result (as a Symbol)' do
@@ -27,9 +27,9 @@ describe Neg::Parser::NonTerminalParser do
27
27
  end
28
28
 
29
29
  parser.parse('X').should ==
30
- [ :x, true, [ 0, 1, 1 ], [
31
- [ nil, false, [ 0, 1, 1 ], "expected \"x\", got \"X\"" ],
32
- [ nil, true, [ 0, 1, 1 ], "X" ] ] ]
30
+ [ :x, [ 0, 1, 1 ], true, nil, [
31
+ [ nil, [ 0, 1, 1 ], false, "expected \"x\", got \"X\"", [] ],
32
+ [ nil, [ 0, 1, 1 ], true, "X", [] ] ] ]
33
33
  end
34
34
 
35
35
  it 'is rendered as x when on the right side' do
@@ -48,6 +48,16 @@ describe Neg::Parser::NonTerminalParser do
48
48
  root: word
49
49
  }.strip
50
50
  end
51
+
52
+ it 'flips burgers' do
53
+
54
+ parser = Class.new(Neg::Parser) do
55
+ sentence == (word + ` `) * 1
56
+ word == _("a-z") * 1
57
+ end
58
+
59
+ pp parser.parse("ab cd ")
60
+ end
51
61
  end
52
62
 
53
63
  context '...["name"]' do
@@ -74,11 +84,14 @@ describe Neg::Parser::NonTerminalParser do
74
84
 
75
85
  parser.parse('car_cluj').should ==
76
86
  [ :transportation,
87
+ [ 0, 1, 1 ],
77
88
  true,
78
- [ 0, 1, 1],
79
- [ [ 'vehicle', true, [ 0, 1, 1 ], [ [ nil, true, [ 0, 1, 1 ], 'car' ] ] ],
80
- [ nil, true, [ 3, 1, 4 ], '_'],
81
- [ 'city', true, [ 4, 1, 5 ], [ [ nil, true, [ 4, 1, 5 ], 'cluj' ] ] ] ] ]
89
+ nil,
90
+ [ [ 'vehicle', [ 0, 1, 1 ], true, nil, [
91
+ [ nil, [ 0, 1, 1 ], true, 'car', [] ] ] ],
92
+ [ nil, [ 3, 1, 4 ], true, '_', [] ],
93
+ [ 'city', [ 4, 1, 5 ], true, nil, [
94
+ [ nil, [ 4, 1, 5 ], true, 'cluj', [] ] ] ] ] ]
82
95
  end
83
96
  end
84
97
  end
@@ -15,7 +15,7 @@ describe Neg::Parser::RepetitionParser do
15
15
  it 'parses the empty string' do
16
16
 
17
17
  parser.parse('').should ==
18
- [ :text, true, [ 0, 1, 1 ], [] ]
18
+ [ :text, [ 0, 1, 1 ], true, nil, [] ]
19
19
  end
20
20
 
21
21
  it 'fails gracefully' do
@@ -48,16 +48,16 @@ describe Neg::Parser::RepetitionParser do
48
48
  it 'parses the empty string' do
49
49
 
50
50
  parser.parse('').should ==
51
- [ :text, true, [ 0, 1, 1 ], [] ]
51
+ [ :text, [ 0, 1, 1 ], true, nil, [] ]
52
52
  end
53
53
 
54
54
  it 'parses' do
55
55
 
56
56
  parser.parse('xxx').should ==
57
- [ :text, true, [ 0, 1, 1 ], [
58
- [ nil, true, [ 0, 1, 1 ], 'x' ],
59
- [ nil, true, [ 1, 1, 2 ], 'x' ],
60
- [ nil, true, [ 2, 1, 3 ], 'x' ] ] ]
57
+ [ :text, [ 0, 1, 1 ], true, nil, [
58
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
59
+ [ nil, [ 1, 1, 2 ], true, 'x', [] ],
60
+ [ nil, [ 2, 1, 3 ], true, 'x', [] ] ] ]
61
61
  end
62
62
 
63
63
  it 'fails gracefully' do
@@ -81,18 +81,18 @@ describe Neg::Parser::RepetitionParser do
81
81
  it 'parses' do
82
82
 
83
83
  parser.parse('xxx').should ==
84
- [ :text, true, [ 0, 1, 1 ], [
85
- [ nil, true, [ 0, 1, 1 ], 'x' ],
86
- [ nil, true, [ 1, 1, 2 ], 'x' ],
87
- [ nil, true, [ 2, 1, 3 ], 'x' ] ] ]
84
+ [ :text, [ 0, 1, 1 ], true, nil, [
85
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
86
+ [ nil, [ 1, 1, 2 ], true, 'x', [] ],
87
+ [ nil, [ 2, 1, 3 ], true, 'x', [] ] ] ]
88
88
  end
89
89
 
90
90
  it 'fails gracefully' do
91
91
 
92
92
  parser.parse('x').should ==
93
- [ :text, false, [ 0, 1, 1 ], [
94
- [ nil, true, [ 0, 1, 1 ], 'x' ],
95
- [ nil, false, [ 1, 1, 2 ], 'expected "x", got ""' ] ] ]
93
+ [ :text, [ 0, 1, 1 ], false, nil, [
94
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
95
+ [ nil, [ 1, 1, 2 ], false, 'expected "x", got ""', [] ] ] ]
96
96
  end
97
97
  end
98
98
 
@@ -107,19 +107,19 @@ describe Neg::Parser::RepetitionParser do
107
107
  it 'parses' do
108
108
 
109
109
  parser.parse('xxx').should ==
110
- [ :text, true, [ 0, 1, 1 ], [
111
- [ nil, true, [ 0, 1, 1 ], 'x' ],
112
- [ nil, true, [ 1, 1, 2 ], 'x' ],
113
- [ nil, true, [ 2, 1, 3 ], 'x' ] ] ]
110
+ [ :text, [ 0, 1, 1 ], true, nil, [
111
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
112
+ [ nil, [ 1, 1, 2 ], true, 'x', [] ],
113
+ [ nil, [ 2, 1, 3 ], true, 'x', [] ] ] ]
114
114
  end
115
115
 
116
116
  it 'fails gracefully' do
117
117
 
118
118
  parser.parse('xx').should ==
119
- [ :text, false, [ 0, 1, 1 ], [
120
- [ nil, true, [ 0, 1, 1 ], 'x' ],
121
- [ nil, true, [ 1, 1, 2 ], 'x' ],
122
- [ nil, false, [ 2, 1, 3 ], 'expected "x", got ""' ] ] ]
119
+ [ :text, [ 0, 1, 1 ], false, nil, [
120
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
121
+ [ nil, [ 1, 1, 2 ], true, 'x', [] ],
122
+ [ nil, [ 2, 1, 3 ], false, 'expected "x", got ""', [] ] ] ]
123
123
  end
124
124
 
125
125
  it 'fails gracefully (unconsumed input)' do
@@ -11,17 +11,17 @@ describe Neg::Parser::SequenceParser do
11
11
  it 'parses' do
12
12
 
13
13
  SeqParser.parse('xy').should ==
14
- [ :text, true, [ 0, 1, 1 ], [
15
- [ nil, true, [ 0, 1, 1 ], 'x' ],
16
- [ nil, true, [ 1, 1, 2 ], 'y' ] ] ]
14
+ [ :text, [ 0, 1, 1 ], true, nil, [
15
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
16
+ [ nil, [ 1, 1, 2 ], true, 'y', [] ] ] ]
17
17
  end
18
18
 
19
19
  it 'fails gracefully' do
20
20
 
21
21
  SeqParser.parse('xx').should ==
22
- [ :text, false, [ 0, 1, 1 ], [
23
- [ nil, true, [ 0, 1, 1 ], 'x' ],
24
- [ nil, false, [ 1, 1, 2 ], 'expected "y", got "x"' ] ] ]
22
+ [ :text, [ 0, 1, 1 ], false, nil, [
23
+ [ nil, [ 0, 1, 1 ], true, 'x', [] ],
24
+ [ nil, [ 1, 1, 2 ], false, 'expected "y", got "x"', [] ] ] ]
25
25
  end
26
26
 
27
27
  it 'goes beyond two elements' do
@@ -48,18 +48,21 @@ describe Neg::Parser::SequenceParser do
48
48
 
49
49
  parser.parse('pool').should ==
50
50
  [ :word,
51
- true,
52
51
  [ 0, 1, 1 ],
52
+ true,
53
+ nil,
53
54
  [ [ :poodle,
54
- false,
55
55
  [ 0, 1, 1 ],
56
- [ [ nil, true, [ 0, 1, 1 ], "poo" ],
57
- [ nil, false, [ 3, 1, 4 ], "expected \"dle\", got \"l\"" ] ] ],
56
+ false,
57
+ nil,
58
+ [ [ nil, [ 0, 1, 1 ], true, "poo", [] ],
59
+ [ nil, [ 3, 1, 4 ], false, "expected \"dle\", got \"l\"", [] ] ] ],
58
60
  [ :pool,
61
+ [ 0, 1, 1 ],
59
62
  true,
60
- [ 0, 1, 1],
61
- [ [ nil, true, [ 0, 1, 1 ], "poo" ],
62
- [ nil, true, [ 3, 1, 4 ], "l" ] ] ] ] ]
63
+ nil,
64
+ [ [ nil, [ 0, 1, 1 ], true, "poo", [] ],
65
+ [ nil, [ 3, 1, 4 ], true, "l", [] ] ] ] ] ]
63
66
  end
64
67
  end
65
68
 
@@ -11,7 +11,7 @@ describe Neg::Parser::StringParser do
11
11
  parser = Neg::Parser::StringParser.new('xxx')
12
12
 
13
13
  parser.parse('xxx').should ==
14
- [ nil, true, [ 0, 1, 1 ], 'xxx' ]
14
+ [ nil, [ 0, 1, 1 ], true, 'xxx', [] ]
15
15
  end
16
16
 
17
17
  it 'fails gracefully' do
@@ -19,7 +19,7 @@ describe Neg::Parser::StringParser do
19
19
  parser = Neg::Parser::StringParser.new('xxx')
20
20
 
21
21
  parser.parse('yyy').should ==
22
- [ nil, false, [ 0, 1, 1 ], 'expected "xxx", got "yyy"' ]
22
+ [ nil, [ 0, 1, 1 ], false, 'expected "xxx", got "yyy"', [] ]
23
23
  end
24
24
  end
25
25
 
@@ -34,7 +34,7 @@ describe Neg::Parser::StringParser do
34
34
  it 'parses an exact string' do
35
35
 
36
36
  parser.parse('x').should ==
37
- [ :root, true, [ 0, 1, 1 ], 'x' ]
37
+ [ :root, [ 0, 1, 1 ], true, 'x', [] ]
38
38
  end
39
39
  end
40
40
  end
@@ -6,23 +6,7 @@ describe 'sample JSON parser' do
6
6
 
7
7
  class JsonParser < Neg::Parser
8
8
 
9
- #rule(:spaces) { match('\s').repeat(1) }
10
- #rule(:spaces?) { spaces.maybe }
11
-
12
9
  #rule(:comma) { spaces? >> str(',') >> spaces? }
13
- #rule(:digit) { match('[0-9]') }
14
-
15
- #rule(:number) {
16
- # (
17
- # str('-').maybe >> (
18
- # str('0') | (match('[1-9]') >> digit.repeat)
19
- # ) >> (
20
- # str('.') >> digit.repeat(1)
21
- # ).maybe >> (
22
- # match('[eE]') >> (str('+') | str('-')).maybe >> digit.repeat(1)
23
- # ).maybe
24
- # ).as(:number)
25
- #}
26
10
 
27
11
  #rule(:array) {
28
12
  # str('[') >> spaces? >>
@@ -46,31 +30,32 @@ describe 'sample JSON parser' do
46
30
 
47
31
  #rule(:attribute) { (entry | value).as(:attribute) }
48
32
 
49
- json == spaces? + value + spaces?
50
-
51
- value == string | number | object | array | btrue | bfalse | null
52
-
53
- btrue == `true`
54
- bfalse == `false`
55
- null == `null`
56
-
57
- # TODO: continue here with "string"
58
-
59
33
  #rule(:string) {
60
34
  # str('"') >> (
61
- # str('\\') >> any | str('"').absent? >> any
35
+ # #str('\\') >> any | str('"').absent? >> any
36
+ # #(str('\\') | str('"').absent?) >> any
37
+ # (str('\\') >> any | match('[^"]')
62
38
  # ).repeat.as(:string) >> str('"')
63
39
  #}
64
40
 
65
- #rule(:value) {
66
- # string | number |
67
- # object | array |
68
- # str('true').as(:true) | str('false').as(:false) |
69
- # str('null').as(:null)
70
- #}
41
+ json == spaces? + value + spaces?
42
+
43
+ spaces? == _(" \t") * 0
71
44
 
72
- #rule(:top) { spaces? >> value >> spaces? }
73
- #root(:top)
45
+ #value == string | number | object | array | btrue | bfalse | null
46
+ value == number | btrue | bfalse | null
47
+
48
+ digit == _("0-9")
49
+
50
+ number ==
51
+ `-` * -1 +
52
+ (`0` | (_("1-9") + digit * 0)) +
53
+ (`.` + digit * 1) * -1 +
54
+ (_("eE") + _("+-") * -1 + digit * 1) * -1
55
+
56
+ btrue == `true`
57
+ bfalse == `false`
58
+ null == `null`
74
59
  end
75
60
 
76
61
  it 'flips burgers' do
@@ -79,5 +64,23 @@ describe 'sample JSON parser' do
79
64
  puts JsonParser
80
65
  puts '-' * 80
81
66
  end
67
+
68
+ it 'parses "false"' do
69
+
70
+ pp JsonParser.parse("false")
71
+ JsonParser.parse("false")[2].should == true
72
+ end
73
+
74
+ it 'parses "13"' do
75
+
76
+ pp JsonParser.parse("13")
77
+ JsonParser.parse("13")[2].should == true
78
+ end
79
+
80
+ it 'parses "-12"' do
81
+
82
+ pp JsonParser.parse("-12")
83
+ JsonParser.parse("-12")[2].should == true
84
+ end
82
85
  end
83
86
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-16 00:00:00.000000000 Z
12
+ date: 2012-10-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -58,6 +58,7 @@ files:
58
58
  - spec/input_spec.rb
59
59
  - spec/parser_alternative_spec.rb
60
60
  - spec/parser_character_spec.rb
61
+ - spec/parser_lookahead_parser_spec.rb
61
62
  - spec/parser_non_terminal_spec.rb
62
63
  - spec/parser_repetition_spec.rb
63
64
  - spec/parser_sequence_spec.rb