llip 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,13 @@
1
+ == 0.2.0 / 2007-07-17
2
+
3
+ * 2 major enhacement
4
+ * added the '[a-Z]' syntax to regular expression support
5
+ * added the possibility to define two token in which final states of the first are internal states of the second
6
+ * 1 minor enhacement
7
+ * spec loading fixed
8
+ * added a simple REPL based on Ariteval
9
+ * aliased :recursive with :iterative because it's more intuitive
10
+
1
11
  == 0.1.0 / 2007-06-09
2
12
 
3
13
  * 1 major enhancement
@@ -5,6 +5,7 @@ README.txt
5
5
  Rakefile
6
6
  examples/ariteval
7
7
  examples/ariteval/ariteval.rb
8
+ examples/ariteval/ariteval_repl.rb
8
9
  examples/ariteval/evaluator.rb
9
10
  examples/ariteval/exp.rb
10
11
  lib/llip
@@ -1,5 +1,5 @@
1
- require 'parser'
2
- require 'evaluator'
1
+ require File.dirname(__FILE__) + '/evaluator'
2
+ require File.dirname(__FILE__) + '/exp'
3
3
 
4
4
  # It's a simple arithmetical evaluator. It's able to parse expressions like these:
5
5
  # * ( a = 3 * 2 ) - ( 24 + a ),
@@ -25,7 +25,7 @@ require 'evaluator'
25
25
  # FACTOR ::= ( EXP )
26
26
  # }
27
27
  #
28
- class Ariteval < Parser
28
+ class Ariteval < LLIP::Parser
29
29
 
30
30
  def initialize
31
31
  super
@@ -39,8 +39,7 @@ class Ariteval < Parser
39
39
 
40
40
  # tokens definitions
41
41
 
42
- numbers = ("0".."9").to_a.join("|")
43
- token :number, "(#{numbers})+ *"
42
+ token :number, "[0-9]+ *"
44
43
 
45
44
  token :plus, '\+ *'
46
45
 
@@ -54,19 +53,27 @@ class Ariteval < Parser
54
53
 
55
54
  token ")".to_sym, '\) *'
56
55
 
57
- identifiers = (("a".."z").to_a + ("A".."Z").to_a).join("|")
58
- token :ident, "(#{identifiers}) *"
56
+ token :ident, "[a-Z] *"
59
57
 
60
58
  token :assign, "= *"
61
59
 
60
+ token :space, " "
61
+
62
62
  # production definitions
63
63
 
64
64
  lookahead(true)
65
65
 
66
66
  scope :exp
67
67
 
68
- production(:exp,:recursive) do |prod|
69
- prod.default { |scanner,parser| parser.parse_term }
68
+ production(:exp,:iterative) do |prod|
69
+ prod.default do |scanner,parser|
70
+ #this is needed to trim spaces from the beginning of the string to parse
71
+ while scanner.current == :space
72
+ scanner.next
73
+ end
74
+
75
+ parser.parse_term
76
+ end
70
77
 
71
78
  prod.token(:plus) do |term_seq,scanner,parser|
72
79
  scanner.next
@@ -79,10 +86,9 @@ class Ariteval < Parser
79
86
  next_term = parser.parse_term
80
87
  MinusExp.new(term_seq,next_term)
81
88
  end
82
-
83
89
  end
84
90
 
85
- production(:term,:recursive) do |prod|
91
+ production(:term,:iterative) do |prod|
86
92
  prod.default { |scanner,parser| parser.parse_factor }
87
93
 
88
94
  prod.token(:mul) do |factor_seq,scanner,parser|
@@ -129,4 +135,4 @@ class Ariteval < Parser
129
135
 
130
136
  end
131
137
 
