neg 0.2.0 → 0.3.0

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/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