added --check option to voodooc
[voodoo-lang.git] / bin / voodooc
blobd7afb7e60b4818b503c693dba3984e4ced514e01
1 #! /usr/bin/env ruby
3 require 'getoptlong'
5 require 'voodoo'
6 require 'voodoo/generators/dummy_generator'
8 USAGE="USAGE: voodooc [options] <input file>"
9 HELP=<<EOT
10 Input file denotes the file to compile. The special name '-' causes
11 voodooc to read from standard input. In that case, the -o option is
12 mandatory.
14 Valid options are:
16 -a <architecture>
17 --arch <architecture>
18 --architecture <architecture>
19 Select target architecture. Use -a help to get a list of
20 supported architectures.
23 --check
24 Check program for correctness, but do not actually compile it.
26 -f <format>
27 --format <format>
28 --output-format <format>
29 Select output format. Use -a <architecture> -f help to get a list of
30 supported output formats for architecture.
32 --features
33 Lists the features supported by this implementation. The features
34 are listed in the format <feature name><tab><version>, ordered
35 by feature name. The program exits after printing the list of
36 features; no compilation is performed.
39 --help
40 Display usage information and exit. No compilation will be performed.
42 -o <output file>
43 --output <output file>
44 --output-file <output file>
45 Set output file name. The special name '-' causes voodooc to write
46 to standard output.
48 --version
49 Display version information and exit. No compilation will be performed.
50 EOT
52 architecture = Voodoo::Config.default_architecture
53 check_only = false
54 input_file = nil
55 output_file = nil
56 output_format = Voodoo::Config.default_format
57 show_features = false
59 # Gets the input file name from the command line.
60 def get_input_file_name
61 if ARGV.length == 1
62 input_file = ARGV[0]
63 else
64 if ARGV.length < 1
65 $stderr.puts "no input files"
66 else
67 $stderr.puts "Too many arguments"
68 end
69 $stderr.puts USAGE
70 exit 0x80
71 end
72 input_file
73 end
75 # If error is a Voodoo::Compiler::Error, prints error messages.
76 # Else, re-raises error.
77 def handle_error error
78 # If error is a compiler error, iterate over all child errors and
79 # print user-friendly messages. Else, re-raise so that the default
80 # handling is performed.
81 if error.kind_of? Voodoo::Compiler::Error
82 error.errors.each do |e|
83 message = ''
84 if e.start_line != nil
85 message << "#{e.start_line}: "
86 if e.input_name != nil
87 message = "#{e.input_name}:#{message}"
88 else
89 message = "line #{message}"
90 end
91 end
92 message << e.message
93 $stderr.puts message
94 if e.text != nil
95 $stderr.print "\n #{e.text.gsub("\n", "\n ")}\n"
96 end
97 end
98 else
99 raise error
104 # Process command line
107 opts = GetoptLong.new(
108 ['--arch', '--architecture', '-a', GetoptLong::REQUIRED_ARGUMENT],
109 ['--check', '-c', GetoptLong::NO_ARGUMENT],
110 ['--features', GetoptLong::NO_ARGUMENT],
111 ['--help', '-h', GetoptLong::NO_ARGUMENT],
112 ['--output-file', '--output', '-o', GetoptLong::REQUIRED_ARGUMENT],
113 ['--output-format', '--format', '-f', GetoptLong::REQUIRED_ARGUMENT ],
114 ['--version', GetoptLong::NO_ARGUMENT]
117 # Process options
118 opts.each do |opt, arg|
119 case opt
120 when '--arch'
121 architecture = arg.to_sym
122 when '--check'
123 check_only = true
124 when '--features'
125 show_features = true
126 when '--help'
127 puts USAGE
128 puts HELP
129 exit
130 when '--output-file'
131 output_file = arg
132 when '--output-format'
133 output_format = arg.to_sym
134 when '--version'
135 puts "#{Voodoo::Config::IMPLEMENTATION_NAME} version " +
136 Voodoo::Config::IMPLEMENTATION_VERSION
137 exit
141 if architecture == :help
142 # List supported architectures
143 puts "Supported architectures:"
144 puts Voodoo::CodeGenerator.architectures.map{|arch| arch.to_s}.sort
145 exit
148 if output_format == :help
149 # List supported output formats
150 puts "Supported output formats for architecture #{architecture}:"
151 puts Voodoo::CodeGenerator.formats(architecture).map{|f| f.to_s}.sort
152 exit
155 if check_only
156 input_file = get_input_file_name
157 infile = input_file == '-' ? $stdin : open(input_file)
158 begin
159 parser = Voodoo::Parser.new infile
160 generator = Voodoo::DummyGenerator.new
161 compiler = Voodoo::Compiler.new parser, generator, nil
162 compiler.compile
163 rescue => error
164 handle_error error
165 exit 1
166 ensure
167 infile.close
169 puts 'OK'
170 exit 0
173 # Select code generator based on output format
174 begin
175 generator = Voodoo::CodeGenerator.get_generator :architecture => architecture,
176 :format => output_format
177 rescue NotImplementedError
178 if Voodoo::CodeGenerator.architecture_supported? architecture
179 $stderr.puts "Format #{output_format} is not supported for architecture #{architecture}"
180 $stderr.puts "Supported formats for #{architecture} are:"
181 $stderr.puts Voodoo::CodeGenerator.formats(architecture)
182 else
183 $stderr.puts "Architecture #{architecture} is not supported."
184 $stderr.puts "Supported architectures are:"
185 $stderr.puts Voodoo::CodeGenerator.architectures
187 exit 1
190 # If requested, show features and exit
191 if show_features
192 generator.features.to_a.sort{|x,y| x[0].to_s <=> y[0].to_s}.each do |feature|
193 puts "#{feature[0]}\t#{feature[1]}"
195 exit
198 input_file = get_input_file_name
201 # Compile
204 if input_file == '-'
205 infile = $stdin
206 unless output_file
207 $stderr.puts "The -o option is mandatory when reading from standard input"
208 exit 0x80
210 else
211 infile = open input_file
212 # Set output_file if not already set
213 output_file = generator.output_file_name input_file unless output_file
216 if output_file == '-'
217 outfile = $stdout
218 else
219 outfile = open output_file, 'w'
222 begin
223 parser = Voodoo::Parser.new infile
224 compiler = Voodoo::Compiler.new parser, generator, outfile
226 compiler.compile
227 rescue => e
228 if output_file != '-'
229 File::unlink(output_file) if File::exists?(output_file)
232 handle_error e
233 exit 1
234 ensure
235 outfile.close
236 infile.close