diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..d770d19f288f2d7bb087fcbfdbca58a2de1899fd --- /dev/null +++ b/src/protocol/mod.rs @@ -0,0 +1,243 @@ +mod ast; +mod eval; +pub mod inputsource; +mod lexer; +mod library; +mod parser; + +use crate::common::*; +use crate::protocol::ast::*; +use crate::protocol::inputsource::*; +use crate::protocol::parser::*; +use crate::protocol::eval::*; +use std::hint::unreachable_unchecked; + +pub struct ProtocolDescriptionImpl { + heap: Heap, + source: InputSource, + root: RootId, + main: ComponentId, +} + +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) => { + // Find main definition (grammar rule ensures this exists) + let sym = heap.get_external_identifier(b"main"); + let def = heap[root].get_definition(&heap, sym.upcast()).unwrap(); + let main = heap[def].as_component().this(); + return Ok(ProtocolDescriptionImpl { heap, source, root, main }); + } + Err(err) => { + let mut vec: Vec = Vec::new(); + err.write(&source, &mut vec).unwrap(); + Err(String::from_utf8_lossy(&vec).to_string()) + } + } + } + fn main_interface_polarities(&self) -> Vec { + let def = &self.heap[self.main]; + let mut result = Vec::new(); + for ¶m in def.parameters().iter() { + let param = &self.heap[param]; + let type_annot = &self.heap[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!() + } + } + result + } + fn new_main_component(&self, interface: &[Key]) -> ComponentStateImpl { + let mut args = Vec::new(); + for (&x, y) in interface.iter().zip(self.main_interface_polarities()) { + match y { + Polarity::Getter => args.push(Value::Input(InputValue(x))), + Polarity::Putter => args.push(Value::Output(OutputValue(x))) + } + } + ComponentStateImpl { + prompt: Prompt::new(&self.heap, self.main.upcast(), &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!() + } + }, + } + } +} \ No newline at end of file