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 diff --git a/src/lib.rs b/src/lib.rs index 1f3e76cc3424f898e5c1dad63dca15e481f43457..fa75b6de1590bf488509d07a6a803de321356ece 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,4 +7,4 @@ pub mod runtime; pub mod runtime2; mod collections; -pub use protocol::ProtocolDescription; \ No newline at end of file +pub use protocol::{ProtocolDescription, ProtocolDescriptionBuilder, ComponentCreationError}; \ No newline at end of file diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 518b5f07d699dd1f3800407424add0738a7c0751..c7c4ba07d617734fe1aaab99fcbe75c5634f550b 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -46,11 +46,6 @@ pub enum ComponentCreationError { InSync, } -impl std::fmt::Debug for ProtocolDescription { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "(An opaque protocol description)") - } -} impl ProtocolDescription { pub fn parse(buffer: &[u8]) -> Result { let source = InputSource::new(String::new(), Vec::from(buffer)); @@ -217,3 +212,41 @@ pub trait RunContext { fn performed_fork(&mut self) -> Option; // None if not yet forked fn created_channel(&mut self) -> Option<(Value, Value)>; // None if not yet prepared } + +pub struct ProtocolDescriptionBuilder { + parser: Parser, +} + +impl ProtocolDescriptionBuilder { + pub fn new() -> Self { + return Self{ + parser: Parser::new(), + } + } + + pub fn add(&mut self, filename: String, buffer: Vec) -> Result<(), ParseError> { + let input = InputSource::new(filename, buffer); + self.parser.feed(input)?; + + return Ok(()) + } + + pub fn compile(mut self) -> Result { + self.parser.parse()?; + + let modules: Vec = self.parser.modules.into_iter() + .map(|module| Module{ + source: module.source, + root_id: module.root_id, + name: module.name.map(|(_, name)| name) + }) + .collect(); + + return Ok(ProtocolDescription { + modules, + heap: self.parser.heap, + types: self.parser.type_table, + pool: Mutex::new(self.parser.string_pool), + }); + } +} diff --git a/src/runtime2/mod.rs b/src/runtime2/mod.rs index 691c7ca21685901f3a3f2a0c58d6ec7d3ef0bd50..05881c7b85be8a3fd71f8e4d892c8d6c395064db 100644 --- a/src/runtime2/mod.rs +++ b/src/runtime2/mod.rs @@ -3,4 +3,6 @@ mod runtime; mod component; mod communication; mod scheduler; -#[cfg(test)] mod tests; \ No newline at end of file +#[cfg(test)] mod tests; + +pub use runtime::Runtime; \ No newline at end of file diff --git a/src/runtime2/runtime.rs b/src/runtime2/runtime.rs index 5b093be34c844f31be546b7853789b2f815dfe50..155dcd51e8311df571e18a31cb85c81134a37887 100644 --- a/src/runtime2/runtime.rs +++ b/src/runtime2/runtime.rs @@ -183,6 +183,20 @@ impl Runtime { return runtime; } + + pub fn create_component(&self, module_name: &[u8], routine_name: &[u8]) -> Result<(), ComponentCreationError> { + use crate::protocol::eval::ValueGroup; + let prompt = self.inner.protocol.new_component( + module_name, routine_name, + ValueGroup::new_stack(Vec::new()) + )?; + let reserved = self.inner.start_create_pdl_component(); + let ctx = CompCtx::new(&reserved); + let (key, _) = self.inner.finish_create_pdl_component(reserved, CompPDL::new(prompt, 0), ctx, false); + self.inner.enqueue_work(key); + + return Ok(()) + } } impl Drop for Runtime {