Changeset - ce77f83608df
[Not reviewed]
0 8 0
MH - 4 years ago 2021-05-26 20:32:57
contact@maxhenger.nl
Integrate with old runtime, pending some tiny fixes
7 files changed with 263 insertions and 60 deletions:
0 comments (0 inline, 0 general)
src/protocol/eval/executor.rs
Show inline comments
 
@@ -356,24 +356,34 @@ impl Prompt {
 
                            let (deallocate_heap_pos, value_to_push, subject_heap_pos) = match subject {
 
                                Value::Ref(value_ref) => {
 
                                    // Our expression stack value is a reference to something that
 
                                    // exists in the normal stack/heap. We don't want to deallocate
 
                                    // this thing. Rather we want to return a reference to it.
 
                                    let subject = self.store.read_ref(value_ref);
 
                                    let subject_heap_pos = subject.as_array();
 
                                    let subject_heap_pos = match subject {
 
                                        Value::String(v) => *v,
 
                                        Value::Array(v) => *v,
 
                                        Value::Message(v) => *v,
 
                                        _ => unreachable!(),
 
                                    };
 

	
 
                                    if array_inclusive_index_is_invalid(&self.store, subject_heap_pos, index) {
 
                                        return Err(construct_array_error(self, modules, heap, expr_id, subject_heap_pos, index));
 
                                    }
 

	
 
                                    (None, Value::Ref(ValueId::Heap(subject_heap_pos, index as u32)), subject_heap_pos)
 
                                },
 
                                _ => {
 
                                    // Our value lives on the expression stack, hence we need to
 
                                    // clone whatever we're referring to. Then drop the subject.
 
                                    let subject_heap_pos = subject.as_array();
 
                                    let subject_heap_pos = match &subject {
 
                                        Value::String(v) => *v,
 
                                        Value::Array(v) => *v,
 
                                        Value::Message(v) => *v,
 
                                        _ => unreachable!(),
 
                                    };
 

	
 
                                    if array_inclusive_index_is_invalid(&self.store, subject_heap_pos, index) {
 
                                        return Err(construct_array_error(self, modules, heap, expr_id, subject_heap_pos, index));
 
                                    }
 

	
 
                                    let subject_indexed = Value::Ref(ValueId::Heap(subject_heap_pos, index as u32));
 
@@ -406,13 +416,20 @@ impl Prompt {
 
                            // Dereference subject if needed
 
                            let subject = cur_frame.expr_values.pop_back().unwrap();
 
                            let deref_subject = self.store.maybe_read_ref(&subject);
 

	
 
                            // Slicing needs to produce a copy anyway (with the
 
                            // current evaluator implementation)
 
                            let array_heap_pos = deref_subject.as_array();
 
                            enum ValueKind{ Array, String, Message }
 
                            let (value_kind, array_heap_pos) = match deref_subject {
 
                                Value::Array(v) => (ValueKind::Array, *v),
 
                                Value::String(v) => (ValueKind::String, *v),
 
                                Value::Message(v) => (ValueKind::Message, *v),
 
                                _ => unreachable!()
 
                            };
 

	
 
                            if array_inclusive_index_is_invalid(&self.store, array_heap_pos, from_index) {
 
                                return Err(construct_array_error(self, modules, heap, expr.from_index, array_heap_pos, from_index));
 
                            }
 
                            if array_exclusive_index_is_invalid(&self.store, array_heap_pos, to_index) {
 
                                return Err(construct_array_error(self, modules, heap, expr.to_index, array_heap_pos, to_index));
 
                            }
 
@@ -430,13 +447,17 @@ impl Prompt {
 
                                }
 

	
 
                                self.store.heap_regions[new_heap_pos as usize].values = values;
 

	
 
                            } // else: empty range
 

	
 
                            cur_frame.expr_values.push_back(Value::Array(new_heap_pos));
 
                            cur_frame.expr_values.push_back(match value_kind {
 
                                ValueKind::Array => Value::Array(new_heap_pos),
 
                                ValueKind::String => Value::String(new_heap_pos),
 
                                ValueKind::Message => Value::Message(new_heap_pos),
 
                            });
 

	
 
                            // Dropping the original subject, because we don't
 
                            // want to drop something on the stack
 
                            self.store.drop_value(subject.get_heap_pos());
 
                        },
 
                        Expression::Select(expr) => {
 
@@ -542,12 +563,82 @@ impl Prompt {
 
                            self.store.drop_value(subject.get_heap_pos());
 
                        }
 
                        Expression::Call(expr) => {
 
                            // If we're dealing with a builtin we don't do any
 
                            // fancy shenanigans at all, just push the result.
 
                            match expr.method {
 
                                Method::Get => {
 
                                    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) {
 
                                        Some(result) => {
 
                                            cur_frame.expr_values.push_back(result)
 
                                        },
 
                                        None => {
 
                                            cur_frame.expr_values.push_front(value.clone());
 
                                            cur_frame.expr_stack.push_back(ExprInstruction::EvalExpr(expr_id));
 
                                            return Ok(EvalContinuation::BlockGet(value));
 
                                        }
 
                                    }
 
                                },
 
                                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 msg_value = cur_frame.expr_values.pop_front().unwrap();
 
                                    let deref_msg_value = self.store.maybe_read_ref(&msg_value).clone();
 

	
 
                                    if ctx.did_put(deref_port_value.clone()) {
 
                                        // We're fine, deallocate in case the expression value stack
 
                                        // held an owned value
 
                                        self.store.drop_value(msg_value.get_heap_pos());
 
                                    } else {
 
                                        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));
 
                                    }
 
                                },
 
                                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()) {
 
                                        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));
 
                                        },
 
                                        Some(value) => {
 
                                            cur_frame.expr_values.push_back(value);
 
                                        }
 
                                    }
 
                                },
 
                                Method::Create => {
 
                                    let length_value = cur_frame.expr_values.pop_front().unwrap();
 
                                    let length_value = self.store.maybe_read_ref(&length_value);
 
                                    let length = if length_value.is_signed_integer() {
 
                                        let length_value = length_value.as_signed_integer();
 
                                        if length_value < 0 {
 
                                            return Err(EvalError::new_error_at_expr(
 
                                                self, modules, heap, expr_id,
 
                                                format!("got length '{}', can only create a message with a non-negative length", length_value)
 
                                            ));
 
                                        }
 

	
 
                                        length_value as u64
 
                                    } else {
 
                                        debug_assert!(length_value.is_unsigned_integer());
 
                                        length_value.as_unsigned_integer()
 
                                    };
 

	
 
                                    let heap_pos = self.store.alloc_heap();
 
                                    let values = &mut self.store.heap_regions[heap_pos as usize].values;
 
                                    debug_assert!(values.is_empty());
 
                                    values.resize(length as usize, Value::UInt8(0));
 
                                    cur_frame.expr_values.push_back(Value::Message(heap_pos));
 
                                },
 
                                Method::Length => {
 
                                    let value = cur_frame.expr_values.pop_front().unwrap();
 
                                    let value_heap_pos = value.get_heap_pos();
 
                                    let value = self.store.maybe_read_ref(&value);
 

	
 
                                    let heap_pos = match value {
 
@@ -559,13 +650,25 @@ impl Prompt {
 
                                    let len = self.store.heap_regions[heap_pos as usize].values.len();
 

	
 
                                    // TODO: @PtrInt
 
                                    cur_frame.expr_values.push_back(Value::UInt32(len as u32));
 
                                    self.store.drop_value(value_heap_pos);
 
                                },
 
                                Method::UserComponent => todo!("component creation"),
 
                                Method::Assert => {
 
                                    let value = cur_frame.expr_values.pop_front().unwrap();
 
                                    let value = self.store.maybe_read_ref(&value).clone();
 
                                    if !value.as_bool() {
 
                                        return Ok(EvalContinuation::Inconsistent)
 
                                    }
 
                                },
 
                                Method::UserComponent => {
 
                                    // This is actually handled by the evaluation
 
                                    // of the statement.
 
                                    debug_assert_eq!(heap[expr.definition].parameters().len(), cur_frame.expr_values.len());
 
                                    debug_assert_eq!(heap[cur_frame.position].as_new().expression, expr.this)
 
                                },
 
                                Method::UserFunction => {
 
                                    // Push a new frame. Note that all expressions have
 
                                    // been pushed to the front, so they're in the order
 
                                    // of the definition.
 
                                    let num_args = expr.arguments.len();
 

	
 
@@ -592,13 +695,12 @@ impl Prompt {
 
                                    self.store.reserve_stack(new_stack_size);
 

	
 
                                    // To simplify the logic a little bit we will now
 
                                    // return and ask our caller to call us again
 
                                    return Ok(EvalContinuation::Stepping);
 
                                },
 
                                _ => todo!("other builtins"),
 
                            }
 
                        },
 
                        Expression::Variable(expr) => {
 
                            let variable = &heap[expr.declaration.unwrap()];
 
                            let ref_value = if expr.used_as_binding_target {
 
                                Value::Binding(variable.unique_id_in_scope as StackPos)
 
@@ -668,13 +770,14 @@ impl Prompt {
 
                cur_frame.position = stmt.body;
 

	
 
                Ok(EvalContinuation::Stepping)
 
            },
 
            Statement::If(stmt) => {
 
                debug_assert_eq!(cur_frame.expr_values.len(), 1, "expected one expr value for if statement");
 
                let test_value = cur_frame.expr_values.pop_back().unwrap().as_bool();
 
                let test_value = cur_frame.expr_values.pop_back().unwrap();
 
                let test_value = self.store.maybe_read_ref(&test_value).as_bool();
 
                if test_value {
 
                    cur_frame.position = stmt.true_body.upcast();
 
                } else if let Some(false_body) = stmt.false_body {
 
                    cur_frame.position = false_body.upcast();
 
                } else {
 
                    // Not true, and no false body
 
@@ -686,13 +789,14 @@ impl Prompt {
 
            Statement::EndIf(stmt) => {
 
                cur_frame.position = stmt.next;
 
                Ok(EvalContinuation::Stepping)
 
            },
 
            Statement::While(stmt) => {
 
                debug_assert_eq!(cur_frame.expr_values.len(), 1, "expected one expr value for while statement");
 
                let test_value = cur_frame.expr_values.pop_back().unwrap().as_bool();
 
                let test_value = cur_frame.expr_values.pop_back().unwrap();
 
                let test_value = self.store.maybe_read_ref(&test_value).as_bool();
 
                if test_value {
 
                    cur_frame.position = stmt.body.upcast();
 
                } else {
 
                    cur_frame.position = stmt.end_while.upcast();
 
                }
 

	
 
@@ -795,19 +899,18 @@ impl Prompt {
 
                for arg in &args {
 
                    self.store.drop_value(arg.get_heap_pos());
 
                }
 

	
 
                cur_frame.position = stmt.next;
 

	
 
                todo!("Make sure this is handled correctly, transfer 'heap' values to another Prompt");
 
                Ok(EvalContinuation::NewComponent(call_expr.definition, expr_data.field_or_monomorph_idx, argument_group))
 
            },
 
            Statement::Expression(stmt) => {
 
                // The expression has just been completely evaluated. Some
 
                // values might have remained on the expression value stack.
 
                cur_frame.expr_values.clear();
 
                // cur_frame.expr_values.clear(); PROPER CLEARING
 
                cur_frame.position = stmt.next;
 

	
 
                Ok(EvalContinuation::Stepping)
 
            },
 
        };
 

	
src/protocol/eval/value.rs
Show inline comments
 
@@ -187,12 +187,13 @@ impl ValueGroup {
 
    }
 

	
 
    /// Transfers a provided value from a store into a local value with its
 
    /// heap allocations (if any) stored in the ValueGroup. Calling this
 
    /// function will not store the returned value in the `values` member.
 
    fn retrieve_value(&mut self, value: &Value, from_store: &Store) -> Value {
 
        let value = from_store.maybe_read_ref(value);
 
        if let Some(heap_pos) = value.get_heap_pos() {
 
            // Value points to a heap allocation, so transfer the heap values
 
            // internally.
 
            let from_region = &from_store.heap_regions[heap_pos as usize].values;
 
            let mut new_region = Vec::with_capacity(from_region.len());
 
            for value in from_region {
src/protocol/mod.rs
Show inline comments
 
@@ -339,18 +339,17 @@ impl EvalContext<'_> {
 
            EvalContext::Sync(context) => match port {
 
                Value::Output(port) => {
 
                    debug_assert!(false, "Getting from an output port? Am I mad?");
 
                    unreachable!();
 
                }
 
                Value::Input(port) => {
 
                    let heap_pos = store.alloc_heap();
 
                    let heap_pos_usize = heap_pos as usize;
 

	
 
                    let payload = context.read_msg(port);
 
                    if payload.is_none() { return None; }
 

	
 
                    let heap_pos = store.alloc_heap();
 
                    let heap_pos_usize = heap_pos as usize;
 
                    let payload = payload.unwrap();
 
                    store.heap_regions[heap_pos_usize].values.reserve(payload.0.len());
 
                    for value in payload.0.iter() {
 
                        store.heap_regions[heap_pos_usize].values.push(Value::UInt8(*value));
 
                    }
 

	
src/protocol/parser/pass_definitions.rs
Show inline comments
 
@@ -690,13 +690,13 @@ impl PassDefinitions {
 

	
 
    fn consume_channel_statement(
 
        &mut self, module: &Module, iter: &mut TokenIter, ctx: &mut PassCtx
 
    ) -> Result<ChannelStatementId, ParseError> {
 
        // Consume channel specification
 
        let channel_span = consume_exact_ident(&module.source, iter, KW_STMT_CHANNEL)?;
 
        let channel_type = if Some(TokenKind::OpenAngle) == iter.next() {
 
        let inner_port_type = if Some(TokenKind::OpenAngle) == iter.next() {
 
            // Retrieve the type of the channel, we're cheating a bit here by
 
            // consuming the first '<' and setting the initial angle depth to 1
 
            // such that our final '>' will be consumed as well.
 
            iter.consume();
 
            let definition_id = self.cur_definition;
 
            let poly_vars = ctx.heap[definition_id].poly_vars();
 
@@ -716,25 +716,33 @@ impl PassDefinitions {
 
        let from_identifier = consume_ident_interned(&module.source, iter, ctx)?;
 
        consume_token(&module.source, iter, TokenKind::ArrowRight)?;
 
        let to_identifier = consume_ident_interned(&module.source, iter, ctx)?;
 
        consume_token(&module.source, iter, TokenKind::SemiColon)?;
 

	
 
        // Construct ports
 
        let port_type_len = inner_port_type.elements.len() + 1;
 
        let mut from_port_type = ParserType{ elements: Vec::with_capacity(port_type_len) };
 
        from_port_type.elements.push(ParserTypeElement{ full_span: channel_span, variant: ParserTypeVariant::Output });
 
        from_port_type.elements.extend_from_slice(&inner_port_type.elements);
 
        let from = ctx.heap.alloc_variable(|this| Variable{
 
            this,
 
            kind: VariableKind::Local,
 
            identifier: from_identifier,
 
            parser_type: channel_type.clone(),
 
            parser_type: from_port_type,
 
            relative_pos_in_block: 0,
 
            unique_id_in_scope: -1,
 
        });
 

	
 
        let mut to_port_type = ParserType{ elements: Vec::with_capacity(port_type_len) };
 
        to_port_type.elements.push(ParserTypeElement{ full_span: channel_span, variant: ParserTypeVariant::Input });
 
        to_port_type.elements.extend_from_slice(&inner_port_type.elements);
 
        let to = ctx.heap.alloc_variable(|this|Variable{
 
            this,
 
            kind: VariableKind::Local,
 
            identifier: to_identifier,
 
            parser_type: channel_type,
 
            parser_type: to_port_type,
 
            relative_pos_in_block: 0,
 
            unique_id_in_scope: -1,
 
        });
 

	
 
        // Construct the channel
 
        Ok(ctx.heap.alloc_channel_statement(|this| ChannelStatement{
src/protocol/parser/pass_validation_linking.rs
Show inline comments
 
@@ -400,12 +400,13 @@ impl Visitor2 for PassValidationLinking {
 
    //--------------------------------------------------------------------------
 
    // Expression visitors
 
    //--------------------------------------------------------------------------
 

	
 
    fn visit_assignment_expr(&mut self, ctx: &mut Ctx, id: AssignmentExpressionId) -> VisitorResult {
 
        let upcast_id = id.upcast();
 

	
 
        let assignment_expr = &mut ctx.heap[id];
 

	
 
        let left_expr_id = assignment_expr.left;
 
        let right_expr_id = assignment_expr.right;
 
        let old_expr_parent = self.expr_parent;
 
        assignment_expr.parent = old_expr_parent;
 
@@ -583,14 +584,18 @@ impl Visitor2 for PassValidationLinking {
 
        indexing_expr.parent = old_expr_parent;
 
        indexing_expr.unique_id_in_definition = self.next_expr_index;
 
        self.next_expr_index += 1;
 

	
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 0);
 
        self.visit_expr(ctx, subject_expr_id)?;
 

	
 
        let old_assignable = self.must_be_assignable.take();
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 1);
 
        self.visit_expr(ctx, index_expr_id)?;
 

	
 
        self.must_be_assignable = old_assignable;
 
        self.expr_parent = old_expr_parent;
 

	
 
        Ok(())
 
    }
 

	
 
    fn visit_slicing_expr(&mut self, ctx: &mut Ctx, id: SlicingExpressionId) -> VisitorResult {
 
@@ -605,16 +610,20 @@ impl Visitor2 for PassValidationLinking {
 
        slicing_expr.parent = old_expr_parent;
 
        slicing_expr.unique_id_in_definition = self.next_expr_index;
 
        self.next_expr_index += 1;
 

	
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 0);
 
        self.visit_expr(ctx, subject_expr_id)?;
 

	
 
        let old_assignable = self.must_be_assignable.take();
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 1);
 
        self.visit_expr(ctx, from_expr_id)?;
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 2);
 
        self.visit_expr(ctx, to_expr_id)?;
 

	
 
        self.must_be_assignable = old_assignable;
 
        self.expr_parent = old_expr_parent;
 

	
 
        Ok(())
 
    }
 

	
 
    fn visit_select_expr(&mut self, ctx: &mut Ctx, id: SelectExpressionId) -> VisitorResult {
 
@@ -862,13 +871,13 @@ impl Visitor2 for PassValidationLinking {
 
                if !self.def_type.is_primitive() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'get' may only occur in primitive component definitions"
 
                    ));
 
                }
 
                if !self.in_sync.is_invalid() {
 
                if self.in_sync.is_invalid() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'get' may only occur inside synchronous blocks"
 
                    ));
 
                }
 
            },
 
@@ -876,13 +885,13 @@ impl Visitor2 for PassValidationLinking {
 
                if !self.def_type.is_primitive() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'put' may only occur in primitive component definitions"
 
                    ));
 
                }
 
                if !self.in_sync.is_invalid() {
 
                if self.in_sync.is_invalid() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'put' may only occur inside synchronous blocks"
 
                    ));
 
                }
 
            },
 
@@ -890,13 +899,13 @@ impl Visitor2 for PassValidationLinking {
 
                if !self.def_type.is_primitive() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'fires' may only occur in primitive component definitions"
 
                    ));
 
                }
 
                if !self.in_sync.is_invalid() {
 
                if self.in_sync.is_invalid() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "a call to 'fires' may only occur inside synchronous blocks"
 
                    ));
 
                }
 
            },
 
@@ -906,13 +915,13 @@ impl Visitor2 for PassValidationLinking {
 
                if self.def_type.is_function() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "assert statement may only occur in components"
 
                    ));
 
                }
 
                if !self.in_sync.is_invalid() {
 
                if self.in_sync.is_invalid() {
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module.source, call_expr.span,
 
                        "assert statements may only occur inside synchronous blocks"
 
                    ));
 
                }
 
            },