132
- end
138
+ end
@@ -0,0 +1,24 @@
1
+ #! /usr/bin/ruby
2
+
3
+ unless Object.const_defined? :LLIP
4
+ require File.join(File.dirname(__FILE__), "/../../lib/llip")
5
+ end
6
+
7
+ require File.dirname(__FILE__) + "/ariteval"
8
+
9
+ Signal.trap("INT") do
10
+ puts "Goodbye!"
11
+ exit(0)
12
+ end
13
+
14
+ parser = Ariteval.new
15
+
16
+ loop do
17
+ print "> "
18
+ string = readline.strip
19
+ begin
20
+ puts "=> " + parser.evaluate(string).to_s
21
+ rescue Exception => er
22
+ puts "Exception raised: \"#{er.message}\""
23
+ end
24
+ end
@@ -39,6 +39,7 @@ class Evaluator
39
39
  end
40
40
 
41
41
  def visit_ident_exp(exp)
42
+ raise "Unknown variable \"#{exp.value}\"" unless ident_table.has_key?(exp.value)
42
43
  @result = ident_table[exp.value]
43
44
  end
44
45
 
@@ -1,8 +1,6 @@
1
- require 'visitable'
2
-
3
1
  class NumExp
4
2
 
5
- include Visitable
3
+ include LLIP::Visitable
6
4
 
7
5
  attr_reader :value
8
6
 
@@ -16,7 +14,7 @@ class NumExp
16
14
  end
17
15
 
18
16
  class IdentExp
19
- include Visitable
17
+ include LLIP::Visitable
20
18
 
21
19
  attr_reader :value
22
20
 
@@ -31,7 +29,7 @@ end
31
29
 
32
30
  class AssignIdentExp
33
31
 
34
- include Visitable
32
+ include LLIP::Visitable
35
33
 
36
34
  attr_reader :name
37
35
  attr_reader :value
@@ -49,7 +47,7 @@ end
49
47
 
50
48
  class OpExp
51
49
 
52
- include Visitable
50
+ include LLIP::Visitable
53
51
 
54
52
  attr_reader :op
55
53
  attr_reader :left
@@ -1,6 +1,7 @@
1
1
  # :include: README.txt
2
2
  module LLIP
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
 
6
6
  require File.dirname(__FILE__) + '/llip/parser'
7
+ require File.dirname(__FILE__) + '/llip/visitable'
@@ -83,7 +83,7 @@ module LLIP
83
83
  @parser = Class.new(AbstractParser)
84
84
  @scanner = Class.new(RegexpAbstractScanner)
85
85
 
86
- @regexp_scanner = RegexpScanner.new
86
+ @regexp_scanner = Buffer.new(RegexpScanner.new)
87
87
  @regexp_parser = RegexpParser.new
88
88
 
89
89
  @lookahead = false
@@ -27,8 +27,8 @@ module LLIP
27
27
  # They are specified through ProductionSpecification#token.
28
28
  attr_reader :tokens
29
29
 
30
- # The mode of the production. It can be :single or :recursive.
31
- attr_accessor :mode
30
+ # The mode of the production. It can be :single or :recursive (:iterative is just an alias for :recursive).
31
+ attr_reader :mode
32
32
 
33
33
  # This attribute specifies if the production should raise an exception if the current token hasn't been recognized.
34
34
  # It's important only for :single productions.
@@ -75,5 +75,13 @@ module LLIP
75
75
  @default
76
76
  end
77
77
 
78
+ # see ProductionSpecification#mode
79
+ def mode=(value)
80
+ if value == :iterative
81
+ value = :recursive
82
+ end
83
+ @mode = value
84
+ end
85
+
78
86
  end
79
87
  end
@@ -6,11 +6,11 @@ module LLIP
6
6
  #
7
7
  # === Grammar
8
8
  #
9
- # VN = { EXP , ELEMENT}
9
+ # VN = { EXP , ELEMENT , META}
10
10
  #
11
11
  # char = every charachter
12
12
  #
13
- # symb = { ( , ) , . , * , + , \ , |}
13
+ # symb = { ( , ) , . , * , + , \ , | , [ , ] }
14
14
  #
15
15
  # VT = char U symb
16
16
  #
@@ -24,7 +24,12 @@ module LLIP
24
24
  # META -> ELEMENT+
25
25
  # META -> ELEMENT
