diff --git a/src/protocol/eval/executor.rs b/src/protocol/eval/executor.rs index e7bb604b13a60c3d851918811cc9ae566d8686bb..f95a61b3c62f75ac315120a8b9dfa3baac09d2a3 100644 --- a/src/protocol/eval/executor.rs +++ b/src/protocol/eval/executor.rs @@ -199,9 +199,10 @@ pub enum EvalContinuation { SyncBlockStart, SyncBlockEnd, NewComponent(DefinitionId, i32, ValueGroup), - BlockFires(Value), - BlockGet(Value), - Put(Value, Value), + NewChannel, + BlockFires(PortId), + BlockGet(PortId), + Put(PortId, Value), } // Note: cloning is fine, methinks. cloning all values and the heap regions then @@ -230,7 +231,14 @@ impl Prompt { prompt } - pub(crate) fn step(&mut self, types: &TypeTable, heap: &Heap, modules: &[Module], ctx: &mut EvalContext) -> EvalResult { + /// Big 'ol function right here. Didn't want to break it up unnecessarily. + /// It consists of, in sequence: executing any expressions that should be + /// executed before the next statement can be evaluated, then a section that + /// performs debug printing, and finally a section that takes the next + /// statement and executes it. If the statement requires any expressions to + /// be evaluated, then they will be added such that the next time `step` is + /// called, all of these expressions are indeed evaluated. + pub(crate) fn step(&mut self, types: &TypeTable, heap: &Heap, modules: &[Module], ctx: &mut impl RunContext) -> EvalResult { // Helper function to transfer multiple values from the expression value // array into a heap region (e.g. constructing arrays or structs). fn transfer_expression_values_front_into_heap(cur_frame: &mut Frame, store: &mut Store, num_values: usize) -> HeapPos { @@ -570,20 +578,36 @@ impl Prompt { let value = cur_frame.expr_values.pop_front().unwrap(); let value = self.store.maybe_read_ref(&value).clone(); - match ctx.get(value.clone(), &mut self.store) { + let port_id = if let Value::Input(port_id) = value { + port_id + } else { + unreachable!("executor calling 'get' on value {:?}", value) + }; + + match ctx.get(port_id, &mut self.store) { Some(result) => { + // We have the result cur_frame.expr_values.push_back(result) }, None => { + // Don't have the result yet, prepare the expression to + // get run again after we've received a message. cur_frame.expr_values.push_front(value.clone()); cur_frame.expr_stack.push_back(ExprInstruction::EvalExpr(expr_id)); - return Ok(EvalContinuation::BlockGet(value)); + return Ok(EvalContinuation::BlockGet(port_id)); } } }, Method::Put => { let port_value = cur_frame.expr_values.pop_front().unwrap(); let deref_port_value = self.store.maybe_read_ref(&port_value).clone(); + + let port_id = if let Value::Output(port_id) = deref_port_value { + port_id + } else { + unreachable!("executor calling 'put' on value {:?}", deref_port_value) + }; + let msg_value = cur_frame.expr_values.pop_front().unwrap(); let deref_msg_value = self.store.maybe_read_ref(&msg_value).clone(); @@ -597,7 +621,7 @@ impl Prompt { } } - if ctx.did_put(deref_port_value.clone()) { + if ctx.did_put(port_id) { // We're fine, deallocate in case the expression value stack // held an owned value self.store.drop_value(msg_value.get_heap_pos()); @@ -605,17 +629,24 @@ impl Prompt { cur_frame.expr_values.push_front(msg_value); cur_frame.expr_values.push_front(port_value); cur_frame.expr_stack.push_back(ExprInstruction::EvalExpr(expr_id)); - return Ok(EvalContinuation::Put(deref_port_value, deref_msg_value)); + return Ok(EvalContinuation::Put(port_id, deref_msg_value)); } }, Method::Fires => { let port_value = cur_frame.expr_values.pop_front().unwrap(); let port_value_deref = self.store.maybe_read_ref(&port_value).clone(); - match ctx.fires(port_value_deref.clone()) { + + let port_id = match port_value_deref { + Value::Input(port_id) => port_id, + Value::Output(port_id) => port_id, + _ => unreachable!("executor calling 'fires' on value {:?}", value), + }; + + match ctx.fires(port_id) { None => { cur_frame.expr_values.push_front(port_value); cur_frame.expr_stack.push_back(ExprInstruction::EvalExpr(expr_id)); - return Ok(EvalContinuation::BlockFires(port_value_deref)); + return Ok(EvalContinuation::BlockFires(port_id)); }, Some(value) => { cur_frame.expr_values.push_back(value); @@ -765,17 +796,25 @@ impl Prompt { self.store.write(ValueId::Stack(variable.unique_id_in_scope as u32), Value::Unassigned); cur_frame.position = stmt.next; + Ok(EvalContinuation::Stepping) }, LocalStatement::Channel(stmt) => { - let [from_value, to_value] = ctx.new_channel(); - self.store.write(ValueId::Stack(heap[stmt.from].unique_id_in_scope as u32), from_value); - self.store.write(ValueId::Stack(heap[stmt.to].unique_id_in_scope as u32), to_value); - - cur_frame.position = stmt.next; + // Need to create a new channel by requesting it from + // the runtime. + match ctx.get_channel() { + None => { + // No channel is pending. So request one + Ok(EvalContinuation::NewChannel) + }, + Some((put_port, get_port)) => { + self.store.write(ValueId::Stack(heap[stmt.from].unique_id_in_scope as u32), put_port); + self.store.write(ValueId::Stack(heap[stmt.to].unique_id_in_scope as u32), get_port); + cur_frame.position = stmt.next; + Ok(EvalContinuation::Stepping) + } + } } } - - Ok(EvalContinuation::Stepping) }, Statement::Labeled(stmt) => { cur_frame.position = stmt.body;