redparse 0.8.4 → 1.0.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.
- checksums.yaml +4 -0
- data/COPYING.LGPL +503 -158
- data/History.txt +192 -0
- data/Makefile +9 -0
- data/README.txt +72 -39
- data/bin/redparse +108 -14
- data/lib/miniredparse.rb +1543 -0
- data/lib/redparse.rb +971 -105
- data/lib/redparse/ReduceWithsFor_RedParse_1_8.rb +17412 -0
- data/lib/redparse/ReduceWithsFor_RedParse_1_9.rb +17633 -0
- data/lib/redparse/babynodes.rb +17 -0
- data/lib/redparse/babyparser.rb +17 -0
- data/lib/redparse/cache.rb +290 -6
- data/lib/redparse/compile.rb +6 -97
- data/lib/redparse/decisiontree.rb +1 -1
- data/lib/redparse/float_accurate_to_s.rb +30 -6
- data/lib/redparse/generate.rb +18 -0
- data/lib/redparse/node.rb +415 -124
- data/lib/redparse/parse_tree_server.rb +20 -2
- data/lib/redparse/problemfiles.rb +1 -1
- data/lib/redparse/pthelper.rb +17 -31
- data/lib/redparse/reg_more_sugar.rb +1 -1
- data/lib/redparse/replacing/parse_tree.rb +30 -0
- data/lib/redparse/replacing/ripper.rb +20 -0
- data/lib/redparse/replacing/ruby_parser.rb +28 -0
- data/lib/redparse/ripper.rb +393 -0
- data/lib/redparse/ripper_sexp.rb +153 -0
- data/lib/redparse/stackableclasses.rb +113 -0
- data/lib/redparse/version.rb +18 -1
- data/redparse.gemspec +29 -9
- data/rplt.txt +31 -0
- data/test/data/hd_with_blank_string.rb +3 -0
- data/test/data/pt_known_output.rb +13273 -0
- data/test/data/wp.pp +0 -0
- data/test/generate_parse_tree_server_rc.rb +17 -0
- data/test/rp-locatetest.rb +2 -2
- data/test/test_1.9.rb +338 -35
- data/test/test_all.rb +22 -3
- data/test/test_part.rb +32 -0
- data/test/test_redparse.rb +396 -74
- data/test/test_xform_tree.rb +18 -0
- data/test/unparse_1.9_exceptions.txt +85 -0
- data/test/unparse_1.9_exceptions.txt.old +81 -0
- metadata +71 -46
- data/Rakefile +0 -35
data/lib/redparse/babynodes.rb
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
=begin
|
2
|
+
redparse - a ruby parser written in ruby
|
3
|
+
Copyright (C) 2008,2009, 2012, 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
=end
|
1
18
|
require 'pp'
|
2
19
|
require 'rubygems'
|
3
20
|
require 'rubylexer'
|
data/lib/redparse/babyparser.rb
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
=begin
|
2
|
+
redparse - a ruby parser written in ruby
|
3
|
+
Copyright (C) 2012, 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
=end
|
1
18
|
require 'pp'
|
2
19
|
require 'rubygems'
|
3
20
|
require 'rubylexer'
|
data/lib/redparse/cache.rb
CHANGED
@@ -1,7 +1,38 @@
|
|
1
|
+
=begin
|
2
|
+
redparse - a ruby parser written in ruby
|
3
|
+
Copyright (C) 2012, 2016 Caleb Clausen
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU Lesser General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
=end
|
1
18
|
require 'digest/sha2'
|
19
|
+
require 'fileutils'
|
20
|
+
begin
|
21
|
+
require 'etc'
|
22
|
+
rescue LoadError #ignore it
|
23
|
+
end
|
2
24
|
class RedParse
|
3
25
|
class Cache
|
4
|
-
def initialize
|
26
|
+
def initialize(is_file,name,*params)
|
27
|
+
divider=params.index(:/)
|
28
|
+
@input_id=params[0...divider]
|
29
|
+
@output_id=params[divider+1..-1]
|
30
|
+
@rubyversion=@input_id.pop
|
31
|
+
@name=name
|
32
|
+
@is_file=is_file
|
33
|
+
end
|
34
|
+
|
35
|
+
def old_initialize *params
|
5
36
|
@callersfile=Digest::SHA2.hexdigest params.join(',')
|
6
37
|
@homedir=find_home+"/.redparse/"
|
7
38
|
Dir.mkdir @homedir unless File.exist? @homedir
|
@@ -13,6 +44,8 @@ class RedParse
|
|
13
44
|
File.open(@homedir+"/parserdigest","wb"){|fd| fd.puts actual_digest } #update saved digest
|
14
45
|
end
|
15
46
|
retire_old_entries
|
47
|
+
rescue Errno::EACCES
|
48
|
+
#do nothing
|
16
49
|
end
|
17
50
|
|
18
51
|
def cachedir
|
@@ -76,7 +109,16 @@ class RedParse
|
|
76
109
|
# it should fallback to USERPROFILE and HOMEDRIVE + HOMEPATH (at
|
77
110
|
# least on Win32).
|
78
111
|
#(originally stolen from rubygems)
|
79
|
-
|
112
|
+
#before trying env variables, try getpwuid, since the environment
|
113
|
+
#might have been cleansed (eg by a cgi server) or altered (eg by
|
114
|
+
#rubygems tests).
|
115
|
+
def Cache.find_home
|
116
|
+
begin
|
117
|
+
return Etc.getpwuid.dir
|
118
|
+
rescue Exception
|
119
|
+
#do nothing
|
120
|
+
end
|
121
|
+
|
80
122
|
['HOME', 'USERPROFILE'].each do |homekey|
|
81
123
|
return ENV[homekey] if ENV[homekey]
|
82
124
|
end
|
@@ -95,6 +137,7 @@ class RedParse
|
|
95
137
|
end
|
96
138
|
end
|
97
139
|
end
|
140
|
+
def find_home; Cache.find_home end
|
98
141
|
private :find_home, :entry_files, :redparse_rb_hexdigest, :retire_old_entries, :max_size, :hexdigest_of_file
|
99
142
|
|
100
143
|
def hash_of_input input
|
@@ -105,7 +148,7 @@ class RedParse
|
|
105
148
|
end
|
106
149
|
end
|
107
150
|
|
108
|
-
def
|
151
|
+
def old_get input
|
109
152
|
hash=hash_of_input input
|
110
153
|
cachefile=cachedir+hash
|
111
154
|
if File.exist? cachefile
|
@@ -138,17 +181,17 @@ class RedParse
|
|
138
181
|
end
|
139
182
|
return result
|
140
183
|
end
|
141
|
-
rescue EOFError
|
184
|
+
rescue EOFError,Errno::EACCES
|
142
185
|
return nil
|
143
186
|
end
|
144
187
|
|
145
|
-
def
|
188
|
+
def old_put input,result
|
146
189
|
hash=hash_of_input input
|
147
190
|
File.open(cachedir+hash, "wb"){|fd|
|
148
191
|
begin
|
149
192
|
Thread.current["Marshal.ignore_sclass"]=true
|
150
193
|
Marshal.dump(result,fd)
|
151
|
-
rescue TypeError
|
194
|
+
rescue TypeError #dump failed
|
152
195
|
File.unlink cachedir+hash
|
153
196
|
begin
|
154
197
|
require 'ron'
|
@@ -168,5 +211,246 @@ class RedParse
|
|
168
211
|
warn "cache write failed for:\n#{result.inspect}"
|
169
212
|
File.unlink cachedir+hash
|
170
213
|
end
|
214
|
+
|
215
|
+
def get input,output_type="parsed"
|
216
|
+
output_type=@rubyversion.to_s+output_type
|
217
|
+
if @is_file
|
218
|
+
Cache.read_for_file(input,@name,@input_id,output_type,@output_id)
|
219
|
+
else
|
220
|
+
Cache.read_for_str(input,@input_id,output_type,@output_id)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def put input,result,output_type="parsed"
|
225
|
+
output_type=@rubyversion.to_s+output_type
|
226
|
+
if @is_file
|
227
|
+
Cache.write_for_file(input,@name,@input_id,output_type,@output_id,result)
|
228
|
+
else
|
229
|
+
Cache.write_for_str(input,@input_id,output_type,@output_id,result)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
CACHEDIRNAME="obj"
|
235
|
+
GLOBALCACHEDIRNAME=".ruby-"+CACHEDIRNAME
|
236
|
+
|
237
|
+
def Cache.get input,name,input_id,output_type,outputter_id
|
238
|
+
if String===input
|
239
|
+
read_for_str(input,input_id,output_type,outputter_id)
|
240
|
+
else
|
241
|
+
read_for_file(input,name,input_id,output_type,outputter_id)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def Cache.put input,name,input_id,output_type,outputter_id,result
|
246
|
+
if String===input
|
247
|
+
write_for_str(input,input_id,output_type,outputter_id,result)
|
248
|
+
else
|
249
|
+
write_for_file(input,name,input_id,output_type,outputter_id,result)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def Cache.read input,name,input_id,output_type,outputter_id
|
254
|
+
result=get input,name,input_id,output_type,outputter_id
|
255
|
+
return result if result
|
256
|
+
|
257
|
+
result=yield
|
258
|
+
put input,name,input_id,output_type,outputter_id,result
|
259
|
+
end
|
260
|
+
|
261
|
+
def Cache.cachename_for_file(name,output_type)
|
262
|
+
cache_fn=File.join(File.dirname(name),CACHEDIRNAME,File.basename(name))+"."+output_type
|
263
|
+
dir=File.dirname(cache_fn)
|
264
|
+
begin
|
265
|
+
Dir.mkdir dir unless File.exists?(dir)
|
266
|
+
raise unless File.writable?(dir)
|
267
|
+
rescue Exception #chosen dir is not writeable
|
268
|
+
cache_fn=File.join(find_home,GLOBALCACHEDIRNAME,name)+"."+output_type
|
269
|
+
FileUtils.mkdir_p( File.dirname( cache_fn ) )
|
270
|
+
end
|
271
|
+
return cache_fn
|
272
|
+
end
|
273
|
+
|
274
|
+
def Cache.cachename_for_str(str,options,output_type)
|
275
|
+
options=options.to_a.sort_by{|k,v| k}.map{|k,v| k+'='+v} if Hash===options
|
276
|
+
options=options.join(',') unless String===options
|
277
|
+
#options.gsub!('%n','%%n'); options.gsub!("\n",'%n')
|
278
|
+
#fail if /\n/===options
|
279
|
+
#str=options+"\n"+str
|
280
|
+
options=Digest::SHA2.hexdigest(options) if options.size>100
|
281
|
+
digest=Digest::SHA2.hexdigest(str)
|
282
|
+
cache_fn=File.join(find_home, GLOBALCACHEDIRNAME,"-e",options,digest)+"."+output_type
|
283
|
+
FileUtils.mkdir_p( File.dirname( cache_fn ) )
|
284
|
+
return cache_fn
|
285
|
+
end
|
286
|
+
|
287
|
+
HEADER_REX=/\A\n\#encoded\ with\ (ascii|Ron|Marshal)\n
|
288
|
+
\#(.*)\n
|
289
|
+
\#([0-9A-Fa-f]+)\n
|
290
|
+
\#([0-9A-Fa-f]+)\n
|
291
|
+
\#\s{0,9}([0-9]{1,9})\s{0,9}\n\z
|
292
|
+
/x
|
293
|
+
|
294
|
+
#encoder, options, inputhash, outputterhash, size
|
295
|
+
def Cache.read_trailer(f)
|
296
|
+
f.seek(-(9*3+2+1),IO::SEEK_END)
|
297
|
+
size=f.read[/\n\# *([0-9]+) *\n\z/,1].to_i
|
298
|
+
return if size.zero?
|
299
|
+
f.seek(-size,IO::SEEK_END)
|
300
|
+
buf=f.read
|
301
|
+
return unless result=buf.match(HEADER_REX)
|
302
|
+
result=result.to_a
|
303
|
+
result.shift
|
304
|
+
return result
|
305
|
+
end
|
306
|
+
|
307
|
+
def Cache.attempt_read(cache_fn,inputdigest,options,output_identity,want_file=false)
|
308
|
+
return if !File.exist? cache_fn
|
309
|
+
|
310
|
+
#warn "...reading from cache file #{cache_fn}"
|
311
|
+
#warn "...options=#{options.inspect}"
|
312
|
+
|
313
|
+
outid=Digest::SHA2.hexdigest output_identity.join(',')
|
314
|
+
|
315
|
+
cache_f=File.open(cache_fn,"rb")
|
316
|
+
pos=cache_f.pos
|
317
|
+
options=options.to_s
|
318
|
+
|
319
|
+
encoder,saved_options,saved_inputdigest,saved_outid=read_trailer cache_f
|
320
|
+
error=case
|
321
|
+
when !encoder; "trailer not found"
|
322
|
+
when saved_inputdigest!=inputdigest; "input changed"
|
323
|
+
when saved_outid!=outid; "outputter changed"
|
324
|
+
when saved_options!=options; "options changed from #{saved_options.inspect} to #{options.inspect}"
|
325
|
+
end
|
326
|
+
if error
|
327
|
+
#warn "...cache read failed because #{error}"
|
328
|
+
cache_f.close
|
329
|
+
cache_f=nil
|
330
|
+
return
|
331
|
+
end
|
332
|
+
|
333
|
+
case encoder
|
334
|
+
when 'ascii'
|
335
|
+
return cache_f if want_file
|
336
|
+
return cache_f.read
|
337
|
+
when 'Ron'
|
338
|
+
begin
|
339
|
+
require 'ron'
|
340
|
+
return Ron.load( cache_f.read )
|
341
|
+
rescue Exception=>e
|
342
|
+
warn "#{e.class}: #{e}"
|
343
|
+
warn "cache ron read failed for:#{cache_fn}"
|
344
|
+
return nil
|
345
|
+
end
|
346
|
+
when 'Marshal'
|
347
|
+
cache_f.pos=pos
|
348
|
+
begin
|
349
|
+
return Marshal.load( cache_f )
|
350
|
+
rescue Exception=>e
|
351
|
+
warn "#{e.class}: #{e}"
|
352
|
+
warn "cache read failed for:#{cache_fn}"
|
353
|
+
return nil
|
354
|
+
end
|
355
|
+
else
|
356
|
+
warn "unrecognized RedParse::Cache encoder type: #{encoder}"
|
357
|
+
return nil
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def Cache.attempt_write(cache_fn,inputdigest,options,output_identity,result)
|
362
|
+
#STDERR.write "...writing to cache file #{cache_fn}... "
|
363
|
+
|
364
|
+
if result.respond_to? :sysread
|
365
|
+
path=result.path
|
366
|
+
begin
|
367
|
+
FileUtils.move(path,cache_fn)
|
368
|
+
rescue Exception
|
369
|
+
FileUtils.copy(path,cache_fn)
|
370
|
+
end
|
371
|
+
encoder= "ascii"
|
372
|
+
#STDERR.puts 'file'
|
373
|
+
cache_f=File.open(cache_fn,"a")
|
374
|
+
else
|
375
|
+
cache_f=File.open(cache_fn,"wb")
|
376
|
+
|
377
|
+
if String===result
|
378
|
+
cache_f.write result
|
379
|
+
encoder= "ascii"
|
380
|
+
#STDERR.puts 'ascii'
|
381
|
+
else begin
|
382
|
+
Thread.current["Marshal.ignore_sclass"]=true
|
383
|
+
Marshal.dump(result,cache_f)
|
384
|
+
encoder= "Marshal"
|
385
|
+
#STDERR.puts 'Marshal'
|
386
|
+
rescue TypeError #dump failed
|
387
|
+
#STDERR.write "Marshal failed => "
|
388
|
+
cache_f.close
|
389
|
+
cache_f=File.open(cache_fn,"wb")
|
390
|
+
begin
|
391
|
+
require 'ron'
|
392
|
+
cache_f.write Ron.dump(result)
|
393
|
+
encoder='Ron'
|
394
|
+
#STDERR.puts "Ron"
|
395
|
+
rescue Exception
|
396
|
+
#STDERR.puts "Ron failed"
|
397
|
+
File.unlink(cache_fn)
|
398
|
+
return
|
399
|
+
end
|
400
|
+
ensure
|
401
|
+
Thread.current["Marshal.ignore_sclass"]=nil
|
402
|
+
end end
|
403
|
+
end
|
404
|
+
|
405
|
+
outid=Digest::SHA2.hexdigest output_identity.join(',')
|
406
|
+
trailer= "\n#encoded with #{encoder}\n##{options}\n##{inputdigest}\n##{outid}\n"
|
407
|
+
sz=trailer.size+2
|
408
|
+
szsz=sz.to_s.size
|
409
|
+
sz+=szsz
|
410
|
+
sz+=1 unless szsz==sz.to_s.size
|
411
|
+
trailer<< "##{sz}\n"
|
412
|
+
fail 'bad trailer size' unless trailer[/^\#([0-9]+)\n\Z/,1].to_i==trailer.size
|
413
|
+
cache_f.write trailer
|
414
|
+
|
415
|
+
return result
|
416
|
+
ensure
|
417
|
+
cache_f.close if cache_f
|
418
|
+
#STDERR.puts("...options=#{options.inspect}")
|
419
|
+
end
|
420
|
+
|
421
|
+
def Cache.read_for_file(input,name,options,output_type,output_identity,&if_missing)
|
422
|
+
name=File.expand_path(name)
|
423
|
+
inputdigest=Digest::SHA2.file(name).hexdigest
|
424
|
+
cache_fn=cachename_for_file name,output_type
|
425
|
+
result=attempt_read(cache_fn,inputdigest,options,output_identity,:want_file)
|
426
|
+
return result if result
|
427
|
+
|
428
|
+
if if_missing and result=if_missing.call
|
429
|
+
write_for_file(input,name,options,output_type,output_identity,result)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
def Cache.write_for_file(input,name,options,output_type,output_identity,result)
|
434
|
+
name=File.expand_path(name)
|
435
|
+
inputdigest=Digest::SHA2.file(name).hexdigest
|
436
|
+
cache_fn=cachename_for_file name,output_type
|
437
|
+
attempt_write(cache_fn,inputdigest,options,output_identity,result)
|
438
|
+
end
|
439
|
+
|
440
|
+
def Cache.read_for_str(input,options,output_type,output_identity,&if_missing)
|
441
|
+
inputdigest=Digest::SHA2.hexdigest(input)
|
442
|
+
cache_fn= cachename_for_str input,options,output_type
|
443
|
+
result=attempt_read(cache_fn,inputdigest,options,output_identity)
|
444
|
+
return result if result
|
445
|
+
|
446
|
+
if if_missing and result=if_missing.call
|
447
|
+
write_for_str(input,options,output_type,output_identity,result)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def Cache.write_for_str(input,options,output_type,output_identity,result)
|
452
|
+
inputdigest=Digest::SHA2.hexdigest(input)
|
453
|
+
cache_fn= cachename_for_str input,options,output_type
|
454
|
+
attempt_write(cache_fn,inputdigest,options,output_identity,result)
|
171
455
|
end
|
172
456
|
end
|
data/lib/redparse/compile.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
=begin
|
2
2
|
redparse - a ruby parser written in ruby
|
3
|
-
Copyright (C) 2008,2009 Caleb Clausen
|
3
|
+
Copyright (C) 2008,2009, 2012, 2016 Caleb Clausen
|
4
4
|
|
5
5
|
This program is free software: you can redistribute it and/or modify
|
6
6
|
it under the terms of the GNU Lesser General Public License as published by
|
@@ -35,6 +35,7 @@ require "redparse/node"
|
|
35
35
|
require "redparse/reg_more_sugar"
|
36
36
|
require "redparse/generate"
|
37
37
|
require "redparse/cache"
|
38
|
+
require "redparse/stackableclasses"
|
38
39
|
|
39
40
|
class RedParse
|
40
41
|
|
@@ -143,101 +144,8 @@ if defined? END_ATTACK
|
|
143
144
|
|
144
145
|
end
|
145
146
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#just the left side (the stack/lookahead matchers)
|
150
|
-
def LEFT
|
151
|
-
@rules.map{|r| r.left.subregs }.flatten
|
152
|
-
end
|
153
|
-
|
154
|
-
#remove lookahead and lookback decoration
|
155
|
-
def LEFT_NO_LOOKING
|
156
|
-
l=LEFT()
|
157
|
-
l.map!{|m|
|
158
|
-
case m #
|
159
|
-
when Reg::LookAhead,Reg::LookBack; m.subregs[0]
|
160
|
-
when Proc; []
|
161
|
-
else m #
|
162
|
-
end #
|
163
|
-
}
|
164
|
-
l
|
165
|
-
end
|
166
|
-
|
167
|
-
#all classes mentioned in rules, on left and right sides
|
168
|
-
def STACKABLE_CLASSES #
|
169
|
-
return @sc_result unless @sc_result.nil?
|
170
|
-
@sc_result=false
|
171
|
-
l=LEFT_NO_LOOKING()
|
172
|
-
l=l.map{|lm| sc_juice lm}.flatten.compact
|
173
|
-
r= @rules.map{|rr| rr.right }.grep(Class) #classes in productions
|
174
|
-
result=l+r
|
175
|
-
@sc_result=result.grep(Class).uniq
|
176
|
-
fail if @sc_result.empty?
|
177
|
-
return @sc_result
|
178
|
-
end
|
147
|
+
include RedParse::StackableClasses
|
179
148
|
|
180
|
-
def juice(m)
|
181
|
-
case m #
|
182
|
-
when Class;
|
183
|
-
return [m] unless @subclasses_of
|
184
|
-
result=[m] # and subclasses too
|
185
|
-
i=0
|
186
|
-
while item=result[i]
|
187
|
-
#p item
|
188
|
-
result.concat @subclasses_of[item]
|
189
|
-
i += 1
|
190
|
-
end
|
191
|
-
result
|
192
|
-
when String,Regexp; juice(RedParse.KW(m))
|
193
|
-
when Reg::And; m.subregs.map{|x| juice(x).flatten.compact}.inject{|sum,rr| sum&rr}
|
194
|
-
when Reg::Or; m.subregs.map( &method(:juice) )
|
195
|
-
when Reg::Not;
|
196
|
-
m=m.subregs[0]
|
197
|
-
if Class===m or (Reg::Or===m and
|
198
|
-
m.subregs.inject{|sum,x| sum && (Class===x) })
|
199
|
-
j=juice(m)
|
200
|
-
STACKABLE_CLASSES()-j.flatten.compact rescue j
|
201
|
-
else
|
202
|
-
STACKABLE_CLASSES()
|
203
|
-
end
|
204
|
-
else STACKABLE_CLASSES()
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def sc_juice(m)
|
209
|
-
case m #
|
210
|
-
when Class; [m]
|
211
|
-
when String,Regexp; juice(RedParse.KW(m))
|
212
|
-
# when String,Regexp; [KeywordToken]
|
213
|
-
when Reg::And; m.subregs.map{|x| sc_juice(x)}.compact.map{|x| x.flatten.compact}.inject{|sum,rr| sum&rr }
|
214
|
-
when Reg::Or; m.subregs.map( &method(:sc_juice) )
|
215
|
-
when Reg::Not; sc_juice(m.subregs[0])
|
216
|
-
when Reg::LookAhead, Reg::LookBack; sc_juice(m.subregs[0])
|
217
|
-
else []
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def LOOKAHEAD_CLASSES rule
|
222
|
-
last=rule.left.subregs.last
|
223
|
-
return STACKABLE_CLASSES() unless Reg::LookAhead===last
|
224
|
-
la= last.subregs[0]
|
225
|
-
return juice(la).flatten.compact
|
226
|
-
end
|
227
|
-
#
|
228
|
-
def TOS_CLASSES rule
|
229
|
-
i=-1
|
230
|
-
mats=rule.left.subregs
|
231
|
-
m=mats[i]
|
232
|
-
m=mats[i-=1] if Reg::LookAhead===m || Proc===m
|
233
|
-
result=[]
|
234
|
-
while Reg::Repeat===m and m.times.min.zero?
|
235
|
-
result<<juice(m.subregs[0])
|
236
|
-
m=mats[i-=1]
|
237
|
-
end
|
238
|
-
return (result+juice(m)).flatten.compact
|
239
|
-
end
|
240
|
-
|
241
149
|
def [](i)
|
242
150
|
@rules[i]
|
243
151
|
end
|
@@ -1386,9 +1294,10 @@ end
|
|
1386
1294
|
|
1387
1295
|
states=all_states
|
1388
1296
|
# @rules=expanded_RULES
|
1389
|
-
@inputs=nil #Marshal no like it
|
1390
1297
|
|
1298
|
+
false && \
|
1391
1299
|
begin
|
1300
|
+
@inputs=nil #Marshal no like it
|
1392
1301
|
p :dumping
|
1393
1302
|
Marshal.dump(self,f=open("cached_parse_tables.drb","wb"))
|
1394
1303
|
p :dump_done!
|
@@ -1399,7 +1308,7 @@ end
|
|
1399
1308
|
@inputs=enumerate_exemplars
|
1400
1309
|
end
|
1401
1310
|
end
|
1402
|
-
f.close
|
1311
|
+
f.close if f
|
1403
1312
|
|
1404
1313
|
#look for unused dotted rules and actions
|
1405
1314
|
#also states with drs past the end
|