diff --git a/bin-compiler/src/main.rs b/bin-compiler/src/main.rs index a8567bd6b37ce60434ce8049071f179c88082d04..35b337b9ab642a23aeb3e0288a5298a172c9d675 100644 --- a/bin-compiler/src/main.rs +++ b/bin-compiler/src/main.rs @@ -1,3 +1,6 @@ +use std::fs::File; +use std::io::Read; + use clap::{App, Arg}; use reowolf_rs as rw; @@ -14,19 +17,97 @@ fn main() { .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) ); + // Retrieve arguments and convert let app = app.get_matches(); let input_files = app.values_of("input"); if input_files.is_none() { - println!("Expected at least one input file"); + 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; + } + }; + + // 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 { - println!("Got input: {}", input_file); + 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, 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!("Done!"); + println!("Success"); + println!("Now running until all components have exited"); } \ No newline at end of file