src/protocol/tests/eval_binding.rs
Show inline comments
 
@@ -79,12 +79,59 @@ fn test_binding_from_array() {
 
        }
 
    ").for_function("foo", |f| { f
 
        .call_ok(Some(Value::Bool(true)));
 
    });
 
}
 

	
 
#[test]
 
fn test_binding_from_union() {
 
    Tester::new_single_source_expect_ok("option type", "
 
        union Option<T> { Some(T), None }
 

	
 
        func is_some<T>(Option<T> opt) -> bool {
 
            if (let Option::Some(throwaway) = opt) return true;
 
            else                                   return false;
 
        }
 
        func is_none<T>(Option<T> opt) -> bool {
 
            if (let Option::Some(throwaway) = opt) return false;
 
            else                                   return true;
 
        }
 

	
 
        func foo() -> u32 {
 
            // Hey look, we're so modern, we have algebraic discriminated sum datauniontypes
 
            auto something = Option::Some(5);
 
            auto nonething = Option<u32>::None;
 

	
 
            bool success1 = false;
 
            if (let Option::Some(value) = something && let Option::None = nonething) {
 
                success1 = value == 5;
 
            }
 

	
 
            bool success2 = false;
 
            if (is_some(something) && is_none(nonething)) {
 
                success2 = true;
 
            }
 

	
 
            bool success3 = true;
 
            if (let Option::None = something) success3 = false;
 
            if (let Option::Some(value) = nonething) success3 = false;
 

	
 
            bool success4 = true;
 
            if (is_none(something) || is_some(nonething)) success4 = false;
 

	
 
            if (success1 && success2 && success3 && success4) {
 
                if (let Option::Some(value) = something) return value;
 
            }
 

	
 
            return 0;
 
        }
 
    ").for_function("foo", |f| { f
 
        .call_ok(Some(Value::UInt32(5)));
 
    });
 
}
 

	
 
