Changeset - 03af3095927d
[Not reviewed]
0 8 0
MH - 4 years ago 2021-04-08 16:01:45
contact@maxhenger.nl
remove (de)serialization of AST for now
8 files changed with 121 insertions and 361 deletions:
0 comments (0 inline, 0 general)
src/common.rs
Show inline comments
 
@@ -23,68 +23,60 @@ pub(crate) use std::{
 
};
 
pub(crate) use Polarity::*;
 

	
 
pub(crate) trait IdParts {
 
    fn id_parts(self) -> (ConnectorId, U32Suffix);
 
}
 

	
 
/// Used by various distributed algorithms to identify connectors.
 
pub type ConnectorId = u32;
 

	
 
/// Used in conjunction with the `ConnectorId` type to create identifiers for ports and components
 
pub type U32Suffix = u32;
 
#[derive(
 
    Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd, serde::Serialize, serde::Deserialize,
 
)]
 
#[derive(Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd)]
 

	
 
/// Generalization of a port/component identifier
 
#[derive(serde::Serialize, serde::Deserialize)]
 
#[repr(C)]
 
pub struct Id {
 
    pub(crate) connector_id: ConnectorId,
 
    pub(crate) u32_suffix: U32Suffix,
 
}
 
#[derive(Clone, Debug, Default)]
 
pub struct U32Stream {
 
    next: u32,
 
}
 

	
 
/// Identifier of a component in a session
 
#[derive(
 
    Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd, serde::Serialize, serde::Deserialize,
 
)]
 
#[derive(Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd, serde::Serialize, serde::Deserialize)]
 
pub struct ComponentId(Id); // PUB because it can be returned by errors
 

	
 
/// Identifier of a port in a session
 
#[derive(
 
    Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd, serde::Serialize, serde::Deserialize,
 
)]
 
#[derive(Copy, Clone, Eq, PartialEq, Ord, Hash, PartialOrd, serde::Serialize, serde::Deserialize)]
 
#[repr(transparent)]
 
pub struct PortId(Id);
 

	
 
/// A safely aliasable heap-allocated payload of message bytes
 
#[derive(Default, Eq, PartialEq, Clone, Ord, PartialOrd)]
 
pub struct Payload(Arc<Vec<u8>>);
 
#[derive(
 
    Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd, serde::Serialize, serde::Deserialize,
 
)]
 
#[derive(Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd)]
 

	
 
/// "Orientation" of a port, determining whether they can send or receive messages with `put` and `get` respectively.
 
#[repr(C)]
 
#[derive(serde::Serialize, serde::Deserialize)]
 
pub enum Polarity {
 
    Putter, // output port (from the perspective of the component)
 
    Getter, // input port (from the perspective of the component)
 
}
 
#[derive(
 
    Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd, serde::Serialize, serde::Deserialize,
 
)]
 
#[derive(Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd)]
 

	
 
/// "Orientation" of a transport-layer network endpoint, dictating how it's connection procedure should
 
/// be conducted. Corresponds with connect() / accept() familiar to TCP socket programming.
 
#[repr(C)]
 
pub enum EndpointPolarity {
 
    Active,  // calls connect()
 
    Passive, // calls bind() listen() accept()
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub(crate) enum NonsyncBlocker {
 
    Inconsistent,
src/protocol/arena.rs
Show inline comments
 
use crate::common::*;
 
use core::hash::Hash;
 
use core::marker::PhantomData;
 

	
 
#[derive(serde::Serialize, serde::Deserialize)]
 
pub struct Id<T> {
 
    pub(crate) index: u32,
 
    _phantom: PhantomData<T>,
 
}
 

	
 
impl<T> Id<T> {
 
    pub(crate) fn new(index: u32) -> Self {
 
        Self{ index, _phantom: Default::default() }
 
    }
 
}
 

	
 
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug)]
 
pub(crate) struct Arena<T> {
 
    store: Vec<T>,
 
}
 
//////////////////////////////////
 

	
 
impl<T> Debug for Id<T> {
 
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
        f.debug_struct("Id").field("index", &self.index).finish()
 
    }
 
}
 
impl<T> Clone for Id<T> {
 
    fn clone(&self) -> Self {
src/protocol/ast.rs
Show inline comments
 
@@ -51,25 +51,25 @@ macro_rules! define_aliased_ast_id {
 
            pub fn $fn_name(&mut self, f: impl FnOnce($name) -> $indexed_type) -> $name {
 
                self.$indexed_arena.alloc_with_id(|id| f(id))
 
            }
 
        }
 
    };
 
}
 

	
 
/// Helper macro that defines a wrapper type for a particular variant of an AST
 
/// element ID. Only used to define single-wrapping IDs.
 