26
26
  # ELEMENT -> char or . or \symb
27
+ # ELEMENT -> [CLASS]
27
28
  # ELEMENT -> (EXP)
29
+ # CLASS -> char
30
+ # CLASS -> char CLASS
31
+ # CLASS -> char - char
32
+ # CLASS -> char - char CLASS
28
33
  # }
29
34
  #
30
35
  # or in EBNF format
@@ -32,7 +37,8 @@ module LLIP
32
37
  # P' = {
33
38
  # EXP ::= META{[|]EXP}
34
39
  # META ::= ELEMENT[* or +]
35
- # ELEMENT ::= char or . or \symb or (EXP)
40
+ # ELEMENT ::= char or . or \symb or (EXP) or [CLASS]
41
+ # CLASS ::= char{ - char or - char char or char}
36
42
  # }
37
43
  #
38
44
  class LLIP::RegexpParser < LLIP::AbstractParser
@@ -67,7 +73,6 @@ module LLIP
67
73
  end
68
74
 
69
75
  p.token("|") do |result,scanner,parser|
70
- result
71
76
  scanner.next
72
77
  parser[:last] = result
73
78
  parser.parse_meta.last
@@ -88,6 +93,11 @@ module LLIP
88
93
  result
89
94
  end
90
95
 
96
+ p.token("[") do |result,scanner,parser|
97
+ parser.parse_meta
98
+ result
99
+ end
100
+
91
101
  p.token("\\") do |result,scanner,parser|
92
102
  parser.parse_meta
93
103
  result
@@ -171,6 +181,55 @@ module LLIP
171
181
  parser[:last] = first_state.last
172
182
  first_state.keys
173
183
  end
184
+
185
+ p.token("[") do |result, scanner, parser|
186
+ scanner.next
187
+
188
+ chars = parser.parse_class
189
+ unless scanner.current == "]"
190
+ raise "Every '[' must be followed by a ']'"
191
+ end
192
+ scanner.next
193
+
194
+ state = parser[:regexp].add_state
195
+ chars.each do |char|
196
+ parser[:last].each { |s| s[char] = state }
197
+ end
198
+
199
+ parser[:last] = [state]
200
+ chars
201
+ end
202
+ end
203
+
204
+ production :class, :recursive do |prod|
205
+ prod.default do |scanner,parser|
206
+ []
207
+ end
208
+
209
+ prod.token(:char) do |result, scanner, parser|
210
+ result << scanner.current.value
211
+ scanner.next
212
+ result
213
+ end
214
+
215
+ prod.token(:char,"-",:char) do |result, scanner, parser|
216
+ first_char = scanner.current.value
217
+ scanner.next
218
+ last_char = scanner.next.value
219
+
220
+ block = lambda do |char|
221
+ result << char
222
+ end
223
+
224
+ if first_char =~ /[a-z]/ and last_char =~ /[A-Z]/
225
+ (first_char.."z").to_a.each(&block)
226
+ ("A"..last_char).to_a.each(&block)
227
+ else
228
+ (first_char..last_char).to_a.each(&block)
229
+ end
230
+ scanner.next
231
+ result
232
+ end
174
233
  end
175
234
 
176
235
  def add_char(parser, scanner, char=scanner.current.value)
@@ -15,7 +15,7 @@ module LLIP
15
15
 
16
16
  add_regexp(CHAR)
17
17
 
18
- # It represents the regular expression '(.|*|+|\(|\)|\\|\|)' so it matches the chars: . * + ( ) \ |
18
+ # It represents the regular expression '(.|*|+|\(|\)|\\|\|\[|\]-)' so it matches the chars: . * + ( ) \ | [ ] -
19
19
  SYMBOL = LLIP::RegexpSpecification.new(:symbol)
20
20
 
21
21
  SYMBOL.add_state
@@ -27,6 +27,8 @@ module LLIP
27
27
  SYMBOL.init[')'] = final
28
28
  SYMBOL.init['\\'] = final
29
29
  SYMBOL.init['|'] = final
