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::*; /// 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 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)); 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 definition = &self.heap[definition_id]; if !definition.is_component() { return Err(ComponentCreationError::DefinitionNotComponent); } // Make sure that the types of the provided value group matches that of // the expected types. let definition = definition.as_component(); if !definition.poly_vars.is_empty() { return Err(ComponentCreationError::DefinitionNotComponent); } // - check number of arguments let expr_data = self.types.get_procedure_expression_data(&definition_id, 0); if expr_data.arg_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 = &expr_data.arg_types[arg_idx]; 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, definition_id, 0, 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::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::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 }