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("loglevel") .long("log_level") .short('l') .help("set log level ('none', 'info', 'debug' or 'all')") .default_value("all") .takes_value(true) ) .arg( Arg::new("stdlib") .long("stdlib") .short('s') .help("standard library directory (overrides default)") .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!("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 log_level = app.value_of("loglevel").unwrap(); let log_level = match log_level { "none" | "None" => rw::runtime2::LogLevel::None, "debug" | "Debug" => rw::runtime2::LogLevel::Debug, "info" | "Info" | "all" | "All" => rw::runtime2::LogLevel::Info, _ => { println!("ERROR: Unexpected log level"); return; } }; let standard_library_dir = app.value_of("stdlib") .map(|v| v.to_string()); // 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(standard_library_dir) .expect("create protocol description builder"); 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"); // Start runtime print!("Startup of runtime ... "); let runtime = rw::runtime2::Runtime::new(num_threads, log_level, protocol_description); if let Err(err) = &runtime { println!("FAILED\nbecause:\n{}", err); } println!("Success"); // Make sure there is a nameless module with a main component print!("Creating main component ... "); let runtime = runtime.unwrap(); 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"); }