Changeset - a226385adc2d
[Not reviewed]
0 11 0
Christopher Esterhuyse - 5 years ago 2020-02-05 16:50:00
christopheresterhuyse@gmail.com
natives working
8 files changed:
0 comments (0 inline, 0 general)
Cargo.toml
Show inline comments
 
[package]
 
name = "reowolf_rs"
 
version = "0.1.1"
 
authors = [
 
	"Christopher Esterhuyse <christopher.esterhuyse@gmail.com>",
 
	"Hans-Dieter Hiep <hdh@cwi.nl>"
 
]
 
edition = "2018"
 

	
 
[dependencies]
 

	
 
# runtime stuff
 
getrandom = "0.1.14" # tiny crate. used to guess controller-id
 
take_mut = "0.2.2"
 
maplit = "1.0.2" # convenience macros
 
indexmap = "1.3.0" # hashsets/hashmaps with efficient arbitrary element removal
 

	
 
# network stuff
 
integer-encoding = "1.0.7"
 
byteorder = "1.3.2"
 
mio = "0.6.21" # migrate to mio 0.7.0 when it stabilizes. It's much better.
 
mio-extras = "2.0.6"
 

	
 
# protocol stuff
 
id-arena = "2.2.1"
 
backtrace = "0.3"
 

	
 
[dev-dependencies]
 
test-generator = "0.3.0"
 
crossbeam-utils = "0.7.0"
 

	
 
[lib]
 
crate-type = ["cdylib"]
 

	
 
[features]
 
default = ["ffi"]
 
ffi = [] # no feature dependencies
 
\ No newline at end of file
src/protocol/ast.rs
Show inline comments
 
use std::fmt;
 
use std::fmt::{Debug, Display, Formatter};
 
use std::ops::{Index, IndexMut};
 

	
 
use id_arena::{Arena, Id};
 

	
 
