badger 0.2.1

JavaScript transpiler in Rust
Documentation
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::io::prelude::*;
use std::io::Error;
use std::fs::File;
use std::time::{ Instant, Duration };
use docopt::Docopt;

pub mod lexicon;
pub mod tokenizer;
pub mod parser;
pub mod grammar;
pub mod transformer;
pub mod codegen;

fn print_ms(label: &str, duration: &Duration) {
    let delta = ((duration.as_secs() as f64) * 1000.0) +
                (duration.subsec_nanos() as f64) / 1_000_000.0;

    println!("{} {}ms", label, delta);
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
honeybadger

Usage:
  badger [options]
  badger --version

Options:
  -h --help                 Show this screen.
  --version                 Show version.
  -f FILE, --file=FILE      Specifies the input file.
  -o FILE, --output=FILE    Specifies the output file.
  --pretty                  Don't minify the output.
  --ast                     Print out the Abstract Syntax Tree of the input.
";

fn read_file(path: &str) -> Result<String, Error> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(err) => Err(err)
    }
}

fn write_file(filename: &str, program: String) -> Result<(), Error> {
    let mut f = try!(File::create(filename));
    match f.write_all(&program.into_bytes()[..]) {
        Ok(_) => Ok(()),
        Err(err) => Err(err)
    }
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_file: Option<String>,
    flag_output: Option<String>,
    flag_version: bool,
    flag_ast: bool,
    flag_pretty: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("v{}", VERSION);
        process::exit(0);
    }

    if args.flag_file.is_none() {
        println!("{}", USAGE);
        process::exit(0);
    }

    let file = match read_file(&args.flag_file.unwrap()) {
        Ok(file) => file,
        Err(err) => {
            println!("ERR Couldn't read file: {:?}", err);
            process::exit(1)
        }
    };

    let start = Instant::now();
    let mut ast = parser::parse(file);
    let parse_duration = Instant::now().duration_since(start);

    if args.flag_ast {
        println!("{:#?}", ast);
        print_ms("Parsing", &parse_duration);
        process::exit(0);
    }

    let start = Instant::now();
    transformer::transform(&mut ast, transformer::Settings::target_es5());
    let transform_duration = Instant::now().duration_since(start);

    let start = Instant::now();
    let program = codegen::generate_code(ast, !args.flag_pretty);
    let codegen_duration = Instant::now().duration_since(start);

    if args.flag_output.is_none() {
        println!("{}", program);
        print_ms("Parsing        ", &parse_duration);
        print_ms("Transformation ", &transform_duration);
        print_ms("Code generation", &codegen_duration);

        process::exit(0);
    }

    match write_file(&args.flag_output.unwrap(), program) {
        Ok(()) => {
            print_ms("Parsing        ", &parse_duration);
            print_ms("Transformation ", &transform_duration);
            print_ms("Code generation", &codegen_duration);
        },
        Err(err) => {
            println!("ERR Writing out.js {}", err);
            process::exit(1);
        }
    }
}