30
+ SYMBOL.init['['] = final
31
+ SYMBOL.init[']'] = final
30
32
 
31
33
  add_regexp(SYMBOL)
32
34
  end
@@ -177,8 +177,14 @@ module LLIP
177
177
  examined[new_first] ||= state
178
178
  examined[new_second] ||= state
179
179
 
180
- if new_first.final? or new_second.final?
180
+ if new_first.final? and new_second.final?
181
181
  raise "It's impossible to mix two regexp with final states in common."
182
+ elsif new_first.final?
183
+ state.regexp = new_first.regexp
184
+ state.final = true
185
+ elsif new_second.final?
186
+ state.regexp = new_second.regexp
187
+ state.final = true
182
188
  end
183
189
  mix_accessor(new_first,new_second,regexp,state,examined)
184
190
  end
@@ -80,6 +80,10 @@ describe "An Ariteval should be able to parse" do
80
80
  it "'( a = 3 * 2 ) - ( 24 + a )'" do
81
81
  @parser.parse('( a = 3 * 2 ) - ( 24 + a )').to_s.should == "( ( a = ( 3 * 2 ) ) - ( 24 + a ) )"
82
82
  end
83
+
84
+ it "' 3 + 2'" do
85
+ @parser.parse(' 3 + 2').to_s.should == "( 3 + 2 )"
86
+ end
83
87
  end
84
88
 
85
89
  describe "An Ariteval shouldn't be able to parse" do
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'ariteval'
2
3
  require 'evaluator'
3
- require 'buffer'
4
4
 
5
5
 
6
6
  describe 'An Evaluator' do
@@ -61,26 +61,26 @@ describe "An Evaluator should be able to eval" do
61
61
  expression = "3 * (4 - 2) + 5*(4/2)/(3-2)"
62
62
 
63
63
  exp = PlusExp.new(
64
- MulExp.new(
65
- NumExp.new(3),
66
- MinusExp.new(
67
- NumExp.new(4),
68
- NumExp.new(2)
69
- )
70
- ),
71
- DivExp.new(
72
- MulExp.new(
73
- NumExp.new(5),
74
- DivExp.new(
75
- NumExp.new(4),
76
- NumExp.new(2)
77
- )
78
- ),
79
- DivExp.new(
80
- NumExp.new(3),
81
- NumExp.new(2)
82
- )
83
- )
64
+ MulExp.new(
65
+ NumExp.new(3),
66
+ MinusExp.new(
67
+ NumExp.new(4),
68
+ NumExp.new(2)
69
+ )
70
+ ),
71
+ DivExp.new(
72
+ MulExp.new(
73
+ NumExp.new(5),
74
+ DivExp.new(
75
+ NumExp.new(4),
76
+ NumExp.new(2)
77
+ )
78
+ ),
79
+ DivExp.new(
80
+ NumExp.new(3),
81
+ NumExp.new(2)
82
+ )
83
+ )
84
84
  )
85
85
 
86
86
  exp.accept(@eval)
@@ -103,4 +103,8 @@ describe "An Evaluator should be able to eval" do
103
103
  @parser.parse("a").accept(@eval)
104
104
  @eval.result.should == @eval.ident_table["a"]
105
105
  end
106
+
107
+ it "an IdentExp with an unknown name" do
108
+ lambda { @parser.parse("a").accept(@eval) }.should raise_error
109
+ end
106
110
  end
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'abstract_parser'
3
2
 
4
3
  describe "A class descending from AbstractParser" do
5
4
 
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'abstract_scanner'
3
2
  require 'stringio'
4
3
 
5
4
  describe "An AbstractScanner" do
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'llip_error'
3
2
 
4
3
  describe "An LLIPError" do
5
4
 
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'parser'
3
2
  require 'stringio'
4
3
 
5
4
  describe "A class that descend from Parser" do
@@ -38,7 +37,8 @@ describe "A class that descend from Parser" do
38
37
  @class.should respond_to(:regexp_scanner)
39
38
 
40
39
  @class.regexp_parser.should be_kind_of(RegexpParser)