#[test]
 
fn test_binding_fizz_buzz() {
 
    Tester::new_single_source_expect_ok("am I employable?", "
 
        union Fizzable { Number(u32), FizzBuzz, Fizz, Buzz }
 

	
 
        func construct_fizz_buzz(u32 num) -> Fizzable[] {
src/runtime/tests.rs
Show inline comments
 
@@ -34,12 +34,25 @@ fn file_logged_configured_connector(
 
    let path = dir_path.join(format!("cid_{:?}.txt", connector_id));
 
    let file = File::create(path).expect("Failed to create log output file!");
 
    let file_logger = Box::new(FileLogger::new(connector_id, file));
 
    Connector::new(file_logger, pd, connector_id)
 
}
 
static MINIMAL_PDL: &'static [u8] = b"
 
primitive sync(in<msg> a, out<msg> b) {
 
    while (true) {
 
        synchronous {
 
            if (fires(a) && fires(b)) {
 
            	msg x = get(a);
 
            	put(b, x);
 
            } else {
 
                assert(!fires(a) && !fires(b));
 
            }
 
        }
 
    }
 
}
 

	
 
primitive together(in<msg> ia, in<msg> ib, out<msg> oa, out<msg> ob){
 
  while(true) synchronous {
 
    if(fires(ia)) {
 
      put(oa, get(ia));
 
      put(ob, get(ib));
 
    }
 
@@ -967,19 +980,21 @@ fn pdl_reo_fifo1() {
 

	
 
#[test]
 
fn pdl_reo_fifo1full() {
 
    let test_log_path = Path::new("./logs/pdl_reo_fifo1full");
 
    let pdl = b"
 
    primitive fifo1full(in<msg> a, out<msg> b) {
 
        bool is_set = true;
 
        msg m = create(0);
 
        while(true) synchronous {
 
            if(m == null) {
 
            if(!is_set) {
 
                if(fires(a)) m=get(a);
 
                is_set = false;
 
            } else {
 
                if(fires(b)) put(b, m);
 
                m = null;
 
                is_set = true;
 
            }
 
        }
 
    }
 
    ";
 
    let pd = reowolf::ProtocolDescription::parse(pdl).unwrap();
 
    let mut c = file_logged_configured_connector(0, test_log_path, Arc::new(pd));
 
@@ -1021,13 +1036,13 @@ fn pdl_msg_consensus() {
 

	
 
#[test]
 
fn sequencer3_prim() {
 
    let test_log_path = Path::new("./logs/sequencer3_prim");
 
    let pdl = b"
 
    primitive sequencer3(out<msg> a, out<msg> b, out<msg> c) {
 
        int i = 0;
 
        u32 i = 0;
 
        while(true) synchronous {
 
            out to = a;
 
            if     (i==1) to = b;
 
            else if(i==2) to = c;
 
            if(fires(to)) {
 
                put(to, create(0));
 
@@ -1067,27 +1082,41 @@ fn sequencer3_prim() {
 
}
 

	
 
#[test]
 
fn sequencer3_comp() {
 
    let test_log_path = Path::new("./logs/sequencer3_comp");
 
    let pdl = b"
 
    primitive fifo1_init<T>(T m, in<T> a, out<T> b) {
 
    primitive replicator<T>(in<T> a, out<T> b, out<T> c) {
 
        while (true) {
 
            synchronous {
 
                if (fires(a) && fires(b) && fires(c)) {
 
                    msg x = get(a);
 
                    put(b, x);
 
                    put(c, x);
 
                } else {
 
                    assert(!fires(a) && !fires(b) && !fires(c));
 
                }
 
            }
 
        }
 
    }
 
    primitive fifo1_init<T>(bool has_value, T m, in<T> a, out<T> b) {
 
        while(true) synchronous {
 
            if(m != null && fires(b)) {
 
            if(has_value && fires(b)) {
 
                put(b, m);
 
                m = null;
 
            } else if (m == null && fires(a)) {
 
                has_value = false;
 
            } else if (!has_value && fires(a)) {
 
                m = get(a);
 
                has_value = true;
 
            }
 
        }
 
    }
 
    composite fifo1_full<T>(in<T> a, out<T> b) {
 
        new fifo1_init(create(0), a, b);
 
        new fifo1_init(true, create(0), a, b);
 
    }
 
    composite fifo1<T>(in<T> a, out<T> b) {
 
        new fifo1_init(null, a, b);
 
        new fifo1_init(false, create(0), a, b);
 
    }
 
    composite sequencer3(out<msg> a, out<msg> b, out<msg> c) {
 
        channel d -> e;
 
        channel f -> g;
 
        channel h -> i;
 
        channel j -> k;
 
@@ -1188,25 +1217,53 @@ fn xrouter_prim() {
 
    println!("PRIM {:?}", now.elapsed());
 
}
 
#[test]
 
fn xrouter_comp() {
 
    let test_log_path = Path::new("./logs/xrouter_comp");
 
    let pdl = b"
 
    primitive replicator<T>(in<T> a, out<T> b, out<T> c) {
 
        while (true) {
 
            synchronous {
 
                if (fires(a) && fires(b) && fires(c)) {
 
                    msg x = get(a);
 
                    put(b, x);
 
                    put(c, x);
 
                } else {
 
                    assert(!fires(a) && !fires(b) && !fires(c));
 
                }
 
            }
 
        }
 
    }
 

	
 
    primitive merger(in<msg> a, in<msg> b, out<msg> c) {
 
        while (true) {
 
            synchronous {
 
                if (fires(a) && !fires(b) && fires(c)) {
 
                    put(c, get(a));
 
                } else if (!fires(a) && fires(b) && fires(c)) {
 
                    put(c, get(b));
 
                } else {
 
                    assert(!fires(a) && !fires(b) && !fires(c));
 
                }
 
            }
 
        }
 
    }
 

	
 
    primitive lossy<T>(in<T> a, out<T> b) {
 
        while(true) synchronous {
 
            if(fires(a)) {
 
                auto m = get(a);
 
                if(fires(b)) put(b, m);
 
            }
 
        }
 
    }
 
    primitive sync_drain<T>(in<T> a, in<T> b) {
 
        while(true) synchronous {
 
            if(fires(a)) {
 
                get(a);
 
                get(b);
 
                msg drop_it = get(a);
 
                msg on_the_floor = get(b);
 
            }
 
        }
 
    }
 
    composite xrouter(in<msg> a, out<msg> b, out<msg> c) {
 
        channel d -> e;
 
        channel f -> g;
 
@@ -1286,19 +1343,19 @@ fn count_stream() {
 

	
 
#[test]
 
fn for_msg_byte() {
 
    let test_log_path = Path::new("./logs/for_msg_byte");
 
    let pdl = b"
 
    primitive for_msg_byte(out<msg> o) {
 
        byte i = 0;
 
        int idx = 0;
 
        u8 i = 0;
 
        u32 idx = 0;
 
        while(i<8) {
 
            msg m = create(1);
 
            m[idx] = i;
 
            synchronous put(o, m);
 
            i++;
 
            i += 1;
 
        }
 
    }
 
    ";
 
    let pd = reowolf::ProtocolDescription::parse(pdl).unwrap();
 
    let mut c = file_logged_configured_connector(0, test_log_path, Arc::new(pd));
 

	
 
@@ -1317,14 +1374,14 @@ fn for_msg_byte() {
 

	
 
#[test]
 
fn eq_causality() {
 
    let test_log_path = Path::new("./logs/eq_causality");
 
    let pdl = b"
 
    primitive eq(in<msg> a, in<msg> b, out<msg> c) {
 
        msg ma = null;
 
        msg mb = null;
 
        msg ma = create(0);
 
        msg mb = create(0);
 
        while(true) synchronous {
 
            if(fires(a)) {
 
                // b and c also fire!
 
                // left first!
 
                ma = get(a);
 
                put(c, ma);
 
@@ -1373,57 +1430,36 @@ fn eq_no_causality() {
 
    let pdl = b"
 
    composite eq(in<msg> a, in<msg> b, out<msg> c) {
 
        channel leftfirsto -> leftfirsti;
 
        new eqinner(a, b, c, leftfirsto, leftfirsti);
 
    }
 
    primitive eqinner(in<msg> a, in<msg> b, out<msg> c, out<msg> leftfirsto, in<msg> leftfirsti) {
 
        msg ma = null;
 
        msg mb = null;
 
        msg ma = create(0);
 
        msg mb = create(0);
 
        while(true) synchronous {
 
            if(fires(a)) {
 
                // b and c also fire!
 
                if(fires(leftfirsti)) {
 
                    // left first! DO USE DUMMY
 
                    ma = get(a);
 
                    put(c, ma);
 
                    mb = get(b);
 

	
 
                    // using dummy!
 
                    put(leftfirsto, ma);
 
                    get(leftfirsti);
 
                    auto drop_it = get(leftfirsti);
 
                } else {
 
                    // right first! DON'T USE DUMMY
 
                    mb = get(b);
 
                    put(c, mb);
 
                    ma = get(a);
 
                }
 
                assert(ma == mb);
 
            }
 
        }
 
    }
 
    T some_function<T>(int a, int b) {
 
        T something = a;
 
        return something;
 
    }
 
    primitive quick_test(in<int> a, in<int> b) {
 
        // msg ma = null;
 
        auto test1 = 0;
 
        auto test2 = 0;
 
        auto ma = some_function(test1, test2);
 
        while(true) synchronous {
 
            if (fires(a)) {
 
                ma = get(a);
 
            }
 
            if (fires(b)) {
 
                ma = get(b);
 
            }
 
            if (fires(a) && fires(b)) {
 
                ma = get(a) + get(b);
 
            }
 
        }
 
    }
 
    ";
 
    let pd = reowolf::ProtocolDescription::parse(pdl).unwrap();
 
    let mut c = file_logged_configured_connector(0, test_log_path, Arc::new(pd));
 

	
 
    /*
 
    [native]p0-->g0[eq]p1--.
0 comments (0 inline, 0 general)