pub use crulz::*;
use std::{
collections::HashMap,
io::{self, Write},
};
fn print_ast(step: &str, trs: &[crulz::ast::ASTNode]) {
eprintln!(
"crulz: {}:\n{:#?}\n----",
ansi_term::Style::new().bold().paint(step),
trs
);
}
fn timing_of_intern(print_timings: bool, tbfx: std::time::Instant, fname: &'static str) {
if print_timings {
let elp = tbfx.elapsed().as_micros();
if elp > 9 {
eprintln!(
"crulz: {}: {} {} μs",
ansi_term::Style::new().bold().paint("timings"),
fname,
elp
);
}
}
}
macro_rules! timing_of {
($print_timings:ident, $name:path, $fn:expr) => {{
let now = std::time::Instant::now();
let ret = $fn;
timing_of_intern($print_timings, now, stringify!($name));
ret
}};
}
fn main() {
use crate::mangle_ast::MangleAST;
use clap::Arg;
#[allow(unused_mut)]
let mut matches = clap::App::new("crulz")
.version(clap::crate_version!())
.author("Erik Zscheile <zseri.devel@ytrizja.de>")
.about("a macro language parser + interpreter")
.arg(
Arg::with_name("INPUT")
.help("sets the input file to use")
.required(true)
.index(1),
)
.arg(
Arg::with_name("escc")
.short("e")
.long("escc")
.takes_value(true)
.help("sets the escape character"),
)
.arg(
Arg::with_name("pass-escc")
.short("p")
.long("pass-escc")
.help("if set, double escape character gets passed through"),
)
.arg(
Arg::with_name("timings")
.short("t")
.long("timings")
.help("if set, output various timings"),
)
.arg(
Arg::with_name("v")
.short("v")
.long("verbose")
.multiple(true)
.help("sets the level of verbosity"),
)
.arg(
Arg::with_name("quiet")
.short("q")
.long("quiet")
.help("if set, suppress output of evaluated data"),
);
#[cfg(feature = "compile")]
{
matches = matches
.arg(
Arg::with_name("map-to-compilate")
.short("m")
.long("map-to-compilate")
.multiple(true)
.takes_value(true)
.help("if set, map includes of $1 to $2"),
)
.arg(
Arg::with_name("compile-output")
.short("c")
.long("compile-output")
.takes_value(true)
.help("if set, writes the processed output including defines to the given output file"),
);
}
let matches = matches.get_matches();
let escc = matches.value_of("escc").unwrap_or("\\");
let escc = {
let mut chx = escc.chars();
let escc_aso = chx.next();
if escc_aso == None || chx.next() != None {
panic!("invalid escc argument");
}
escc_aso.unwrap()
};
let escc_pass = matches.is_present("pass-escc");
let vblvl = matches.occurrences_of("v");
let print_timings = matches.is_present("timings");
let input_file = matches.value_of("INPUT").unwrap().to_owned();
let opts = parser::ParserOptions::new(escc, escc_pass);
let mut trs = timing_of!(
print_timings,
parser::file2ast,
parser::file2ast(&input_file, opts).expect("failed to parse input file")
);
if vblvl > 1 {
print_ast("AST before evaluation", &trs);
}
cfg_if::cfg_if! {
if #[cfg(feature = "compile")] {
let comp_map = matches
.values_of("map-to-compilate")
.map(|x| {
x.map(|y| {
let tmp: Vec<_> = y.split('=').take(2).collect();
(tmp[0], tmp[1])
})
.collect()
})
.unwrap_or_else(HashMap::new);
timing_of!(
print_timings,
interp::eval,
interp::eval(
&mut trs,
opts,
&comp_map,
matches.value_of("compile-output")
)
);
} else {
timing_of!(
print_timings,
interp::eval,
interp::eval(&mut trs, opts, &HashMap::new(), None)
);
}
}
if vblvl > 0 {
print_ast("AST after evaluation", &trs);
}
if !matches.is_present("quiet") {
print!("{}", trs.to_str(escc));
io::stdout().flush().expect("unable to flush result");
}
}