mod arena; pub(crate) mod eval; pub(crate) mod input_source; mod parser; #[cfg(test)] mod tests; pub(crate) mod ast; pub(crate) mod ast_printer; use std::sync::Mutex; use crate::collections::{StringPool, StringRef}; use crate::protocol::ast::*; use crate::protocol::eval::*; use crate::protocol::input_source::*; use crate::protocol::parser::*; use crate::protocol::type_table::*; pub use parser::type_table::TypeId; /// A protocol description module pub struct Module { pub(crate) source: InputSource, pub(crate) root_id: RootId, pub(crate) name: Option>, } /// Description of a protocol object, used to configure new connectors. #[repr(C)] pub struct ProtocolDescription { pub(crate) modules: Vec, pub(crate) heap: Heap, pub(crate) types: TypeTable, pub(crate) pool: Mutex, } #[derive(Debug, Clone)] pub(crate) struct ComponentState { pub(crate) prompt: Prompt, } #[derive(Debug)] pub enum ComponentCreationError { ModuleDoesntExist, DefinitionDoesntExist, DefinitionNotComponent, InvalidNumArguments, InvalidArgumentType(usize), UnownedPort, InSync, } impl ProtocolDescription { pub fn parse(buffer: &[u8]) -> Result { let source = InputSource::new(String::new(), Vec::from(buffer)); let mut parser = Parser::new(); parser.feed(source).expect("failed to feed source"); if let Err(err) = parser.parse() { println!("ERROR:\n{}", err); return Err(format!("{}", err)) } debug_assert_eq!(parser.modules.len(), 1, "only supporting one module here for now"); let modules: Vec = 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: parser.heap, types: parser.type_table, pool: Mutex::new(parser.string_pool), }); } pub(crate) fn new_component( &self, module_name: &[u8], identifier: &[u8], arguments: ValueGroup ) -> Result { // Find the module in which the definition can be found let module_root = self.lookup_module_root(module_name); if module_root.is_none() { return Err(ComponentCreationError::ModuleDoesntExist); } let module_root = module_root.unwrap(); let root = &self.heap[module_root]; let definition_id = root.get_definition_ident(&self.heap, identifier); if definition_id.is_none() { return Err(ComponentCreationError::DefinitionDoesntExist); } let definition_id = definition_id.unwrap(); let ast_definition = &self.heap[definition_id]; if !ast_definition.is_procedure() { return Err(ComponentCreationError::DefinitionNotComponent); } // Make sure that the types of the provided value group matches that of // the expected types. let ast_definition = ast_definition.as_procedure(); if !ast_definition.poly_vars.is_empty() || ast_definition.kind == ProcedureKind::Function { return Err(ComponentCreationError::DefinitionNotComponent); } // - check number of arguments by retrieving the one instantiated // monomorph let concrete_type = ConcreteType{ parts: vec![ConcreteTypePart::Component(ast_definition.this, 0)] }; let procedure_type_id = self.types.get_procedure_monomorph_type_id(&definition_id, &concrete_type.parts).unwrap(); let procedure_monomorph_index = self.types.get_monomorph(procedure_type_id).variant.as_procedure().monomorph_index; let monomorph_info = &ast_definition.monomorphs[procedure_monomorph_index as usize]; if monomorph_info.argument_types.len() != arguments.values.len() { return Err(ComponentCreationError::InvalidNumArguments); } // - for each argument try to make sure the types match for arg_idx in 0..arguments.values.len() { let expected_type_id = monomorph_info.argument_types[arg_idx]; let expected_type = &self.types.get_monomorph(expected_type_id).concrete_type; let provided_value = &arguments.values[arg_idx]; if !self.verify_same_type(expected_type, 0, &arguments, provided_value) { return Err(ComponentCreationError::InvalidArgumentType(arg_idx)); } } // By now we're sure that all of the arguments are correct. So create // the connector. return Ok(Prompt::new(&self.types, &self.heap, ast_definition.this, procedure_type_id, arguments)); } fn lookup_module_root(&self, module_name: &[u8]) -> Option { for module in self.modules.iter() { match &module.name { Some(name) => if name.as_bytes() == module_name { return Some(module.root_id); }, None => if module_name.is_empty() { return Some(module.root_id); } } } return None; } fn verify_same_type(&self, expected: &ConcreteType, expected_idx: usize, arguments: &ValueGroup, argument: &Value) -> bool { use ConcreteTypePart as CTP; match &expected.parts[expected_idx] { CTP::Void | CTP::Message | CTP::Slice | CTP::Pointer | CTP::Function(_, _) | CTP::Component(_, _) => unreachable!(), CTP::Bool => if let Value::Bool(_) = argument { true } else { false }, CTP::UInt8 => if let Value::UInt8(_) = argument { true } else { false }, CTP::UInt16 => if let Value::UInt16(_) = argument { true } else { false }, CTP::UInt32 => if let Value::UInt32(_) = argument { true } else { false }, CTP::UInt64 => if let Value::UInt64(_) = argument { true } else { false }, CTP::SInt8 => if let Value::SInt8(_) = argument { true } else { false }, CTP::SInt16 => if let Value::SInt16(_) = argument { true } else { false }, CTP::SInt32 => if let Value::SInt32(_) = argument { true } else { false }, CTP::SInt64 => if let Value::SInt64(_) = argument { true } else { false }, CTP::Character => if let Value::Char(_) = argument { true } else { false }, CTP::String => { // Match outer string type and embedded character types if let Value::String(heap_pos) = argument { for element in &arguments.regions[*heap_pos as usize] { if let Value::Char(_) = element {} else { return false; } } } else { return false; } return true; }, CTP::Array => { if let Value::Array(heap_pos) = argument { let heap_pos = *heap_pos; for element in &arguments.regions[heap_pos as usize] { if !self.verify_same_type(expected, expected_idx + 1, arguments, element) { return false; } } return true; } else { return false; } }, CTP::Input => if let Value::Input(_) = argument { true } else { false }, CTP::Output => if let Value::Output(_) = argument { true } else { false }, CTP::Tuple(_) => todo!("implement full type checking on user-supplied arguments"), CTP::Instance(definition_id, _num_embedded) => { let definition = self.types.get_base_definition(definition_id).unwrap(); match &definition.definition { DefinedTypeVariant::Enum(definition) => { if let Value::Enum(variant_value) = argument { let is_valid = definition.variants.iter() .any(|v| v.value == *variant_value); return is_valid; } }, _ => todo!("implement full type checking on user-supplied arguments"), } return false; }, } } } pub trait RunContext { fn performed_put(&mut self, port: PortId) -> bool; fn performed_get(&mut self, port: PortId) -> Option; // None if still waiting on message fn fires(&mut self, port: PortId) -> Option; // None if not yet branched fn performed_fork(&mut self) -> Option; // None if not yet forked fn created_channel(&mut self) -> Option<(Value, Value)>; // None if not yet prepared fn performed_select_wait(&mut self) -> Option; // None if not yet notified runtime of select blocker } 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), }); } }