mod ast; mod eval; pub mod inputsource; mod lexer; mod library; mod parser; use crate::common::*; use crate::protocol::ast::*; use crate::protocol::eval::*; use crate::protocol::inputsource::*; use crate::protocol::parser::*; use std::hint::unreachable_unchecked; pub struct ProtocolDescriptionImpl { heap: Heap, source: InputSource, root: RootId } impl std::fmt::Debug for ProtocolDescriptionImpl { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Protocol") } } impl ProtocolDescription for ProtocolDescriptionImpl { type S = ComponentStateImpl; fn parse(buffer: &[u8]) -> Result { let mut heap = Heap::new(); let mut source = InputSource::from_buffer(buffer).unwrap(); let mut parser = Parser::new(&mut source); match parser.parse(&mut heap) { Ok(root) => { return Ok(ProtocolDescriptionImpl { heap, source, root }); } Err(err) => { let mut vec: Vec = Vec::new(); err.write(&source, &mut vec).unwrap(); Err(String::from_utf8_lossy(&vec).to_string()) } } } fn component_polarities(&self, identifier: &[u8]) -> Result, MainComponentErr> { let h = &self.heap; let root = &h[self.root]; let def = root.get_definition_ident(h, identifier); if def.is_none() { return Err(MainComponentErr::NoSuchComponent); } let def = &h[def.unwrap()]; if !def.is_component() { return Err(MainComponentErr::NoSuchComponent); } for ¶m in def.parameters().iter() { let param = &h[param]; let type_annot = &h[param.type_annotation]; if type_annot.the_type.array { return Err(MainComponentErr::NonPortTypeParameters); } match type_annot.the_type.primitive { PrimitiveType::Input | PrimitiveType::Output => continue, _ => { return Err(MainComponentErr::NonPortTypeParameters); } } } let mut result = Vec::new(); for ¶m in def.parameters().iter() { let param = &h[param]; let type_annot = &h[param.type_annotation]; let ptype = &type_annot.the_type.primitive; if ptype == &PrimitiveType::Input { result.push(Polarity::Getter) } else if ptype == &PrimitiveType::Output { result.push(Polarity::Putter) } else { unreachable!() } } Ok(result) } fn new_main_component(&self, identifier: &[u8], ports: &[Key]) -> ComponentStateImpl { let mut args = Vec::new(); for (&x, y) in ports.iter().zip(self.component_polarities(identifier).unwrap()) { match y { Polarity::Getter => args.push(Value::Input(InputValue(x))), Polarity::Putter => args.push(Value::Output(OutputValue(x))) } } let h = &self.heap; let root = &h[self.root]; let def = root.get_definition_ident(h, identifier).unwrap(); ComponentStateImpl { prompt: Prompt::new(h, def, &args) } } } #[derive(Debug, Clone)] pub struct ComponentStateImpl { prompt: Prompt, } impl ComponentState for ComponentStateImpl { type D = ProtocolDescriptionImpl; fn pre_sync_run>( &mut self, context: &mut C, pd: &ProtocolDescriptionImpl, ) -> MonoBlocker { let mut context = EvalContext::Mono(context); loop { let result = self.prompt.step(&pd.heap, &mut context); match result { // In component definitions, there are no return statements Ok(_) => unreachable!(), Err(cont) => match cont { EvalContinuation::Stepping => continue, EvalContinuation::Inconsistent => return MonoBlocker::Inconsistent, EvalContinuation::Terminal => return MonoBlocker::ComponentExit, EvalContinuation::SyncBlockStart => return MonoBlocker::SyncBlockStart, // Not possible to end sync block if never entered one EvalContinuation::SyncBlockEnd => unreachable!(), EvalContinuation::NewComponent(args) => { todo!(); continue; } // Outside synchronous blocks, no fires/get/put happens EvalContinuation::BlockFires(val) => unreachable!(), EvalContinuation::BlockGet(val) => unreachable!(), EvalContinuation::Put(port, msg) => unreachable!(), }, } } } fn sync_run>( &mut self, context: &mut C, pd: &ProtocolDescriptionImpl, ) -> PolyBlocker { let mut context = EvalContext::Poly(context); loop { let result = self.prompt.step(&pd.heap, &mut context); match result { // Inside synchronous blocks, there are no return statements Ok(_) => unreachable!(), Err(cont) => match cont { EvalContinuation::Stepping => continue, EvalContinuation::Inconsistent => return PolyBlocker::Inconsistent, // First need to exit synchronous block before definition may end EvalContinuation::Terminal => unreachable!(), // No nested synchronous blocks EvalContinuation::SyncBlockStart => unreachable!(), EvalContinuation::SyncBlockEnd => return PolyBlocker::SyncBlockEnd, // Not possible to create component in sync block EvalContinuation::NewComponent(args) => unreachable!(), EvalContinuation::BlockFires(port) => match port { Value::Output(OutputValue(key)) => { return PolyBlocker::CouldntCheckFiring(key); } Value::Input(InputValue(key)) => { return PolyBlocker::CouldntCheckFiring(key); } _ => unreachable!(), }, EvalContinuation::BlockGet(port) => match port { Value::Output(OutputValue(key)) => { return PolyBlocker::CouldntReadMsg(key); } Value::Input(InputValue(key)) => { return PolyBlocker::CouldntReadMsg(key); } _ => unreachable!(), }, EvalContinuation::Put(port, message) => { let key; match port { Value::Output(OutputValue(the_key)) => { key = the_key; } Value::Input(InputValue(the_key)) => { key = the_key; } _ => unreachable!(), } let payload; match message { Value::Message(MessageValue(None)) => { // Putting a null message is inconsistent return PolyBlocker::Inconsistent; } Value::Message(MessageValue(Some(buffer))) => { // Create a copy of the payload payload = buffer.clone(); } _ => unreachable!(), } return PolyBlocker::PutMsg(key, payload); } }, } } } } pub enum EvalContext<'a> { Mono(&'a mut dyn MonoContext), Poly(&'a mut dyn PolyContext), None, } impl EvalContext<'_> { fn random(&mut self) -> LongValue { match self { EvalContext::None => unreachable!(), EvalContext::Mono(context) => todo!(), EvalContext::Poly(context) => unreachable!(), } } fn channel(&mut self) -> (Value, Value) { match self { EvalContext::None => unreachable!(), EvalContext::Mono(context) => unreachable!(), EvalContext::Poly(context) => todo!(), } } fn fires(&mut self, port: Value) -> Option { match self { EvalContext::None => unreachable!(), EvalContext::Mono(context) => unreachable!(), EvalContext::Poly(context) => match port { Value::Output(OutputValue(key)) => context.is_firing(key).map(Value::from), Value::Input(InputValue(key)) => context.is_firing(key).map(Value::from), _ => unreachable!(), }, } } fn get(&mut self, port: Value) -> Option { match self { EvalContext::None => unreachable!(), EvalContext::Mono(context) => unreachable!(), EvalContext::Poly(context) => match port { Value::Output(OutputValue(key)) => { context.read_msg(key).map(Value::receive_message) } Value::Input(InputValue(key)) => context.read_msg(key).map(Value::receive_message), _ => unreachable!(), }, } } }