use crate::protocol::inputsource::*;
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct RootId(Id<Root>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct PragmaId(Id<Pragma>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ImportId(Id<Import>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct IdentifierId(Id<Identifier>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct SourceIdentifierId(IdentifierId);
 

	
 
impl SourceIdentifierId {
 
    pub fn upcast(self) -> IdentifierId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct ExternalIdentifierId(IdentifierId);
 

	
 
impl ExternalIdentifierId {
 
    pub fn upcast(self) -> IdentifierId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct TypeAnnotationId(Id<TypeAnnotation>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct VariableId(Id<Variable>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct ParameterId(VariableId);
 

	
 
impl ParameterId {
 
    pub fn upcast(self) -> VariableId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
pub struct LocalId(VariableId);
 

	
 
impl LocalId {
 
    pub fn upcast(self) -> VariableId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct DefinitionId(Id<Definition>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ComponentId(DefinitionId);
 

	
 
impl ComponentId {
 
    pub fn upcast(self) -> DefinitionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct FunctionId(DefinitionId);
 

	
 
impl FunctionId {
 
    pub fn upcast(self) -> DefinitionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct CompositeId(ComponentId);
 

	
 
impl CompositeId {
 
    pub fn upcast(self) -> ComponentId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct PrimitiveId(ComponentId);
 

	
 
impl PrimitiveId {
 
    pub fn upcast(self) -> ComponentId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct StatementId(Id<Statement>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct BlockStatementId(StatementId);
 

	
 
impl BlockStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct LocalStatementId(StatementId);
 

	
 
impl LocalStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct MemoryStatementId(LocalStatementId);
 

	
 
impl MemoryStatementId {
 
    pub fn upcast(self) -> LocalStatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ChannelStatementId(LocalStatementId);
 

	
 
impl ChannelStatementId {
 
    pub fn upcast(self) -> LocalStatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct SkipStatementId(StatementId);
 

	
 
impl SkipStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct LabeledStatementId(StatementId);
 

	
 
impl LabeledStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct IfStatementId(StatementId);
 

	
 
impl IfStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct EndIfStatementId(StatementId);
 

	
 
impl EndIfStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct WhileStatementId(StatementId);
 

	
 
impl WhileStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct EndWhileStatementId(StatementId);
 

	
 
impl EndWhileStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct BreakStatementId(StatementId);
 

	
 
impl BreakStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ContinueStatementId(StatementId);
 

	
 
impl ContinueStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct SynchronousStatementId(StatementId);
 

	
 
impl SynchronousStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct EndSynchronousStatementId(StatementId);
 

	
 
impl EndSynchronousStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ReturnStatementId(StatementId);
 

	
 
impl ReturnStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct AssertStatementId(StatementId);
 

	
 
impl AssertStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct GotoStatementId(StatementId);
 

	
 
impl GotoStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct NewStatementId(StatementId);
 

	
 
impl NewStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct PutStatementId(StatementId);
 

	
 
impl PutStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ExpressionStatementId(StatementId);
 

	
 
impl ExpressionStatementId {
 
    pub fn upcast(self) -> StatementId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ExpressionId(Id<Expression>);
 

	
 
#[derive(Debug, Clone, Copy)]
 
pub struct AssignmentExpressionId(ExpressionId);
 

	
 
impl AssignmentExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ConditionalExpressionId(ExpressionId);
 

	
 
impl ConditionalExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct BinaryExpressionId(ExpressionId);
 

	
 
impl BinaryExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct UnaryExpressionId(ExpressionId);
 

	
 
impl UnaryExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct IndexingExpressionId(ExpressionId);
 

	
 
impl IndexingExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct SlicingExpressionId(ExpressionId);
 

	
 
impl SlicingExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct SelectExpressionId(ExpressionId);
 

	
 
impl SelectExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ArrayExpressionId(ExpressionId);
 

	
 
impl ArrayExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ConstantExpressionId(ExpressionId);
 

	
 
impl ConstantExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct CallExpressionId(ExpressionId);
 

	
 
impl CallExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct VariableExpressionId(ExpressionId);
 

	
 
impl VariableExpressionId {
 
    pub fn upcast(self) -> ExpressionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct DeclarationId(Id<Declaration>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct DefinedDeclarationId(DeclarationId);
 

	
 
impl DefinedDeclarationId {
 
    pub fn upcast(self) -> DeclarationId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq)]
 
pub struct ImportedDeclarationId(DeclarationId);
 

	
 
impl ImportedDeclarationId {
 
    pub fn upcast(self) -> DeclarationId {
 
        self.0
 
    }
 
}
 

	
 
pub struct Heap {
 
    // Phase 0: allocation
 
    protocol_descriptions: Arena<Root>,
 
    pragmas: Arena<Pragma>,
 
    imports: Arena<Import>,
 
    identifiers: Arena<Identifier>,
 
    type_annotations: Arena<TypeAnnotation>,
 
    variables: Arena<Variable>,
 
    definitions: Arena<Definition>,
 
    statements: Arena<Statement>,
 
    expressions: Arena<Expression>,
 
    declarations: Arena<Declaration>,
 
}
 

	
 
impl Heap {
 
    pub fn new() -> Heap {
 
        Heap {
 
            protocol_descriptions: Arena::new(),
 
            pragmas: Arena::new(),
 
            imports: Arena::new(),
 
            identifiers: Arena::new(),
 
            type_annotations: Arena::new(),
 
            variables: Arena::new(),
 
            definitions: Arena::new(),
 
            statements: Arena::new(),
 
            expressions: Arena::new(),
 
            declarations: Arena::new(),
 
        }
 
    }
 
    pub fn alloc_source_identifier(
 
        &mut self,
 
        f: impl FnOnce(SourceIdentifierId) -> SourceIdentifier,
 
    ) -> SourceIdentifierId {
 
        SourceIdentifierId(IdentifierId(
 
            self.identifiers
 
                .alloc_with_id(|id| Identifier::Source(f(SourceIdentifierId(IdentifierId(id))))),
 
        ))
 
    }
 
    pub fn alloc_external_identifier(
 
        &mut self,
 
        f: impl FnOnce(ExternalIdentifierId) -> ExternalIdentifier,
 
    ) -> ExternalIdentifierId {
 
        ExternalIdentifierId(IdentifierId(
 
            self.identifiers.alloc_with_id(|id| {
 
                Identifier::External(f(ExternalIdentifierId(IdentifierId(id))))
 
            }),
 
        ))
 
    }
 
    pub fn alloc_type_annotation(
 
        &mut self,
 
        f: impl FnOnce(TypeAnnotationId) -> TypeAnnotation,
 
    ) -> TypeAnnotationId {
 
        TypeAnnotationId(self.type_annotations.alloc_with_id(|id| f(TypeAnnotationId(id))))
 
    }
 
    pub fn alloc_parameter(&mut self, f: impl FnOnce(ParameterId) -> Parameter) -> ParameterId {
 
        ParameterId(VariableId(
 
            self.variables.alloc_with_id(|id| Variable::Parameter(f(ParameterId(VariableId(id))))),
 
        ))
 
    }
 
    pub fn alloc_local(&mut self, f: impl FnOnce(LocalId) -> Local) -> LocalId {
 
        LocalId(VariableId(
 
            self.variables.alloc_with_id(|id| Variable::Local(f(LocalId(VariableId(id))))),
 
        ))
 
    }
 
    pub fn alloc_assignment_expression(
 
        &mut self,
 
        f: impl FnOnce(AssignmentExpressionId) -> AssignmentExpression,
 
    ) -> AssignmentExpressionId {
 
        AssignmentExpressionId(ExpressionId(self.expressions.alloc_with_id(|id| {
 
            Expression::Assignment(f(AssignmentExpressionId(ExpressionId(id))))
 
        })))
 
    }
 
    pub fn alloc_conditional_expression(
 
        &mut self,
 
        f: impl FnOnce(ConditionalExpressionId) -> ConditionalExpression,
 
    ) -> ConditionalExpressionId {
 
        ConditionalExpressionId(ExpressionId(self.expressions.alloc_with_id(|id| {
 
            Expression::Conditional(f(ConditionalExpressionId(ExpressionId(id))))
 
        })))
 
    }
 
    pub fn alloc_binary_expression(
 
        &mut self,
 
        f: impl FnOnce(BinaryExpressionId) -> BinaryExpression,
 
    ) -> BinaryExpressionId {
 
        BinaryExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Binary(f(BinaryExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_unary_expression(
 
        &mut self,
 
        f: impl FnOnce(UnaryExpressionId) -> UnaryExpression,
 
    ) -> UnaryExpressionId {
 
        UnaryExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Unary(f(UnaryExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_slicing_expression(
 
        &mut self,
 
        f: impl FnOnce(SlicingExpressionId) -> SlicingExpression,
 
    ) -> SlicingExpressionId {
 
        SlicingExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Slicing(f(SlicingExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_indexing_expression(
 
        &mut self,
 
        f: impl FnOnce(IndexingExpressionId) -> IndexingExpression,
 
    ) -> IndexingExpressionId {
 
        IndexingExpressionId(ExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Indexing(f(IndexingExpressionId(ExpressionId(id))))
 
            }),
 
        ))
 
    }
 
    pub fn alloc_select_expression(
 
        &mut self,
 
        f: impl FnOnce(SelectExpressionId) -> SelectExpression,
 
    ) -> SelectExpressionId {
 
        SelectExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Select(f(SelectExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_array_expression(
 
        &mut self,
 
        f: impl FnOnce(ArrayExpressionId) -> ArrayExpression,
 
    ) -> ArrayExpressionId {
 
        ArrayExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Array(f(ArrayExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_constant_expression(
 
        &mut self,
 
        f: impl FnOnce(ConstantExpressionId) -> ConstantExpression,
 
    ) -> ConstantExpressionId {
 
        ConstantExpressionId(ExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Constant(f(ConstantExpressionId(ExpressionId(id))))
 
            }),
 
        ))
 
    }
 
    pub fn alloc_call_expression(
 
        &mut self,
 
        f: impl FnOnce(CallExpressionId) -> CallExpression,
 
    ) -> CallExpressionId {
 
        CallExpressionId(ExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Call(f(CallExpressionId(ExpressionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_variable_expression(
 
        &mut self,
 
        f: impl FnOnce(VariableExpressionId) -> VariableExpression,
 
    ) -> VariableExpressionId {
 
        VariableExpressionId(ExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Variable(f(VariableExpressionId(ExpressionId(id))))
 
            }),
 
        ))
 
    }
 
    pub fn alloc_block_statement(
 
        &mut self,
 
        f: impl FnOnce(BlockStatementId) -> BlockStatement,
 
    ) -> BlockStatementId {
 
        BlockStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Block(f(BlockStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_memory_statement(
 
        &mut self,
 
        f: impl FnOnce(MemoryStatementId) -> MemoryStatement,
 
    ) -> MemoryStatementId {
 
        MemoryStatementId(LocalStatementId(StatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Local(LocalStatement::Memory(f(MemoryStatementId(LocalStatementId(
 
                StatementId(id),
 
            )))))
 
        }))))
 
    }
 
    pub fn alloc_channel_statement(
 
        &mut self,
 
        f: impl FnOnce(ChannelStatementId) -> ChannelStatement,
 
    ) -> ChannelStatementId {
 
        ChannelStatementId(LocalStatementId(StatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Local(LocalStatement::Channel(f(ChannelStatementId(LocalStatementId(
 
                StatementId(id),
 
            )))))
 
        }))))
 
    }
 
    pub fn alloc_skip_statement(
 
        &mut self,
 
        f: impl FnOnce(SkipStatementId) -> SkipStatement,
 
    ) -> SkipStatementId {
 
        SkipStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Skip(f(SkipStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_if_statement(
 
        &mut self,
 
        f: impl FnOnce(IfStatementId) -> IfStatement,
 
    ) -> IfStatementId {
 
        IfStatementId(StatementId(
 
            self.statements.alloc_with_id(|id| Statement::If(f(IfStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_end_if_statement(
 
        &mut self,
 
        f: impl FnOnce(EndIfStatementId) -> EndIfStatement,
 
    ) -> EndIfStatementId {
 
        EndIfStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::EndIf(f(EndIfStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_while_statement(
 
        &mut self,
 
        f: impl FnOnce(WhileStatementId) -> WhileStatement,
 
    ) -> WhileStatementId {
 
        WhileStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::While(f(WhileStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_end_while_statement(
 
        &mut self,
 
        f: impl FnOnce(EndWhileStatementId) -> EndWhileStatement,
 
    ) -> EndWhileStatementId {
 
        EndWhileStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::EndWhile(f(EndWhileStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_break_statement(
 
        &mut self,
 
        f: impl FnOnce(BreakStatementId) -> BreakStatement,
 
    ) -> BreakStatementId {
 
        BreakStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Break(f(BreakStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_continue_statement(
 
        &mut self,
 
        f: impl FnOnce(ContinueStatementId) -> ContinueStatement,
 
    ) -> ContinueStatementId {
 
        ContinueStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Continue(f(ContinueStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_synchronous_statement(
 
        &mut self,
 
        f: impl FnOnce(SynchronousStatementId) -> SynchronousStatement,
 
    ) -> SynchronousStatementId {
 
        SynchronousStatementId(StatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Synchronous(f(SynchronousStatementId(StatementId(id))))
 
        })))
 
    }
 
    pub fn alloc_end_synchronous_statement(
 
        &mut self,
 
        f: impl FnOnce(EndSynchronousStatementId) -> EndSynchronousStatement,
 
    ) -> EndSynchronousStatementId {
 
        EndSynchronousStatementId(StatementId(self.statements.alloc_with_id(|id| {
 
            Statement::EndSynchronous(f(EndSynchronousStatementId(StatementId(id))))
 
        })))
 
    }
 
    pub fn alloc_return_statement(
 
        &mut self,
 
        f: impl FnOnce(ReturnStatementId) -> ReturnStatement,
 
    ) -> ReturnStatementId {
 
        ReturnStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Return(f(ReturnStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_assert_statement(
 
        &mut self,
 
        f: impl FnOnce(AssertStatementId) -> AssertStatement,
 
    ) -> AssertStatementId {
 
        AssertStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Assert(f(AssertStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_goto_statement(
 
        &mut self,
 
        f: impl FnOnce(GotoStatementId) -> GotoStatement,
 
    ) -> GotoStatementId {
 
        GotoStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Goto(f(GotoStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_new_statement(
 
        &mut self,
 
        f: impl FnOnce(NewStatementId) -> NewStatement,
 
    ) -> NewStatementId {
 
        NewStatementId(StatementId(
 
            self.statements.alloc_with_id(|id| Statement::New(f(NewStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_put_statement(
 
        &mut self,
 
        f: impl FnOnce(PutStatementId) -> PutStatement,
 
    ) -> PutStatementId {
 
        PutStatementId(StatementId(
 
            self.statements.alloc_with_id(|id| Statement::Put(f(PutStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_labeled_statement(
 
        &mut self,
 
        f: impl FnOnce(LabeledStatementId) -> LabeledStatement,
 
    ) -> LabeledStatementId {
 
        LabeledStatementId(StatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Labeled(f(LabeledStatementId(StatementId(id))))),
 
        ))
 
    }
 
    pub fn alloc_expression_statement(
 
        &mut self,
 
        f: impl FnOnce(ExpressionStatementId) -> ExpressionStatement,
 
    ) -> ExpressionStatementId {
 
        ExpressionStatementId(StatementId(
 
            self.statements.alloc_with_id(|id| {
 
                Statement::Expression(f(ExpressionStatementId(StatementId(id))))
 
            }),
 
        ))
 
    }
 
    pub fn alloc_composite(&mut self, f: impl FnOnce(CompositeId) -> Composite) -> CompositeId {
 
        CompositeId(ComponentId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(Component::Composite(f(CompositeId(ComponentId(DefinitionId(
 
                id,
 
            ))))))
 
        }))))
 
    }
 
    pub fn alloc_primitive(&mut self, f: impl FnOnce(PrimitiveId) -> Primitive) -> PrimitiveId {
 
        PrimitiveId(ComponentId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(Component::Primitive(f(PrimitiveId(ComponentId(DefinitionId(
 
                id,
 
            ))))))
 
        }))))
 
    }
 
    pub fn alloc_function(&mut self, f: impl FnOnce(FunctionId) -> Function) -> FunctionId {
 
        FunctionId(DefinitionId(
 
            self.definitions
 
                .alloc_with_id(|id| Definition::Function(f(FunctionId(DefinitionId(id))))),
 
        ))
 
    }
 
    pub fn alloc_pragma(&mut self, f: impl FnOnce(PragmaId) -> Pragma) -> PragmaId {
 
        PragmaId(self.pragmas.alloc_with_id(|id| f(PragmaId(id))))
 
    }
 
    pub fn alloc_import(&mut self, f: impl FnOnce(ImportId) -> Import) -> ImportId {
 
        ImportId(self.imports.alloc_with_id(|id| f(ImportId(id))))
 
    }
 
    pub fn alloc_protocol_description(
 
        &mut self,
 
        f: impl FnOnce(RootId) -> Root,
 
    ) -> RootId {
 
        RootId(
 
            self.protocol_descriptions.alloc_with_id(|id| f(RootId(id))),
 
        )
 
    pub fn alloc_protocol_description(&mut self, f: impl FnOnce(RootId) -> Root) -> RootId {
 
        RootId(self.protocol_descriptions.alloc_with_id(|id| f(RootId(id))))
 
    }
 
    pub fn alloc_imported_declaration(
 
        &mut self,
 
        f: impl FnOnce(ImportedDeclarationId) -> ImportedDeclaration,
 
    ) -> ImportedDeclarationId {
 
        ImportedDeclarationId(DeclarationId(self.declarations.alloc_with_id(|id| {
 
            Declaration::Imported(f(ImportedDeclarationId(DeclarationId(id))))
 
        })))
 
    }
 
    pub fn alloc_defined_declaration(
 
        &mut self,
 
        f: impl FnOnce(DefinedDeclarationId) -> DefinedDeclaration,
 
    ) -> DefinedDeclarationId {
 
        DefinedDeclarationId(DeclarationId(
 
            self.declarations.alloc_with_id(|id| {
 
                Declaration::Defined(f(DefinedDeclarationId(DeclarationId(id))))
 
            }),
 
        ))
 
    }
 

	
 
    pub fn get_external_identifier(&mut self, ident: &[u8]) -> ExternalIdentifierId {
 
        for (_, id) in self.identifiers.iter() {
 
            if id.is_external() && id.ident() == ident {
 
                return id.as_external().this;
 
            }
 
        }
 
        // Not found
 
        self.alloc_external_identifier(|this| ExternalIdentifier { this, value: ident.to_vec() })
 
    }
 
}
 

	
 
impl Index<RootId> for Heap {
 
    type Output = Root;
 
    fn index(&self, index: RootId) -> &Self::Output {
 
        &self.protocol_descriptions[index.0]
 
    }
 
}
 

	
 
impl IndexMut<RootId> for Heap {
 
    fn index_mut(&mut self, index: RootId) -> &mut Self::Output {
 
        &mut self.protocol_descriptions[index.0]
 
    }
 
}
 

	
 
impl Index<PragmaId> for Heap {
 
    type Output = Pragma;
 
    fn index(&self, index: PragmaId) -> &Self::Output {
 
        &self.pragmas[index.0]
 
    }
 
}
 

	
 
impl Index<ImportId> for Heap {
 
    type Output = Import;
 
    fn index(&self, index: ImportId) -> &Self::Output {
 
        &self.imports[index.0]
 
    }
 
}
 

	
 
impl Index<IdentifierId> for Heap {
 
    type Output = Identifier;
 
    fn index(&self, index: IdentifierId) -> &Self::Output {
 
        &self.identifiers[index.0]
 
    }
 
}
 

	
 
impl Index<SourceIdentifierId> for Heap {
 
    type Output = SourceIdentifier;
 
    fn index(&self, index: SourceIdentifierId) -> &Self::Output {
 
        &self.identifiers[(index.0).0].as_source()
 
    }
 
}
 

	
 
impl Index<ExternalIdentifierId> for Heap {
 
    type Output = ExternalIdentifier;
 
    fn index(&self, index: ExternalIdentifierId) -> &Self::Output {
 
        &self.identifiers[(index.0).0].as_external()
 
    }
 
}
 

	
 
impl Index<TypeAnnotationId> for Heap {
 
    type Output = TypeAnnotation;
 
    fn index(&self, index: TypeAnnotationId) -> &Self::Output {
 
        &self.type_annotations[index.0]
 
    }
 
}
 

	
 
impl Index<VariableId> for Heap {
 
    type Output = Variable;
 
    fn index(&self, index: VariableId) -> &Self::Output {
 
        &self.variables[index.0]
 
    }
 
}
 

	
 
impl Index<ParameterId> for Heap {
 
    type Output = Parameter;
 
    fn index(&self, index: ParameterId) -> &Self::Output {
 
        &self.variables[(index.0).0].as_parameter()
 
    }
 
}
 

	
 
impl Index<LocalId> for Heap {
 
    type Output = Local;
 
    fn index(&self, index: LocalId) -> &Self::Output {
 
        &self.variables[(index.0).0].as_local()
 
    }
 
}
 

	
 
impl Index<DefinitionId> for Heap {
 
    type Output = Definition;
 
    fn index(&self, index: DefinitionId) -> &Self::Output {
 
        &self.definitions[index.0]
 
    }
 
}
 

	
 
impl Index<ComponentId> for Heap {
 
    type Output = Component;
 
    fn index(&self, index: ComponentId) -> &Self::Output {
 
        &self.definitions[(index.0).0].as_component()
 
    }
 
}
 

	
 
impl Index<FunctionId> for Heap {
 
    type Output = Function;
 
    fn index(&self, index: FunctionId) -> &Self::Output {
 
        &self.definitions[(index.0).0].as_function()
 
    }
 
}
 

	
 
impl Index<CompositeId> for Heap {
 
    type Output = Composite;
 
    fn index(&self, index: CompositeId) -> &Self::Output {
 
        &self.definitions[((index.0).0).0].as_composite()
 
    }
 
}
 

	
 
impl Index<PrimitiveId> for Heap {
 
    type Output = Primitive;
 
    fn index(&self, index: PrimitiveId) -> &Self::Output {
 
        &self.definitions[((index.0).0).0].as_primitive()
 
    }
 
}
 

	
 
impl Index<StatementId> for Heap {
 
    type Output = Statement;
 
    fn index(&self, index: StatementId) -> &Self::Output {
 
        &self.statements[index.0]
 
    }
 
}
 

	
 
impl IndexMut<StatementId> for Heap {
 
    fn index_mut(&mut self, index: StatementId) -> &mut Self::Output {
 
        &mut self.statements[index.0]
 
    }
 
}
 

	
 
impl Index<BlockStatementId> for Heap {
 
    type Output = BlockStatement;
 
    fn index(&self, index: BlockStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_block()
 
    }
 
}
 

	
 
impl IndexMut<BlockStatementId> for Heap {
 
    fn index_mut(&mut self, index: BlockStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_block_mut()
 
    }
 
}
 

	
 
impl Index<LocalStatementId> for Heap {
 
    type Output = LocalStatement;
 
    fn index(&self, index: LocalStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_local()
 
    }
 
}
 

	
 
impl Index<MemoryStatementId> for Heap {
 
    type Output = MemoryStatement;
 
    fn index(&self, index: MemoryStatementId) -> &Self::Output {
 
        &self.statements[((index.0).0).0].as_memory()
 
    }
 
}
 

	
 
impl Index<ChannelStatementId> for Heap {
 
    type Output = ChannelStatement;
 
    fn index(&self, index: ChannelStatementId) -> &Self::Output {
 
        &self.statements[((index.0).0).0].as_channel()
 
    }
 
}
 

	
 
impl Index<SkipStatementId> for Heap {
 
    type Output = SkipStatement;
 
    fn index(&self, index: SkipStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_skip()
 
    }
 
}
 

	
 
impl Index<LabeledStatementId> for Heap {
 
    type Output = LabeledStatement;
 
    fn index(&self, index: LabeledStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_labeled()
 
    }
 
}
 

	
 
impl IndexMut<LabeledStatementId> for Heap {
 
    fn index_mut(&mut self, index: LabeledStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_labeled_mut()
 
    }
 
}
 

	
 
impl Index<IfStatementId> for Heap {
 
    type Output = IfStatement;
 
    fn index(&self, index: IfStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_if()
 
    }
 
}
 

	
 
impl Index<EndIfStatementId> for Heap {
 
    type Output = EndIfStatement;
 
    fn index(&self, index: EndIfStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_end_if()
 
    }
 
}
 

	
 
impl Index<WhileStatementId> for Heap {
 
    type Output = WhileStatement;
 
    fn index(&self, index: WhileStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_while()
 
    }
 
}
 

	
 
impl IndexMut<WhileStatementId> for Heap {
 
    fn index_mut(&mut self, index: WhileStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_while_mut()
 
    }
 
}
 

	
 
impl Index<BreakStatementId> for Heap {
 
    type Output = BreakStatement;
 
    fn index(&self, index: BreakStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_break()
 
    }
 
}
 

	
 
impl IndexMut<BreakStatementId> for Heap {
 
    fn index_mut(&mut self, index: BreakStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_break_mut()
 
    }
 
}
 

	
 
impl Index<ContinueStatementId> for Heap {
 
    type Output = ContinueStatement;
 
    fn index(&self, index: ContinueStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_continue()
 
    }
 
}
 

	
 
impl IndexMut<ContinueStatementId> for Heap {
 
    fn index_mut(&mut self, index: ContinueStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_continue_mut()
 
    }
 
}
 

	
 
impl Index<SynchronousStatementId> for Heap {
 
    type Output = SynchronousStatement;
 
    fn index(&self, index: SynchronousStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_synchronous()
 
    }
 
}
 

	
 
impl IndexMut<SynchronousStatementId> for Heap {
 
    fn index_mut(&mut self, index: SynchronousStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_synchronous_mut()
 
    }
 
}
 

	
 
impl Index<EndSynchronousStatementId> for Heap {
 
    type Output = EndSynchronousStatement;
 
    fn index(&self, index: EndSynchronousStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_end_synchronous()
 
    }
 
}
 

	
 
impl Index<ReturnStatementId> for Heap {
 
    type Output = ReturnStatement;
 
    fn index(&self, index: ReturnStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_return()
 
    }
 
}
 

	
 
impl Index<AssertStatementId> for Heap {
 
    type Output = AssertStatement;
 
    fn index(&self, index: AssertStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_assert()
 
    }
 
}
 

	
 
impl Index<GotoStatementId> for Heap {
 
    type Output = GotoStatement;
 
    fn index(&self, index: GotoStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_goto()
 
    }
 
}
 

	
 
impl IndexMut<GotoStatementId> for Heap {
 
    fn index_mut(&mut self, index: GotoStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_goto_mut()
 
    }
 
}
 

	
 
impl Index<NewStatementId> for Heap {
 
    type Output = NewStatement;
 
    fn index(&self, index: NewStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_new()
 
    }
 
}
 

	
 
impl Index<PutStatementId> for Heap {
 
    type Output = PutStatement;
 
    fn index(&self, index: PutStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_put()
 
    }
 
}
 

	
 
impl Index<ExpressionStatementId> for Heap {
 
    type Output = ExpressionStatement;
 
    fn index(&self, index: ExpressionStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_expression()
 
    }
 
}
 

	
 
impl Index<ExpressionId> for Heap {
 
    type Output = Expression;
 
    fn index(&self, index: ExpressionId) -> &Self::Output {
 
        &self.expressions[index.0]
 
    }
 
}
 

	
 
impl Index<AssignmentExpressionId> for Heap {
 
    type Output = AssignmentExpression;
 
    fn index(&self, index: AssignmentExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_assignment()
 
    }
 
}
 

	
 
impl Index<ConditionalExpressionId> for Heap {
 
    type Output = ConditionalExpression;
 
    fn index(&self, index: ConditionalExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_conditional()
 
    }
 
}
 

	
 
impl Index<BinaryExpressionId> for Heap {
 
    type Output = BinaryExpression;
 
    fn index(&self, index: BinaryExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_binary()
 
    }
 
}
 

	
 
impl Index<UnaryExpressionId> for Heap {
 
    type Output = UnaryExpression;
 
    fn index(&self, index: UnaryExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_unary()
 
    }
 
}
 

	
 
impl Index<IndexingExpressionId> for Heap {
 
    type Output = IndexingExpression;
 
    fn index(&self, index: IndexingExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_indexing()
 
    }
 
}
 

	
 
impl Index<SlicingExpressionId> for Heap {
 
    type Output = SlicingExpression;
 
    fn index(&self, index: SlicingExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_slicing()
 
    }
 
}
 

	
 
impl Index<SelectExpressionId> for Heap {
 
    type Output = SelectExpression;
 
    fn index(&self, index: SelectExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_select()
 
    }
 
}
 

	
 
impl Index<ArrayExpressionId> for Heap {
 
    type Output = ArrayExpression;
 
    fn index(&self, index: ArrayExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_array()
 
    }
 
}
 

	
 
impl Index<ConstantExpressionId> for Heap {
 
    type Output = ConstantExpression;
 
    fn index(&self, index: ConstantExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_constant()
 
    }
 
}
 

	
 
impl Index<CallExpressionId> for Heap {
 
    type Output = CallExpression;
 
    fn index(&self, index: CallExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_call()
 
    }
 
}
 

	
 
impl IndexMut<CallExpressionId> for Heap {
 
    fn index_mut(&mut self, index: CallExpressionId) -> &mut Self::Output {
 
        (&mut self.expressions[(index.0).0]).as_call_mut()
 
    }
 
}
 

	
 
impl Index<VariableExpressionId> for Heap {
 
    type Output = VariableExpression;
 
    fn index(&self, index: VariableExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_variable()
 
    }
 
}
 

	
 
impl IndexMut<VariableExpressionId> for Heap {
 
    fn index_mut(&mut self, index: VariableExpressionId) -> &mut Self::Output {
 
        (&mut self.expressions[(index.0).0]).as_variable_mut()
 
    }
 
}
 

	
 
impl Index<DeclarationId> for Heap {
 
    type Output = Declaration;
 
    fn index(&self, index: DeclarationId) -> &Self::Output {
 
        &self.declarations[index.0]
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Root {
 
    pub this: RootId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub pragmas: Vec<PragmaId>,
 
    pub imports: Vec<ImportId>,
 
    pub definitions: Vec<DefinitionId>,
 
    // Pase 2: linker
 
    pub declarations: Vec<DeclarationId>,
 
}
 

	
 
impl Root {
 
    pub fn get_definition(&self, h: &Heap, id: IdentifierId) -> Option<DefinitionId> {
 
        for &def in self.definitions.iter() {
 
            if h[h[def].identifier()] == h[id] {
 
                return Some(def);
 
            }
 
        }
 
        None
 
    }
 
    pub fn get_declaration(&self, h: &Heap, id: IdentifierId) -> Option<DeclarationId> {
 
        for &decl in self.declarations.iter() {
 
            if h[h[decl].identifier()] == h[id] {
 
                return Some(decl);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
impl SyntaxElement for Root {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Pragma {
 
    pub this: PragmaId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl SyntaxElement for Pragma {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Import {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl SyntaxElement for Import {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Identifier {
 
    External(ExternalIdentifier),
 
    Source(SourceIdentifier),
 
}
 

	
 
impl Identifier {
 
    pub fn as_source(&self) -> &SourceIdentifier {
 
        match self {
 
            Identifier::Source(result) => result,
 
            _ => panic!("Unable to cast `Identifier` to `SourceIdentifier`"),
 
        }
 
    }
 
    pub fn is_external(&self) -> bool {
 
        match self {
 
            Identifier::External(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_external(&self) -> &ExternalIdentifier {
 
        match self {
 
            Identifier::External(result) => result,
 
            _ => panic!("Unable to cast `Identifier` to `ExternalIdentifier`"),
 
        }
 
    }
 
    fn ident(&self) -> &[u8] {
 
        match self {
 
            Identifier::External(eid) => eid.ident(),
 
            Identifier::Source(sid) => sid.ident(),
 
        }
 
    }
 
}
 

	
 
impl Display for Identifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(self.ident()))
 
    }
 
}
 

	
 
impl PartialEq<Identifier> for Identifier {
 
    fn eq(&self, rhs: &Identifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
impl PartialEq<SourceIdentifier> for Identifier {
 
    fn eq(&self, rhs: &SourceIdentifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ExternalIdentifier {
 
    pub this: ExternalIdentifierId,
 
    // Phase 1: parser
 
    pub value: Vec<u8>,
 
}
 

	
 
impl ExternalIdentifier {
 
    fn ident(&self) -> &[u8] {
 
        &self.value
 
    }
 
}
 

	
 
impl Display for ExternalIdentifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(&self.value))
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct SourceIdentifier {
 
    pub this: SourceIdentifierId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl SourceIdentifier {
 
    fn ident(&self) -> &[u8] {
 
        &self.value
 
    }
 
}
 

	
 
impl SyntaxElement for SourceIdentifier {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
impl Display for SourceIdentifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(&self.value))
 
    }
 
}
 

	
 
impl PartialEq<Identifier> for SourceIdentifier {
 
    fn eq(&self, rhs: &Identifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
impl PartialEq<SourceIdentifier> for SourceIdentifier {
 
    fn eq(&self, rhs: &SourceIdentifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
type TypeData = Vec<u8>;
 

	
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
pub enum PrimitiveType {
 
    Input,
 
    Output,
 
    Message,
 
    Boolean,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
    Symbolic(TypeData),
 
}
 

	
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
pub struct Type {
 
    pub primitive: PrimitiveType,
 
    pub array: bool,
 
}
 

	
 
#[allow(dead_code)]
 
impl Type {
 
    pub const INPUT: Type = Type { primitive: PrimitiveType::Input, array: false };
 
    pub const OUTPUT: Type = Type { primitive: PrimitiveType::Output, array: false };
 
    pub const MESSAGE: Type = Type { primitive: PrimitiveType::Message, array: false };
 
    pub const BOOLEAN: Type = Type { primitive: PrimitiveType::Boolean, array: false };
 
    pub const BYTE: Type = Type { primitive: PrimitiveType::Byte, array: false };
 
    pub const SHORT: Type = Type { primitive: PrimitiveType::Short, array: false };
 
    pub const INT: Type = Type { primitive: PrimitiveType::Int, array: false };
 
    pub const LONG: Type = Type { primitive: PrimitiveType::Long, array: false };
 

	
 
    pub const INPUT_ARRAY: Type = Type { primitive: PrimitiveType::Input, array: true };
 
    pub const OUTPUT_ARRAY: Type = Type { primitive: PrimitiveType::Output, array: true };
 
    pub const MESSAGE_ARRAY: Type = Type { primitive: PrimitiveType::Message, array: true };
 
    pub const BOOLEAN_ARRAY: Type = Type { primitive: PrimitiveType::Boolean, array: true };
 
    pub const BYTE_ARRAY: Type = Type { primitive: PrimitiveType::Byte, array: true };
 
    pub const SHORT_ARRAY: Type = Type { primitive: PrimitiveType::Short, array: true };
 
    pub const INT_ARRAY: Type = Type { primitive: PrimitiveType::Int, array: true };
 
    pub const LONG_ARRAY: Type = Type { primitive: PrimitiveType::Long, array: true };
 
}
 

	
 
impl Display for Type {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        match &self.primitive {
 
            PrimitiveType::Input => {
 
                write!(f, "in")?;
 
            }
 
            PrimitiveType::Output => {
 
                write!(f, "out")?;
 
            }
 
            PrimitiveType::Message => {
 
                write!(f, "msg")?;
 
            }
 
            PrimitiveType::Boolean => {
 
                write!(f, "boolean")?;
 
            }
 
            PrimitiveType::Byte => {
 
                write!(f, "byte")?;
 
            }
 
            PrimitiveType::Short => {
 
                write!(f, "short")?;
 
            }
 
            PrimitiveType::Int => {
 
                write!(f, "int")?;
 
            }
 
            PrimitiveType::Long => {
 
                write!(f, "long")?;
 
            }
 
            PrimitiveType::Symbolic(data) => {
 
                // Type data is in ASCII range.
 
                write!(f, "{}", String::from_utf8_lossy(&data))?;
 
            }
 
        }
 
        if self.array {
 
            write!(f, "[]")
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct TypeAnnotation {
 
    pub this: TypeAnnotationId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub the_type: Type,
 
}
 

	
 
impl SyntaxElement for TypeAnnotation {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
type CharacterData = Vec<u8>;
 
type IntegerData = Vec<u8>;
 

	
 
#[derive(Debug, Clone)]
 
pub enum Constant {
 
    Null, // message
 
    True,
 
    False,
 
    Character(CharacterData),
 
    Integer(IntegerData),
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Method {
 
    Get,
 
    Fires,
 
    Create,
 
    Symbolic(SourceIdentifierId),
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Field {
 
    Length,
 
    Symbolic(SourceIdentifierId),
 
}
 
impl Field {
 
    pub fn is_length(&self) -> bool {
 
        match self {
 
            Field::Length => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy)]
 
pub enum Scope {
 
    Definition(DefinitionId),
 
    Block(BlockStatementId),
 
    Synchronous(SynchronousStatementId),
 
}
 

	
 
impl Scope {
 
    pub fn to_block(&self) -> BlockStatementId {
 
        match &self {
 
            Scope::Block(id) => *id,
 
            _ => panic!("Unable to cast `Scope` to `BlockStatement`"),
 
        }
 
    }
 
}
 

	
 
pub trait VariableScope {
 
    fn parent_scope(&self, h: &Heap) -> Option<Scope>;
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId>;
 
}
 

	
 
impl VariableScope for Scope {
 
    fn parent_scope(&self, h: &Heap) -> Option<Scope> {
 
        match self {
 
            Scope::Definition(def) => h[*def].parent_scope(h),
 
            Scope::Block(stmt) => h[*stmt].parent_scope(h),
 
            Scope::Synchronous(stmt) => h[*stmt].parent_scope(h),
 
        }
 
    }
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId> {
 
        match self {
 
            Scope::Definition(def) => h[*def].get_variable(h, id),
 
            Scope::Block(stmt) => h[*stmt].get_variable(h, id),
 
            Scope::Synchronous(stmt) => h[*stmt].get_variable(h, id),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Variable {
 
    Parameter(Parameter),
 
    Local(Local),
 
}
 

	
 
impl Variable {
 
    pub fn identifier(&self) -> SourceIdentifierId {
 
        match self {
 
            Variable::Parameter(var) => var.identifier,
 
            Variable::Local(var) => var.identifier,
 
        }
 
    }
 
    pub fn is_parameter(&self) -> bool {
 
        match self {
 
            Variable::Parameter(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_parameter(&self) -> &Parameter {
 
        match self {
 
            Variable::Parameter(result) => result,
 
            _ => panic!("Unable to cast `Variable` to `Parameter`"),
 
        }
 
    }
 
    pub fn as_local(&self) -> &Local {
 
        match self {
 
            Variable::Local(result) => result,
 
            _ => panic!("Unable to cast `Variable` to `Local`"),
 
        }
 
    }
 
    pub fn the_type<'b>(&self, h: &'b Heap) -> &'b Type {
 
        match self {
 
            Variable::Parameter(param) => &h[param.type_annotation].the_type,
 
            Variable::Local(local) => &h[local.type_annotation].the_type,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Variable {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Variable::Parameter(decl) => decl.position(),
 
            Variable::Local(decl) => decl.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Parameter {
 
    pub this: ParameterId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub type_annotation: TypeAnnotationId,
 
    pub identifier: SourceIdentifierId,
 
}
 

	
 
impl SyntaxElement for Parameter {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Local {
 
    pub this: LocalId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub type_annotation: TypeAnnotationId,
 
    pub identifier: SourceIdentifierId,
 
}
 
impl SyntaxElement for Local {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Definition {
 
    Component(Component),
 
    Function(Function),
 
}
 

	
 
impl Definition {
 
    pub fn is_component(&self) -> bool {
 
        match self {
 
            Definition::Component(_) => true,
 
            _ => false,
 
         }
 
        }
 
    }
 
    pub fn as_component(&self) -> &Component {
 
        match self {
 
            Definition::Component(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Component`"),
 
        }
 
    }
 
    pub fn as_function(&self) -> &Function {
 
        match self {
 
            Definition::Function(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Function`"),
 
        }
 
    }
 
    pub fn as_composite(&self) -> &Composite {
 
        self.as_component().as_composite()
 
    }
 
    pub fn as_primitive(&self) -> &Primitive {
 
        self.as_component().as_primitive()
 
    }
 
    pub fn identifier(&self) -> SourceIdentifierId {
 
        match self {
 
            Definition::Component(com) => com.identifier(),
 
            Definition::Function(fun) => fun.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        match self {
 
            Definition::Component(com) => com.parameters(),
 
            Definition::Function(fun) => &fun.parameters,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        match self {
 
            Definition::Component(com) => com.body(),
 
            Definition::Function(fun) => fun.body,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Definition {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Definition::Component(def) => def.position(),
 
            Definition::Function(def) => def.position(),
 
        }
 
    }
 
}
 

	
 
impl VariableScope for Definition {
 
    fn parent_scope(&self, _h: &Heap) -> Option<Scope> {
 
        None
 
    }
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId> {
 
        for &param in self.parameters().iter() {
 
            if h[h[param].identifier] == h[id] {
 
                return Some(param.0);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Component {
 
    Composite(Composite),
 
    Primitive(Primitive),
 
}
 

	
 
impl Component {
 
    pub fn this(&self) -> ComponentId {
 
        match self {
 
            Component::Composite(com) => com.this.upcast(),
 
            Component::Primitive(prim) => prim.this.upcast(),
 
        }
 
    }
 
    pub fn as_composite(&self) -> &Composite {
 
        match self {
 
            Component::Composite(result) => result,
 
            _ => panic!("Unable to cast `Component` to `Composite`"),
 
        }
 
    }
 
    pub fn as_primitive(&self) -> &Primitive {
 
        match self {
 
            Component::Primitive(result) => result,
 
            _ => panic!("Unable to cast `Component` to `Primitive`"),
 
        }
 
    }
 
    fn identifier(&self) -> SourceIdentifierId {
 
        match self {
 
            Component::Composite(com) => com.identifier,
 
            Component::Primitive(prim) => prim.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        match self {
 
            Component::Composite(com) => &com.parameters,
 
            Component::Primitive(prim) => &prim.parameters,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        match self {
 
            Component::Composite(com) => com.body,
 
            Component::Primitive(prim) => prim.body,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Component {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Component::Composite(def) => def.position(),
 
            Component::Primitive(def) => def.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Composite {
 
    pub this: CompositeId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: SourceIdentifierId,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

	
 
impl SyntaxElement for Composite {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Primitive {
 
    pub this: PrimitiveId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: SourceIdentifierId,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

	
 
impl SyntaxElement for Primitive {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Function {
 
    pub this: FunctionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub return_type: TypeAnnotationId,
 
    pub identifier: SourceIdentifierId,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

	
 
impl SyntaxElement for Function {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Declaration {
 
    Defined(DefinedDeclaration),
 
    Imported(ImportedDeclaration),
 
}
 

	
 
impl Declaration {
 
    pub fn signature(&self) -> &Signature {
 
        match self {
 
            Declaration::Defined(decl) => &decl.signature,
 
            Declaration::Imported(decl) => &decl.signature,
 
        }
 
    }
 
    pub fn identifier(&self) -> IdentifierId {
 
        self.signature().identifier()
 
    }
 
    pub fn is_component(&self) -> bool {
 
        self.signature().is_component()
 
    }
 
    pub fn is_function(&self) -> bool {
 
        self.signature().is_function()
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct DefinedDeclaration {
 
    pub this: DefinedDeclarationId,
 
    // Phase 2: linker
 
    pub definition: DefinitionId,
 
    pub signature: Signature,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ImportedDeclaration {
 
    pub this: ImportedDeclarationId,
 
    // Phase 2: linker
 
    pub import: ImportId,
 
    pub signature: Signature,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Signature {
 
    Component(ComponentSignature),
 
    Function(FunctionSignature),
 
}
 

	
 
impl Signature {
 
    pub fn from_definition(h: &Heap, def: DefinitionId) -> Signature {
 
        match &h[def] {
 
            Definition::Component(com) => Signature::Component(ComponentSignature {
 
                identifier: com.identifier().0,
 
                arity: Signature::convert_parameters(h, com.parameters()),
 
            }),
 
            Definition::Function(fun) => Signature::Function(FunctionSignature {
 
                return_type: h[fun.return_type].the_type.clone(),
 
                identifier: fun.identifier.0,
 
                arity: Signature::convert_parameters(h, &fun.parameters),
 
            }),
 
        }
 
    }
 
    fn convert_parameters(h: &Heap, params: &Vec<ParameterId>) -> Vec<Type> {
 
        let mut result = Vec::new();
 
        for &param in params.iter() {
 
            result.push(h[h[param].type_annotation].the_type.clone());
 
        }
 
        result
 
    }
 
    fn identifier(&self) -> IdentifierId {
 
        match self {
 
            Signature::Component(com) => com.identifier,
 
            Signature::Function(fun) => fun.identifier,
 
        }
 
    }
 
    pub fn is_component(&self) -> bool {
 
        match self {
 
            Signature::Component(_) => true,
 
            Signature::Function(_) => false,
 
        }
 
    }
 
    pub fn is_function(&self) -> bool {
 
        match self {
 
            Signature::Component(_) => false,
 
            Signature::Function(_) => true,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ComponentSignature {
 
    pub identifier: IdentifierId,
 
    pub arity: Vec<Type>,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct FunctionSignature {
 
    pub return_type: Type,
 
    pub identifier: IdentifierId,
 
    pub arity: Vec<Type>,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Statement {
 
    Block(BlockStatement),
 
    Local(LocalStatement),
 
    Skip(SkipStatement),
 
    Labeled(LabeledStatement),
 
    If(IfStatement),
 
    EndIf(EndIfStatement),
 
    While(WhileStatement),
 
    EndWhile(EndWhileStatement),
 
    Break(BreakStatement),
 
    Continue(ContinueStatement),
 
    Synchronous(SynchronousStatement),
 
    EndSynchronous(EndSynchronousStatement),
 
    Return(ReturnStatement),
 
    Assert(AssertStatement),
 
    Goto(GotoStatement),
 
    New(NewStatement),
 
    Put(PutStatement),
 
    Expression(ExpressionStatement),
 
}
 

	
 
impl Statement {
 
    pub fn as_block(&self) -> &BlockStatement {
 
        match self {
 
            Statement::Block(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `BlockStatement`"),
 
        }
 
    }
 
    pub fn as_block_mut(&mut self) -> &mut BlockStatement {
 
        match self {
 
            Statement::Block(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `BlockStatement`"),
 
        }
 
    }
 
    pub fn as_local(&self) -> &LocalStatement {
 
        match self {
 
            Statement::Local(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `LocalStatement`"),
 
        }
 
    }
 
    pub fn as_memory(&self) -> &MemoryStatement {
 
        self.as_local().as_memory()
 
    }
 
    pub fn as_channel(&self) -> &ChannelStatement {
 
        self.as_local().as_channel()
 
    }
 
    pub fn as_skip(&self) -> &SkipStatement {
 
        match self {
 
            Statement::Skip(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `SkipStatement`"),
 
        }
 
    }
 
    pub fn as_labeled(&self) -> &LabeledStatement {
 
        match self {
 
            Statement::Labeled(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `LabeledStatement`"),
 
        }
 
    }
 
    pub fn as_labeled_mut(&mut self) -> &mut LabeledStatement {
 
        match self {
 
            Statement::Labeled(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `LabeledStatement`"),
 
        }
 
    }
 
    pub fn as_if(&self) -> &IfStatement {
 
        match self {
 
            Statement::If(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `IfStatement`"),
 
        }
 
    }
 
    pub fn as_end_if(&self) -> &EndIfStatement {
 
        match self {
 
            Statement::EndIf(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `EndIfStatement`"),
 
        }
 
    }
 
    pub fn is_while(&self) -> bool {
 
        match self {
 
            Statement::While(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_while(&self) -> &WhileStatement {
 
        match self {
 
            Statement::While(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `WhileStatement`"),
 
        }
 
    }
 
    pub fn as_while_mut(&mut self) -> &mut WhileStatement {
 
        match self {
 
            Statement::While(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `WhileStatement`"),
 
        }
 
    }
 
    pub fn as_end_while(&self) -> &EndWhileStatement {
 
        match self {
 
            Statement::EndWhile(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `EndWhileStatement`"),
 
        }
 
    }
 
    pub fn as_break(&self) -> &BreakStatement {
 
        match self {
 
            Statement::Break(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `BreakStatement`"),
 
        }
 
    }
 
    pub fn as_break_mut(&mut self) -> &mut BreakStatement {
 
        match self {
 
            Statement::Break(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `BreakStatement`"),
 
        }
 
    }
 
    pub fn as_continue(&self) -> &ContinueStatement {
 
        match self {
 
            Statement::Continue(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `ContinueStatement`"),
 
        }
 
    }
 
    pub fn as_continue_mut(&mut self) -> &mut ContinueStatement {
 
        match self {
 
            Statement::Continue(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `ContinueStatement`"),
 
        }
 
    }
 
    pub fn as_synchronous(&self) -> &SynchronousStatement {
 
        match self {
 
            Statement::Synchronous(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `SynchronousStatement`"),
 
        }
 
    }
 
    pub fn as_synchronous_mut(&mut self) -> &mut SynchronousStatement {
 
        match self {
 
            Statement::Synchronous(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `SynchronousStatement`"),
 
        }
 
    }
 
    pub fn as_end_synchronous(&self) -> &EndSynchronousStatement {
 
        match self {
 
            Statement::EndSynchronous(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `EndSynchronousStatement`"),
 
        }
 
    }
 
    pub fn as_return(&self) -> &ReturnStatement {
 
        match self {
 
            Statement::Return(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `ReturnStatement`"),
 
        }
 
    }
 
    pub fn as_assert(&self) -> &AssertStatement {
 
        match self {
 
            Statement::Assert(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `AssertStatement`"),
 
        }
 
    }
 
    pub fn as_goto(&self) -> &GotoStatement {
 
        match self {
 
            Statement::Goto(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `GotoStatement`"),
 
        }
 
    }
 
    pub fn as_goto_mut(&mut self) -> &mut GotoStatement {
 
        match self {
 
            Statement::Goto(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `GotoStatement`"),
 
        }
 
    }
 
    pub fn as_new(&self) -> &NewStatement {
 
        match self {
 
            Statement::New(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `NewStatement`"),
 
        }
 
    }
 
    pub fn as_put(&self) -> &PutStatement {
 
        match self {
 
            Statement::Put(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `PutStatement`"),
 
        }
 
    }
 
    pub fn as_expression(&self) -> &ExpressionStatement {
 
        match self {
 
            Statement::Expression(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `ExpressionStatement`"),
 
        }
 
    }
 
    pub fn link_next(&mut self, next: StatementId) {
 
        match self {
 
            Statement::Block(stmt) => panic!(),
 
            Statement::Local(stmt) => match stmt {
 
                LocalStatement::Channel(stmt) => stmt.next = Some(next),
 
                LocalStatement::Memory(stmt) => stmt.next = Some(next),
 
            },
 
            Statement::Skip(stmt) => stmt.next = Some(next),
 
            Statement::Labeled(stmt) => panic!(),
 
            Statement::If(stmt) => panic!(),
 
            Statement::EndIf(stmt) => stmt.next = Some(next),
 
            Statement::While(stmt) => panic!(), // although while has a next field, it is linked manually
 
            Statement::EndWhile(stmt) => stmt.next = Some(next),
 
            Statement::Break(stmt) => panic!(),
 
            Statement::Continue(stmt) => panic!(),
 
            Statement::Synchronous(stmt) => panic!(),
 
            Statement::EndSynchronous(stmt) => stmt.next = Some(next),
 
            Statement::Return(stmt) => panic!(),
 
            Statement::Assert(stmt) => stmt.next = Some(next),
 
            Statement::Goto(stmt) => panic!(),
 
            Statement::New(stmt) => stmt.next = Some(next),
 
            Statement::Put(stmt) => stmt.next = Some(next),
 
            Statement::Expression(stmt) => stmt.next = Some(next),
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Statement {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Statement::Block(stmt) => stmt.position(),
 
            Statement::Local(stmt) => stmt.position(),
 
            Statement::Skip(stmt) => stmt.position(),
 
            Statement::Labeled(stmt) => stmt.position(),
 
            Statement::If(stmt) => stmt.position(),
 
            Statement::EndIf(stmt) => stmt.position(),
 
            Statement::While(stmt) => stmt.position(),
 
            Statement::EndWhile(stmt) => stmt.position(),
 
            Statement::Break(stmt) => stmt.position(),
 
            Statement::Continue(stmt) => stmt.position(),
 
            Statement::Synchronous(stmt) => stmt.position(),
 
            Statement::EndSynchronous(stmt) => stmt.position(),
 
            Statement::Return(stmt) => stmt.position(),
 
            Statement::Assert(stmt) => stmt.position(),
 
            Statement::Goto(stmt) => stmt.position(),
 
            Statement::New(stmt) => stmt.position(),
 
            Statement::Put(stmt) => stmt.position(),
 
            Statement::Expression(stmt) => stmt.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct BlockStatement {
 
    pub this: BlockStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub statements: Vec<StatementId>,
 
    // Phase 2: linker
 
    pub parent_scope: Option<Scope>,
 
    pub locals: Vec<LocalId>,
 
    pub labels: Vec<LabeledStatementId>,
 
}
 

	
 
impl BlockStatement {
 
    pub fn parent_block(&self, h: &Heap) -> Option<BlockStatementId> {
 
        let parent = self.parent_scope.unwrap();
 
        match parent {
 
            Scope::Definition(_) => {
 
                // If the parent scope is a definition, then there is no
 
                // parent block.
 
                None
 
            }
 
            Scope::Synchronous(parent) => {
 
                // It is always the case that when this function is called,
 
                // the parent of a synchronous statement is a block statement:
 
                // nested synchronous statements are flagged illegal,
 
                // and that happens before resolving variables that
 
                // creates the parent_scope references in the first place.
 
                Some(h[parent].parent_scope(h).unwrap().to_block())
 
            }
 
            Scope::Block(parent) => {
 
                // A variable scope is either a definition, sync, or block.
 
                Some(parent)
 
            }
 
        }
 
    }
 
    pub fn first(&self) -> StatementId {
 
        *self.statements.first().unwrap()
 
    }
 
}
 

	
 
impl SyntaxElement for BlockStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
impl VariableScope for BlockStatement {
 
    fn parent_scope(&self, _h: &Heap) -> Option<Scope> {
 
        self.parent_scope
 
    }
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId> {
 
        for &local in self.locals.iter() {
 
            if h[h[local].identifier] == h[id] {
 
                return Some(local.0);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum LocalStatement {
 
    Memory(MemoryStatement),
 
    Channel(ChannelStatement),
 
}
 

	
 
impl LocalStatement {
 
    pub fn this(&self) -> LocalStatementId {
 
        match self {
 
            LocalStatement::Memory(stmt) => stmt.this.upcast(),
 
            LocalStatement::Channel(stmt) => stmt.this.upcast(),
 
        }
 
    }
 
    pub fn as_memory(&self) -> &MemoryStatement {
 
        match self {
 
            LocalStatement::Memory(result) => result,
 
            _ => panic!("Unable to cast `LocalStatement` to `MemoryStatement`"),
 
        }
 
    }
 
    pub fn as_channel(&self) -> &ChannelStatement {
 
        match self {
 
            LocalStatement::Channel(result) => result,
 
            _ => panic!("Unable to cast `LocalStatement` to `ChannelStatement`"),
 
        }
 
    }
 
    pub fn next(&self) -> Option<StatementId> {
 
        match self {
 
            LocalStatement::Memory(stmt) => stmt.next,
 
            LocalStatement::Channel(stmt) => stmt.next,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for LocalStatement {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            LocalStatement::Memory(stmt) => stmt.position(),
 
            LocalStatement::Channel(stmt) => stmt.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct MemoryStatement {
 
    pub this: MemoryStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub variable: LocalId,
 
    pub initial: ExpressionId,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

	
 
impl SyntaxElement for MemoryStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ChannelStatement {
 
    pub this: ChannelStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub from: LocalId, // output
 
    pub to: LocalId,   // input
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

	
 
impl SyntaxElement for ChannelStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct SkipStatement {
 
    pub this: SkipStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

	
 
impl SyntaxElement for SkipStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct LabeledStatement {
 
    pub this: LabeledStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub label: SourceIdentifierId,
 
    pub body: StatementId,
 
    // Phase 2: linker
 
    pub in_sync: Option<SynchronousStatementId>,
 
}
 

	
 
impl SyntaxElement for LabeledStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct IfStatement {
 
    pub this: IfStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub test: ExpressionId,
 
    pub true_body: StatementId,
 
    pub false_body: StatementId,
 
}
 

	
 
impl SyntaxElement for IfStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct EndIfStatement {
 
    pub this: EndIfStatementId,
 
    // Phase 2: linker
 
    pub position: InputPosition, // of corresponding if statement
 
    pub next: Option<StatementId>,
 
}
 

	
 
impl SyntaxElement for EndIfStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct WhileStatement {
 
    pub this: WhileStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub test: ExpressionId,
 
    pub body: StatementId,
 
    // Phase 2: linker
 
    pub next: Option<EndWhileStatementId>,
 
    pub in_sync: Option<SynchronousStatementId>,
 
}
 

	
 
impl SyntaxElement for WhileStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct EndWhileStatement {
 
    pub this: EndWhileStatementId,
 
    // Phase 2: linker
 
    pub position: InputPosition, // of corresponding while
 
    pub next: Option<StatementId>,
 
}
 

	
 
impl SyntaxElement for EndWhileStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct BreakStatement {
 
    pub this: BreakStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub label: Option<SourceIdentifierId>,
 
    // Phase 2: linker
 
    pub target: Option<EndWhileStatementId>,
 
}
 

	
 
impl SyntaxElement for BreakStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ContinueStatement {
 
    pub this: ContinueStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub label: Option<SourceIdentifierId>,
 
    // Phase 2: linker
 
    pub target: Option<WhileStatementId>,
 
}
 

	
 
impl SyntaxElement for ContinueStatement {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct SynchronousStatement {
 
    pub this: SynchronousStatementId,
 
    // Phase 1: parser
src/protocol/eval.rs
Show inline comments
 
use std::collections::HashMap;
 
use std::fmt;
 
use std::fmt::{Debug, Display, Formatter};
 
use std::{i16, i32, i64, i8};
 

	
 
use crate::common::*;
 

	
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 
use crate::protocol::EvalContext;
 

	
 
const MAX_RECURSION: usize = 1024;
 

	
 
const BYTE_MIN: i64 = i8::MIN as i64;
 
const BYTE_MAX: i64 = i8::MAX as i64;
 
const SHORT_MIN: i64 = i16::MIN as i64;
 
const SHORT_MAX: i64 = i16::MAX as i64;
 
const INT_MIN: i64 = i32::MIN as i64;
 
const INT_MAX: i64 = i32::MAX as i64;
 

	
 
const MESSAGE_MAX_LENGTH: i64 = SHORT_MAX;
 

	
 
const ONE: Value = Value::Byte(ByteValue(1));
 

	
 
trait ValueImpl {
 
    fn exact_type(&self) -> Type;
 
    fn is_type_compatible(&self, t: &Type) -> bool;
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub enum Value {
 
    Input(InputValue),
 
    Output(OutputValue),
 
    Message(MessageValue),
 
    Boolean(BooleanValue),
 
    Byte(ByteValue),
 
    Short(ShortValue),
 
    Int(IntValue),
 
    Long(LongValue),
 
    InputArray(InputArrayValue),
 
    OutputArray(OutputArrayValue),
 
    MessageArray(MessageArrayValue),
 
    BooleanArray(BooleanArrayValue),
 
    ByteArray(ByteArrayValue),
 
    ShortArray(ShortArrayValue),
 
    IntArray(IntArrayValue),
 
    LongArray(LongArrayValue),
 
}
 
impl Value {
 
    pub fn receive_message(buffer: &Vec<u8>) -> Value {
 
        Value::Message(MessageValue(Some(buffer.clone())))
 
    }
 
    fn create_message(length: Value) -> Value {
 
        match length {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let length : i64 = i64::from(length);
 
                let length: i64 = i64::from(length);
 
                if length < 0 || length > MESSAGE_MAX_LENGTH {
 
                    // Only messages within the expected length are allowed
 
                    Value::Message(MessageValue(None))
 
                } else {
 
                    Value::Message(MessageValue(Some(vec![0; length.try_into().unwrap()])))
 
                }
 
            }
 
            _ => unimplemented!()
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn from_constant(constant: &Constant) -> Value {
 
        match constant {
 
            Constant::Null => Value::Message(MessageValue(None)),
 
            Constant::True => Value::Boolean(BooleanValue(true)),
 
            Constant::False => Value::Boolean(BooleanValue(false)),
 
            Constant::Integer(data) => {
 
                // Convert raw ASCII data to UTF-8 string
 
                let raw = String::from_utf8_lossy(data);
 
                let val = raw.parse::<i64>().unwrap();
 
                if val >= BYTE_MIN && val <= BYTE_MAX {
 
                    Value::Byte(ByteValue(val as i8))
 
                } else if val >= SHORT_MIN && val <= SHORT_MAX {
 
                    Value::Short(ShortValue(val as i16))
 
                } else if val >= INT_MIN && val <= INT_MAX {
 
                    Value::Int(IntValue(val as i32))
 
                } else {
 
                    Value::Long(LongValue(val))
 
                }
 
            }
 
            Constant::Character(data) => unimplemented!(),
 
        }
 
    }
 
    fn set(&mut self, index: &Value, value: &Value) -> Option<Value> {
 
        // The index must be of integer type, and non-negative
 
        let the_index : usize;
 
        let the_index: usize;
 
        match index {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let index = i64::from(index);
 
                if index < 0 || index > MESSAGE_MAX_LENGTH {
 
                    // It is inconsistent to update out of bounds
 
                    return None;
 
                }
 
                the_index = index.try_into().unwrap();
 
            }
 
            _ => unreachable!()
 
            _ => unreachable!(),
 
        }
 
        // The subject must be either a message or an array
 
        // And the value and the subject must be compatible
 
        match (self, value) {
 
            (Value::Message(MessageValue(None)), _) => {
 
                // It is inconsistent to update the null message
 
                None
 
            }
 
            (Value::Message(MessageValue(Some(buffer))), Value::Byte(ByteValue(b))) => {
 
                if *b < 0 {
 
                    // It is inconsistent to update with a negative value
 
                    return None;
 
                }
 
                if let Some(slot) = buffer.get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::Message(MessageValue(Some(buffer))), Value::Short(ShortValue(b))) => {
 
                if *b < 0 || *b > BYTE_MAX as i16 {
 
                    // It is inconsistent to update with a negative value or a too large value
 
                    return None;
 
                }
 
                if let Some(slot) = buffer.get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::InputArray(_), Value::Input(_)) => todo!(),
 
            (Value::OutputArray(_), Value::Output(_)) => todo!(),
 
            (Value::MessageArray(_), Value::Message(_)) => todo!(),
 
            (Value::BooleanArray(_), Value::Boolean(_)) => todo!(),
 
            (Value::ByteArray(_), Value::Byte(_)) => todo!(),
 
            (Value::ShortArray(_), Value::Short(_)) => todo!(),
 
            (Value::IntArray(_), Value::Int(_)) => todo!(),
 
            (Value::LongArray(_), Value::Long(_)) => todo!(),
 
            _ => unreachable!()
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn plus(&self, other: &Value) -> Value {
 
        // TODO: do a match on the value directly
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) + i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn minus(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) - i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn modulus(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) % i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn eq(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) == i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn neq(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) != i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn lt(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) < i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn lte(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) <= i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn gt(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) > i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn gte(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) >= i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn as_boolean(&self) -> &BooleanValue {
 
        match self {
 
            Value::Boolean(result) => result,
 
            _ => panic!("Unable to cast `Value` to `BooleanValue`"),
 
        }
 
    }
 
}
 

	
 
impl From<bool> for Value {
 
    fn from(b: bool) -> Self {
 
        Value::Boolean(BooleanValue(b))
 
    }
 
}
 
impl From<Value> for bool {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Boolean(BooleanValue(b)) => b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for bool {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Boolean(BooleanValue(b)) => *b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i8 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i8 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => *b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i16 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i16::from(b),
 
            Value::Short(ShortValue(s)) => s,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i16 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i16::from(*b),
 
            Value::Short(ShortValue(s)) => *s,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i32 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i32::from(b),
 
            Value::Short(ShortValue(s)) => i32::from(s),
 
            Value::Int(IntValue(i)) => i,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i32 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i32::from(*b),
 
            Value::Short(ShortValue(s)) => i32::from(*s),
 
            Value::Int(IntValue(i)) => *i,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i64 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i64::from(b),
 
            Value::Short(ShortValue(s)) => i64::from(s),
 
            Value::Int(IntValue(i)) => i64::from(i),
 
            Value::Long(LongValue(l)) => l,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i64 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i64::from(*b),
 
            Value::Short(ShortValue(s)) => i64::from(*s),
 
            Value::Int(IntValue(i)) => i64::from(*i),
 
            Value::Long(LongValue(l)) => *l,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl ValueImpl for Value {
 
    fn exact_type(&self) -> Type {
 
        match self {
 
            Value::Input(val) => val.exact_type(),
 
            Value::Output(val) => val.exact_type(),
 
            Value::Message(val) => val.exact_type(),
 
            Value::Boolean(val) => val.exact_type(),
 
            Value::Byte(val) => val.exact_type(),
 
            Value::Short(val) => val.exact_type(),
 
            Value::Int(val) => val.exact_type(),
 
            Value::Long(val) => val.exact_type(),
 
            Value::InputArray(val) => val.exact_type(),
 
            Value::OutputArray(val) => val.exact_type(),
 
            Value::MessageArray(val) => val.exact_type(),
 
            Value::BooleanArray(val) => val.exact_type(),
 
            Value::ByteArray(val) => val.exact_type(),
 
            Value::ShortArray(val) => val.exact_type(),
 
            Value::IntArray(val) => val.exact_type(),
 
            Value::LongArray(val) => val.exact_type(),
 
        }
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        match self {
 
            Value::Input(val) => val.is_type_compatible(t),
 
            Value::Output(val) => val.is_type_compatible(t),
 
            Value::Message(val) => val.is_type_compatible(t),
 
            Value::Boolean(val) => val.is_type_compatible(t),
 
            Value::Byte(val) => val.is_type_compatible(t),
 
            Value::Short(val) => val.is_type_compatible(t),
 
            Value::Int(val) => val.is_type_compatible(t),
 
            Value::Long(val) => val.is_type_compatible(t),
 
            Value::InputArray(val) => val.is_type_compatible(t),
 
            Value::OutputArray(val) => val.is_type_compatible(t),
 
            Value::MessageArray(val) => val.is_type_compatible(t),
 
            Value::BooleanArray(val) => val.is_type_compatible(t),
 
            Value::ByteArray(val) => val.is_type_compatible(t),
 
            Value::ShortArray(val) => val.is_type_compatible(t),
 
            Value::IntArray(val) => val.is_type_compatible(t),
 
            Value::LongArray(val) => val.is_type_compatible(t),
 
        }
 
    }
 
}
 

	
 
impl Display for Value {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        let disp: &dyn Display;
 
        match self {
 
            Value::Input(val) => disp = val,
 
            Value::Output(val) => disp = val,
 
            Value::Message(val) => disp = val,
 
            Value::Boolean(val) => disp = val,
 
            Value::Byte(val) => disp = val,
 
            Value::Short(val) => disp = val,
 
            Value::Int(val) => disp = val,
 
            Value::Long(val) => disp = val,
 
            Value::InputArray(val) => disp = val,
 
            Value::OutputArray(val) => disp = val,
 
            Value::MessageArray(val) => disp = val,
 
            Value::BooleanArray(val) => disp = val,
 
            Value::ByteArray(val) => disp = val,
 
            Value::ShortArray(val) => disp = val,
 
            Value::IntArray(val) => disp = val,
 
            Value::LongArray(val) => disp = val,
 
        }
 
        disp.fmt(f)
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct InputValue(pub Key);
 

	
 
impl Display for InputValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "#in")
 
    }
 
}
 

	
 
impl ValueImpl for InputValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INPUT
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Input => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct OutputValue(pub Key);
 

	
 
impl Display for OutputValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "#out")
 
    }
 
}
 

	
 
impl ValueImpl for OutputValue {
 
    fn exact_type(&self) -> Type {
 
        Type::OUTPUT
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Output => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct MessageValue(pub Option<Vec<u8>>);
 

	
 
impl Display for MessageValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        match &self.0 {
 
            None => write!(f, "null"),
 
            Some(vec) => {
 
                write!(f, "#msg({};", vec.len())?;
 
                let mut i = 0;
 
                for v in vec.iter() {
 
                    if i > 0 {
 
                        write!(f, ",")?;
 
                    }
 
                    write!(f, "{}", v)?;
 
                    i += 1;
 
                    if i >= 10 {
 
                        write!(f, ",...")?;
 
                        break;
 
                    }
 
                }
 
                write!(f, ")")
 
            },
 
            }
 
        }
 
    }
 
}
 

	
 
impl ValueImpl for MessageValue {
 
    fn exact_type(&self) -> Type {
 
        Type::MESSAGE
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Message => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct BooleanValue(bool);
 

	
 
impl Display for BooleanValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for BooleanValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BOOLEAN
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Boolean => true,
 
            PrimitiveType::Byte => true,
 
            PrimitiveType::Short => true,
 
            PrimitiveType::Int => true,
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ByteValue(i8);
 

	
 
impl Display for ByteValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for ByteValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BYTE
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Byte => true,
 
            PrimitiveType::Short => true,
 
            PrimitiveType::Int => true,
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ShortValue(i16);
 

	
 
impl Display for ShortValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for ShortValue {
 
    fn exact_type(&self) -> Type {
 
        Type::SHORT
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Short => true,
 
            PrimitiveType::Int => true,
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct IntValue(i32);
 

	
 
impl Display for IntValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for IntValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INT
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Int => true,
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct LongValue(i64);
 

	
 
impl Display for LongValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for LongValue {
 
    fn exact_type(&self) -> Type {
 
        Type::LONG
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct InputArrayValue(Vec<InputValue>);
 

	
 
impl Display for InputArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for InputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INPUT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Input => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct OutputArrayValue(Vec<OutputValue>);
 

	
 
impl Display for OutputArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for OutputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::OUTPUT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Output => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct MessageArrayValue(Vec<MessageValue>);
 

	
 
impl Display for MessageArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for MessageArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::MESSAGE_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Message => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct BooleanArrayValue(Vec<BooleanValue>);
 

	
 
impl Display for BooleanArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for BooleanArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BOOLEAN_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Boolean => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ByteArrayValue(Vec<ByteValue>);
 

	
 
impl Display for ByteArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for ByteArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BYTE_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Byte => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ShortArrayValue(Vec<ShortValue>);
 

	
 
impl Display for ShortArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for ShortArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::SHORT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Short => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct IntArrayValue(Vec<IntValue>);
 

	
 
impl Display for IntArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for IntArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Int => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct LongArrayValue(Vec<LongValue>);
 

	
 
impl Display for LongArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for LongArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::LONG_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
struct Store {
 
    map: HashMap<VariableId, Value>,
 
}
 
impl Store {
 
    fn new() -> Self {
 
        Store { map: HashMap::new() }
 
    }
 
    fn initialize(&mut self, h: &Heap, var: VariableId, value: Value) {
 
        // Ensure value is compatible with type of variable
 
        let the_type = h[var].the_type(h);
 
        assert!(value.is_type_compatible(the_type));
 
        // Overwrite mapping
 
        self.map.insert(var, value.clone());
 
    }
 
    fn update(&mut self, h: &Heap, ctx: &mut EvalContext, lexpr: ExpressionId, value: Value) -> EvalResult {
 
    fn update(
 
        &mut self,
 
        h: &Heap,
 
        ctx: &mut EvalContext,
 
        lexpr: ExpressionId,
 
        value: Value,
 
    ) -> EvalResult {
 
        match &h[lexpr] {
 
            Expression::Variable(var) => {
 
                let var = var.declaration.unwrap();
 
                // Ensure value is compatible with type of variable
 
                let the_type = h[var].the_type(h);
 
                assert!(value.is_type_compatible(the_type));
 
                // Overwrite mapping
 
                self.map.insert(var, value.clone());
 
                Ok(value)
 
            }
 
            Expression::Indexing(indexing) => {
 
                // Evaluate index expression, which must be some integral type
 
                let index = self.eval(h, ctx, indexing.index)?;
 
                // Mutable reference to the subject
 
                let subject;
 
                match &h[indexing.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get_mut(&var).unwrap();
 
                    }
 
                    _ => unreachable!(),
 
                }
 
                match subject.set(&index, &value) {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent)
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            _ => unimplemented!("{:?}", h[lexpr]),
 
        }
 
    }
 
    fn get(&mut self, h: &Heap, rexpr: ExpressionId) -> EvalResult {
 
        match &h[rexpr] {
 
            Expression::Variable(var) => {
 
                let var = var.declaration.unwrap();
 
                let value = self.map.get(&var).unwrap();
 
                Ok(value.clone())
 
            }
 
            _ => unimplemented!("{:?}", h[rexpr]),
 
        }
 
    }
 
    fn eval(&mut self, h: &Heap, ctx: &mut EvalContext, expr: ExpressionId) -> EvalResult {
 
        match &h[expr] {
 
            Expression::Assignment(expr) => {
 
                let value = self.eval(h, ctx, expr.right)?;
 
                match expr.operation {
 
                    AssignmentOperator::Set => {
 
                        self.update(h, ctx, expr.left, value.clone());
 
                    }
 
                    AssignmentOperator::Added => {
 
                        let old = self.get(h, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.plus(&value));
 
                    }
 
                    AssignmentOperator::Subtracted => {
 
                        let old = self.get(h, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.minus(&value));
 
                    }
 
                    _ => unimplemented!("{:?}", expr),
 
                }
 
                Ok(value)
 
            }
 
            Expression::Conditional(expr) => {
 
                let test = self.eval(h, ctx, expr.test)?;
 
                if test.as_boolean().0 {
 
                    self.eval(h, ctx, expr.true_expression)
 
                } else {
 
                    self.eval(h, ctx, expr.false_expression)
 
                }
 
            }
 
            Expression::Binary(expr) => {
 
                let left = self.eval(h, ctx, expr.left)?;
 
                let right = self.eval(h, ctx,expr.right)?;
 
                let right = self.eval(h, ctx, expr.right)?;
 
                match expr.operation {
 
                    BinaryOperator::Equality => Ok(left.eq(&right)),
 
                    BinaryOperator::Inequality => Ok(left.neq(&right)),
 
                    BinaryOperator::LessThan => Ok(left.lt(&right)),
 
                    BinaryOperator::LessThanEqual => Ok(left.lte(&right)),
 
                    BinaryOperator::GreaterThan => Ok(left.gt(&right)),
 
                    BinaryOperator::GreaterThanEqual => Ok(left.gte(&right)),
 
                    BinaryOperator::Remainder => Ok(left.modulus(&right)),
 
                    _ => unimplemented!(),
 
                }
 
            }
 
            Expression::Unary(expr) => {
 
                let mut value = self.eval(h, ctx, expr.expression)?;
 
                match expr.operation {
 
                    UnaryOperation::PostIncrement => {
 
                        self.update(h, ctx, expr.expression, value.plus(&ONE));
 
                    }
 
                    UnaryOperation::PreIncrement => {
 
                        value = value.plus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone());
 
                    }
 
                    UnaryOperation::PostDecrement => {
 
                        self.update(h, ctx, expr.expression, value.minus(&ONE));
 
                    }
 
                    UnaryOperation::PreDecrement => {
 
                        value = value.minus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone());
 
                    }
 
                    _ => unimplemented!(),
 
                }
 
                Ok(value)
 
            }
 
            Expression::Indexing(expr) => self.get(h, expr.this.upcast()),
 
            Expression::Slicing(expr) => unimplemented!(),
 
            Expression::Select(expr) => self.get(h, expr.this.upcast()),
 
            Expression::Array(expr) => unimplemented!(),
 
            Expression::Constant(expr) => Ok(Value::from_constant(&expr.value)),
 
            Expression::Call(expr) => {
 
                match expr.method {
 
                    Method::Create => {
 
                        assert_eq!(1, expr.arguments.len());
 
                        let length = self.eval(h, ctx, expr.arguments[0])?;
 
                        Ok(Value::create_message(length))
 
                    }
 
                    Method::Fires => {
 
                        assert_eq!(1, expr.arguments.len());
 
                        let value = self.eval(h, ctx, expr.arguments[0])?;
 
                        match ctx.fires(value.clone()) {
 
                            None => Err(EvalContinuation::BlockFires(value)),
 
                            Some(result) => Ok(result),
 
                        }
 
            Expression::Call(expr) => match expr.method {
 
                Method::Create => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let length = self.eval(h, ctx, expr.arguments[0])?;
 
                    Ok(Value::create_message(length))
 
                }
 
                Method::Fires => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let value = self.eval(h, ctx, expr.arguments[0])?;
 
                    match ctx.fires(value.clone()) {
 
                        None => Err(EvalContinuation::BlockFires(value)),
 
                        Some(result) => Ok(result),
 
                    }
 
                    Method::Get => {
 
                        assert_eq!(1, expr.arguments.len());
 
                        let value = self.eval(h, ctx, expr.arguments[0])?;
 
                        match ctx.get(value.clone()) {
 
                            None => Err(EvalContinuation::BlockGet(value)),
 
                            Some(result) => Ok(result)
 
                        }
 
                }
 
                Method::Get => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let value = self.eval(h, ctx, expr.arguments[0])?;
 
                    match ctx.get(value.clone()) {
 
                        None => Err(EvalContinuation::BlockGet(value)),
 
                        Some(result) => Ok(result),
 
                    }
 
                    Method::Symbolic(symbol) => unimplemented!()
 
                }
 
            }
 
                Method::Symbolic(symbol) => unimplemented!(),
 
            },
 
            Expression::Variable(expr) => self.get(h, expr.this.upcast()),
 
        }
 
    }
 
}
 

	
 
type EvalResult = Result<Value, EvalContinuation>;
 
pub enum EvalContinuation {
 
    Stepping,
 
    Inconsistent,
 
    Terminal,
 
    SyncBlockStart,
 
    SyncBlockEnd,
 
    NewComponent(Vec<Value>),
 
    BlockFires(Value),
 
    BlockGet(Value),
 
    Put(Value, Value),
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Prompt {
 
    definition: DefinitionId,
 
    store: Store,
 
    position: Option<StatementId>,
 
}
 

	
 
impl Prompt {
 
    pub fn new(h: &Heap, def: DefinitionId, args: &Vec<Value>) -> Self {
 
        let mut prompt = Prompt {
 
            definition: def,
 
            store: Store::new(),
 
            position: Some((&h[def]).body())
 
        };
 
        let mut prompt =
 
            Prompt { definition: def, store: Store::new(), position: Some((&h[def]).body()) };
 
        prompt.set_arguments(h, args);
 
        prompt
 
    }
 
    fn set_arguments(&mut self, h: &Heap, args: &Vec<Value>) {
 
        let def = &h[self.definition];
 
        let params = def.parameters();
 
        assert_eq!(params.len(), args.len());
 
        for (param, value) in params.iter().zip(args.iter()) {
 
            let hparam = &h[*param];
 
            let type_annot = &h[hparam.type_annotation];
 
            assert!(value.is_type_compatible(&type_annot.the_type));
 
            self.store.initialize(h, param.upcast(), value.clone());
 
        }
 
    }
 
    pub fn step(&mut self, h: &Heap, ctx: &mut EvalContext) -> EvalResult {
 
        if let Some(stmt) = self.position {
 
            let stmt = &h[stmt];
 
            match stmt {
 
                Statement::Block(stmt) => {
 
                    // Continue to first statement
 
                    self.position = Some(stmt.first());
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Local(stmt) => {
 
                    match stmt {
 
                        LocalStatement::Memory(stmt) => {
 
                            // Evaluate initial expression
 
                            let value = self.store.eval(h, ctx, stmt.initial)?;
 
                            // Update store
 
                            self.store.initialize(h, stmt.variable.upcast(), value);
 
                        }
 
                        LocalStatement::Channel(stmt) => unimplemented!(),
 
                    }
 
                    // Continue to next statement
 
                    self.position = stmt.next();
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Skip(stmt) => {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Labeled(stmt) => {
 
                    // Continue to next statement
 
                    self.position = Some(stmt.body);
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::If(stmt) => {
 
                    // Evaluate test
 
                    let value = self.store.eval(h, ctx, stmt.test)?;
 
                    // Continue with either branch
 
                    if value.as_boolean().0 {
 
                        self.position = Some(stmt.true_body);
 
                    } else {
 
                        self.position = Some(stmt.false_body);
 
                    }
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::EndIf(stmt) => {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::While(stmt) => {
 
                    // Evaluate test
 
                    let value = self.store.eval(h, ctx, stmt.test)?;
 
                    // Either continue with body, or go to next
 
                    if value.as_boolean().0 {
 
                        self.position = Some(stmt.body);
 
                    } else {
 
                        self.position = stmt.next.map(|x| x.upcast());
 
                    }
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::EndWhile(stmt) => {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Synchronous(stmt) => {
 
                    // Continue to next statement, and signal upward
 
                    self.position = Some(stmt.body);
 
                    Err(EvalContinuation::SyncBlockStart)
 
                }
 
                Statement::EndSynchronous(stmt) => {
 
                    // Continue to next statement, and signal upward
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::SyncBlockEnd)
 
                }
 
                Statement::Return(stmt) => {
 
                    // Evaluate expression
 
                    let value = self.store.eval(h, ctx, stmt.expression)?;
 
                    // Done with evaluation
 
                    Ok(value)
 
                }
 
                Statement::Goto(stmt) => {
 
                    // Continue to target
 
                    self.position = stmt.target.map(|x| x.upcast());
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::New(stmt) => todo!(),
 
                Statement::Put(stmt) => {
 
                    // Evaluate port and message
 
                    let port = self.store.eval(h, ctx, stmt.port)?;
 
                    let message = self.store.eval(h, ctx, stmt.message)?;
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    // Signal the put upwards
 
                    Err(EvalContinuation::Put(port, message))
 
                }
 
                Statement::Expression(stmt) => {
 
                    // Evaluate expression
 
                    let value = self.store.eval(h, ctx, stmt.expression)?;
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                _ => unimplemented!("{:?}", stmt),
 
            }
 
        } else {
 
            Err(EvalContinuation::Terminal)
 
        }
 
    }
 
    fn compute_function(h: &Heap, fun: FunctionId, args: &Vec<Value>) -> Option<Value> {
 
        let mut prompt = Self::new(h, fun.upcast(), args);
 
        let mut context = EvalContext::None;
 
        loop {
 
            let result = prompt.step(h, &mut context);
 
            match result {
 
                Ok(val) => return Some(val),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return None,
 
                    // Functions never terminate without returning
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // Functions never encounter any blocking behavior
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(args) => unreachable!(),
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!()
 
                }
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    extern crate test_generator;
 

	
 
    use std::fs::File;
 
    use std::io::Read;
 
    use std::path::Path;
 
    use test_generator::test_resources;
 

	
 
    use super::*;
 

	
 
    #[test_resources("testdata/eval/positive/*.pdl")]
 
    fn batch1(resource: &str) {
 
        let path = Path::new(resource);
 
        let expect = path.with_extension("txt");
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_file(&path).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        let pd = parser.parse(&mut heap).unwrap();
 
        let test = heap.get_external_identifier(b"test");
 
        let def = heap[pd].get_definition(&heap, test.upcast()).unwrap();
 
        let fun = heap[def].as_function().this;
 
        let args = Vec::new();
 
        let result = Prompt::compute_function(&heap, fun, &args).unwrap();
 
        let valstr: String = format!("{}", result);
 
        println!("{}", valstr);
 

	
 
        let mut cev: Vec<u8> = Vec::new();
 
        let mut f = File::open(expect).unwrap();
 
        f.read_to_end(&mut cev).unwrap();
 
        let lavstr = String::from_utf8_lossy(&cev);
 
        println!("{}", lavstr);
 

	
 
        assert_eq!(valstr, lavstr);
 
    }
 
}
src/protocol/lexer.rs
Show inline comments
 
@@ -853,930 +853,927 @@ impl Lexer<'_> {
 
            }
 
            self.consume_whitespace(false)?;
 
            if self.level >= MAX_LEVEL {
 
                return Err(self.source.error("Too deeply nested expression"));
 
            }
 
            self.level += 1;
 
            let result = self.consume_prefix_expression(h);
 
            self.level -= 1;
 
            let expression = result?;
 
            return Ok(h
 
                .alloc_unary_expression(|this| UnaryExpression {
 
                    this,
 
                    position,
 
                    operation,
 
                    expression,
 
                })
 
                .upcast());
 
        }
 
        self.consume_postfix_expression(h)
 
    }
 
    fn consume_postfix_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        let mut result = self.consume_primary_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        while self.has_string(b"++")
 
            || self.has_string(b"--")
 
            || self.has_string(b"[")
 
            || (self.has_string(b".") && !self.has_string(b".."))
 
        {
 
            let mut position = self.source.pos();
 
            if self.has_string(b"++") {
 
                self.consume_string(b"++")?;
 
                let operation = UnaryOperation::PostIncrement;
 
                let expression = result;
 
                self.consume_whitespace(false)?;
 
                result = h
 
                    .alloc_unary_expression(|this| UnaryExpression {
 
                        this,
 
                        position,
 
                        operation,
 
                        expression,
 
                    })
 
                    .upcast();
 
            } else if self.has_string(b"--") {
 
                self.consume_string(b"--")?;
 
                let operation = UnaryOperation::PostDecrement;
 
                let expression = result;
 
                self.consume_whitespace(false)?;
 
                result = h
 
                    .alloc_unary_expression(|this| UnaryExpression {
 
                        this,
 
                        position,
 
                        operation,
 
                        expression,
 
                    })
 
                    .upcast();
 
            } else if self.has_string(b"[") {
 
                self.consume_string(b"[")?;
 
                self.consume_whitespace(false)?;
 
                let subject = result;
 
                let index = self.consume_expression(h)?;
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b"..") || self.has_string(b":") {
 
                    position = self.source.pos();
 
                    if self.has_string(b"..") {
 
                        self.consume_string(b"..")?;
 
                    } else {
 
                        self.consume_string(b":")?;
 
                    }
 
                    self.consume_whitespace(false)?;
 
                    let to_index = self.consume_expression(h)?;
 
                    self.consume_whitespace(false)?;
 
                    result = h
 
                        .alloc_slicing_expression(|this| SlicingExpression {
 
                            this,
 
                            position,
 
                            subject,
 
                            from_index: index,
 
                            to_index,
 
                        })
 
                        .upcast();
 
                } else {
 
                    result = h
 
                        .alloc_indexing_expression(|this| IndexingExpression {
 
                            this,
 
                            position,
 
                            subject,
 
                            index,
 
                        })
 
                        .upcast();
 
                }
 
                self.consume_string(b"]")?;
 
                self.consume_whitespace(false)?;
 
            } else {
 
                assert!(self.has_string(b"."));
 
                self.consume_string(b".")?;
 
                self.consume_whitespace(false)?;
 
                let subject = result;
 
                let field;
 
                if self.has_keyword(b"length") {
 
                    self.consume_keyword(b"length")?;
 
                    field = Field::Length;
 
                } else {
 
                    field = Field::Symbolic(self.consume_identifier(h)?);
 
                }
 
                result = h
 
                    .alloc_select_expression(|this| SelectExpression {
 
                        this,
 
                        position,
 
                        subject,
 
                        field,
 
                    })
 
                    .upcast();
 
            }
 
        }
 
        Ok(result)
 
    }
 
    fn consume_primary_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        if self.has_string(b"(") {
 
            return self.consume_paren_expression(h);
 
        }
 
        if self.has_string(b"{") {
 
            return Ok(self.consume_array_expression(h)?.upcast());
 
        }
 
        if self.has_constant()
 
            || self.has_keyword(b"null")
 
            || self.has_keyword(b"true")
 
            || self.has_keyword(b"false")
 
        {
 
            return Ok(self.consume_constant_expression(h)?.upcast());
 
        }
 
        if self.has_call_expression() {
 
            return Ok(self.consume_call_expression(h)?.upcast());
 
        }
 
        Ok(self.consume_variable_expression(h)?.upcast())
 
    }
 
    fn consume_array_expression(&mut self, h: &mut Heap) -> Result<ArrayExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let mut elements = Vec::new();
 
        self.consume_string(b"{")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b"}") {
 
            while self.source.next().is_some() {
 
                elements.push(self.consume_expression(h)?);
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b"}") {
 
                    break;
 
                }
 
                self.consume_string(b",")?;
 
                self.consume_whitespace(false)?;
 
            }
 
        }
 
        self.consume_string(b"}")?;
 
        Ok(h.alloc_array_expression(|this| ArrayExpression { this, position, elements }))
 
    }
 
    fn has_constant(&self) -> bool {
 
        is_constant(self.source.next())
 
    }
 
    fn consume_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ConstantExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let value;
 
        if self.has_keyword(b"null") {
 
            self.consume_keyword(b"null")?;
 
            value = Constant::Null;
 
        } else if self.has_keyword(b"true") {
 
            self.consume_keyword(b"true")?;
 
            value = Constant::True;
 
        } else if self.has_keyword(b"false") {
 
            self.consume_keyword(b"false")?;
 
            value = Constant::False;
 
        } else if self.source.next() == Some(b'\'') {
 
            self.source.consume();
 
            let mut data = Vec::new();
 
            let mut next = self.source.next();
 
            while next != Some(b'\'') && (is_vchar(next) || next == Some(b' ')) {
 
                data.push(next.unwrap());
 
                self.source.consume();
 
                next = self.source.next();
 
            }
 
            if next != Some(b'\'') || data.len() == 0 {
 
                return Err(self.source.error("Expected character constant"));
 
            }
 
            self.source.consume();
 
            value = Constant::Character(data);
 
        } else {
 
            let mut data = Vec::new();
 
            let mut next = self.source.next();
 
            if !is_integer_start(next) {
 
                return Err(self.source.error("Expected integer constant"));
 
            }
 
            while is_integer_rest(next) {
 
                data.push(next.unwrap());
 
                self.source.consume();
 
                next = self.source.next();
 
            }
 
            value = Constant::Integer(data);
 
        }
 
        Ok(h.alloc_constant_expression(|this| ConstantExpression { this, position, value }))
 
    }
 
    fn has_call_expression(&mut self) -> bool {
 
        /* We prevent ambiguity with variables, by looking ahead
 
        the identifier to see if we can find an opening
 
        parenthesis: this signals a call expression. */
 
        if self.has_builtin_keyword() {
 
            return true;
 
        }
 
        let backup = self.source.clone();
 
        let mut result = false;
 
        match self.consume_identifier_spilled() {
 
            Ok(_) => match self.consume_whitespace(false) {
 
                Ok(_) => {
 
                    result = self.has_string(b"(");
 
                }
 
                Err(_) => {}
 
            },
 
            Err(_) => {}
 
        }
 
        *self.source = backup;
 
        return result;
 
    }
 
    fn consume_call_expression(&mut self, h: &mut Heap) -> Result<CallExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let method;
 
        if self.has_keyword(b"get") {
 
            self.consume_keyword(b"get")?;
 
            method = Method::Get;
 
        } else if self.has_keyword(b"fires") {
 
            self.consume_keyword(b"fires")?;
 
            method = Method::Fires;
 
        } else if self.has_keyword(b"create") {
 
            self.consume_keyword(b"create")?;
 
            method = Method::Create;
 
        } else {
 
            let identifier = self.consume_identifier(h)?;
 
            method = Method::Symbolic(identifier)
 
        }
 
        self.consume_whitespace(false)?;
 
        let mut arguments = Vec::new();
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b")") {
 
            while self.source.next().is_some() {
 
                arguments.push(self.consume_expression(h)?);
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b")") {
 
                    break;
 
                }
 
                self.consume_string(b",")?;
 
                self.consume_whitespace(false)?
 
            }
 
        }
 
        self.consume_string(b")")?;
 
        Ok(h.alloc_call_expression(|this| CallExpression {
 
            this,
 
            position,
 
            method,
 
            arguments,
 
            declaration: None,
 
        }))
 
    }
 
    fn consume_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<VariableExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let identifier = self.consume_identifier(h)?;
 
        Ok(h.alloc_variable_expression(|this| VariableExpression {
 
            this,
 
            position,
 
            identifier,
 
            declaration: None,
 
        }))
 
    }
 

	
 
    // ====================
 
    // Statements
 
    // ====================
 

	
 
    fn consume_statement(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        if self.level >= MAX_LEVEL {
 
            return Err(self.source.error("Too deeply nested statement"));
 
        }
 
        self.level += 1;
 
        let result = self.consume_statement_impl(h);
 
        self.level -= 1;
 
        result
 
    }
 
    fn has_label(&mut self) -> bool {
 
        /* To prevent ambiguity with expression statements consisting
 
        only of an identifier, we look ahead and match the colon
 
        that signals a labeled statement. */
 
        let backup = self.source.clone();
 
        let mut result = false;
 
        match self.consume_identifier_spilled() {
 
            Ok(_) => match self.consume_whitespace(false) {
 
                Ok(_) => {
 
                    result = self.has_string(b":");
 
                }
 
                Err(_) => {}
 
            },
 
            Err(_) => {}
 
        }
 
        *self.source = backup;
 
        return result;
 
    }
 
    fn consume_statement_impl(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        if self.has_string(b"{") {
 
            Ok(self.consume_block_statement(h)?)
 
        } else if self.has_keyword(b"skip") {
 
            Ok(self.consume_skip_statement(h)?.upcast())
 
        } else if self.has_keyword(b"if") {
 
            Ok(self.consume_if_statement(h)?.upcast())
 
        } else if self.has_keyword(b"while") {
 
            Ok(self.consume_while_statement(h)?.upcast())
 
        } else if self.has_keyword(b"break") {
 
            Ok(self.consume_break_statement(h)?.upcast())
 
        } else if self.has_keyword(b"continue") {
 
            Ok(self.consume_continue_statement(h)?.upcast())
 
        } else if self.has_keyword(b"synchronous") {
 
            Ok(self.consume_synchronous_statement(h)?.upcast())
 
        } else if self.has_keyword(b"return") {
 
            Ok(self.consume_return_statement(h)?.upcast())
 
        } else if self.has_keyword(b"assert") {
 
            Ok(self.consume_assert_statement(h)?.upcast())
 
        } else if self.has_keyword(b"goto") {
 
            Ok(self.consume_goto_statement(h)?.upcast())
 
        } else if self.has_keyword(b"new") {
 
            Ok(self.consume_new_statement(h)?.upcast())
 
        } else if self.has_keyword(b"put") {
 
            Ok(self.consume_put_statement(h)?.upcast())
 
        } else if self.has_label() {
 
            Ok(self.consume_labeled_statement(h)?.upcast())
 
        } else {
 
            Ok(self.consume_expression_statement(h)?.upcast())
 
        }
 
    }
 
    fn has_local_statement(&mut self) -> bool {
 
        /* To avoid ambiguity, we look ahead to find either the
 
        channel keyword that signals a variable declaration, or
 
        a type annotation followed by another identifier.
 
        Example:
 
          my_type[] x = {5}; // memory statement
 
          my_var[5] = x; // assignment expression, expression statement
 
        Note how both the local and the assignment
 
        start with arbitrary identifier followed by [. */
 
        if self.has_keyword(b"channel") {
 
            return true;
 
        }
 
        if self.has_statement_keyword() {
 
            return false;
 
        }
 
        let backup = self.source.clone();
 
        let mut result = false;
 
        match self.consume_type_annotation_spilled() {
 
            Ok(_) => match self.consume_whitespace(false) {
 
                Ok(_) => {
 
                    result = self.has_identifier();
 
                }
 
                Err(_) => {}
 
            },
 
            Err(_) => {}
 
        }
 
        *self.source = backup;
 
        return result;
 
    }
 
    fn consume_block_statement(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        let position = self.source.pos();
 
        let mut statements = Vec::new();
 
        self.consume_string(b"{")?;
 
        self.consume_whitespace(false)?;
 
        while self.has_local_statement() {
 
            statements.push(self.consume_local_statement(h)?.upcast());
 
            self.consume_whitespace(false)?;
 
        }
 
        while !self.has_string(b"}") {
 
            statements.push(self.consume_statement(h)?);
 
            self.consume_whitespace(false)?;
 
        }
 
        self.consume_string(b"}")?;
 
        if statements.len() == 0 {
 
            Ok(h.alloc_skip_statement(|this| SkipStatement { this, position, next: None }).upcast())
 
        } else {
 
            Ok(h.alloc_block_statement(|this| BlockStatement {
 
                this,
 
                position,
 
                statements,
 
                parent_scope: None,
 
                locals: Vec::new(),
 
                labels: Vec::new(),
 
            })
 
            .upcast())
 
        }
 
    }
 
    fn consume_local_statement(&mut self, h: &mut Heap) -> Result<LocalStatementId, ParseError> {
 
        if self.has_keyword(b"channel") {
 
            Ok(self.consume_channel_statement(h)?.upcast())
 
        } else {
 
            Ok(self.consume_memory_statement(h)?.upcast())
 
        }
 
    }
 
    fn consume_channel_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ChannelStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"channel")?;
 
        self.consume_whitespace(true)?;
 
        let from_annotation = self.create_type_annotation_output(h)?;
 
        let from_identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"->")?;
 
        self.consume_whitespace(false)?;
 
        let to_annotation = self.create_type_annotation_input(h)?;
 
        let to_identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        let from = h.alloc_local(|this| Local {
 
            this,
 
            position,
 
            type_annotation: from_annotation,
 
            identifier: from_identifier,
 
        });
 
        let to = h.alloc_local(|this| Local {
 
            this,
 
            position,
 
            type_annotation: to_annotation,
 
            identifier: to_identifier,
 
        });
 
        Ok(h.alloc_channel_statement(|this| ChannelStatement {
 
            this,
 
            position,
 
            from,
 
            to,
 
            next: None,
 
        }))
 
    }
 
    fn consume_memory_statement(&mut self, h: &mut Heap) -> Result<MemoryStatementId, ParseError> {
 
        let position = self.source.pos();
 
        let type_annotation = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"=")?;
 
        self.consume_whitespace(false)?;
 
        let initial = self.consume_expression(h)?;
 
        let variable = h.alloc_local(|this| Local { this, position, type_annotation, identifier });
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_memory_statement(|this| MemoryStatement {
 
            this,
 
            position,
 
            variable,
 
            initial,
 
            next: None,
 
        }))
 
    }
 
    fn consume_labeled_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<LabeledStatementId, ParseError> {
 
        let position = self.source.pos();
 
        let label = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b":")?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_statement(h)?;
 
        Ok(h.alloc_labeled_statement(|this| LabeledStatement {
 
            this,
 
            position,
 
            label,
 
            body,
 
            in_sync: None,
 
        }))
 
    }
 
    fn consume_skip_statement(&mut self, h: &mut Heap) -> Result<SkipStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"skip")?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_skip_statement(|this| SkipStatement { this, position, next: None }))
 
    }
 
    fn consume_if_statement(&mut self, h: &mut Heap) -> Result<IfStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"if")?;
 
        self.consume_whitespace(false)?;
 
        let test = self.consume_paren_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        let true_body = self.consume_statement(h)?;
 
        self.consume_whitespace(false)?;
 
        let false_body;
 
        if self.has_keyword(b"else") {
 
            self.consume_keyword(b"else")?;
 
            self.consume_whitespace(false)?;
 
            false_body = self.consume_statement(h)?;
 
        } else {
 
            false_body = h
 
                .alloc_skip_statement(|this| SkipStatement { this, position, next: None })
 
                .upcast();
 
        }
 
        Ok(h.alloc_if_statement(|this| IfStatement { this, position, test, true_body, false_body }))
 
    }
 
    fn consume_while_statement(&mut self, h: &mut Heap) -> Result<WhileStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"while")?;
 
        self.consume_whitespace(false)?;
 
        let test = self.consume_paren_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_statement(h)?;
 
        Ok(h.alloc_while_statement(|this| WhileStatement {
 
            this,
 
            position,
 
            test,
 
            body,
 
            next: None,
 
            in_sync: None,
 
        }))
 
    }
 
    fn consume_break_statement(&mut self, h: &mut Heap) -> Result<BreakStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"break")?;
 
        self.consume_whitespace(false)?;
 
        let label;
 
        if self.has_identifier() {
 
            label = Some(self.consume_identifier(h)?);
 
            self.consume_whitespace(false)?;
 
        } else {
 
            label = None;
 
        }
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_break_statement(|this| BreakStatement { this, position, label, target: None }))
 
    }
 
    fn consume_continue_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ContinueStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"continue")?;
 
        self.consume_whitespace(false)?;
 
        let label;
 
        if self.has_identifier() {
 
            label = Some(self.consume_identifier(h)?);
 
            self.consume_whitespace(false)?;
 
        } else {
 
            label = None;
 
        }
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_continue_statement(|this| ContinueStatement {
 
            this,
 
            position,
 
            label,
 
            target: None,
 
        }))
 
    }
 
    fn consume_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<SynchronousStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"synchronous")?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        if self.has_string(b"(") {
 
            self.consume_parameters(h, &mut parameters)?;
 
            self.consume_whitespace(false)?;
 
        } else if !self.has_keyword(b"skip") && !self.has_string(b"{") {
 
            return Err(self.source.error("Expected block statement"));
 
        }
 
        let body = self.consume_statement(h)?;
 
        Ok(h.alloc_synchronous_statement(|this| SynchronousStatement {
 
            this,
 
            position,
 
            parameters,
 
            body,
 
            parent_scope: None,
 
        }))
 
    }
 
    fn consume_return_statement(&mut self, h: &mut Heap) -> Result<ReturnStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"return")?;
 
        self.consume_whitespace(false)?;
 
        let expression;
 
        if self.has_string(b"(") {
 
            expression = self.consume_paren_expression(h)?;
 
        } else {
 
            expression = self.consume_expression(h)?;
 
        }
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_return_statement(|this| ReturnStatement { this, position, expression }))
 
    }
 
    fn consume_assert_statement(&mut self, h: &mut Heap) -> Result<AssertStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"assert")?;
 
        self.consume_whitespace(false)?;
 
        let expression;
 
        if self.has_string(b"(") {
 
            expression = self.consume_paren_expression(h)?;
 
        } else {
 
            expression = self.consume_expression(h)?;
 
        }
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_assert_statement(|this| AssertStatement {
 
            this,
 
            position,
 
            expression,
 
            next: None,
 
        }))
 
    }
 
    fn consume_goto_statement(&mut self, h: &mut Heap) -> Result<GotoStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"goto")?;
 
        self.consume_whitespace(false)?;
 
        let label = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_goto_statement(|this| GotoStatement { this, position, label, target: None }))
 
    }
 
    fn consume_new_statement(&mut self, h: &mut Heap) -> Result<NewStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"new")?;
 
        self.consume_whitespace(false)?;
 
        let expression = self.consume_call_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_new_statement(|this| NewStatement { this, position, expression, next: None }))
 
    }
 
    fn consume_put_statement(&mut self, h: &mut Heap) -> Result<PutStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"put")?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"(")?;
 
        let port = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b",")?;
 
        self.consume_whitespace(false)?;
 
        let message = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b")")?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_put_statement(|this| PutStatement { this, position, port, message, next: None }))
 
    }
 
    fn consume_expression_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ExpressionStatementId, ParseError> {
 
        let position = self.source.pos();
 
        let expression = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_expression_statement(|this| ExpressionStatement {
 
            this,
 
            position,
 
            expression,
 
            next: None,
 
        }))
 
    }
 

	
 
    // ====================
 
    // Symbol definitions
 
    // ====================
 

	
 
    fn has_symbol_definition(&self) -> bool {
 
        self.has_keyword(b"composite")
 
            || self.has_keyword(b"primitive")
 
            || self.has_type_keyword()
 
            || self.has_identifier()
 
    }
 
    fn consume_symbol_definition(&mut self, h: &mut Heap) -> Result<DefinitionId, ParseError> {
 
        if self.has_keyword(b"composite") || self.has_keyword(b"primitive") {
 
            Ok(self.consume_component_definition(h)?.upcast())
 
        } else {
 
            Ok(self.consume_function_definition(h)?.upcast())
 
        }
 
    }
 
    fn consume_component_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError> {
 
        if self.has_keyword(b"composite") {
 
            Ok(self.consume_composite_definition(h)?.upcast())
 
        } else {
 
            Ok(self.consume_primitive_definition(h)?.upcast())
 
        }
 
    }
 
    fn consume_composite_definition(&mut self, h: &mut Heap) -> Result<CompositeId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"composite")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_composite(|this| Composite { this, position, identifier, parameters, body }))
 
    }
 
    fn consume_primitive_definition(&mut self, h: &mut Heap) -> Result<PrimitiveId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"primitive")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_primitive(|this| Primitive { this, position, identifier, parameters, body }))
 
    }
 
    fn consume_function_definition(&mut self, h: &mut Heap) -> Result<FunctionId, ParseError> {
 
        let position = self.source.pos();
 
        let return_type = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_function(|this| Function {
 
            this,
 
            position,
 
            return_type,
 
            identifier,
 
            parameters,
 
            body,
 
        }))
 
    }
 
    fn has_pragma(&self) -> bool {
 
        if let Some(c) = self.source.next() {
 
            c == b'#'
 
        } else {
 
            false
 
        }
 
    }
 
    fn consume_pragma(&mut self, h: &mut Heap) -> Result<PragmaId, ParseError> {
 
        let position = self.source.pos();
 
        let next = self.source.next();
 
        if next != Some(b'#') {
 
            return Err(self.source.error("Expected pragma"));
 
        }
 
        self.source.consume();
 
        if !is_vchar(self.source.next()) {
 
            return Err(self.source.error("Expected pragma"));
 
        }
 
        let value = self.consume_line()?;
 
        Ok(h.alloc_pragma(|this| Pragma { this, position, value }))
 
    }
 
    fn has_import(&self) -> bool {
 
        self.has_keyword(b"import")
 
    }
 
    fn consume_import(&mut self, h: &mut Heap) -> Result<ImportId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"import")?;
 
        self.consume_whitespace(true)?;
 
        let mut value = Vec::new();
 
        let mut ident = self.consume_ident()?;
 
        value.append(&mut ident);
 
        while self.has_string(b".") {
 
            self.consume_string(b".")?;
 
            value.push(b'.');
 
            ident = self.consume_ident()?;
 
            value.append(&mut ident);
 
        }
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_import(|this| Import { this, position, value }))
 
    }
 
    pub fn consume_protocol_description(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<RootId, ParseError> {
 
    pub fn consume_protocol_description(&mut self, h: &mut Heap) -> Result<RootId, ParseError> {
 
        let position = self.source.pos();
 
        let mut pragmas = Vec::new();
 
        let mut imports = Vec::new();
 
        let mut definitions = Vec::new();
 
        self.consume_whitespace(false)?;
 
        while self.has_pragma() {
 
            let pragma = self.consume_pragma(h)?;
 
            pragmas.push(pragma);
 
            self.consume_whitespace(false)?;
 
        }
 
        while self.has_import() {
 
            let import = self.consume_import(h)?;
 
            imports.push(import);
 
            self.consume_whitespace(false)?;
 
        }
 
        // do-while block
 
        while {
 
            let def = self.consume_symbol_definition(h)?;
 
            definitions.push(def);
 
            self.consume_whitespace(false)?;
 
            self.has_symbol_definition()
 
        } {}
 
        // end of file
 
        if !self.source.is_eof() {
 
            return Err(self.source.error("Expected end of file"));
 
        }
 
        Ok(h.alloc_protocol_description(|this| Root {
 
            this,
 
            position,
 
            pragmas,
 
            imports,
 
            definitions,
 
            declarations: Vec::new(),
 
        }))
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    use crate::protocol::ast::Expression::*;
 
    use crate::protocol::{ast, lexer::*};
 

	
 
    #[test]
 
    fn test_lowercase() {
 
        assert_eq!(lowercase(b'a'), b'a');
 
        assert_eq!(lowercase(b'A'), b'a');
 
        assert_eq!(lowercase(b'z'), b'z');
 
        assert_eq!(lowercase(b'Z'), b'z');
 
    }
 

	
 
    #[test]
 
    fn test_basic_expression() {
 
        let mut h = Heap::new();
 
        let mut is = InputSource::from_string("a+b;").unwrap();
 
        let mut lex = Lexer::new(&mut is);
 
        match lex.consume_expression(&mut h) {
 
            Ok(expr) => {
 
                println!("{:?}", expr);
 
                if let Binary(bin) = &h[expr] {
 
                    if let Variable(left) = &h[bin.left] {
 
                        if let Variable(right) = &h[bin.right] {
 
                            assert_eq!("a", format!("{}", h[left.identifier]));
 
                            assert_eq!("b", format!("{}", h[right.identifier]));
 
                            assert_eq!(Some(b';'), is.next());
 
                            return;
 
                        }
 
                    }
 
                }
 
                assert!(false);
 
            }
 
            Err(err) => {
 
                err.print(&is);
 
                assert!(false);
 
            }
 
        }
 
    }
 

	
 
    #[test]
 
    fn test_paren_expression() {
 
        let mut h = Heap::new();
 
        let mut is = InputSource::from_string("(true)").unwrap();
 
        let mut lex = Lexer::new(&mut is);
 
        match lex.consume_paren_expression(&mut h) {
 
            Ok(expr) => {
 
                println!("{:#?}", expr);
 
                if let Constant(con) = &h[expr] {
 
                    if let ast::Constant::True = con.value {
 
                        return;
 
                    }
 
                }
 
                assert!(false);
 
            }
 
            Err(err) => {
 
                err.print(&is);
 
                assert!(false);
 
            }
 
        }
 
    }
 

	
 
    #[test]
 
    fn test_expression() {
 
        let mut h = Heap::new();
 
        let mut is = InputSource::from_string("(x(1+5,get(y))-w[5])+z++\n").unwrap();
 
        let mut lex = Lexer::new(&mut is);
 
        match lex.consume_expression(&mut h) {
 
            Ok(expr) => {
 
                println!("{:#?}", expr);
 
            }
 
            Err(err) => {
 
                err.print(&is);
 
                assert!(false);
 
            }
 
        }
 
    }
 

	
 
    #[test]
 
    fn test_basic_statement() {
 
        let mut h = Heap::new();
 
        let mut is = InputSource::from_string("while (true) { skip; }").unwrap();
 
        let mut lex = Lexer::new(&mut is);
 
        match lex.consume_statement(&mut h) {
 
            Ok(stmt) => {
 
                println!("{:#?}", stmt);
 
                if let Statement::While(w) = &h[stmt] {
 
                    if let Expression::Constant(_) = h[w.test] {
 
                        if let Statement::Block(_) = h[w.body] {
 
                            return;
 
                        }
 
                    }
 
                }
 
                assert!(false);
 
            }
 
            Err(err) => {
 
                err.print(&is);
 
                assert!(false);
 
            }
 
        }
 
    }
 

	
 
    #[test]
 
    fn test_statement() {
 
        let mut h = Heap::new();
 
        let mut is = InputSource::from_string(
 
            "label: while (true) { if (x++ > y[0]) break label; else continue; }\n",
 
        )
 
        .unwrap();
 
        let mut lex = Lexer::new(&mut is);
 
        match lex.consume_statement(&mut h) {
 
            Ok(stmt) => {
 
                println!("{:#?}", stmt);
 
            }
 
            Err(err) => {
 
                err.print(&is);
 
                assert!(false);
 
            }
 
        }
 
    }
 
}
src/protocol/mod.rs
Show inline comments
 
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 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<Self, String> {
 
        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<u8> = Vec::new();
 
                err.write(&source, &mut vec).unwrap();
 
                Err(String::from_utf8_lossy(&vec).to_string())
 
            }
 
        }
 
    }
 
    fn main_interface_polarities(&self) -> Vec<Polarity> {
 
        let def = &self.heap[self.main];
 
        let mut result = Vec::new();
 
        for &param 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)))
 
                Polarity::Putter => args.push(Value::Output(OutputValue(x))),
 
            }
 
        }
 
        ComponentStateImpl {
 
            prompt: Prompt::new(&self.heap, self.main.upcast(), &args)
 
        }
 
        ComponentStateImpl { prompt: Prompt::new(&self.heap, self.main.upcast(), &args) }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ComponentStateImpl {
 
    prompt: Prompt
 
    prompt: Prompt,
 
}
 
impl ComponentState for ComponentStateImpl {
 
    type D = ProtocolDescriptionImpl;
 

	
 
    fn pre_sync_run<C: MonoContext<D = ProtocolDescriptionImpl, S = Self>>(
 
        &mut self, context: &mut C, pd: &ProtocolDescriptionImpl,
 
        &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
 
                        continue;
 
                    }
 
                    // Outside synchronous blocks, no fires/get/put happens
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!()
 
                }
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    fn sync_run<C: PolyContext<D = ProtocolDescriptionImpl>>(
 
        &mut self, context: &mut C,  pd: &ProtocolDescriptionImpl,
 
        &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::BlockFires(port) => match port {
 
                        Value::Output(OutputValue(key)) => {
 
                            return PolyBlocker::CouldntCheckFiring(key);
 
                        }
 
                    }
 
                    EvalContinuation::BlockGet(port) => {
 
                        match port {
 
                            Value::Output(OutputValue(key)) => {
 
                                return PolyBlocker::CouldntReadMsg(key);
 
                            }
 
                            Value::Input(InputValue(key)) => {
 
                                return PolyBlocker::CouldntReadMsg(key);
 
                            }
 
                            _ => unreachable!()
 
                        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!()
 
                            _ => 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!()
 
                            _ => unreachable!(),
 
                        }
 
                        return PolyBlocker::PutMsg(key, payload);
 
                    }
 
                }
 
                },
 
            }
 
        }
 
    }
 
}
 

	
 
pub enum EvalContext<'a> {
 
    Mono(&'a mut dyn MonoContext<D = ProtocolDescriptionImpl, S = ComponentStateImpl>),
 
    Poly(&'a mut dyn PolyContext<D = ProtocolDescriptionImpl>),
 
    None
 
    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<Value> {
 
        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!()
 
                }
 
            }
 
            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<Value> {
 
        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!()
 
            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
 
}
src/runtime/actors.rs
Show inline comments
 
use crate::common::*;
 
use crate::runtime::{endpoint::*, *};
 

	
 
#[derive(Debug)]
 
pub(crate) struct MonoN {
 
    pub ekeys: HashSet<Key>,
 
    pub result: Option<(usize, HashMap<Key, Payload>)>,
 
}
 
#[derive(Debug)]
 
pub(crate) struct PolyN {
 
    pub ekeys: HashSet<Key>,
 
    pub branches: HashMap<Predicate, BranchN>,
 
}
 
#[derive(Debug, Clone)]
 
pub(crate) struct BranchN {
 
    pub to_get: HashSet<Key>,
 
    pub gotten: HashMap<Key, Payload>,
 
    pub sync_batch_index: usize,
 
}
 

	
 
#[derive(Debug)]
 
pub struct MonoP {
 
    pub state: ProtocolS,
 
    pub ekeys: HashSet<Key>,
 
}
 
#[derive(Debug)]
 
pub(crate) struct PolyP {
 
    pub incomplete: HashMap<Predicate, BranchP>,
 
    pub complete: HashMap<Predicate, BranchP>,
 
    pub ekeys: HashSet<Key>,
 
}
 
#[derive(Debug, Clone)]
 
pub(crate) struct BranchP {
 
    pub outbox: HashMap<Key, Payload>,
 
    pub inbox: HashMap<Key, Payload>,
 
    pub state: ProtocolS,
 
}
 

	
 
//////////////////////////////////////////////////////////////////
 

	
 
impl PolyP {
 
    pub(crate) fn poly_run(
 
        &mut self,
 
        m_ctx: PolyPContext,
 
        protocol_description: &ProtocolD,
 
    ) -> Result<SyncRunResult, EndpointErr> {
 
        let to_run: Vec<_> = self.incomplete.drain().collect();
 
        self.poly_run_these_branches(m_ctx, protocol_description, to_run)
 
    }
 

	
 
    pub(crate) fn poly_run_these_branches(
 
        &mut self,
 
        mut m_ctx: PolyPContext,
 
        protocol_description: &ProtocolD,
 
        mut to_run: Vec<(Predicate, BranchP)>,
 
    ) -> Result<SyncRunResult, EndpointErr> {
 
        use SyncRunResult as Srr;
 
        let cid = m_ctx.inner.channel_id_stream.controller_id;
 
        log!(&mut m_ctx.inner.logger, "~ Running branches for PolyP {:?}!", m_ctx.my_subtree_id,);
 
        while let Some((mut predicate, mut branch)) = to_run.pop() {
 
        'to_run_loop: while let Some((mut predicate, mut branch)) = to_run.pop() {
 
            let mut r_ctx = BranchPContext {
 
                m_ctx: m_ctx.reborrow(),
 
                ekeys: &self.ekeys,
 
                predicate: &predicate,
 
                inbox: &branch.inbox,
 
            };
 
            use PolyBlocker as Sb;
 
            let blocker = branch.state.sync_run(&mut r_ctx, protocol_description);
 
            log!(
 
                &mut r_ctx.m_ctx.inner.logger,
 
                "~ ... ran PolyP {:?} with branch pred {:?} to blocker {:?}",
 
                r_ctx.m_ctx.my_subtree_id,
 
                &predicate,
 
                &blocker
 
            );
 
            match blocker {
 
                Sb::Inconsistent => {} // DROP
 
                Sb::CouldntReadMsg(ekey) => {
 
                    assert!(self.ekeys.contains(&ekey));
 
                    let channel_id =
 
                        r_ctx.m_ctx.inner.endpoint_exts.get(ekey).unwrap().info.channel_id;
 
                    log!(
 
                        &mut r_ctx.m_ctx.inner.logger,
 
                        "~ ... {:?} couldnt read msg for port {:?}. has inbox {:?}",
 
                        r_ctx.m_ctx.my_subtree_id,
 
                        channel_id,
 
                        &branch.inbox,
 
                    );
 
                    if predicate.replace_assignment(channel_id, true) != Some(false) {
 
                        // don't rerun now. Rerun at next `sync_run`
 

	
 
                        log!(&mut m_ctx.inner.logger, "~ ... Delay {:?}", m_ctx.my_subtree_id,);
 
                        self.incomplete.insert(predicate, branch);
 
                    } else {
 
                        log!(&mut m_ctx.inner.logger, "~ ... Drop {:?}", m_ctx.my_subtree_id,);
 
                    }
 
                    // ELSE DROP
 
                }
 
                Sb::CouldntCheckFiring(ekey) => {
 
                    assert!(self.ekeys.contains(&ekey));
 
                    let channel_id =
 
                        r_ctx.m_ctx.inner.endpoint_exts.get(ekey).unwrap().info.channel_id;
 
                    // split the branch!
 
                    let branch_f = branch.clone();
 
                    let mut predicate_f = predicate.clone();
 
                    if predicate_f.replace_assignment(channel_id, false).is_some() {
 
                        panic!("OI HANS QUERY FIRST!");
 
                    }
 
                    assert!(predicate.replace_assignment(channel_id, true).is_none());
 
                    to_run.push((predicate, branch));
 
                    to_run.push((predicate_f, branch_f));
 
                }
 
                Sb::SyncBlockEnd => {
 
                    let ControllerInner { logger, endpoint_exts, .. } = m_ctx.inner;
 
                    log!(
 
                        &mut m_ctx.inner.logger,
 
                        "~ ... ran PolyP {:?} with branch pred {:?} to blocker {:?}",
 
                        logger,
 
                        "~ ... ran {:?} reached SyncBlockEnd with pred {:?} ...",
 
                        m_ctx.my_subtree_id,
 
                        &predicate,
 
                        &blocker
 
                    );
 
                    // come up with the predicate for this local solution
 
                    let lookup =
 
                        |&ekey| m_ctx.inner.endpoint_exts.get(ekey).unwrap().info.channel_id;
 
                    let ekeys_channel_id_iter = self.ekeys.iter().map(lookup);
 
                    predicate.batch_assign_nones(ekeys_channel_id_iter, false);
 

	
 
                    // OK now check we really received all the messages we expected to
 
                    let num_fired = predicate.iter_matching(true).count();
 
                    let num_msgs =
 
                        branch.inbox.keys().chain(branch.outbox.keys()).map(lookup).count();
 
                    match num_fired.cmp(&num_msgs) {
 
                        Ordering::Less => unreachable!(),
 
                        Ordering::Greater => log!(
 
                            &mut m_ctx.inner.logger,
 
                            "{:?} with pred {:?} finished but |inbox|+|outbox| < .",
 
                            m_ctx.my_subtree_id,
 
                            &predicate,
 
                        ),
 
                        Ordering::Equal => {
 
                            log!(
 
                                &mut m_ctx.inner.logger,
 
                                "{:?} with pred {:?} finished! Storing this solution locally.",
 
                                m_ctx.my_subtree_id,
 
                                &predicate,
 
                            );
 
                            m_ctx.solution_storage.submit_and_digest_subtree_solution(
 
                                m_ctx.my_subtree_id,
 
                                predicate.clone(),
 
                            );
 
                            // store the solution for recovering later
 
                            self.complete.insert(predicate, branch);
 
                    for ekey in self.ekeys.iter() {
 
                        let channel_id = endpoint_exts.get(*ekey).unwrap().info.channel_id;
 
                        let fired =
 
                            branch.inbox.contains_key(ekey) || branch.outbox.contains_key(ekey);
 
                        match predicate.query(channel_id) {
 
                            Some(true) => {
 
                                if !fired {
 
                                    // This branch should have fired but didn't!
 
                                    log!(
 
                                        logger,
 
                                        "~ ... ... should have fired {:?} and didn't! pruning!",
 
                                        channel_id,
 
                                    );
 
                                    continue 'to_run_loop;
 
                                }
 
                            }
 
                            Some(false) => assert!(!fired),
 
                            None => {
 
                                predicate.replace_assignment(channel_id, false);
 
                                assert!(!fired)
 
                            }
 
                        }
 
                    }
 
                    log!(logger, "~ ... ... and finished just fine!",);
 
                    m_ctx.solution_storage.submit_and_digest_subtree_solution(
 
                        &mut m_ctx.inner.logger,
 
                        m_ctx.my_subtree_id,
 
                        predicate.clone(),
 
                    );
 
                    self.complete.insert(predicate, branch);
 
                }
 
                Sb::PutMsg(ekey, payload) => {
 
                    assert!(self.ekeys.contains(&ekey));
 
                    let EndpointExt { info, endpoint } =
 
                        m_ctx.inner.endpoint_exts.get_mut(ekey).unwrap();
 
                    if predicate.replace_assignment(info.channel_id, true) != Some(false) {
 
                        branch.outbox.insert(ekey, payload.clone());
 
                        let msg = CommMsgContents::SendPayload {
 
                            payload_predicate: predicate.clone(),
 
                            payload,
 
                        }
 
                        .into_msg(m_ctx.inner.round_index);
 
                        endpoint.send(msg)?;
 
                        to_run.push((predicate, branch));
 
                    }
 
                    // ELSE DROP
 
                }
 
            }
 
        }
 
        // all in self.incomplete most recently returned Blocker::CouldntReadMsg
 
        Ok(if self.incomplete.is_empty() {
 
            if self.complete.is_empty() {
 
                Srr::NoBranches
 
            } else {
 
                Srr::AllBranchesComplete
 
            }
 
        } else {
 
            Srr::BlockingForRecv
 
        })
 
    }
 

	
 
    pub(crate) fn poly_recv_run(
 
        &mut self,
 
        m_ctx: PolyPContext,
 
        protocol_description: &ProtocolD,
 
        ekey: Key,
 
        payload_predicate: Predicate,
 
        payload: Payload,
 
    ) -> Result<SyncRunResult, EndpointErr> {
 
        // try exact match
 

	
 
        let to_run = if self.complete.contains_key(&payload_predicate) {
 
            // exact match with stopped machine
 

	
 
            log!(
 
                &mut m_ctx.inner.logger,
 
                "... poly_recv_run matched stopped machine exactly! nothing to do here",
 
            );
 
            vec![]
 
        } else if let Some(mut branch) = self.incomplete.remove(&payload_predicate) {
 
            // exact match with running machine
 

	
 
            log!(
 
                &mut m_ctx.inner.logger,
 
                "... poly_recv_run matched running machine exactly! pred is {:?}",
 
                &payload_predicate
 
            );
 
            branch.inbox.insert(ekey, payload);
 
            vec![(payload_predicate, branch)]
 
        } else {
 
            log!(
 
                &mut m_ctx.inner.logger,
 
                "... poly_recv_run didn't have any exact matches... Let's try feed it to all branches",
 

	
 
            );
 
            let mut incomplete2 = HashMap::<_, _>::default();
 
            let to_run = self
 
                .incomplete
 
                .drain()
 
                .filter_map(|(old_predicate, mut branch)| {
 
                    use CommonSatResult as Csr;
 
                    match old_predicate.common_satisfier(&payload_predicate) {
 
                        Csr::FormerNotLatter | Csr::Equivalent => {
 
                            log!(
 
                &mut m_ctx.inner.logger,
 
                                &mut m_ctx.inner.logger,
 
                                "... poly_recv_run This branch is compatible unaltered! branch pred: {:?}",
 
                              
 
                                &old_predicate
 
                            );
 
                            // old_predicate COVERS the assumptions of payload_predicate
 
                            let was = branch.inbox.insert(ekey, payload.clone());
 
                            assert!(was.is_none()); // INBOX MUST BE EMPTY!
 
                            Some((old_predicate, branch))
 
                        }
 
                        Csr::New(new) => {
 

	
 
                            log!(
 
                &mut m_ctx.inner.logger,
 
                                &mut m_ctx.inner.logger,
 
                                "... poly_recv_run payloadpred {:?} and branchpred {:?} satisfied by new pred {:?}. FORKING",
 
                              
 
                                &payload_predicate,
 
                                &old_predicate,
 
                                &new,
 
                            );
 
                            // payload_predicate has new assumptions. FORK!
 
                            let mut payload_branch = branch.clone();
 
                            let was = payload_branch.inbox.insert(ekey, payload.clone());
 
                            assert!(was.is_none()); // INBOX MUST BE EMPTY!
 

	
 
                            // put the original back untouched
 
                            incomplete2.insert(old_predicate, branch);
 
                            Some((new, payload_branch))
 
                        }
 
                        Csr::LatterNotFormer => {
 

	
 
                            log!(
 
                &mut m_ctx.inner.logger,
 
                                &mut m_ctx.inner.logger,
 
                                "... poly_recv_run payloadpred {:?} subsumes branch pred {:?}. FORKING",
 
                           
 
                                &old_predicate,
 
                                &payload_predicate,
 
                            );
 
                            // payload_predicate has new assumptions. FORK!
 
                            let mut payload_branch = branch.clone();
 
                            let was = payload_branch.inbox.insert(ekey, payload.clone());
 
                            assert!(was.is_none()); // INBOX MUST BE EMPTY!
 

	
 
                            // put the original back untouched
 
                            incomplete2.insert(old_predicate, branch);
 
                            Some((payload_predicate.clone(), payload_branch))
 
                        }
 
                        Csr::Nonexistant => {
 
                            log!(
 
                &mut m_ctx.inner.logger,
 
                                &mut m_ctx.inner.logger,
 
                                "... poly_recv_run SKIPPING because branchpred={:?}. payloadpred={:?}",
 
                              
 
                                &old_predicate,
 
                                &payload_predicate,
 
                            );
 
                            // predicates contradict
 
                            incomplete2.insert(old_predicate, branch);
 
                            None
 
                        }
 
                    }
 
                })
 
                .collect();
 
            std::mem::swap(&mut self.incomplete, &mut incomplete2);
 
            to_run
 
        };
 
        log!(
 
            &mut m_ctx.inner.logger,
 
            "... DONE FEEDING BRANCHES. {} branches to run!",
 
            to_run.len(),
 
        );
 
        self.poly_run_these_branches(m_ctx, protocol_description, to_run)
 
    }
 

	
 
    pub(crate) fn become_mono(
 
        mut self,
 
        decision: &Predicate,
 
        table_row: &mut HashMap<Key, Payload>,
 
    ) -> MonoP {
 
        if let Some((_, branch)) = self.complete.drain().find(|(p, _)| decision.satisfies(p)) {
 
            let BranchP { inbox, state, outbox } = branch;
 
            for (key, payload) in inbox.into_iter().chain(outbox.into_iter()) {
 
                table_row.insert(key, payload);
 
            }
 
            self.incomplete.clear();
 
            MonoP { state, ekeys: self.ekeys }
 
        } else {
 
            panic!("No such solution!")
 
        }
 
    }
 
}
 

	
 
impl PolyN {
 
    pub fn sync_recv(
 
        &mut self,
 
        ekey: Key,
 
        logger: &mut String,
 
        payload: Payload,
 
        payload_predicate: Predicate,
 
        solution_storage: &mut SolutionStorage,
 
    ) {
 
        for (predicate, branch) in self.branches.iter_mut() {
 
            if branch.to_get.remove(&ekey) {
 
                branch.gotten.insert(ekey, payload.clone());
 
                if branch.to_get.is_empty() {
 
                    solution_storage
 
                        .submit_and_digest_subtree_solution(SubtreeId::PolyN, predicate.clone());
 
        let mut branches2: HashMap<_, _> = Default::default();
 
        for (old_predicate, mut branch) in self.branches.drain() {
 
            use CommonSatResult as Csr;
 
            let case = old_predicate.common_satisfier(&payload_predicate);
 
            let mut report_if_solution =
 
                |branch: &BranchN, pred: &Predicate, logger: &mut String| {
 
                    if branch.to_get.is_empty() {
 
                        solution_storage.submit_and_digest_subtree_solution(
 
                            logger,
 
                            SubtreeId::PolyN,
 
                            pred.clone(),
 
                        );
 
                    }
 
                };
 
            log!(
 
                logger,
 
                "Feeding msg {:?} {:?} to native branch with pred {:?}. Predicate case {:?}",
 
                &payload_predicate,
 
                &payload,
 
                &old_predicate,
 
                &case
 
            );
 
            match case {
 
                Csr::Nonexistant => { /* skip branch */ }
 
                Csr::FormerNotLatter | Csr::Equivalent => {
 
                    // Feed the message to this branch in-place. no need to modify pred.
 
                    if branch.to_get.remove(&ekey) {
 
                        branch.gotten.insert(ekey, payload.clone());
 
                        report_if_solution(&branch, &old_predicate, logger);
 
                    }
 
                }
 
                Csr::LatterNotFormer => {
 
                    // create a new branch with the payload_predicate.
 
                    let mut forked = branch.clone();
 
                    if forked.to_get.remove(&ekey) {
 
                        forked.gotten.insert(ekey, payload.clone());
 
                        report_if_solution(&forked, &payload_predicate, logger);
 
                        branches2.insert(payload_predicate.clone(), forked);
 
                    }
 
                }
 
                Csr::New(new) => {
 
                    // create a new branch with the newly-created predicate
 
                    let mut forked = branch.clone();
 
                    if forked.to_get.remove(&ekey) {
 
                        forked.gotten.insert(ekey, payload.clone());
 
                        report_if_solution(&forked, &new, logger);
 
                        branches2.insert(new.clone(), forked);
 
                    }
 
                }
 
            }
 
            // unlike PolyP machines, Native branches do not become inconsistent
 
            branches2.insert(old_predicate, branch);
 
        }
 
        log!(
 
            logger,
 
            "Native now has {} branches with predicates: {:?}",
 
            branches2.len(),
 
            branches2.keys().collect::<Vec<_>>()
 
        );
 
        std::mem::swap(&mut branches2, &mut self.branches);
 
    }
 

	
 
    pub fn become_mono(
 
        mut self,
 
        decision: &Predicate,
 
        table_row: &mut HashMap<Key, Payload>,
 
    ) -> MonoN {
 
        if let Some((_, branch)) = self.branches.drain().find(|(p, _)| decision.satisfies(p)) {
 
            let BranchN { gotten, sync_batch_index, .. } = branch;
 
            for (&key, payload) in gotten.iter() {
 
                assert!(table_row.insert(key, payload.clone()).is_none());
 
            }
 
            MonoN { ekeys: self.ekeys, result: Some((sync_batch_index, gotten)) }
 
        } else {
 
            panic!("No such solution!")
 
        }
 
    }
 
}
src/runtime/communication.rs
Show inline comments
 
use crate::common::*;
 
use crate::runtime::{actors::*, endpoint::*, errors::*, *};
 

	
 
impl Controller {
 
    fn end_round_with_decision(&mut self, decision: Predicate) -> Result<(), SyncErr> {
 
        log!(&mut self.inner.logger, "ENDING ROUND WITH DECISION! {:?}", &decision);
 

	
 
        let mut table_row = HashMap::default();
 
        self.inner.mono_n = self
 
            .ephemeral
 
            .poly_n
 
            .take()
 
            .map(|poly_n| poly_n.become_mono(&decision, &mut table_row));
 
        self.inner.mono_ps.extend(
 
            self.ephemeral.poly_ps.drain(..).map(|m| m.become_mono(&decision, &mut table_row)),
 
        );
 
        for (ekey, payload) in table_row {
 
            let channel_id = self.inner.endpoint_exts.get(ekey).unwrap().info.channel_id;
 
            log!(&mut self.inner.logger, "VALUE {:?} => Message({:?})", channel_id, payload);
 
        }
 
        for channel_id in decision.iter_matching(false) {
 
            log!(&mut self.inner.logger, "VALUE {:?} => *", channel_id);
 
        }
 
        let announcement =
 
            CommMsgContents::Announce { oracle: decision }.into_msg(self.inner.round_index);
 
        for &child_ekey in self.inner.family.children_ekeys.iter() {
 
            log!(
 
                &mut self.inner.logger,
 
                "Forwarding {:?} to child with ekey {:?}",
 
                &announcement,
 
                child_ekey
 
            );
 
            self.inner
 
                .endpoint_exts
 
                .get_mut(child_ekey)
 
                .expect("eefef")
 
                .endpoint
 
                .send(announcement.clone())?;
 
        }
 
        self.inner.round_index += 1;
 
        self.ephemeral.clear();
 
        Ok(())
 
    }
 

	
 
    // Drain self.ephemeral.solution_storage and handle the new locals. Return decision if one is found
 
    fn handle_locals_maybe_decide(&mut self) -> Result<bool, SyncErr> {
 
        if let Some(parent_ekey) = self.inner.family.parent_ekey {
 
            // I have a parent -> I'm not the leader
 
            let parent_endpoint =
 
                &mut self.inner.endpoint_exts.get_mut(parent_ekey).expect("huu").endpoint;
 
            for partial_oracle in self.ephemeral.solution_storage.iter_new_local_make_old() {
 
                let msg =
 
                    CommMsgContents::Elaborate { partial_oracle }.into_msg(self.inner.round_index);
 
                log!(&mut self.inner.logger, "Sending {:?} to parent {:?}", &msg, parent_ekey);
 
                parent_endpoint.send(msg)?;
 
            }
 
            Ok(false)
 
        } else {
 
            // I have no parent -> I'm the leader
 
            assert!(self.inner.family.parent_ekey.is_none());
 
            let maybe_decision = self.ephemeral.solution_storage.iter_new_local_make_old().next();
 
            Ok(if let Some(decision) = maybe_decision {
 
                log!(&mut self.inner.logger, "DECIDE ON {:?} AS LEADER!", &decision);
 
                self.end_round_with_decision(decision)?;
 
                true
 
            } else {
 
                false
 
            })
 
        }
 
    }
 

	
 
    fn kick_off_native(
 
        &mut self,
 
        sync_batches: impl Iterator<Item = SyncBatch>,
 
    ) -> Result<PolyN, EndpointErr> {
 
        let MonoN { ekeys, .. } = self.inner.mono_n.take().unwrap();
 
        let Self { inner: ControllerInner { endpoint_exts, round_index, .. }, .. } = self;
 
        let mut branches = HashMap::<_, _>::default();
 
        for (sync_batch_index, SyncBatch { puts, gets }) in sync_batches.enumerate() {
 
            let ekey_to_channel_id = |ekey| endpoint_exts.get(ekey).unwrap().info.channel_id;
 
            let all_ekeys = ekeys.iter().copied();
 
            let all_channel_ids = all_ekeys.map(ekey_to_channel_id);
 

	
 
            let mut predicate = Predicate::new_trivial();
 

	
 
            // assign TRUE for puts and gets
 
            let true_ekeys = puts.keys().chain(gets.iter()).copied();
 
            let true_channel_ids = true_ekeys.clone().map(ekey_to_channel_id);
 
            predicate.batch_assign_nones(true_channel_ids, true);
 

	
 
            // assign FALSE for all in interface not assigned true
 
            predicate.batch_assign_nones(all_channel_ids.clone(), false);
 

	
 
            if branches.contains_key(&predicate) {
 
                // TODO what do I do with redundant predicates?
 
                unimplemented!(
 
                    "Having multiple batches with the same
 
                    predicate requires the support of oracle boolean variables"
 
                )
 
            }
 
            let branch = BranchN {
 
                to_get: true_ekeys.collect(),
 
                gotten: Default::default(),
 
                sync_batch_index,
 
            };
 
            let branch = BranchN { to_get: gets, gotten: Default::default(), sync_batch_index };
 
            for (ekey, payload) in puts {
 
                log!(
 
                    &mut self.inner.logger,
 
                    "... ... Initial native put msg {:?} pred {:?} batch {:?}",
 
                    &payload,
 
                    &predicate,
 
                    sync_batch_index,
 
                );
 
                let msg =
 
                    CommMsgContents::SendPayload { payload_predicate: predicate.clone(), payload }
 
                        .into_msg(*round_index);
 
                endpoint_exts.get_mut(ekey).unwrap().endpoint.send(msg)?;
 
            }
 
            log!(
 
                &mut self.inner.logger,
 
                "... Initial native branch (batch index={} with pred {:?}",
 
                sync_batch_index,
 
                &predicate
 
            );
 
            if branch.to_get.is_empty() {
 
                self.ephemeral
 
                    .solution_storage
 
                    .submit_and_digest_subtree_solution(SubtreeId::PolyN, predicate.clone());
 
                self.ephemeral.solution_storage.submit_and_digest_subtree_solution(
 
                    &mut self.inner.logger,
 
                    SubtreeId::PolyN,
 
                    predicate.clone(),
 
                );
 
            }
 
            branches.insert(predicate, branch);
 
        }
 
        Ok(PolyN { ekeys, branches })
 
    }
 

	
 
    // Runs a synchronous round until all the actors are in decided state OR 1+ are inconsistent.
 
    // If a native requires setting up, arg `sync_batches` is Some, and those are used as the sync batches.
 
    pub fn sync_round(
 
        &mut self,
 
        deadline: Instant,
 
        sync_batches: Option<impl Iterator<Item = SyncBatch>>,
 
    ) -> Result<(), SyncErr> {
 
        // TODO! fuse handle_locals_return_decision and end_round_return_decision
 

	
 
        assert!(self.ephemeral.is_clear());
 

	
 
        log!(
 
            &mut self.inner.logger,
 
            "~~~~~~~~ SYNC ROUND STARTS! ROUND={} ~~~~~~~~~",
 
            self.inner.round_index
 
        );
 

	
 
        // 1. Run the Mono for each Mono actor (stored in `self.mono_ps`).
 
        //    Some actors are dropped. some new actors are created.
 
        //    Ultimately, we have 0 Mono actors and a list of unnamed sync_actors
 
        log!(&mut self.inner.logger, "Got {} MonoP's to run!", self.inner.mono_ps.len());
 
        self.ephemeral.poly_ps.clear();
 
        // let mut poly_ps: Vec<PolyP> = vec![];
 
        while let Some(mut mono_p) = self.inner.mono_ps.pop() {
 
            let mut m_ctx = MonoPContext {
 
                ekeys: &mut mono_p.ekeys,
 
                inner: &mut self.inner,
 
                // endpoint_exts: &mut self.endpoint_exts,
 
                // mono_ps: &mut self.mono_ps,
 
                // channel_id_stream: &mut self.channel_id_stream,
 
            };
 
            // cross boundary into crate::protocol
 
            let blocker = mono_p.state.pre_sync_run(&mut m_ctx, &self.protocol_description);
 
            log!(&mut self.inner.logger, "... MonoP's pre_sync_run got blocker {:?}", &blocker);
 
            match blocker {
 
                MonoBlocker::Inconsistent => return Err(SyncErr::Inconsistent),
 
                MonoBlocker::ComponentExit => drop(mono_p),
 
                MonoBlocker::SyncBlockStart => self.ephemeral.poly_ps.push(mono_p.into()),
 
            }
 
        }
 
        log!(
 
            &mut self.inner.logger,
 
            "Finished running all MonoPs! Have {} PolyPs waiting",
 
            self.ephemeral.poly_ps.len()
 
        );
 

	
 
        // 3. define the mapping from ekey -> actor
 
        //    this is needed during the event loop to determine which actor
 
        //    should receive the incoming message.
 
        //    TODO: store and update this mapping rather than rebuilding it each round.
 
        let ekey_to_holder: HashMap<Key, PolyId> = {
 
            use PolyId::*;
 
            let n = self.inner.mono_n.iter().flat_map(|m| m.ekeys.iter().map(move |&e| (e, N)));
 
            let p = self
 
                .ephemeral
 
                .poly_ps
 
                .iter()
 
                .enumerate()
 
                .flat_map(|(index, m)| m.ekeys.iter().map(move |&e| (e, P { index })));
 
            n.chain(p).collect()
 
        };
 
        log!(
 
            &mut self.inner.logger,
 
            "SET OF PolyPs and MonoPs final! ekey lookup map is {:?}",
 
            &ekey_to_holder
 
        );
 

	
 
        // 4. Create the solution storage. it tracks the solutions of "subtrees"
 
        //    of the controller in the overlay tree.
 
        self.ephemeral.solution_storage.reset({
 
            let n = self.inner.mono_n.iter().map(|_| SubtreeId::PolyN);
 
            let m = (0..self.ephemeral.poly_ps.len()).map(|index| SubtreeId::PolyP { index });
 
            let c = self
 
                .inner
 
                .family
 
                .children_ekeys
 
                .iter()
 
                .map(|&ekey| SubtreeId::ChildController { ekey });
 
            let subtree_id_iter = n.chain(m).chain(c);
 
            log!(
 
                &mut self.inner.logger,
 
                "Solution Storage has subtree Ids: {:?}",
 
                &subtree_id_iter.clone().collect::<Vec<_>>()
 
            );
 
            subtree_id_iter
 
        });
 

	
 
        // 5. kick off the synchronous round of the native actor if it exists
 

	
 
        log!(&mut self.inner.logger, "Kicking off native's synchronous round...");
 
        assert_eq!(sync_batches.is_some(), self.inner.mono_n.is_some()); // TODO better err
 
        self.ephemeral.poly_n = if let Some(sync_batches) = sync_batches {
 
            // using if let because of nested ? operator
 
            // TODO check that there are 1+ branches or NO SOLUTION
 
            let poly_n = self.kick_off_native(sync_batches)?;
 
            log!(
 
                &mut self.inner.logger,
 
                "PolyN kicked off, and has branches with predicates... {:?}",
 
                poly_n.branches.keys().collect::<Vec<_>>()
 
            );
 
            Some(poly_n)
 
        } else {
 
            log!(&mut self.inner.logger, "NO NATIVE COMPONENT");
 
            None
 
        };
 

	
 
        // 6. Kick off the synchronous round of each protocol actor
 
        //    If just one actor becomes inconsistent now, there can be no solution!
 
        //    TODO distinguish between completed and not completed poly_p's?
 
        log!(&mut self.inner.logger, "Kicking off {} PolyP's.", self.ephemeral.poly_ps.len());
 
        for (index, poly_p) in self.ephemeral.poly_ps.iter_mut().enumerate() {
 
            let my_subtree_id = SubtreeId::PolyP { index };
 
            let m_ctx = PolyPContext {
 
                my_subtree_id,
 
                inner: &mut self.inner,
 
                solution_storage: &mut self.ephemeral.solution_storage,
 
            };
 
            use SyncRunResult as Srr;
 
            let blocker = poly_p.poly_run(m_ctx, &self.protocol_description)?;
 
            log!(&mut self.inner.logger, "... PolyP's poly_run got blocker {:?}", &blocker);
 
            match blocker {
 
                Srr::NoBranches => return Err(SyncErr::Inconsistent),
 
                Srr::AllBranchesComplete | Srr::BlockingForRecv => (),
 
            }
 
        }
 
        log!(&mut self.inner.logger, "All Poly machines have been kicked off!");
 

	
 
        // 7. `solution_storage` may have new solutions for this controller
 
        //    handle their discovery. LEADER => announce, otherwise => send to parent
 
        {
 
            let peeked = self.ephemeral.solution_storage.peek_new_locals().collect::<Vec<_>>();
 
            log!(
 
                &mut self.inner.logger,
 
                "Got {} controller-local solutions before a single RECV: {:?}",
 
                peeked.len(),
 
                peeked
 
            );
 
        }
 
        if self.handle_locals_maybe_decide()? {
 
            return Ok(());
 
        }
 

	
 
        // 4. Receive incoming messages until the DECISION is made
 
        log!(&mut self.inner.logger, "No decision yet. Time to recv messages");
 
        self.undelay_all();
 
        'recv_loop: loop {
 
            let received = self.recv(deadline)?.ok_or(SyncErr::Timeout)?;
 
            let current_content = match received.msg {
 
                Msg::SetupMsg(_) => {
 
                    log!(&mut self.inner.logger, "recvd message {:?} and its SETUP :(", &received);
 
                    // This occurs in the event the connector was malformed during connect()
 
                    return Err(SyncErr::UnexpectedSetupMsg);
 
                }
 
                Msg::CommMsg(CommMsg { round_index, .. })
 
                    if round_index < self.inner.round_index =>
 
                {
 
                    // Old message! Can safely discard
 
                    log!(&mut self.inner.logger, "recvd message {:?} and its OLD! :(", &received);
 
                    drop(received);
 
                    continue 'recv_loop;
 
                }
 
                Msg::CommMsg(CommMsg { round_index, .. })
 
                    if round_index > self.inner.round_index =>
 
                {
 
                    // Message from a next round. Keep for later!
 
                    log!(
 
                        &mut self.inner.logger,
 
                        "ecvd message {:?} and its for later. DELAY! :(",
 
                        &received
 
                    );
 
                    self.delay(received);
 
                    continue 'recv_loop;
 
                }
 
                Msg::CommMsg(CommMsg { contents, round_index }) => {
 
                    log!(
 
                        &mut self.inner.logger,
 
                        "recvd a round-appropriate CommMsg {:?}",
 
                        &contents
 
                    );
 
                    assert_eq!(round_index, self.inner.round_index);
 
                    contents
 
                }
 
            };
 
            match current_content {
 
                CommMsgContents::Elaborate { partial_oracle } => {
 
                    // Child controller submitted a subtree solution.
 
                    if !self.inner.family.children_ekeys.contains(&received.recipient) {
 
                        return Err(SyncErr::ElaborateFromNonChild);
 
                    }
 
                    let subtree_id = SubtreeId::ChildController { ekey: received.recipient };
 
                    log!(
 
                        &mut self.inner.logger,
 
                        "Received elaboration from child for subtree {:?}: {:?}",
 
                        subtree_id,
 
                        &partial_oracle
 
                    );
 
                    self.ephemeral
 
                        .solution_storage
 
                        .submit_and_digest_subtree_solution(subtree_id, partial_oracle);
 
                    self.ephemeral.solution_storage.submit_and_digest_subtree_solution(
 
                        &mut self.inner.logger,
 
                        subtree_id,
 
                        partial_oracle,
 
                    );
 

	
 
                    if self.handle_locals_maybe_decide()? {
 
                        return Ok(());
 
                    }
 
                }
 
                CommMsgContents::Announce { oracle } => {
 
                    if self.inner.family.parent_ekey != Some(received.recipient) {
 
                        return Err(SyncErr::AnnounceFromNonParent);
 
                    }
 
                    log!(
 
                        &mut self.inner.logger,
 
                        "Received ANNOUNCEMENT from from parent {:?}: {:?}",
 
                        received.recipient,
 
                        &oracle
 
                    );
 
                    return self.end_round_with_decision(oracle);
 
                }
 
                CommMsgContents::SendPayload { payload_predicate, payload } => {
 
                    // message for some actor. Feed it to the appropriate actor
 
                    // and then give them another chance to run.
 
                    let subtree_id = ekey_to_holder.get(&received.recipient);
 
                    log!(
 
                        &mut self.inner.logger,
 
                        "Received SendPayload for subtree {:?} with pred {:?} and payload {:?}",
 
                        subtree_id,
 
                        &payload_predicate,
 
                        &payload
 
                    );
 
                    match subtree_id {
 
                        None => {
 
                            // this happens when a message is sent to a component that has exited.
 
                            // It's safe to drop this message;
 
                            // The sender branch will certainly not be part of the solution
 
                            continue 'recv_loop;
 
                        }
 
                        Some(PolyId::N) => {
 
                            // Message for NativeMachine
 
                            self.ephemeral.poly_n.as_mut().unwrap().sync_recv(
 
                                received.recipient,
 
                                &mut self.inner.logger,
 
                                payload,
 
                                payload_predicate,
 
                                &mut self.ephemeral.solution_storage,
 
                            );
 
                            if self.handle_locals_maybe_decide()? {
 
                                return Ok(());
 
                            }
 
                        }
 
                        Some(PolyId::P { index }) => {
 
                            // Message for protocol actor
 
                            let channel_id = self
 
                                .inner
 
                                .endpoint_exts
 
                                .get(received.recipient)
 
                                .expect("UEHFU")
 
                                .info
 
                                .channel_id;
 
                            if payload_predicate.query(channel_id) != Some(true) {
 
                                // sender didn't preserve the invariant
 
                                return Err(SyncErr::PayloadPremiseExcludesTheChannel(channel_id));
 
                            }
 
                            let poly_p = &mut self.ephemeral.poly_ps[*index];
 

	
 
                            let m_ctx = PolyPContext {
 
                                my_subtree_id: SubtreeId::PolyP { index: *index },
 
                                inner: &mut self.inner,
 
                                solution_storage: &mut self.ephemeral.solution_storage,
 
                            };
 
                            use SyncRunResult as Srr;
 
                            let blocker = poly_p.poly_recv_run(
 
                                m_ctx,
 
                                &self.protocol_description,
 
                                received.recipient,
 
                                payload_predicate,
 
                                payload,
 
                            )?;
 
                            log!(
 
                                &mut self.inner.logger,
 
                                "... Fed the msg to PolyP {:?} and ran it to blocker {:?}",
 
                                subtree_id,
 
                                blocker
 
                            );
 
                            match blocker {
 
                                Srr::NoBranches => return Err(SyncErr::Inconsistent),
 
                                Srr::BlockingForRecv | Srr::AllBranchesComplete => {
 
                                    {
 
                                        let peeked = self
 
                                            .ephemeral
 
                                            .solution_storage
 
                                            .peek_new_locals()
 
                                            .collect::<Vec<_>>();
 
                                        log!(
 
                                            &mut self.inner.logger,
 
                                            "Got {} new controller-local solutions from RECV: {:?}",
 
                                            peeked.len(),
 
                                            peeked
 
                                        );
 
                                    }
 
                                    if self.handle_locals_maybe_decide()? {
 
                                        return Ok(());
 
                                    }
 
                                }
 
                            }
 
                        }
 
                    };
 
                }
 
            }
 
        }
 
    }
 
}
 
impl ControllerEphemeral {
 
    fn is_clear(&self) -> bool {
 
        self.solution_storage.is_clear()
 
            && self.poly_n.is_none()
 
            && self.poly_ps.is_empty()
 
            && self.ekey_to_holder.is_empty()
 
    }
 
    fn clear(&mut self) {
 
        self.solution_storage.clear();
 
        self.poly_n.take();
 
        self.poly_ps.clear();
 
        self.ekey_to_holder.clear();
 
    }
 
}
 
impl Into<PolyP> for MonoP {
 
    fn into(self) -> PolyP {
 
        PolyP {
 
            complete: Default::default(),
 
            incomplete: hashmap! {
 
                Predicate::new_trivial() =>
 
                BranchP {
 
                    state: self.state,
 
                    inbox: Default::default(),
 
                    outbox: Default::default(),
 
                }
 
            },
 
            ekeys: self.ekeys,
 
        }
 
    }
 
}
 

	
 
impl From<EndpointErr> for SyncErr {
 
    fn from(e: EndpointErr) -> SyncErr {
 
        SyncErr::EndpointErr(e)
 
    }
 
}
 

	
 
impl MonoContext for MonoPContext<'_> {
 
    type D = ProtocolD;
 
    type S = ProtocolS;
 
    fn new_component(&mut self, moved_ekeys: HashSet<Key>, init_state: Self::S) {
 
        log!(
 
            &mut self.inner.logger,
 
            "!! MonoContext callback to new_component with ekeys {:?}!",
 
            &moved_ekeys,
 
        );
 
        if moved_ekeys.is_subset(self.ekeys) {
 
            self.ekeys.retain(|x| !moved_ekeys.contains(x));
 
            self.inner.mono_ps.push(MonoP { state: init_state, ekeys: moved_ekeys });
 
        } else {
 
            panic!("MachineP attempting to move alien ekey!");
 
        }
 
    }
 
    fn new_channel(&mut self) -> [Key; 2] {
 
        let [a, b] = Endpoint::new_memory_pair();
 
        let channel_id = self.inner.channel_id_stream.next();
 
        let kp = self.inner.endpoint_exts.alloc(EndpointExt {
 
            info: EndpointInfo { polarity: Putter, channel_id },
 
            endpoint: a,
 
        });
 
        let kg = self.inner.endpoint_exts.alloc(EndpointExt {
 
            info: EndpointInfo { polarity: Putter, channel_id },
 
            endpoint: b,
 
        });
 
        log!(
 
            &mut self.inner.logger,
 
            "!! MonoContext callback to new_channel. returning ekeys {:?}!",
 
            [kp, kg],
 
        );
 
        [kp, kg]
 
    }
 
    fn new_random(&mut self) -> u64 {
 
        type Bytes8 = [u8; std::mem::size_of::<u64>()];
 
        let mut bytes = Bytes8::default();
 
        getrandom::getrandom(&mut bytes).unwrap();
 
        let val = unsafe { std::mem::transmute::<Bytes8, _>(bytes) };
 
        log!(
 
            &mut self.inner.logger,
 
            "!! MonoContext callback to new_random. returning val {:?}!",
 
            val,
 
        );
 
        val
 
    }
 
}
 

	
 
impl SolutionStorage {
 
    fn is_clear(&self) -> bool {
 
        self.subtree_id_to_index.is_empty()
 
            && self.subtree_solutions.is_empty()
 
            && self.old_local.is_empty()
 
            && self.new_local.is_empty()
 
    }
 
    fn clear(&mut self) {
 
        self.subtree_id_to_index.clear();
 
        self.subtree_solutions.clear();
 
        self.old_local.clear();
 
        self.new_local.clear();
 
    }
 
    pub(crate) fn reset(&mut self, subtree_ids: impl Iterator<Item = SubtreeId>) {
 
        self.subtree_id_to_index.clear();
 
        self.subtree_solutions.clear();
 
        self.old_local.clear();
 
        self.new_local.clear();
 
        for key in subtree_ids {
 
            self.subtree_id_to_index.insert(key, self.subtree_solutions.len());
 
            self.subtree_solutions.push(Default::default())
 
        }
 
    }
 

	
 
    pub(crate) fn peek_new_locals(&self) -> impl Iterator<Item = &Predicate> + '_ {
 
        self.new_local.iter()
 
    }
 

	
 
    pub(crate) fn iter_new_local_make_old(&mut self) -> impl Iterator<Item = Predicate> + '_ {
 
        let Self { old_local, new_local, .. } = self;
 
        new_local.drain().map(move |local| {
 
            old_local.insert(local.clone());
 
            local
 
        })
 
    }
 

	
 
    pub(crate) fn submit_and_digest_subtree_solution(
 
        &mut self,
 
        logger: &mut String,
 
        subtree_id: SubtreeId,
 
        predicate: Predicate,
 
    ) {
 
        log!(logger, "NEW COMPONENT SOLUTION {:?} {:?}", subtree_id, &predicate);
 
        let index = self.subtree_id_to_index[&subtree_id];
 
        let left = 0..index;
 
        let right = (index + 1)..self.subtree_solutions.len();
 

	
 
        let Self { subtree_solutions, new_local, old_local, .. } = self;
 
        let was_new = subtree_solutions[index].insert(predicate.clone());
 
        if was_new {
 
            let set_visitor = left.chain(right).map(|index| &subtree_solutions[index]);
 
            Self::elaborate_into_new_local_rec(predicate, set_visitor, old_local, new_local);
 
            Self::elaborate_into_new_local_rec(
 
                logger,
 
                predicate,
 
                set_visitor,
 
                old_local,
 
                new_local,
 
            );
 
        }
 
    }
 

	
 
    fn elaborate_into_new_local_rec<'a, 'b>(
 
        logger: &mut String,
 
        partial: Predicate,
 
        mut set_visitor: impl Iterator<Item = &'b HashSet<Predicate>> + Clone,
 
        old_local: &'b HashSet<Predicate>,
 
        new_local: &'a mut HashSet<Predicate>,
 
    ) {
 
        if let Some(set) = set_visitor.next() {
 
            // incomplete solution. keep traversing
 
            for pred in set.iter() {
 
                if let Some(elaborated) = pred.union_with(&partial) {
 
                    Self::elaborate_into_new_local_rec(
 
                        logger,
 
                        elaborated,
 
                        set_visitor.clone(),
 
                        old_local,
 
                        new_local,
 
                    )
 
                }
 
            }
 
        } else {
 
            // recursive stop condition. `partial` is a local subtree solution
 
            if !old_local.contains(&partial) {
 
                // ... and it hasn't been found before
 
                log!(logger, "... storing NEW LOCAL SOLUTION {:?}", &partial);
 
                new_local.insert(partial);
 
            }
 
        }
 
    }
 
}
 
impl PolyContext for BranchPContext<'_, '_> {
 
    type D = ProtocolD;
 

	
 
    fn is_firing(&mut self, ekey: Key) -> Option<bool> {
 
        assert!(self.ekeys.contains(&ekey));
 
        let channel_id = self.m_ctx.inner.endpoint_exts.get(ekey).unwrap().info.channel_id;
 
        let val = self.predicate.query(channel_id);
 
        log!(
 
            &mut self.m_ctx.inner.logger,
 
            "!! PolyContext callback to is_firing by {:?}! returning {:?}",
 
            self.m_ctx.my_subtree_id,
 
            val,
 
        );
 
        val
 
    }
 
    fn read_msg(&mut self, ekey: Key) -> Option<&Payload> {
 
        assert!(self.ekeys.contains(&ekey));
 
        let val = self.inbox.get(&ekey);
 
        log!(
 
            &mut self.m_ctx.inner.logger,
 
            "!! PolyContext callback to read_msg by {:?}! returning {:?}",
 
            self.m_ctx.my_subtree_id,
 
            val,
 
        );
 
        val
 
    }
 
}
src/runtime/endpoint.rs
Show inline comments
 
use crate::common::*;
 
use crate::runtime::{errors::*, Predicate};
 
use mio::{Evented, PollOpt, Ready};
 

	
 
pub(crate) enum Endpoint {
 
    Memory { s: mio_extras::channel::Sender<Msg>, r: mio_extras::channel::Receiver<Msg> },
 
    Network(NetworkEndpoint),
 
}
 

	
 
#[derive(Debug)]
 
pub(crate) struct EndpointExt {
 
    pub endpoint: Endpoint,
 
    pub info: EndpointInfo,
 
}
 
#[derive(Debug, Copy, Clone)]
 
pub struct EndpointInfo {
 
    pub polarity: Polarity,
 
    pub channel_id: ChannelId,
 
}
 

	
 
#[derive(Clone, Debug)]
 
pub(crate) enum Msg {
 
    SetupMsg(SetupMsg),
 
    CommMsg(CommMsg),
 
}
 
#[derive(Clone, Debug)]
 
pub(crate) enum SetupMsg {
 
    // sent by the passive endpoint to the active endpoint
 
    ChannelSetup { info: EndpointInfo },
 
    LeaderEcho { maybe_leader: ControllerId },
 
    LeaderAnnounce { leader: ControllerId },
 
    YouAreMyParent,
 
}
 
impl Into<Msg> for SetupMsg {
 
    fn into(self) -> Msg {
 
        Msg::SetupMsg(self)
 
    }
 
}
 

	
 
#[derive(Clone, Debug)]
 
pub(crate) struct CommMsg {
 
    pub round_index: usize,
 
    pub contents: CommMsgContents,
 
}
 
#[derive(Clone, Debug)]
 
pub(crate) enum CommMsgContents {
 
    SendPayload { payload_predicate: Predicate, payload: Payload },
 
    Elaborate { partial_oracle: Predicate },
 
    Announce { oracle: Predicate },
 
}
 

	
 
pub struct NetworkEndpoint {
 
    stream: mio::net::TcpStream,
 
    inbox: Vec<u8>,
 
    outbox: Vec<u8>,
 
}
 

	
 
impl std::fmt::Debug for Endpoint {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
 
        let s = match self {
 
            Endpoint::Memory { .. } => "Memory",
 
            Endpoint::Network(..) => "Network",
 
        };
 
        write!(f, "Endpoint::{}", s)
 
        f.write_fmt(format_args!("Endpoint::{}", s))
 
    }
 
}
 

	
 
impl CommMsgContents {
 
    pub fn into_msg(self, round_index: usize) -> Msg {
 
        Msg::CommMsg(CommMsg { round_index, contents: self })
 
    }
 
}
 

	
 
impl From<EndpointErr> for ConnectErr {
 
    fn from(e: EndpointErr) -> Self {
 
        match e {
 
            EndpointErr::Disconnected => ConnectErr::Disconnected,
 
            EndpointErr::MetaProtocolDeviation => ConnectErr::MetaProtocolDeviation,
 
        }
 
    }
 
}
 
impl Endpoint {
 
    // asymmetric
 
    pub(crate) fn from_fresh_stream(stream: mio::net::TcpStream) -> Self {
 
        Self::Network(NetworkEndpoint { stream, inbox: vec![], outbox: vec![] })
 
    }
 

	
 
    // symmetric
 
    pub fn new_memory_pair() -> [Self; 2] {
 
        let (s1, r1) = mio_extras::channel::channel::<Msg>();
 
        let (s2, r2) = mio_extras::channel::channel::<Msg>();
 
        [Self::Memory { s: s1, r: r2 }, Self::Memory { s: s2, r: r1 }]
 
    }
 
    pub fn send(&mut self, msg: Msg) -> Result<(), EndpointErr> {
 
        match self {
 
            Self::Memory { s, .. } => s.send(msg).map_err(|_| EndpointErr::Disconnected),
 
            Self::Network(NetworkEndpoint { stream, outbox, .. }) => {
 
                use crate::runtime::serde::Ser;
 
                outbox.ser(&msg).expect("ser failed");
 
                loop {
 
                    use std::io::Write;
 
                    match stream.write(outbox) {
 
                        Ok(0) => return Ok(()),
 
                        Ok(bytes_written) => {
 
                            outbox.drain(0..bytes_written);
 
                        }
 
                        Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
 
                            panic!("sending shouldn't WouldBlock")
 
                        }
 
                        Err(_e) => return Err(EndpointErr::Disconnected),
 
                    }
 
                }
 
            }
 
        }
 
    }
 
    pub fn recv(&mut self) -> Result<Option<Msg>, EndpointErr> {
 
        match self {
 
            Self::Memory { r, .. } => match r.try_recv() {
 
                Ok(msg) => Ok(Some(msg)),
 
                Err(std::sync::mpsc::TryRecvError::Empty) => Ok(None),
 
                Err(std::sync::mpsc::TryRecvError::Disconnected) => Err(EndpointErr::Disconnected),
 
            },
 
            Self::Network(NetworkEndpoint { stream, inbox, .. }) => {
 
                // populate inbox as much as possible
 
                'read_loop: loop {
 
                    use std::io::Read;
 
                    match stream.read_to_end(inbox) {
 
                        Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => break 'read_loop,
 
                        Ok(0) => break 'read_loop,
 
                        Ok(_) => (),
 
                        Err(e) => {
 
                            println!("BAD IS {:?}", e);
 
                            panic!("BAD");
 
                        }
 
                    }
 
                }
 
                use crate::runtime::serde::{De, MonitoredReader};
 
                let mut monitored = MonitoredReader::from(&inbox[..]);
 
                match De::<Msg>::de(&mut monitored) {
 
                    Ok(msg) => {
 
                        let msg_size2 = monitored.bytes_read();
 
                        inbox.drain(0..(msg_size2.try_into().unwrap()));
 
                        Ok(Some(msg))
 
                    }
 
                    Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Ok(None),
 
                    Err(_) => Err(EndpointErr::MetaProtocolDeviation),
 
                }
 
            }
 
        }
 
    }
 
}
 

	
 
impl Evented for Endpoint {
 
    fn register(
 
        &self,
 
        poll: &Poll,
 
        token: Token,
 
        interest: Ready,
 
        opts: PollOpt,
 
    ) -> Result<(), std::io::Error> {
 
        match self {
 
            Self::Memory { r, .. } => r.register(poll, token, interest, opts),
 
            Self::Network(n) => n.register(poll, token, interest, opts),
 
        }
 
    }
 

	
 
    fn reregister(
 
        &self,
 
        poll: &Poll,
 
        token: Token,
 
        interest: Ready,
 
        opts: PollOpt,
 
    ) -> Result<(), std::io::Error> {
 
        match self {
 
            Self::Memory { r, .. } => r.reregister(poll, token, interest, opts),
 
            Self::Network(n) => n.reregister(poll, token, interest, opts),
 
        }
 
    }
 

	
 
    fn deregister(&self, poll: &Poll) -> Result<(), std::io::Error> {
 
        match self {
 
            Self::Memory { r, .. } => r.deregister(poll),
 
            Self::Network(n) => n.deregister(poll),
 
        }
 
    }
 
}
 

	
 
impl Evented for NetworkEndpoint {
 
    fn register(
 
        &self,
 
        poll: &Poll,
 
        token: Token,
 
        interest: Ready,
 
        opts: PollOpt,
 
    ) -> Result<(), std::io::Error> {
 
        self.stream.register(poll, token, interest, opts)
 
    }
 

	
 
    fn reregister(
 
        &self,
 
        poll: &Poll,
 
        token: Token,
 
        interest: Ready,
 
        opts: PollOpt,
 
    ) -> Result<(), std::io::Error> {
 
        self.stream.reregister(poll, token, interest, opts)
 
    }
 

	
 
    fn deregister(&self, poll: &Poll) -> Result<(), std::io::Error> {
 
        self.stream.deregister(poll)
 
    }
 
}

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)