41
- @class.regexp_scanner.should be_kind_of(RegexpScanner)
40
+ @class.regexp_scanner.should be_kind_of(Buffer)
41
+ @class.regexp_scanner.scanner.should be_kind_of(RegexpScanner)
42
42
  end
43
43
 
44
44
  it "should have a token method which parse a regexp and calls :add_regexp to the scanner" do
@@ -135,7 +135,7 @@ describe "The instance of a class descending from Parser with a simple grammar s
135
135
  @instance = @class.new
136
136
 
137
137
  @class.token(:plus,"\\+")
138
- @class.token(:number,("0".."9").to_a.join("|"))
138
+ @class.token(:number,"[0-9]")
139
139
 
140
140
  @class.scope(:exp)
141
141
 
@@ -137,12 +137,13 @@ describe "A ProductionCompiler" do
137
137
 
138
138
  @production = mock "Production"
139
139
  @production.should_receive(:name).and_return(:fake)
140
- @production.should_receive(:tokens).and_return({ [:look,"3"] => nil, [:look,"1"] => nil, :look => nil})
140
+ @production.should_receive(:tokens).and_return({[:look,"3","2"] => nil, :look => nil, [:look,"1"] => nil, [:look, "2"] => nil })
141
141
  @production.should_receive(:raise_on_error).and_return(true)
142
142
 
143
143
  @compiler.should_receive(:start).with(:fake)
144
- @compiler.should_receive(:token).with([:look,"3"])
144
+ @compiler.should_receive(:token).with([:look,"3","2"])
145
145
  @compiler.should_receive(:token).with([:look,"1"])
146
+ @compiler.should_receive(:token).with([:look,"2"])
146
147
  @compiler.should_receive(:token).with(:look)
147
148
  @compiler.should_receive(:end).with(true)
148
149
 
@@ -156,6 +157,14 @@ describe "A ProductionCompiler" do
156
157
  @production.should_receive(:tokens).and_return({ [:look,"1"] => nil, [:look,"3","2"] => nil, :everything => nil, :look => nil})
157
158
 
158
159
  @compiler.sort_production(@production).should == [[:look,"3","2"],[:look,"1"], :look, :everything]
160
+
161
+ @production = mock "Production"
162
+ tokens = mock "Tokens"
163
+ tokens.should_receive(:keys).twice.and_return([[:look,"3","2"],[:look,"1"]])
164
+ tokens.should_receive(:has_key?).twice.with(:look).and_return(false)
165
+ @production.should_receive(:tokens).and_return(tokens)
166
+
167
+ @compiler.sort_production(@production).should == [[:look,"3","2"],[:look,"1"]]
159
168
  end
160
169
  end
161
170
 
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'production_specification'
3
2
 
4
3
  describe "A ProductionSpecification" do
5
4
 
@@ -72,4 +71,9 @@ describe "A ProductionSpecification" do
72
71
  @production.raise_on_error=false
73
72
  @production.raise_on_error.should == false
74
73
  end
74
+
75
+ it "should alias :recursive with :iterative" do
76
+ @production.mode = :iterative
77
+ @production.mode.should == :recursive
78
+ end
75
79
  end
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'regexp_abstract_scanner'
3
2
 
4
3
  describe "A class descending from RegexpAbstractScanner" do
5
4
 
@@ -1,14 +1,11 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'regexp_parser'
3
- require 'regexp_specification'
4
- require 'token'
5
2
 
6
3
  module RegexpMockScannerBuilder
7
4
 
8
5
  def mock_scanner(*tokens)
9
6
  @scanner = mock "Scanner"
10
7
  tokens.map! do |t|
11
- if t =~ /[\.\+\*\|\(\)\\]/
8
+ if t =~ /[\.\+\*\|\(\)\\\-\[\]]/
12
9
  Token.new(:symbol,t)
13
10
  else
14
11
  Token.new(:char,t)
@@ -19,7 +16,7 @@ module RegexpMockScannerBuilder
19
16
  t = nil
20
17
  @scanner.should_receive(:next).exactly(tokens.size).and_return { t = @tokens.shift }
