diff --git a/bin-compiler/src/main.rs b/bin-compiler/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..f9d1b46c4bb3f139e60139fc4f4394361433a731 --- /dev/null +++ b/bin-compiler/src/main.rs @@ -0,0 +1,122 @@ +use std::fs::File; +use std::io::Read; + +use clap::{App, Arg}; +use reowolf_rs as rw; + +fn main() { + let app = App::new("rwc") + .author("Henger, M.") + .version(env!("CARGO_PKG_VERSION")) + .about("Reowolf compiler") + .arg( + Arg::new("input") + .long("input") + .short('i') + .help("input files") + .required(true) + .takes_value(true) + .multiple_occurrences(true) + ) + .arg( + Arg::new("threads") + .long("threads") + .short('t') + .help("number of runtime threads") + .default_value("1") + .takes_value(true) + ) + .arg( + Arg::new("debug") + .long("debug") + .short('d') + .help("enable debug logging") + ); + + // Retrieve arguments and convert + let app = app.get_matches(); + let input_files = app.values_of("input"); + if input_files.is_none() { + println!("ERROR: Expected at least one input file"); + return; + } + + let num_threads = app.value_of("threads").unwrap(); + let num_threads = match num_threads.parse::() { + Ok(num_threads) => { + if num_threads < 0 || num_threads > 255 { + println!("ERROR: Number of threads must be a number between 0 and 256"); + return; + } + + num_threads as u32 + }, + Err(err) => { + println!("ERROR: Failed to parse number of threads\nbecause: {}", err); + return; + } + }; + + let debug_enabled = app.is_present("debug"); + + // Add input files to file buffer + let input_files = input_files.unwrap(); + assert!(input_files.len() > 0); // because arg is required + + let mut builder = rw::ProtocolDescriptionBuilder::new(); + let mut file_buffer = Vec::with_capacity(4096); + + for input_file in input_files { + print!("Adding file: {} ... ", input_file); + let mut file = match File::open(input_file) { + Ok(file) => file, + Err(err) => { + println!("FAILED (to open file)\nbecause:\n{}", err); + return; + } + }; + + file_buffer.clear(); + if let Err(err) = file.read_to_end(&mut file_buffer) { + println!("FAILED (to read file)\nbecause:\n{}", err); + return; + } + + if let Err(err) = builder.add(input_file.to_string(), file_buffer.clone()) { + println!("FAILED (to tokenize file)\nbecause:\n{}", err); + } + + println!("Success"); + } + + // Compile the program + print!("Compiling program ... "); + let protocol_description = match builder.compile() { + Ok(pd) => pd, + Err(err) => { + println!("FAILED\nbecause:\n{}", err); + return; + } + }; + + println!("Success"); + + // Make sure there is a nameless module with a main component + print!("Creating main component ... "); + let runtime = rw::runtime2::Runtime::new(num_threads, debug_enabled, protocol_description); + if let Err(err) = runtime.create_component(b"", b"main") { + use rw::ComponentCreationError as CCE; + let reason = match err { + CCE::ModuleDoesntExist => "Input files did not contain a nameless module (that should contain the 'main' component)", + CCE::DefinitionDoesntExist => "Input files did not contain a component called 'main'", + CCE::DefinitionNotComponent => "Input file contained a 'main' function, but not a 'main' component", + _ => "Unexpected error" + }; + println!("FAILED\nbecause:\n{} (raw error: {:?})", reason, err); + return; + } + + println!("Success"); + println!("Now running until all components have exited"); + println!("--------------------------------------------\n\n"); +} \ No newline at end of file