root/misc/STD_red/STD_red_run

Revision 22332, 4.7 kB (checked in by putter, 4 months ago)

[STD_red] First rough draft of a dump format for Common Lisp.

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1#!/usr/bin/env ruby
2# encoding: utf-8
3
4RUBY_VERSION =~ /\A(1\.9|2\.)/ or raise "#{$0} needs ruby 1.9.  See README."
5
6
7class STDRedRun
8  def print_usage_and_exit(msg=nil,code=2)
9    msg += "\n\n" if msg
10    msg ||= ""
11    STDERR.print <<END
12#{msg}#{$0} [-q] [--format=FORMAT] [ --start=RULE ] [ FILENAME | -e CODE ]
13
14If the environment variable STD_RED_CACHEDIR is set, output will be
15saved there, and used in preference to reparsing, when the same code
16is seen again.  -e CODE is not cached.  And when std.rb is changed,
17previous cache entries are ignored.
18
19FORMAT
20 p5a    # Dump format for perl5.
21 cl     # Dump format for Common Lisp.
22 yaml   # depreciated
23
24Other arguments:
25
26 --error-message=MSG
27 What to say when the parse fails.
28
29 --at=POS
30 Start parsing at position POS, instead of at 0.
31 Implies that a partial parse is ok.
32 A speculative feature provided to aid the development of other
33 parsers, by permitting them to delegate some parsing tasks.
34
35END
36    exit(code)
37  end
38
39  def main
40    start = '_UNIT'; at = 0
41    quiet = format = false
42    code = nil
43    error_message = ""
44    if ARGV.empty?
45      print "\nRun #{$0} --help  to get help.\n";
46      $:.push(File.dirname($0))
47      require 'std'
48      Repl.new.parser_rule
49      exit(0)
50    end
51    if ARGV.size == 1 and ARGV[0] == '--help'
52      print_usage_and_exit(nil,0)
53    end
54    if m = ARGV[0].match(/--error-message=(.+)/)
55      ARGV.shift
56      error_message = m[1]+"\n"
57    end
58    if ARGV[0] == '-q'
59      ARGV.shift
60      quiet = true
61    end
62    if m = ARGV[0].match(/--format=(\w+)/)
63      ARGV.shift
64      format = m[1]
65    end
66    if m = ARGV[0].match(/--start=(\w+)/)
67      ARGV.shift
68      start = m[1]
69    end
70    if m = ARGV[0].match(/--at=(\d+)/)
71      ARGV.shift
72      at = m[1].to_i
73    end
74    if ARGV[0] == '-e'
75      ARGV.shift
76      code = ARGV.shift
77      code = code.dup.force_encoding('utf-8')
78    elsif not ARGV.empty?
79      filename = ARGV.shift
80      print_usage_and_exit("File #{filename} doesn't exist.") if not File.exists?(filename)
81      code = File.open(filename,'r:utf-8'){|f|f.read}
82    else
83      print_usage_and_exit
84    end
85   
86    $quiet = quiet
87    $:.push(File.dirname($0))
88    require 'std'
89   
90    output = cached_output_for(code, format ? format : nil)
91    if output; print output; exit end
92
93    # Hacks
94    whiteout = ->(s){s.gsub(/[^ \n]/,' ')};
95    #code = code.gsub(/\n=begin.*?\n=end[^\n]*/um) {|m|whiteout.(m)}
96    code = code.gsub(/\n=kwid.*?\n=cut[^\n]*/um) {|m|whiteout.(m)}
97    code = code.gsub(/\n=pod.*?\n=cut[^\n]*/um) {|m|whiteout.(m)}
98    code = code.gsub(/\n=head1.*?\n=cut[^\n]*/um) {|m|whiteout.(m)}
99
100    kibitz = false
101    pn = Perl.new(code,at)
102    tree=nil
103    STDERR.print "parsing...\n" if kibitz
104    begin
105      $env_vars.scope_enter(:unitstopper)
106      $env_vars[:unitstopper] = "_EOS"
107      $env_vars.scope_enter(:stop)
108      $env_vars[:stop] = "if you see this dont stop"
109      tree = pn.send(start.to_sym)
110    rescue RuntimeError => e
111      STDERR.print error_message, e.message
112      bt = e.backtrace
113      bt = bt.slice(0,10) if quiet
114      s = "  "+bt.join("\n  ")+"\n"
115      if m = e.backtrace[0].match('^(.*?)STD_red')
116        s = s.gsub(m[1],'')
117      end
118      STDERR.print s
119      exit(1)
120    rescue Interrupt
121      exit(1)
122    end
123    if not tree
124      STDERR.print "Parse failed.\n"
125      exit(1)
126    end
127    if not format
128      STDERR.print "describing...\n" if kibitz
129      print tree.match_describe
130    elsif format == 'p5a'
131      print out(tree.to_dump0)
132    elsif format == 'cl'
133      print out(tree.to_dump1)
134    elsif format == 'yaml'
135      require "yaml"
136      tree.prepare_for_yaml_dump if tree
137      STDERR.print "yaml dumping...\n" if kibitz
138      yml = YAML::dump(tree)+"\n"
139      STDERR.print "yaml gsub'ing...\n" if kibitz
140      p5yml = yml
141      p5yml.gsub!(/^(\s*):/,'\1')
142      p5yml.gsub!(/^(\s*rule: ):/,'\1')
143      p5yml.gsub!(/ !ruby\/object:Match/,' !!perl/hash:Match')
144      STDERR.print "done.\n" if kibitz
145      print out(p5yml)
146    else
147      STDERR.print "Unknown format: #{format}\n"
148      print_usage_and_exit
149    end
150  end
151
152  def cached_output_for(code,format)
153    cachedir = ENV['STD_RED_CACHEDIR']
154    return nil if not cachedir or not format
155    input = code+format
156    require 'digest/md5'
157    std_file = File.dirname($0)+"/std.rb"
158    std_code = File.open(std_file,"r"){|f|f.read}
159    std_sig = Digest::MD5.hexdigest(std_code)
160    input_sig = Digest::MD5.hexdigest(input)
161    @cache_file = cachedir+'/parse_'+std_sig.slice(0,8)+'_'+input_sig.slice(0,32)
162    if File.exists? @cache_file
163      File.open(@cache_file,"r:utf-8"){|f|f.read}
164    else
165      nil
166    end
167  end
168  def out(output)
169    output = output.force_encoding('utf-8')
170    File.open(@cache_file,"w"){|f|f.print output} if @cache_file
171    output
172  end
173
174end
175STDRedRun.new.main
176
Note: See TracBrowser for help on using the browser.