21
18
  @scanner.should_receive(:current).any_number_of_times.and_return { t }
22
- @scanner
19
+ Buffer.new(@scanner)
23
20
  end
24
21
 
25
22
  end
@@ -245,6 +242,85 @@ describe "A RegexpParser should parse" do
245
242
  regexp.init['a']['c'].final?.should == false
246
243
  regexp.init['a']['c']['e'].final?.should == false
247
244
  end
245
+
246
+ it "[a-zD]" do
247
+ @scanner = mock_scanner("[","a","-","z","D","]")
248
+ regexp = @parser.parse(@scanner)
249
+
250
+ keys = regexp.init.keys
251
+ expected_keys = ("a".."z").to_a + ["D"]
252
+ keys.sort!
253
+ expected_keys.sort!
254
+ keys.should == expected_keys
255
+ keys.each do |key|
256
+ regexp[key].should be_final
257
+ end
258
+ end
259
+
260
+ it "[a-Z]" do
261
+ @scanner = mock_scanner("[","a","-","Z","]")
262
+ regexp = @parser.parse(@scanner)
263
+
264
+ keys = regexp.init.keys
265
+ expected_keys = ("a".."z").to_a + ("A".."Z").to_a
266
+ keys.sort!
267
+ expected_keys.sort!
268
+ keys.should == expected_keys
269
+ keys.each do |key|
270
+ regexp[key].should be_final
271
+ end
272
+ end
273
+
274
+
275
+ it "a[bc]+d" do
276
+ @scanner = mock_scanner("a","[","b","c","]","+","d")
277
+ regexp = @parser.parse(@scanner)
278
+
279
+ regexp.init['a'].keys.should == ['b','c']
280
+
281
+ regexp['a']['b'].keys.should == ['b','c','d']
282
+ regexp['a']['c'].keys.should == ['b','c','d']
283
+
284
+ regexp.init['a']['b']['d'].should be_final
285
+ regexp.init['a']['c']['d'].should be_final
286
+
287
+ regexp.init['a'].should_not == regexp.init['a']['b']
288
+ regexp.init['a'].should_not == regexp.init['a']['c']
289
+
290
+ regexp.init['a']['b']['b'].should == regexp.init['a']['b']
291
+ regexp.init['a']['c']['b'].should == regexp.init['a']['b']
292
+ regexp.init['a']['b']['c'].should == regexp['a']['c']
293
+
294
+ regexp['a']['b'].final?.should == false
295
+ regexp.init['a']['c'].final?.should == false
296
+ regexp.init['a']['c'].final?.should == false
297
+ end
298
+
299
+
300
+ it "a[bc]*d" do
301
+ @scanner = mock_scanner("a","[","b","c","]","*","d")
302
+ regexp = @parser.parse(@scanner)
303
+
304
+ regexp.init['a'].keys.should == ['b','c','d']
305
+ regexp['a']['d'].should be_final
306
+
307
+ regexp['a']['b'].keys.should == ['b','c','d']
308
+ regexp['a']['c'].keys.should == ['b','c','d']
309
+
310
+ regexp.init['a']['b']['d'].should be_final
311
+ regexp.init['a']['c']['d'].should be_final
312
+
313
+ regexp.init['a'].should == regexp.init['a']['b']
314
+ regexp.init['a'].should == regexp.init['a']['c']
315
+
316
+ regexp.init['a']['b']['b'].should == regexp.init['a']['b']
317
+ regexp.init['a']['c']['b'].should == regexp.init['a']['b']
318
+ regexp.init['a']['b']['c'].should == regexp['a']['c']
319
+
320
+ regexp['a']['b'].final?.should == false
321
+ regexp.init['a']['c'].final?.should == false
322
+ regexp.init['a']['c'].final?.should == false
323
+ end
248
324
 
249
325
  end
250
326
 
@@ -261,5 +337,10 @@ describe "A RegexpParser should not parse" do
261
337
  @scanner = mock_scanner("a","(","b","c","d","e","f")
