llip 0.1.0 → 0.2.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.
@@ -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