macro_rules! define_new_ast_id {
 
    // Variant where we just defined the new type, without any indexing
 
    ($name:ident, $parent:ty) => {
 
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
 
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 
        pub struct $name (pub(crate) $parent);
 

	
 
        impl $name {
 
            pub fn upcast(self) -> $parent {
 
                self.0
 
            }
 
        }
 
    };
 
    // Variant where we define the type, and the Index and IndexMut traits
 
    (
 
        $name:ident, $parent:ty, 
 
        index($indexed_type:ty, $wrapper_type:path, $indexed_arena:ident)
 
@@ -158,25 +158,25 @@ define_new_ast_id!(BindingExpressionId, ExpressionId, index(BindingExpression, E
 
define_new_ast_id!(ConditionalExpressionId, ExpressionId, index(ConditionalExpression, Expression::Conditional, expressions), alloc(alloc_conditional_expression));
 
define_new_ast_id!(BinaryExpressionId, ExpressionId, index(BinaryExpression, Expression::Binary, expressions), alloc(alloc_binary_expression));
 
define_new_ast_id!(UnaryExpressionId, ExpressionId, index(UnaryExpression, Expression::Unary, expressions), alloc(alloc_unary_expression));
 
define_new_ast_id!(IndexingExpressionId, ExpressionId, index(IndexingExpression, Expression::Indexing, expressions), alloc(alloc_indexing_expression));
 
define_new_ast_id!(SlicingExpressionId, ExpressionId, index(SlicingExpression, Expression::Slicing, expressions), alloc(alloc_slicing_expression));
 
define_new_ast_id!(SelectExpressionId, ExpressionId, index(SelectExpression, Expression::Select, expressions), alloc(alloc_select_expression));
 
define_new_ast_id!(ArrayExpressionId, ExpressionId, index(ArrayExpression, Expression::Array, expressions), alloc(alloc_array_expression));
 
define_new_ast_id!(LiteralExpressionId, ExpressionId, index(LiteralExpression, Expression::Literal, expressions), alloc(alloc_literal_expression));
 
define_new_ast_id!(CallExpressionId, ExpressionId, index(CallExpression, Expression::Call, expressions), alloc(alloc_call_expression));
 
define_new_ast_id!(VariableExpressionId, ExpressionId, index(VariableExpression, Expression::Variable, expressions), alloc(alloc_variable_expression));
 

	
 
// TODO: @cleanup - pub qualifiers can be removed once done
 
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug)]
 
pub struct Heap {
 
    // Root arena, contains the entry point for different modules. Each root
 
    // contains lists of IDs that correspond to the other arenas.
 
    pub(crate) protocol_descriptions: Arena<Root>,
 
    // Contents of a file, these are the elements the `Root` elements refer to
 
    pragmas: Arena<Pragma>,
 
    pub(crate) imports: Arena<Import>,
 
    identifiers: Arena<Identifier>,
 
    pub(crate) parser_types: Arena<ParserType>,
 
    pub(crate) variables: Arena<Variable>,
 
    pub(crate) definitions: Arena<Definition>,
 
    pub(crate) statements: Arena<Statement>,
 
@@ -225,25 +225,25 @@ impl Index<MemoryStatementId> for Heap {
 
    fn index(&self, index: MemoryStatementId) -> &Self::Output {
 
        &self.statements[index.0.0].as_memory()
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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>,
 
}
 

	
 
impl Root {
 
    pub fn get_definition_ident(&self, h: &Heap, id: &[u8]) -> Option<DefinitionId> {
 
        for &def in self.definitions.iter() {
 
@@ -252,61 +252,61 @@ impl Root {
 
            }
 
        }
 
        None
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Pragma {
 
    Version(PragmaVersion),
 
    Module(PragmaModule)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct PragmaVersion {
 
    pub this: PragmaId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub version: u64,
 
}
 

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Import {
 
    Module(ImportModule),
 
    Symbols(ImportSymbols)
 
}
 

	
 
impl Import {
 
    pub(crate) fn as_module(&self) -> &ImportModule {
 
        match self {
 
            Import::Module(m) => m,
 
            _ => panic!("Unable to cast 'Import' to 'ImportModule'")
 
        }
 
    }
 
@@ -318,80 +318,80 @@ impl Import {
 
    }
 
}
 

	
 
impl SyntaxElement for Import {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Import::Module(m) => m.position,
 
            Import::Symbols(m) => m.position
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ImportModule {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub module_name: Vec<u8>,
 
    pub alias: Identifier,
 
    // Phase 2: module resolving
 
    pub module_id: Option<RootId>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct AliasedSymbol {
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub name: Identifier,
 
    pub alias: Identifier,
 
    // Phase 2: symbol resolving
 
    pub definition_id: Option<DefinitionId>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ImportSymbols {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub module_name: Vec<u8>,
 
    // Phase 2: module resolving
 
    pub module_id: Option<RootId>,
 
    // Phase 1&2
 
    // if symbols is empty, then we implicitly import all symbols without any
 
    // aliases for them. If it is not empty, then symbols are explicitly
 
    // specified, and optionally given an alias.
 
    pub symbols: Vec<AliasedSymbol>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct Identifier {
 
    pub position: InputPosition,
 
    pub value: Vec<u8>
 
}
 

	
 
impl PartialEq for Identifier {
 
    fn eq(&self, other: &Self) -> bool {
 
        return self.value == other.value
 
    }
 
}
 

	
 
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.value))
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum NamespacedIdentifierPart {
 
    // Regular identifier
 
    Identifier{start: u16, end: u16},
 
    // Polyargs associated with a preceding identifier
 
    PolyArgs{start: u16, end: u16},
 
}
 

	
 
impl NamespacedIdentifierPart {
 
    pub(crate) fn is_identifier(&self) -> bool {
 
        match self {
 
            NamespacedIdentifierPart::Identifier{..} => true,
 
            NamespacedIdentifierPart::PolyArgs{..} => false,
 
@@ -414,25 +414,25 @@ impl NamespacedIdentifierPart {
 
                unreachable!("Tried to obtain {:?} as PolyArgs", self)
 
            }
 
        }
 
    }
 
}
 

	
 
/// An identifier with optional namespaces and polymorphic variables. Note that 
 
/// we allow each identifier to be followed by polymorphic arguments during the 
 
/// parsing phase (e.g. Foo<A,B>::Bar<C,D>::Qux). But in our current language 
 
/// implementation we can only have valid namespaced identifier that contain one
 
/// set of polymorphic arguments at the appropriate position.
 
/// TODO: @tokens Reimplement/rename once we have a tokenizer
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct NamespacedIdentifier {
 
    pub position: InputPosition,
 
    pub value: Vec<u8>, // Full name as it resides in the input source
 
    pub poly_args: Vec<ParserTypeId>, // All poly args littered throughout the namespaced identifier
 
    pub parts: Vec<NamespacedIdentifierPart>, // Indices into value/poly_args
 
}
 

	
 
impl NamespacedIdentifier {
 
    /// Returns the identifier value without any of the specific polymorphic
 
    /// arguments.
 
    pub fn strip_poly_args(&self) -> Vec<u8> {
 
        debug_assert!(!self.parts.is_empty() && self.parts[0].is_identifier());
 
@@ -601,25 +601,25 @@ impl<'a> NamespacedIdentifierIter<'a> {
 
    }
 

	
 
    /// Returns the previously returned result from `next()`
 
    pub fn prev(&self) -> Option<<Self as Iterator>::Item> {
 
        match self.prev_idx() {
 
            None => None,
 
            Some(idx) => self.get(idx)
 
        }
 
    }
 
}
 

	
 
/// TODO: @types Remove the Message -> Byte hack at some point...
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum ParserTypeVariant {
 
    // Basic builtin
 
    Message,
 
    Bool,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
    String,
 
    // Literals (need to get concrete builtin type during typechecking)
 
    IntegerLiteral,
 
    Inferred,
 
@@ -635,119 +635,119 @@ impl ParserTypeVariant {
 
        use ParserTypeVariant::*;
 
        match self {
 
            Message | Bool | Byte | Short | Int | Long | String | IntegerLiteral | Inferred => false,
 
            _ => true
 
        }
 
    }
 
}
 

	
 
/// ParserType is a specification of a type during the parsing phase and initial
 
/// linker/validator phase of the compilation process. These types may be
 
/// (partially) inferred or represent literals (e.g. a integer whose bytesize is
 
/// not yet determined).
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ParserType {
 
    pub this: ParserTypeId,
 
    pub pos: InputPosition,
 
    pub variant: ParserTypeVariant,
 
}
 

	
 
/// SymbolicParserType is the specification of a symbolic type. During the
 
/// parsing phase we will only store the identifier of the type. During the
 
/// validation phase we will determine whether it refers to a user-defined type,
 
/// or a polymorphic argument. After the validation phase it may still be the
 
/// case that the resulting `variant` will not pass the typechecker.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct SymbolicParserType {
 
    // Phase 1: parser
 
    pub identifier: NamespacedIdentifier,
 
    // Phase 2: validation/linking (for types in function/component bodies) and
 
    //  type table construction (for embedded types of structs/unions)
 
    pub poly_args2: Vec<ParserTypeId>, // taken from identifier or inferred
 
    pub variant: Option<SymbolicParserTypeVariant>
 
}
 

	
 
/// Specifies whether the symbolic type points to an actual user-defined type,
 
/// or whether it points to a polymorphic argument within the definition (e.g.
 
/// a defined variable `T var` within a function `int func<T>()`
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum SymbolicParserTypeVariant {
 
    Definition(DefinitionId),
 
    // TODO: figure out if I need the DefinitionId here
 
    PolyArg(DefinitionId, usize), // index of polyarg in the definition
 
}
 

	
 
/// ConcreteType is the representation of a type after resolving symbolic types
 
/// and performing type inference
 
#[derive(Debug, Clone, Copy, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
 
pub enum ConcreteTypePart {
 
    // Markers for the use of polymorphic types within a procedure's body that
 
    // refer to polymorphic variables on the procedure's definition. Different
 
    // from markers in the `InferenceType`, these will not contain nested types.
 
    Marker(usize),
 
    // Special types (cannot be explicitly constructed by the programmer)
 
    Void,
 
    // Builtin types without nested types
 
    Message,
 
    Bool,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
    String,
 
    // Builtin types with one nested type
 
    Array,
 
    Slice,
 
    Input,
 
    Output,
 
    // User defined type with any number of nested types
 
    Instance(DefinitionId, usize),
 
}
 

	
 
#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Eq, PartialEq)]
 
pub struct ConcreteType {
 
    pub(crate) parts: Vec<ConcreteTypePart>
 
}
 

	
 
impl Default for ConcreteType {
 
    fn default() -> Self {
 
        Self{ parts: Vec::new() }
 
    }
 
}
 

	
 
impl ConcreteType {
 
    pub(crate) fn has_marker(&self) -> bool {
 
        self.parts
 
            .iter()
 
            .any(|p| {
 
                if let ConcreteTypePart::Marker(_) = p { true } else { false }
 
            })
 
    }
 
}
 

	
 
// TODO: Remove at some point
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
pub enum PrimitiveType {
 
    Unassigned,
 
    Input,
 
    Output,
 
    Message,
 
    Boolean,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
}
 

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

	
 
#[allow(dead_code)]
 
impl Type {
 
    pub const UNASSIGNED: Type = Type { primitive: PrimitiveType::Unassigned, array: false };
 

	
 
    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 };
 
@@ -797,55 +797,55 @@ impl Display for Type {
 
            PrimitiveType::Long => {
 
                write!(f, "long")?;
 
            }
 
        }
 
        if self.array {
 
            write!(f, "[]")
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

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

	
 
    pub fn as_symbolic(&self) -> &FieldSymbolic {
 
        match self {
 
            Field::Symbolic(v) => v,
 
            _ => unreachable!("attempted to get Field::Symbolic from {:?}", self)
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct FieldSymbolic {
 
    // Phase 1: Parser
 
    pub(crate) identifier: Identifier,
 
    // Phase 3: Typing
 
    pub(crate) definition: Option<DefinitionId>,
 
    pub(crate) field_idx: usize,
 
}
 

	
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy)]
 
pub enum Scope {
 
    Definition(DefinitionId),
 
    Regular(BlockStatementId),
 
    Synchronous((SynchronousStatementId, BlockStatementId)),
 
}
 

	
 
impl Scope {
 
    pub fn is_block(&self) -> bool {
 
        match &self {
 
            Scope::Definition(_) => false,
 
            Scope::Regular(_) => true,
 
            Scope::Synchronous(_) => true,
 
@@ -873,25 +873,25 @@ impl VariableScope for Scope {
 
            Scope::Synchronous((stmt, _)) => h[*stmt].parent_scope(h),
 
        }
 
    }
 
    fn get_variable(&self, h: &Heap, id: &Identifier) -> Option<VariableId> {
 
        match self {
 
            Scope::Definition(def) => h[*def].get_variable(h, id),
 
            Scope::Regular(stmt) => h[*stmt].get_variable(h, id),
 
            Scope::Synchronous((stmt, _)) => h[*stmt].get_variable(h, id),
 
        }
 
    }
 
}
 

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

	
 
impl Variable {
 
    pub fn identifier(&self) -> &Identifier {
 
        match self {
 
            Variable::Parameter(var) => &var.identifier,
 
            Variable::Local(var) => &var.identifier,
 
        }
 
    }
 
@@ -923,56 +923,56 @@ impl Variable {
 

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

	
 
/// TODO: Remove distinction between parameter/local and add an enum to indicate
 
///     the distinction between the two
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct Parameter {
 
    pub this: ParameterId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub parser_type: ParserTypeId,
 
    pub identifier: Identifier,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct Local {
 
    pub this: LocalId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub parser_type: ParserTypeId,
 
    pub identifier: Identifier,
 
    // Phase 2: linker
 
    pub relative_pos_in_block: u32,
 
}
 
impl SyntaxElement for Local {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Definition {
 
    Struct(StructDefinition),
 
    Enum(EnumDefinition),
 
    Union(UnionDefinition),
 
    Component(Component),
 
    Function(Function),
 
}
 

	
 
impl Definition {
 
    pub fn is_struct(&self) -> bool {
 
        match self {
 
            Definition::Struct(_) => true,
 
@@ -1079,130 +1079,130 @@ impl VariableScope for Definition {
 
    }
 
    fn get_variable(&self, h: &Heap, id: &Identifier) -> Option<VariableId> {
 
        for &parameter_id in self.parameters().iter() {
 
            let parameter = &h[parameter_id];
 
            if parameter.identifier == *id {
 
                return Some(parameter_id.0);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct StructFieldDefinition {
 
    pub position: InputPosition,
 
    pub field: Identifier,
 
    pub parser_type: ParserTypeId,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct StructDefinition {
 
    pub this: StructId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    pub fields: Vec<StructFieldDefinition>
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum EnumVariantValue {
 
    None,
 
    Integer(i64),
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct EnumVariantDefinition {
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub value: EnumVariantValue,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct EnumDefinition {
 
    pub this: EnumId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    pub variants: Vec<EnumVariantDefinition>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum UnionVariantValue {
 
    None,
 
    Embedded(Vec<ParserTypeId>),
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct UnionVariantDefinition {
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub value: UnionVariantValue,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct UnionDefinition {
 
    pub this: UnionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    pub variants: Vec<UnionVariantDefinition>,
 
}
 

	
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy)]
 
pub enum ComponentVariant {
 
    Primitive,
 
    Composite,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct Component {
 
    pub this: ComponentId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub variant: ComponentVariant,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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),
 
@@ -1418,25 +1418,25 @@ impl SyntaxElement for Statement {
 
            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::Expression(stmt) => stmt.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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 relative_pos_in_parent: u32,
 
    pub locals: Vec<LocalId>,
 
    pub labels: Vec<LabeledStatementId>,
 
}
 

	
 
@@ -1481,25 +1481,25 @@ impl VariableScope for BlockStatement {
 
    }
 
    fn get_variable(&self, h: &Heap, id: &Identifier) -> Option<VariableId> {
 
        for local_id in self.locals.iter() {
 
            let local = &h[*local_id];
 
            if local.identifier == *id {
 
                return Some(local_id.0);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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(),
 
        }
 
    }
 
@@ -1523,195 +1523,195 @@ impl LocalStatement {
 
    }
 
}
 

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

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

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

	
 
/// ChannelStatement is the declaration of an input and output port associated
 
/// with the same channel. Note that the polarity of the ports are from the
 
/// point of view of the component. So an output port is something that a
 
/// component uses to send data over (i.e. it is the "input end" of the
 
/// channel), and vice versa.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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 relative_pos_in_block: u32,
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LabeledStatement {
 
    pub this: LabeledStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub label: Identifier,
 
    pub body: StatementId,
 
    // Phase 2: linker
 
    pub relative_pos_in_block: u32,
 
    pub in_sync: Option<SynchronousStatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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,
 
    // Phase 2: linker
 
    pub end_if: Option<EndIfStatementId>,
 
}
 

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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 end_while: Option<EndWhileStatementId>,
 
    pub in_sync: Option<SynchronousStatementId>,
 
}
 

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

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

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

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

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct SynchronousStatement {
 
    pub this: SynchronousStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    // pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
    // Phase 2: linker
 
    pub end_sync: Option<EndSynchronousStatementId>,
 
    pub parent_scope: Option<Scope>,
 
}
 

	
 
impl SyntaxElement for SynchronousStatement {
 
@@ -1727,130 +1727,130 @@ impl VariableScope for SynchronousStatement {
 
    fn get_variable(&self, _h: &Heap, _id: &Identifier) -> Option<VariableId> {
 
        // TODO: Another case of "where was this used for?"
 
        // for parameter_id in self.parameters.iter() {
 
        //     let parameter = &h[*parameter_id];
 
        //     if parameter.identifier.value == id.value {
 
        //         return Some(parameter_id.0);
 
        //     }
 
        // }
 
        None
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct EndSynchronousStatement {
 
    pub this: EndSynchronousStatementId,
 
    // Phase 2: linker
 
    pub position: InputPosition, // of corresponding sync statement
 
    pub start_sync: SynchronousStatementId,
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ReturnStatement {
 
    pub this: ReturnStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub expression: ExpressionId,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct AssertStatement {
 
    pub this: AssertStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub expression: ExpressionId,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct GotoStatement {
 
    pub this: GotoStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub label: Identifier,
 
    // Phase 2: linker
 
    pub target: Option<LabeledStatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct NewStatement {
 
    pub this: NewStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub expression: CallExpressionId,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ExpressionStatement {
 
    pub this: ExpressionStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub expression: ExpressionId,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 
pub enum ExpressionParent {
 
    None, // only set during initial parsing
 
    If(IfStatementId),
 
    While(WhileStatementId),
 
    Return(ReturnStatementId),
 
    Assert(AssertStatementId),
 
    New(NewStatementId),
 
    ExpressionStmt(ExpressionStatementId),
 
    Expression(ExpressionId, u32) // index within expression (e.g LHS or RHS of expression)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Expression {
 
    Assignment(AssignmentExpression),
 
    Binding(BindingExpression),
 
    Conditional(ConditionalExpression),
 
    Binary(BinaryExpression),
 
    Unary(UnaryExpression),
 
    Indexing(IndexingExpression),
 
    Slicing(SlicingExpression),
 
    Select(SelectExpression),
 
    Array(ArrayExpression),
 
    Literal(LiteralExpression),
 
    Call(CallExpression),
 
@@ -2024,303 +2024,303 @@ impl SyntaxElement for Expression {
 
            Expression::Unary(expr) => expr.position(),
 
            Expression::Indexing(expr) => expr.position(),
 
            Expression::Slicing(expr) => expr.position(),
 
            Expression::Select(expr) => expr.position(),
 
            Expression::Array(expr) => expr.position(),
 
            Expression::Literal(expr) => expr.position(),
 
            Expression::Call(expr) => expr.position(),
 
            Expression::Variable(expr) => expr.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum AssignmentOperator {
 
    Set,
 
    Multiplied,
 
    Divided,
 
    Remained,
 
    Added,
 
    Subtracted,
 
    ShiftedLeft,
 
    ShiftedRight,
 
    BitwiseAnded,
 
    BitwiseXored,
 
    BitwiseOred,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct AssignmentExpression {
 
    pub this: AssignmentExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub left: ExpressionId,
 
    pub operation: AssignmentOperator,
 
    pub right: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct BindingExpression {
 
    pub this: BindingExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub left: LiteralExpressionId,
 
    pub right: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ConditionalExpression {
 
    pub this: ConditionalExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub test: ExpressionId,
 
    pub true_expression: ExpressionId,
 
    pub false_expression: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
pub enum BinaryOperator {
 
    Concatenate,
 
    LogicalOr,
 
    LogicalAnd,
 
    BitwiseOr,
 
    BitwiseXor,
 
    BitwiseAnd,
 
    Equality,
 
    Inequality,
 
    LessThan,
 
    GreaterThan,
 
    LessThanEqual,
 
    GreaterThanEqual,
 
    ShiftLeft,
 
    ShiftRight,
 
    Add,
 
    Subtract,
 
    Multiply,
 
    Divide,
 
    Remainder,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct BinaryExpression {
 
    pub this: BinaryExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub left: ExpressionId,
 
    pub operation: BinaryOperator,
 
    pub right: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
pub enum UnaryOperation {
 
    Positive,
 
    Negative,
 
    BitwiseNot,
 
    LogicalNot,
 
    PreIncrement,
 
    PreDecrement,
 
    PostIncrement,
 
    PostDecrement,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct UnaryExpression {
 
    pub this: UnaryExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub operation: UnaryOperation,
 
    pub expression: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct IndexingExpression {
 
    pub this: IndexingExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub subject: ExpressionId,
 
    pub index: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct SlicingExpression {
 
    pub this: SlicingExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub subject: ExpressionId,
 
    pub from_index: ExpressionId,
 
    pub to_index: ExpressionId,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct SelectExpression {
 
    pub this: SelectExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub subject: ExpressionId,
 
    pub field: Field,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct ArrayExpression {
 
    pub this: ArrayExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub elements: Vec<ExpressionId>,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
// TODO: @tokenizer Symbolic function calls are ambiguous with union literals
 
//  that accept embedded values (although the polymorphic arguments are placed
 
//  differently). To prevent double work we parse as CallExpression, and during
 
//  validation we may transform the expression into a union literal.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct CallExpression {
 
    pub this: CallExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub method: Method,
 
    pub arguments: Vec<ExpressionId>,
 
    pub poly_args: Vec<ParserTypeId>, // if symbolic will be determined during validation phase
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Method {
 
    Get,
 
    Put,
 
    Fires,
 
    Create,
 
    Symbolic(MethodSymbolic)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct MethodSymbolic {
 
    pub(crate) identifier: NamespacedIdentifier,
 
    pub(crate) definition: Option<DefinitionId>
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LiteralExpression {
 
    pub this: LiteralExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Literal,
 
    // Phase 2: linker
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

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

	
 
type LiteralCharacter = Vec<u8>;
 
type LiteralInteger = i64; // TODO: @int_literal
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Literal {
 
    Null, // message
 
    True,
 
    False,
 
    Character(LiteralCharacter),
 
    Integer(LiteralInteger),
 
    Struct(LiteralStruct),
 
    Enum(LiteralEnum),
 
    Union(LiteralUnion),
 
}
 

	
 
impl Literal {
 
@@ -2348,69 +2348,69 @@ impl Literal {
 
        }
 
    }
 

	
 
    pub(crate) fn as_union(&self) -> &LiteralUnion {
 
        if let Literal::Union(literal) = self {
 
            literal
 
        } else {
 
            unreachable!("Attempted to obtain {:?} as Literal::Union", self)
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LiteralStructField {
 
    // Phase 1: parser
 
    pub(crate) identifier: Identifier,
 
    pub(crate) value: ExpressionId,
 
    // Phase 2: linker
 
    pub(crate) field_idx: usize, // in struct definition
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LiteralStruct {
 
    // Phase 1: parser
 
    pub(crate) identifier: NamespacedIdentifier,
 
    pub(crate) fields: Vec<LiteralStructField>,
 
    // Phase 2: linker
 
    pub(crate) poly_args2: Vec<ParserTypeId>, // taken from identifier once linked to a definition
 
    pub(crate) definition: Option<DefinitionId>
 
}
 

	
 
// TODO: @tokenizer Enum literals are ambiguous with union literals that do not
 
//  accept embedded values. To prevent double work for now we parse as a 
 
//  LiteralEnum, and during validation we may transform the expression into a 
 
//  union literal.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LiteralEnum {
 
    // Phase 1: parser
 
    pub(crate) identifier: NamespacedIdentifier,
 
    // Phase 2: linker
 
    pub(crate) poly_args2: Vec<ParserTypeId>, // taken from identifier once linked to a definition
 
    pub(crate) definition: Option<DefinitionId>,
 
    pub(crate) variant_idx: usize, // as present in the type table
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct LiteralUnion {
 
    // Phase 1: parser
 
    pub(crate) identifier: NamespacedIdentifier,
 
    pub(crate) values: Vec<ExpressionId>,
 
    // Phase 2: linker
 
    pub(crate) poly_args2: Vec<ParserTypeId>, // taken from identifier once linked to a definition
 
    pub(crate) definition: Option<DefinitionId>,
 
    pub(crate) variant_idx: usize, // as present in type table
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct VariableExpression {
 
    pub this: VariableExpressionId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: NamespacedIdentifier,
 
    // Phase 2: linker
 
    pub declaration: Option<VariableId>,
 
    pub parent: ExpressionParent,
 
    // Phase 3: type checking
 
    pub concrete_type: ConcreteType,
 
}
 

	
src/protocol/eval.rs
Show inline comments
 
@@ -21,25 +21,25 @@ const MESSAGE_MAX_LENGTH: i64 = SHORT_MAX;
 

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

	
 
// TODO: All goes one day anyway, so dirty typechecking hack
 
trait ValueImpl {
 
    fn exact_type(&self) -> Type;
 
    fn is_type_compatible(&self, h: &Heap, t: &ParserType) -> bool {
 
        Self::is_type_compatible_hack(h, t)
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool;
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub enum Value {
 
    Unassigned,
 
    Input(InputValue),
 
    Output(OutputValue),
 
    Message(MessageValue),
 
    Boolean(BooleanValue),
 
    Byte(ByteValue),
 
    Short(ShortValue),
 
    Int(IntValue),
 
    Long(LongValue),
 
    InputArray(InputArrayValue),
 
    OutputArray(OutputArrayValue),
 
@@ -888,69 +888,69 @@ impl Display for Value {
 
            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, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct InputValue(pub PortId);
 

	
 
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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match &t.variant {
 
            Input(_) | Inferred | Symbolic(_) => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct OutputValue(pub PortId);
 

	
 
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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match &t.variant {
 
            Output(_) | Inferred | Symbolic(_) => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct MessageValue(pub Option<Payload>);
 

	
 
impl Display for MessageValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        match &self.0 {
 
            None => write!(f, "null"),
 
            Some(payload) => {
 
                // format print up to 10 bytes
 
                let mut slice = payload.as_slice();
 
                if slice.len() > 10 {
 
                    slice = &slice[..10];
 
                }
 
@@ -964,113 +964,113 @@ impl ValueImpl for MessageValue {
 
    fn exact_type(&self) -> Type {
 
        Type::MESSAGE
 
    }
 
    fn is_type_compatible_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match &t.variant {
 
            Message | Inferred | Symbolic(_) => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match t.variant {
 
            Symbolic(_) | Inferred | Bool | Byte | Short | Int | Long => true,
 
            _ => false
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match t.variant {
 
            Symbolic(_) | Inferred | Byte | Short | Int | Long => true,
 
            _ => false
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match t.variant {
 
            Symbolic(_) | Inferred | Short | Int | Long => true,
 
            _ => false
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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_hack(_h: &Heap, t: &ParserType) -> bool {
 
        use ParserTypeVariant::*;
 
        match t.variant {
 
            Symbolic(_) | Inferred | Int | Long => true,
 
            _ => false
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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
 
    }
 
@@ -1081,25 +1081,25 @@ impl ValueImpl for LongValue {
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
fn get_array_inner(t: &ParserType) -> Option<ParserTypeId> {
 
    match t.variant {
 
        ParserTypeVariant::Array(inner) => Some(inner),
 
        _ => None
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1110,25 +1110,25 @@ impl Display for InputArrayValue {
 

	
 
impl ValueImpl for InputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INPUT_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| InputValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1139,25 +1139,25 @@ impl Display for OutputArrayValue {
 

	
 
impl ValueImpl for OutputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::OUTPUT_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| OutputValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1168,25 +1168,25 @@ impl Display for MessageArrayValue {
 

	
 
impl ValueImpl for MessageArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::MESSAGE_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| MessageValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1197,25 +1197,25 @@ impl Display for BooleanArrayValue {
 

	
 
impl ValueImpl for BooleanArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BOOLEAN_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| BooleanValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1226,25 +1226,25 @@ impl Display for ByteArrayValue {
 

	
 
impl ValueImpl for ByteArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BYTE_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| ByteValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1255,25 +1255,25 @@ impl Display for ShortArrayValue {
 

	
 
impl ValueImpl for ShortArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::SHORT_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| ShortValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1284,25 +1284,25 @@ impl Display for IntArrayValue {
 

	
 
impl ValueImpl for IntArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INT_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| IntValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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;
 
@@ -1313,25 +1313,25 @@ impl Display for LongArrayValue {
 

	
 
impl ValueImpl for LongArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::LONG_ARRAY
 
    }
 
    fn is_type_compatible_hack(h: &Heap, t: &ParserType) -> bool {
 
        get_array_inner(t)
 
            .map(|v| LongValue::is_type_compatible_hack(h, &h[v]))
 
            .unwrap_or(false)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[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 parser_type = match &h[var] {
 
            Variable::Local(v) => v.parser_type,
 
            Variable::Parameter(v) => v.parser_type,
 
@@ -1568,25 +1568,25 @@ type EvalResult = Result<Value, EvalContinuation>;
 
pub enum EvalContinuation {
 
    Stepping,
 
    Inconsistent,
 
    Terminal,
 
    SyncBlockStart,
 
    SyncBlockEnd,
 
    NewComponent(DefinitionId, Vec<Value>),
 
    BlockFires(Value),
 
    BlockGet(Value),
 
    Put(Value, Value),
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub(crate) 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()) };
 
        prompt.set_arguments(h, args);
 
        prompt
src/protocol/inputsource.rs
Show inline comments
 
use std::fmt;
 
use std::fs::File;
 
use std::io;
 
use std::path::Path;
 

	
 
use backtrace::Backtrace;
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub struct InputSource {
 
    pub(crate) filename: String,
 
    pub(crate) input: Vec<u8>,
 
    line: usize,
 
    column: usize,
 
    offset: usize,
 
}
 

	
 
static STD_LIB_PDL: &'static [u8] = b"
 
primitive forward(in<msg> i, out<msg> o) {
 
    while(true) synchronous put(o, get(i));
 
}
 
@@ -135,25 +135,25 @@ impl InputSource {
 
            }
 
            None => {}
 
        }
 
    }
 
}
 

	
 
impl fmt::Display for InputSource {
 
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
        self.pos().fmt(f)
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy)]
 
pub struct InputPosition {
 
    line: usize,
 
    column: usize,
 
    pub(crate) offset: usize,
 
}
 

	
 
impl InputPosition {
 
    fn context<'a>(&self, source: &'a InputSource) -> &'a [u8] {
 
        let start = self.offset - (self.column - 1);
 
        let mut end = self.offset;
 
        while end < source.input.len() {
 
            let cur = (*source.input)[end];
src/protocol/mod.rs
Show inline comments
 
@@ -19,33 +19,31 @@ lazy_static::lazy_static! {
 
    pub static ref TRIVIAL_PD: std::sync::Arc<ProtocolDescription> = {
 
        std::sync::Arc::new(ProtocolDescription::parse(b"").unwrap())
 
    };
 
}
 

	
 
use crate::common::*;
 
use crate::protocol::ast::*;
 
use crate::protocol::eval::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 

	
 
/// Description of a protocol object, used to configure new connectors.
 
/// (De)serializable.
 
#[derive(serde::Serialize, serde::Deserialize)]
 
#[repr(C)]
 
pub struct ProtocolDescription {
 
    heap: Heap,
 
    source: InputSource,
 
    root: RootId,
 
}
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone)]
 
pub(crate) struct ComponentState {
 
    prompt: Prompt,
 
}
 
pub(crate) enum EvalContext<'a> {
 
    Nonsync(&'a mut NonsyncProtoContext<'a>),
 
    Sync(&'a mut SyncProtoContext<'a>),
 
    // None,
 
}
 
//////////////////////////////////////////////
 

	
 
impl std::fmt::Debug for ProtocolDescription {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
src/runtime/mod.rs
Show inline comments
 
@@ -99,25 +99,25 @@ struct RoundEndedNative {
 

	
 
// Implementation of a set in terms of a vector (optimized for reading, not writing)
 
#[derive(Default)]
 
struct VecSet<T: std::cmp::Ord> {
 
    // invariant: ordered, deduplicated
 
    vec: Vec<T>,
 
}
 

	
 
// Allows a connector to remember how to forward payloads towards the component that
 
// owns their destination port. `LocalComponent` corresponds with messages for components
 
// managed by the connector itself (hinting for it to look it up in a local structure),
 
// whereas the other variants direct the connector to forward the messages over the network.
 
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 
enum Route {
 
    LocalComponent,
 
    NetEndpoint { index: usize },
 
    UdpEndpoint { index: usize },
 
}
 

	
 
// The outcome of a synchronous round, representing the distributed consensus.
 
// In the success case, the attached predicate encodes a row in the session's trace table.
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
enum Decision {
 
    Failure, // some connector timed out!
 
    Success(Predicate),
 
@@ -128,43 +128,26 @@ enum Decision {
 
enum Msg {
 
    SetupMsg(SetupMsg),
 
    CommMsg(CommMsg),
 
}
 

	
 
// Control messages exchanged during the setup phase only
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
enum SetupMsg {
 
    MyPortInfo(MyPortInfo),
 
    LeaderWave { wave_leader: ConnectorId },
 
    LeaderAnnounce { tree_leader: ConnectorId },
 
    YouAreMyParent,
 
    SessionGather { unoptimized_map: HashMap<ConnectorId, SessionInfo> },
 
    SessionScatter { optimized_map: HashMap<ConnectorId, SessionInfo> },
 
}
 

	
 
// A data structure encoding the state of a connector, passed around
 
// during the session optimization procedure.
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
struct SessionInfo {
 
    serde_proto_description: SerdeProtocolDescription,
 
    port_info: PortInfoMap,
 
    endpoint_incoming_to_getter: Vec<PortId>,
 
    proto_components: HashMap<ComponentId, ComponentState>,
 
}
 

	
 
// Newtype wrapper for an Arc<ProtocolDescription>,
 
// such that it can be (de)serialized for transmission over the network.
 
#[derive(Debug, Clone)]
 
struct SerdeProtocolDescription(Arc<ProtocolDescription>);
 

	
 
// Control message particular to the communication phase.
 
// as such, it's annotated with a round_index
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
struct CommMsg {
 
    round_index: usize,
 
    contents: CommMsgContents,
 
}
 

	
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
enum CommMsgContents {
 
    SendPayload(SendPayloadMsg),
 
    CommCtrl(CommCtrlMsg),
 
@@ -287,43 +270,43 @@ struct EndpointManager {
 
    io_byte_buffer: IoByteBuffer,
 
}
 

	
 
// A storage of endpoints, which keeps track of which components have raised
 
// an event during poll(), signifying that they need to be checked for new incoming data
 
#[derive(Debug)]
 
struct EndpointStore<T> {
 
    endpoint_exts: Vec<T>,
 
    polled_undrained: VecSet<usize>,
 
}
 

	
 
// The information associated with a port identifier, designed for local storage.
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
#[derive(Clone, Debug)]
 
struct PortInfo {
 
    owner: ComponentId,
 
    peer: Option<PortId>,
 
    polarity: Polarity,
 
    route: Route,
 
}
 

	
 
// Similar to `PortInfo`, but designed for communication during the setup procedure.
 
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 
struct MyPortInfo {
 
    polarity: Polarity,
 
    port: PortId,
 
    owner: ComponentId,
 
}
 

	
 
// Newtype around port info map, allowing the implementation of some
 
// useful methods
 
#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
 
#[derive(Default, Debug, Clone)]
 
struct PortInfoMap {
 
    // invariant: self.invariant_preserved()
 
    // `owned` is redundant information, allowing for fast lookup
 
    // of a component's owned ports (which occurs during the sync round a lot)
 
    map: HashMap<PortId, PortInfo>,
 
    owned: HashMap<ComponentId, HashSet<PortId>>,
 
}
 

	
 
// A convenient substructure for containing port info and the ID manager.
 
// Houses the bulk of the connector's persistent state between rounds.
 
// It turns out several situations require access to both things.
 
#[derive(Debug, Clone)]
 
@@ -369,25 +352,25 @@ struct ConnectorSetup {
 
// A newtype wrapper for a map from speculative variable to speculative value
 
// A missing mapping corresponds with "unspecified".
 
#[derive(Default, Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
 
struct Predicate {
 
    assigned: BTreeMap<SpecVar, SpecVal>,
 
}
 

	
 
// Identifies a child of this connector in the _solution tree_.
 
// Each connector creates its own local solutions for the consensus procedure during `sync`,
 
// from the solutions of its children. Those children are either locally-managed components,
 
// (which are leaves in the solution tree), or other connectors reachable through the given
 
// network endpoint (which are internal nodes in the solution tree).
 
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 
enum SubtreeId {
 
    LocalComponent(ComponentId),
 
    NetEndpoint { index: usize },
 
}
 

	
 
// An accumulation of the connector's knowledge of all (a) the local solutions its children
 
// in the solution tree have found, and (b) its own solutions derivable from those of its children.
 
// This structure starts off each round with an empty set, and accumulates solutions as they are found
 
// by local components, or received over the network in control messages.
 
// IMPORTANT: solutions, once found, don't go away until the end of the round. That is to
 
// say that these sets GROW until the round is over, and all solutions are reset.
 
#[derive(Debug)]
 
@@ -859,42 +842,24 @@ impl<T: Debug + std::cmp::Ord> Debug for VecSet<T> {
 
}
 
impl Debug for Predicate {
 
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
        struct Assignment<'a>((&'a SpecVar, &'a SpecVal));
 
        impl Debug for Assignment<'_> {
 
            fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
                write!(f, "{:?}={:?}", (self.0).0, (self.0).1)
 
            }
 
        }
 
        f.debug_set().entries(self.assigned.iter().map(Assignment)).finish()
 
    }
 
}
 
impl serde::Serialize for SerdeProtocolDescription {
 
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 
    where
 
        S: serde::Serializer,
 
    {
 
        let inner: &ProtocolDescription = &self.0;
 
        inner.serialize(serializer)
 
    }
 
}
 
impl<'de> serde::Deserialize<'de> for SerdeProtocolDescription {
 
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 
    where
 
        D: serde::Deserializer<'de>,
 
    {
 
        let inner: ProtocolDescription = ProtocolDescription::deserialize(deserializer)?;
 
        Ok(Self(Arc::new(inner)))
 
    }
 
}
 
impl IdParts for SpecVar {
 
    fn id_parts(self) -> (ConnectorId, U32Suffix) {
 
        self.0.id_parts()
 
    }
 
}
 
impl Debug for SpecVar {
 
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
 
        let (a, b) = self.id_parts();
 
        write!(f, "v{}_{}", a, b)
 
    }
 
}
 
impl SpecVal {
src/runtime/setup.rs
Show inline comments
 
@@ -269,36 +269,31 @@ impl Connector {
 
                &endpoint_manager,
 
            );
 
            // leader election and tree construction. Learn our role in the consensus tree,
 
            // from learning who are our children/parents (neighbors) in the consensus tree.
 
            let neighborhood = init_neighborhood(
 
                cu.ips.id_manager.connector_id,
 
                &mut *cu.logger,
 
                &mut endpoint_manager,
 
                &deadline,
 
            )?;
 
            log!(cu.logger, "Successfully created neighborhood {:?}", &neighborhood);
 
            // Put it all together with an initial round index of zero.
 
            let mut comm = ConnectorCommunication {
 
            let comm = ConnectorCommunication {
 
                round_index: 0,
 
                endpoint_manager,
 
                neighborhood,
 
                native_batches: vec![Default::default()],
 
                round_result: Ok(None), // no previous round yet
 
            };
 
            if cfg!(feature = "session_optimization") {
 
                // Perform the session optimization procedure, which may modify the
 
                // internals of the connector, rerouting ports, moving around connectors etc.
 
                session_optimize(&mut cu, &mut comm, &deadline)?;
 
            }
 
            log!(cu.logger, "connect() finished. setup phase complete");
 
            Ok(comm)
 
        };
 
        match try_complete() {
 
            Ok(comm) => {
 
                Ok(Self { unphased: cu, phased: ConnectorPhased::Communication(Box::new(comm)) })
 
            }
 
            Err(err) => Err((err, cu.logger)),
 
        }
 
    }
 
}
 

	
 
@@ -799,27 +794,25 @@ fn init_neighborhood(
 
                                    let election_result: WaveState = best_wave;
 
                                    log!(logger, "Election won! Result {:?}", &election_result);
 
                                    break 'election election_result;
 
                                }
 
                            }
 
                        }
 
                    }
 
                }
 
                msg @ S(Sm::YouAreMyParent) | msg @ S(Sm::MyPortInfo(_)) => {
 
                    log!(logger, "Endpont {:?} sent unexpected msg! {:?}", recv_index, &msg);
 
                    return Err(Ce::SetupAlgMisbehavior);
 
                }
 
                msg @ S(Sm::SessionScatter { .. })
 
                | msg @ S(Sm::SessionGather { .. })
 
                | msg @ Msg::CommMsg { .. } => {
 
                msg @ Msg::CommMsg { .. } => {
 
                    log!(logger, "delaying msg {:?} during election algorithm", msg);
 
                    em.delayed_messages.push((recv_index, msg));
 
                }
 
            }
 
        }
 
    };
 

	
 
    // starting algorithm 2. Send a message to every neighbor
 
    // namely, send "YouAreMyParent" to parent (if they exist),
 
    // and LeaderAnnounce to everyone else
 
    log!(logger, "Starting tree construction. Step 1: send one msg per neighbor");
 
    awaiting.clear();
 
@@ -862,212 +855,25 @@ fn init_neighborhood(
 
                        "Got reply from child index {:?}. Children before... {:?}",
 
                        recv_index,
 
                        children.iter()
 
                    );
 
                    return Err(Ce::SetupAlgMisbehavior);
 
                }
 
                // `recv_index` is my child
 
                children.push(recv_index);
 
            }
 
            msg @ S(Sm::MyPortInfo(_)) | msg @ S(Sm::LeaderWave { .. }) => {
 
                log!(logger, "discarding old message {:?} during election", msg);
 
            }
 
            msg @ S(Sm::SessionScatter { .. })
 
            | msg @ S(Sm::SessionGather { .. })
 
            | msg @ Msg::CommMsg { .. } => {
 
            msg @ Msg::CommMsg { .. } => {
 
                log!(logger, "delaying msg {:?} during election", msg);
 
                em.delayed_messages.push((recv_index, msg));
 
            }
 
        }
 
    }
 
    // Neighborhood complete!
 
    children.shrink_to_fit();
 
    let neighborhood =
 
        Neighborhood { parent: election_result.parent, children: VecSet::new(children) };
 
    log!(logger, "Neighborhood constructed {:?}", &neighborhood);
 
    Ok(neighborhood)
 
}
 

	
 
// Connectors collect a map of type ConnectorId=>SessionInfo,
 
// representing a global view of the session's state at the leader.
 
// The leader rewrites its contents however they like (currently: nothing happens)
 
// and the map is again broadcasted, for each peer to make their local changes to
 
// reflect the results of the rewrite.
 
fn session_optimize(
 
    cu: &mut ConnectorUnphased,
 
    comm: &mut ConnectorCommunication,
 
    deadline: &Option<Instant>,
 
) -> Result<(), ConnectError> {
 
    use {ConnectError as Ce, Msg::SetupMsg as S, SetupMsg as Sm};
 
    log!(cu.logger, "Beginning session optimization");
 
    // populate session_info_map from a message per child
 
    let mut unoptimized_map: HashMap<ConnectorId, SessionInfo> = Default::default();
 
    let mut awaiting: HashSet<usize> = comm.neighborhood.children.iter().copied().collect();
 
    comm.endpoint_manager.undelay_all();
 
    while !awaiting.is_empty() {
 
        log!(
 
            cu.logger,
 
            "Session gather loop. awaiting info from children {:?}...",
 
            awaiting.iter()
 
        );
 
        let (recv_index, msg) =
 
            comm.endpoint_manager.try_recv_any_setup(&mut *cu.logger, deadline)?;
 
        log!(cu.logger, "Received from index {:?} msg {:?}", &recv_index, &msg);
 
        match msg {
 
            S(Sm::SessionGather { unoptimized_map: child_unoptimized_map }) => {
 
                if !awaiting.remove(&recv_index) {
 
                    log!(
 
                        cu.logger,
 
                        "Wasn't expecting session info from {:?}. Got {:?}",
 
                        recv_index,
 
                        &child_unoptimized_map
 
                    );
 
                    return Err(Ce::SetupAlgMisbehavior);
 
                }
 
                unoptimized_map.extend(child_unoptimized_map.into_iter());
 
            }
 
            msg @ S(Sm::YouAreMyParent)
 
            | msg @ S(Sm::MyPortInfo(..))
 
            | msg @ S(Sm::LeaderAnnounce { .. })
 
            | msg @ S(Sm::LeaderWave { .. }) => {
 
                log!(cu.logger, "discarding old message {:?} during election", msg);
 
            }
 
            msg @ S(Sm::SessionScatter { .. }) => {
 
                log!(
 
                    cu.logger,
 
                    "Endpoint {:?} sent unexpected scatter! {:?} I've not contributed yet!",
 
                    recv_index,
 
                    &msg
 
                );
 
                return Err(Ce::SetupAlgMisbehavior);
 
            }
 
            msg @ Msg::CommMsg(..) => {
 
                log!(cu.logger, "delaying msg {:?} during session optimization", msg);
 
                comm.endpoint_manager.delayed_messages.push((recv_index, msg));
 
            }
 
        }
 
    }
 
    log!(
 
        cu.logger,
 
        "Gathered all children's maps. ConnectorId set is... {:?}",
 
        unoptimized_map.keys()
 
    );
 
    // add my own session info to the map
 
    let my_session_info = SessionInfo {
 
        port_info: cu.ips.port_info.clone(),
 
        proto_components: cu.proto_components.clone(),
 
        serde_proto_description: SerdeProtocolDescription(cu.proto_description.clone()),
 
        endpoint_incoming_to_getter: comm
 
            .endpoint_manager
 
            .net_endpoint_store
 
            .endpoint_exts
 
            .iter()
 
            .map(|ee| ee.getter_for_incoming)
 
            .collect(),
 
    };
 
    unoptimized_map.insert(cu.ips.id_manager.connector_id, my_session_info);
 
    log!(cu.logger, "Inserting my own info. Unoptimized subtree map is {:?}", &unoptimized_map);
 
    // acquire the optimized info...
 
    let optimized_map = if let Some(parent) = comm.neighborhood.parent {
 
        // ... as a message from my parent
 
        log!(cu.logger, "Forwarding gathered info to parent {:?}", parent);
 
        let msg = S(Sm::SessionGather { unoptimized_map });
 
        comm.endpoint_manager.send_to_setup(parent, &msg)?;
 
        'scatter_loop: loop {
 
            log!(
 
                cu.logger,
 
                "Session scatter recv loop. awaiting info from children {:?}...",
 
                awaiting.iter()
 
            );
 
            let (recv_index, msg) =
 
                comm.endpoint_manager.try_recv_any_setup(&mut *cu.logger, deadline)?;
 
            log!(cu.logger, "Received from index {:?} msg {:?}", &recv_index, &msg);
 
            match msg {
 
                S(Sm::SessionScatter { optimized_map }) => {
 
                    if recv_index != parent {
 
                        log!(cu.logger, "I expected the scatter from my parent only!");
 
                        return Err(Ce::SetupAlgMisbehavior);
 
                    }
 
                    break 'scatter_loop optimized_map;
 
                }
 
                msg @ Msg::CommMsg { .. } => {
 
                    log!(cu.logger, "delaying msg {:?} during scatter recv", msg);
 
                    comm.endpoint_manager.delayed_messages.push((recv_index, msg));
 
                }
 
                msg @ S(Sm::SessionGather { .. })
 
                | msg @ S(Sm::YouAreMyParent)
 
                | msg @ S(Sm::MyPortInfo(..))
 
                | msg @ S(Sm::LeaderAnnounce { .. })
 
                | msg @ S(Sm::LeaderWave { .. }) => {
 
                    log!(cu.logger, "discarding old message {:?} during election", msg);
 
                }
 
            }
 
        }
 
    } else {
 
        // by computing it myself
 
        log!(cu.logger, "I am the leader! I will optimize this session");
 
        leader_session_map_optimize(&mut *cu.logger, unoptimized_map)?
 
    };
 
    log!(
 
        cu.logger,
 
        "Optimized info map is {:?}. Sending to children {:?}",
 
        &optimized_map,
 
        comm.neighborhood.children.iter()
 
    );
 
    log!(cu.logger, "All session info dumped!: {:#?}", &optimized_map);
 
    // extract my own ConnectorId's entry
 
    let optimized_info =
 
        optimized_map.get(&cu.ips.id_manager.connector_id).expect("HEY NO INFO FOR ME?").clone();
 
    // broadcast the optimized session info to my children
 
    let msg = S(Sm::SessionScatter { optimized_map });
 
    for &child in comm.neighborhood.children.iter() {
 
        comm.endpoint_manager.send_to_setup(child, &msg)?;
 
    }
 
    // apply local optimizations
 
    apply_my_optimizations(cu, comm, optimized_info)?;
 
    log!(cu.logger, "Session optimizations applied");
 
    Ok(())
 
}
 

	
 
// Defines the optimization function, consuming an optimized map,
 
// and returning an optimized map.
 
fn leader_session_map_optimize(
 
    logger: &mut dyn Logger,
 
    m: HashMap<ConnectorId, SessionInfo>,
 
) -> Result<HashMap<ConnectorId, SessionInfo>, ConnectError> {
 
    log!(logger, "Session map optimize START");
 
    // currently, it's the identity function
 
    log!(logger, "Session map optimize END");
 
    Ok(m)
 
}
 

	
 
// Modify the given connector's internals to reflect
 
// the given session info
 
fn apply_my_optimizations(
 
    cu: &mut ConnectorUnphased,
 
    comm: &mut ConnectorCommunication,
 
    session_info: SessionInfo,
 
) -> Result<(), ConnectError> {
 
    let SessionInfo {
 
        proto_components,
 
        port_info,
 
        serde_proto_description,
 
        endpoint_incoming_to_getter,
 
    } = session_info;
 
    // simply overwrite the contents
 
    println!("BEFORE: {:#?}\n{:#?}", cu, comm);
 
    cu.ips.port_info = port_info;
 
    assert!(cu.ips.port_info.invariant_preserved());
 
    cu.proto_components = proto_components;
 
    cu.proto_description = serde_proto_description.0;
 
    for (ee, getter) in comm
 
        .endpoint_manager
 
        .net_endpoint_store
 
        .endpoint_exts
 
        .iter_mut()
 
        .zip(endpoint_incoming_to_getter)
 
    {
 
        ee.getter_for_incoming = getter;
 
    }
 
    // println!("AFTER: {:#?}\n{:#?}", cu, comm);
 
    Ok(())
 
}
0 comments (0 inline, 0 general)