262
338
  lambda { @parser.parse(@scanner) }.should raise_error(RuntimeError)
263
339
  end
340
+
341
+ it "a[cdef" do
342
+ @scanner = mock_scanner("a","[","b","c","d","e","f")
343
+ lambda { @parser.parse(@scanner) }.should raise_error(RuntimeError)
344
+ end
264
345
 
265
346
  end
@@ -1,6 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'regexp_scanner'
3
- require 'token'
4
2
  require 'stringio'
5
3
 
6
4
  describe "A RegexpScanner should scan" do
@@ -37,4 +35,16 @@ describe "A RegexpScanner should scan" do
37
35
  @scanner.next.should == :symbol
38
36
  @scanner.next.should be_nil
39
37
  end
38
+
39
+ it "'[a-zA-Z]'" do
40
+ @scanner.scan('[a-zA-Z]')
41
+ @scanner.next.should == :symbol
42
+ @scanner.next.should == 'a'
43
+ @scanner.next.should == '-'
44
+ @scanner.next.should == 'z'
45
+ @scanner.next.should == 'A'
46
+ @scanner.next.should == '-'
47
+ @scanner.next.should == 'Z'
48
+ @scanner.next.should == :symbol
49
+ end
40
50
  end
@@ -1,5 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require 'regexp_specification'
3
2
 
4
3
  describe "A RegexpSpecification" do
5
4
 
@@ -637,7 +636,7 @@ describe "The :mix method of the RegexpSpecification class" do
637
636
  second['a'].error.should == s3
638
637
  end
639
638
 
640
- it "should raise if trying to mix: 'ab' and 'abc'" do
639
+ it "should be able to mix: 'ab' and 'abc'" do
641
640
  r1 = RegexpSpecification.new("first")
642
641
  r2 = RegexpSpecification.new("second")
643
642
 
@@ -654,8 +653,13 @@ describe "The :mix method of the RegexpSpecification class" do
654
653
  s4['a'] = s5
655
654
  s5['b'] = s6
656
655
  s6['c'] = s7
657
-
658
- lambda { RegexpSpecification.mix(r1,r2) }.should raise_error(RuntimeError)
656
+
657
+ result = RegexpSpecification.mix(r1,r2)
658
+ result.name.should == :"mix between 'first' and 'second'"
659
+ result['a']['b'].should be_final
660
+ result['a']['b'].regexp.should == r1
661
+ result['a']['b']['c'].should be_final
662
+ result['a']['b']['c'].regexp.should == r2
659
663
  end
660
664
 
661
665
  it "should be able to mix: '(a|b)c' and '(b|e)d'" do
@@ -1,10 +1,12 @@
1
- require 'rubygems'
2
- require 'spec'
1
+ unless Object.const_defined? :LLIP
2
+ $:.unshift(File.join(File.dirname(__FILE__), "/../lib/llip"))
3
3
 
4
- $:.unshift(File.join(File.dirname(__FILE__), "/../lib/llip"))
4
+ require File.join(File.dirname(__FILE__), "/../lib/llip")
5
5
 
6
- require 'llip'
6
+ include LLIP
7
7
 
8
- include LLIP
8
+ require 'rubygems'
9
+ require 'spec'
9
10
 
10
- $: << File.dirname(__FILE__) + "/../examples/ariteval"
11
+ $: << File.dirname(__FILE__) + "/../examples/ariteval"
12
+ end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: llip
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-06-09 00:00:00 +02:00
6
+ version: 0.2.0
7
+ date: 2007-07-17 00:00:00 +02:00
8
8
  summary: LLIP is a tool to geneate a LL(k) parser.
9
9
  require_paths:
10
10
  - lib
@@ -36,6 +36,7 @@ files:
36
36
  - Rakefile
37
37
  - examples/ariteval
38
38
  - examples/ariteval/ariteval.rb
39
+ - examples/ariteval/ariteval_repl.rb
39
40
  - examples/ariteval/evaluator.rb
40
41
  - examples/ariteval/exp.rb
41
42
  - lib/llip