#! /usr/bin/env ruby

require 'getoptlong'

require 'voodoo'

usage="USAGE: voodooc [options] <input file>"
help=<<EOT
Input file denotes the file to compile. The special name '-' causes
voodooc to read from standard input. In that case, the -o option is
mandatory.

Valid options are:

-a <architecture>
--arch <architecture>
--architecture <architecture>
        Select target architecture. Use -a help to get a list of
        supported architectures.

-f <format>
--format <format>
--output-format <format>
        Select output format. Use -a <architecture> -f help to get a list of
        supported output formats for architecture.

-o <output file>
--output <output file>
--output-file <output file>
        Set output file name. The special name '-' causes voodooc to write
        to standard output.
EOT

input_file = nil
output_file = nil
architecture = Voodoo::Config.default_architecture
output_format = Voodoo::Config.default_format

#
# Process command line
#

opts = GetoptLong.new(
  ['--help', '-h', GetoptLong::NO_ARGUMENT ],
  ['--arch', '--architecture', '-a', GetoptLong::REQUIRED_ARGUMENT ],
  ['--output-file', '--output', '-o', GetoptLong::REQUIRED_ARGUMENT ],
  ['--output-format', '--format', '-f', GetoptLong::REQUIRED_ARGUMENT ]
)

# Process options
opts.each do |opt, arg|
  case opt
  when '--help'
    puts usage
    puts help
    exit
  when '--arch'
    architecture = arg.to_sym
  when '--output-file'
    output_file = arg
  when '--output-format'
    output_format = arg.to_sym
  end
end

if architecture == :help
  # List supported architectures
  puts "Supported architectures:"
  puts Voodoo::CodeGenerator.architectures.map{|arch| arch.to_s}.sort
  exit
end

if output_format == :help
  # List supported output formats
  puts "Supported output formats for architecture #{architecture}:"
  puts Voodoo::CodeGenerator.formats(architecture).map{|f| f.to_s}.sort
  exit
end

# Get input file name
if ARGV.length == 1
  input_file = ARGV[0]
else
  if ARGV.length < 1
    $stderr.puts "no input files"
  else
    $stderr.puts "Too many arguments"
  end
  $stderr.puts usage
  exit 0x80
end

# Select code generator based on output format
begin
  generator = Voodoo::CodeGenerator.get_generator :architecture => architecture,
                                                  :format => output_format
rescue NotImplementedError
  if Voodoo::CodeGenerator.architecture_supported? architecture
    $stderr.puts "Format #{output_format} is not supported for architecture #{architecture}"
    $stderr.puts "Supported formats for #{architecture} are:"
    $stderr.puts Voodoo::CodeGenerator.formats(architecture)
  else
    $stderr.puts "Architecture #{architecture} is not supported."
    $stderr.puts "Supported architectures are:"
    $stderr.puts Voodoo::CodeGenerator.architectures
  end
  exit 1
end


#
# Compile
#

if input_file == '-'
  infile = $stdin
  unless output_file
    $stderr.puts "The -o option is mandatory when reading from standard input"
    exit 0x80
  end
else
  infile = open input_file
  # Set output_file if not already set
  output_file = generator.output_file_name input_file unless output_file
end

if output_file == '-'
  outfile = $stdout
else
  outfile = open output_file, 'w'
end

begin
  parser = Voodoo::Parser.new infile
  compiler = Voodoo::Compiler.new parser, generator, outfile

  compiler.compile
rescue
  if output_file != '-'
    File::unlink(output_file) if File::exists?(output_file)
  end
  raise
ensure
  outfile.close
  infile.close
end
