Changeset - 6938bcacc41e
[Not reviewed]
0 10 0
MH - 4 years ago 2021-03-22 11:59:28
contact@maxhenger.nl
turn put stmt into call expr, make compiling great again
6 files changed:
0 comments (0 inline, 0 general)
src/protocol/ast.rs
Show inline comments
 
// TODO: @cleanup, rigorous cleanup of dead code and silly object-oriented
 
//  trait impls where I deem them unfit.
 

	
 
use std::fmt;
 
use std::fmt::{Debug, Display, Formatter};
 
use std::ops::{Index, IndexMut};
 

	
 
use super::arena::{Arena, Id};
 
// use super::containers::StringAllocator;
 

	
 
// TODO: @cleanup, transform wrapping types into type aliases where possible
 
use crate::protocol::inputsource::*;
 

	
 
/// Helper macro that defines a type alias for a AST element ID. In this case 
 
/// only used to alias the `Id<T>` types.
 
macro_rules! define_aliased_ast_id {
 
    // Variant where we just defined the alias, without any indexing
 
    ($name:ident, $parent:ty) => {
 
        pub type $name = $parent;
 
    };
 
    // Variant where we define the type, and the Index and IndexMut traits
 
    ($name:ident, $parent:ty, $indexed_type:ty, $indexed_arena:ident) => {
 
        define_aliased_ast_id!($name, $parent);
 
        impl Index<$name> for Heap {
 
            type Output = $indexed_type;
 
            fn index(&self, index: $name) -> &Self::Output {
 
                &self.$indexed_arena[index]
 
            }
 
        }
 

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

	
 
/// 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)]
 
        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, $indexed_type:ty, $wrapper_type:path, $indexed_arena:ident) => {
 
        define_new_ast_id!($name, $parent);
 
        impl Index<$name> for Heap {
 
            type Output = $indexed_type;
 
            fn index(&self, index: $name) -> &Self::Output {
 
                if let $wrapper_type(v) = &self.$indexed_arena[index.0] {
 
                    v
 
                } else {
 
                    unreachable!()
 
                }
 
            }
 
        }
 

	
 
        impl IndexMut<$name> for Heap {
 
            fn index_mut(&mut self, index: $name) -> &mut Self::Output {
 
                if let $wrapper_type(v) = &mut self.$indexed_arena[index.0] {
 
                    v
 
                } else {
 
                    unreachable!()
 
                }
 
            }
 
        }
 
    }
 
}
 

	
 
define_aliased_ast_id!(RootId, Id<Root>, Root, protocol_descriptions);
 
define_aliased_ast_id!(PragmaId, Id<Pragma>, Pragma, pragmas);
 
define_aliased_ast_id!(ImportId, Id<Import>, Import, imports);
 
define_aliased_ast_id!(ParserTypeId, Id<ParserType>, ParserType, parser_types);
 

	
 
define_aliased_ast_id!(VariableId, Id<Variable>, Variable, variables);
 
define_new_ast_id!(ParameterId, VariableId, Parameter, Variable::Parameter, variables);
 
define_new_ast_id!(LocalId, VariableId, Local, Variable::Local, variables);
 

	
 
define_aliased_ast_id!(DefinitionId, Id<Definition>, Definition, definitions);
 
define_new_ast_id!(StructId, DefinitionId, StructDefinition, Definition::Struct, definitions);
 
define_new_ast_id!(EnumId, DefinitionId, EnumDefinition, Definition::Enum, definitions);
 
define_new_ast_id!(ComponentId, DefinitionId, Component, Definition::Component, definitions);
 
define_new_ast_id!(FunctionId, DefinitionId, Function, Definition::Function, definitions);
 

	
 
define_aliased_ast_id!(StatementId, Id<Statement>, Statement, statements);
 
define_new_ast_id!(BlockStatementId, StatementId, BlockStatement, Statement::Block, statements);
 
define_new_ast_id!(LocalStatementId, StatementId, LocalStatement, Statement::Local, statements);
 
define_new_ast_id!(MemoryStatementId, LocalStatementId);
 
define_new_ast_id!(ChannelStatementId, LocalStatementId);
 
define_new_ast_id!(SkipStatementId, StatementId, SkipStatement, Statement::Skip, statements);
 
define_new_ast_id!(LabeledStatementId, StatementId, LabeledStatement, Statement::Labeled, statements);
 
define_new_ast_id!(IfStatementId, StatementId, IfStatement, Statement::If, statements);
 
define_new_ast_id!(EndIfStatementId, StatementId, EndIfStatement, Statement::EndIf, statements);
 
define_new_ast_id!(WhileStatementId, StatementId, WhileStatement, Statement::While, statements);
 
define_new_ast_id!(EndWhileStatementId, StatementId, EndWhileStatement, Statement::EndWhile, statements);
 
define_new_ast_id!(BreakStatementId, StatementId, BreakStatement, Statement::Break, statements);
 
define_new_ast_id!(ContinueStatementId, StatementId, ContinueStatement, Statement::Continue, statements);
 
define_new_ast_id!(SynchronousStatementId, StatementId, SynchronousStatement, Statement::Synchronous, statements);
 
define_new_ast_id!(EndSynchronousStatementId, StatementId, EndSynchronousStatement, Statement::EndSynchronous, statements);
 
define_new_ast_id!(ReturnStatementId, StatementId, ReturnStatement, Statement::Return, statements);
 
define_new_ast_id!(AssertStatementId, StatementId, AssertStatement, Statement::Assert, statements);
 
define_new_ast_id!(GotoStatementId, StatementId, GotoStatement, Statement::Goto, statements);
 
define_new_ast_id!(NewStatementId, StatementId, NewStatement, Statement::New, statements);
 
define_new_ast_id!(PutStatementId, StatementId, PutStatement, Statement::Put, statements);
 
define_new_ast_id!(ExpressionStatementId, StatementId, ExpressionStatement, Statement::Expression, statements);
 

	
 
define_aliased_ast_id!(ExpressionId, Id<Expression>, Expression, expressions);
 
define_new_ast_id!(AssignmentExpressionId, ExpressionId, AssignmentExpression, Expression::Assignment, expressions);
 
define_new_ast_id!(ConditionalExpressionId, ExpressionId, ConditionalExpression, Expression::Conditional, expressions);
 
define_new_ast_id!(BinaryExpressionId, ExpressionId, BinaryExpression, Expression::Binary, expressions);
 
define_new_ast_id!(UnaryExpressionId, ExpressionId, UnaryExpression, Expression::Unary, expressions);
 
define_new_ast_id!(IndexingExpressionId, ExpressionId, IndexingExpression, Expression::Indexing, expressions);
 
define_new_ast_id!(SlicingExpressionId, ExpressionId, SlicingExpression, Expression::Slicing, expressions);
 
define_new_ast_id!(SelectExpressionId, ExpressionId, SelectExpression, Expression::Select, expressions);
 
define_new_ast_id!(ArrayExpressionId, ExpressionId, ArrayExpression, Expression::Array, expressions);
 
define_new_ast_id!(ConstantExpressionId, ExpressionId, ConstantExpression, Expression::Constant, expressions);
 
define_new_ast_id!(CallExpressionId, ExpressionId, CallExpression, Expression::Call, expressions);
 
define_new_ast_id!(VariableExpressionId, ExpressionId, VariableExpression, Expression::Variable, expressions);
 

	
 
// TODO: @cleanup - pub qualifiers can be removed once done
 
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 
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>,
 
    pub(crate) expressions: Arena<Expression>,
 
}
 

	
 
impl Heap {
 
    pub fn new() -> Heap {
 
        Heap {
 
            // string_alloc: StringAllocator::new(),
 
            protocol_descriptions: Arena::new(),
 
            pragmas: Arena::new(),
 
            imports: Arena::new(),
 
            identifiers: Arena::new(),
 
            parser_types: Arena::new(),
 
            variables: Arena::new(),
 
            definitions: Arena::new(),
 
            statements: Arena::new(),
 
            expressions: Arena::new(),
 
        }
 
    }
 
    pub fn alloc_parser_type(
 
        &mut self,
 
        f: impl FnOnce(ParserTypeId) -> ParserType,
 
    ) -> ParserTypeId {
 
        self.parser_types.alloc_with_id(|id| f(id))
 
    }
 

	
 
    pub fn alloc_parameter(&mut self, f: impl FnOnce(ParameterId) -> Parameter) -> ParameterId {
 
        ParameterId(
 
            self.variables.alloc_with_id(|id| Variable::Parameter(f(ParameterId(id)))),
 
        )
 
    }
 
    pub fn alloc_local(&mut self, f: impl FnOnce(LocalId) -> Local) -> LocalId {
 
        LocalId(
 
            self.variables.alloc_with_id(|id| Variable::Local(f(LocalId(id)))),
 
        )
 
    }
 
    pub fn alloc_assignment_expression(
 
        &mut self,
 
        f: impl FnOnce(AssignmentExpressionId) -> AssignmentExpression,
 
    ) -> AssignmentExpressionId {
 
        AssignmentExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Assignment(f(AssignmentExpressionId(id)))
 
            })
 
        )
 
    }
 
    pub fn alloc_conditional_expression(
 
        &mut self,
 
        f: impl FnOnce(ConditionalExpressionId) -> ConditionalExpression,
 
    ) -> ConditionalExpressionId {
 
        ConditionalExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Conditional(f(ConditionalExpressionId(id)))
 
            })
 
        )
 
    }
 
    pub fn alloc_binary_expression(
 
        &mut self,
 
        f: impl FnOnce(BinaryExpressionId) -> BinaryExpression,
 
    ) -> BinaryExpressionId {
 
        BinaryExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Binary(f(BinaryExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_unary_expression(
 
        &mut self,
 
        f: impl FnOnce(UnaryExpressionId) -> UnaryExpression,
 
    ) -> UnaryExpressionId {
 
        UnaryExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Unary(f(UnaryExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_slicing_expression(
 
        &mut self,
 
        f: impl FnOnce(SlicingExpressionId) -> SlicingExpression,
 
    ) -> SlicingExpressionId {
 
        SlicingExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Slicing(f(SlicingExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_indexing_expression(
 
        &mut self,
 
        f: impl FnOnce(IndexingExpressionId) -> IndexingExpression,
 
    ) -> IndexingExpressionId {
 
        IndexingExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Indexing(f(IndexingExpressionId(id)))
 
            }),
 
        )
 
    }
 
    pub fn alloc_select_expression(
 
        &mut self,
 
        f: impl FnOnce(SelectExpressionId) -> SelectExpression,
 
    ) -> SelectExpressionId {
 
        SelectExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Select(f(SelectExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_array_expression(
 
        &mut self,
 
        f: impl FnOnce(ArrayExpressionId) -> ArrayExpression,
 
    ) -> ArrayExpressionId {
 
        ArrayExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Array(f(ArrayExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_constant_expression(
 
        &mut self,
 
        f: impl FnOnce(ConstantExpressionId) -> ConstantExpression,
 
    ) -> ConstantExpressionId {
 
        ConstantExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Constant(f(ConstantExpressionId(id)))
 
            }),
 
        )
 
    }
 
    pub fn alloc_call_expression(
 
        &mut self,
 
        f: impl FnOnce(CallExpressionId) -> CallExpression,
 
    ) -> CallExpressionId {
 
        CallExpressionId(
 
            self.expressions
 
                .alloc_with_id(|id| Expression::Call(f(CallExpressionId(id)))),
 
        )
 
    }
 
    pub fn alloc_variable_expression(
 
        &mut self,
 
        f: impl FnOnce(VariableExpressionId) -> VariableExpression,
 
    ) -> VariableExpressionId {
 
        VariableExpressionId(
 
            self.expressions.alloc_with_id(|id| {
 
                Expression::Variable(f(VariableExpressionId(id)))
 
            }),
 
        )
 
    }
 
    pub fn alloc_block_statement(
 
        &mut self,
 
        f: impl FnOnce(BlockStatementId) -> BlockStatement,
 
    ) -> BlockStatementId {
 
        BlockStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Block(f(BlockStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_memory_statement(
 
        &mut self,
 
        f: impl FnOnce(MemoryStatementId) -> MemoryStatement,
 
    ) -> MemoryStatementId {
 
        MemoryStatementId(LocalStatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Local(LocalStatement::Memory(
 
                f(MemoryStatementId(LocalStatementId(id)))
 
            ))
 
        })))
 
    }
 
    pub fn alloc_channel_statement(
 
        &mut self,
 
        f: impl FnOnce(ChannelStatementId) -> ChannelStatement,
 
    ) -> ChannelStatementId {
 
        ChannelStatementId(LocalStatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Local(LocalStatement::Channel(
 
                f(ChannelStatementId(LocalStatementId(id)))
 
            ))
 
        })))
 
    }
 
    pub fn alloc_skip_statement(
 
        &mut self,
 
        f: impl FnOnce(SkipStatementId) -> SkipStatement,
 
    ) -> SkipStatementId {
 
        SkipStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Skip(f(SkipStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_if_statement(
 
        &mut self,
 
        f: impl FnOnce(IfStatementId) -> IfStatement,
 
    ) -> IfStatementId {
 
        IfStatementId(
 
            self.statements.alloc_with_id(|id| Statement::If(f(IfStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_end_if_statement(
 
        &mut self,
 
        f: impl FnOnce(EndIfStatementId) -> EndIfStatement,
 
    ) -> EndIfStatementId {
 
        EndIfStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::EndIf(f(EndIfStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_while_statement(
 
        &mut self,
 
        f: impl FnOnce(WhileStatementId) -> WhileStatement,
 
    ) -> WhileStatementId {
 
        WhileStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::While(f(WhileStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_end_while_statement(
 
        &mut self,
 
        f: impl FnOnce(EndWhileStatementId) -> EndWhileStatement,
 
    ) -> EndWhileStatementId {
 
        EndWhileStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::EndWhile(f(EndWhileStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_break_statement(
 
        &mut self,
 
        f: impl FnOnce(BreakStatementId) -> BreakStatement,
 
    ) -> BreakStatementId {
 
        BreakStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Break(f(BreakStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_continue_statement(
 
        &mut self,
 
        f: impl FnOnce(ContinueStatementId) -> ContinueStatement,
 
    ) -> ContinueStatementId {
 
        ContinueStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Continue(f(ContinueStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_synchronous_statement(
 
        &mut self,
 
        f: impl FnOnce(SynchronousStatementId) -> SynchronousStatement,
 
    ) -> SynchronousStatementId {
 
        SynchronousStatementId(self.statements.alloc_with_id(|id| {
 
            Statement::Synchronous(f(SynchronousStatementId(id)))
 
        }))
 
    }
 
    pub fn alloc_end_synchronous_statement(
 
        &mut self,
 
        f: impl FnOnce(EndSynchronousStatementId) -> EndSynchronousStatement,
 
    ) -> EndSynchronousStatementId {
 
        EndSynchronousStatementId(self.statements.alloc_with_id(|id| {
 
            Statement::EndSynchronous(f(EndSynchronousStatementId(id)))
 
        }))
 
    }
 
    pub fn alloc_return_statement(
 
        &mut self,
 
        f: impl FnOnce(ReturnStatementId) -> ReturnStatement,
 
    ) -> ReturnStatementId {
 
        ReturnStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Return(f(ReturnStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_assert_statement(
 
        &mut self,
 
        f: impl FnOnce(AssertStatementId) -> AssertStatement,
 
    ) -> AssertStatementId {
 
        AssertStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Assert(f(AssertStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_goto_statement(
 
        &mut self,
 
        f: impl FnOnce(GotoStatementId) -> GotoStatement,
 
    ) -> GotoStatementId {
 
        GotoStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Goto(f(GotoStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_new_statement(
 
        &mut self,
 
        f: impl FnOnce(NewStatementId) -> NewStatement,
 
    ) -> NewStatementId {
 
        NewStatementId(
 
            self.statements.alloc_with_id(|id| Statement::New(f(NewStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_put_statement(
 
        &mut self,
 
        f: impl FnOnce(PutStatementId) -> PutStatement,
 
    ) -> PutStatementId {
 
        PutStatementId(
 
            self.statements.alloc_with_id(|id| Statement::Put(f(PutStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_labeled_statement(
 
        &mut self,
 
        f: impl FnOnce(LabeledStatementId) -> LabeledStatement,
 
    ) -> LabeledStatementId {
 
        LabeledStatementId(
 
            self.statements
 
                .alloc_with_id(|id| Statement::Labeled(f(LabeledStatementId(id)))),
 
        )
 
    }
 
    pub fn alloc_expression_statement(
 
        &mut self,
 
        f: impl FnOnce(ExpressionStatementId) -> ExpressionStatement,
 
    ) -> ExpressionStatementId {
 
        ExpressionStatementId(
 
            self.statements.alloc_with_id(|id| {
 
                Statement::Expression(f(ExpressionStatementId(id)))
 
            }),
 
        )
 
    }
 
    pub fn alloc_struct_definition(&mut self, f: impl FnOnce(StructId) -> StructDefinition) -> StructId {
 
        StructId(self.definitions.alloc_with_id(|id| {
 
            Definition::Struct(f(StructId(id)))
 
        }))
 
    }
 
    pub fn alloc_enum_definition(&mut self, f: impl FnOnce(EnumId) -> EnumDefinition) -> EnumId {
 
        EnumId(self.definitions.alloc_with_id(|id| {
 
            Definition::Enum(f(EnumId(id)))
 
        }))
 
    }
 
    pub fn alloc_component(&mut self, f: impl FnOnce(ComponentId) -> Component) -> ComponentId {
 
        ComponentId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(f(ComponentId(id)))
 
        }))
 
    }
 
    pub fn alloc_function(&mut self, f: impl FnOnce(FunctionId) -> Function) -> FunctionId {
 
        FunctionId(
 
            self.definitions
 
                .alloc_with_id(|id| Definition::Function(f(FunctionId(id)))),
 
        )
 
    }
 
    pub fn alloc_pragma(&mut self, f: impl FnOnce(PragmaId) -> Pragma) -> PragmaId {
 
        self.pragmas.alloc_with_id(|id| f(id))
 
    }
 
    pub fn alloc_import(&mut self, f: impl FnOnce(ImportId) -> Import) -> ImportId {
 
        self.imports.alloc_with_id(|id| f(id))
 
    }
 
    pub fn alloc_protocol_description(&mut self, f: impl FnOnce(RootId) -> Root) -> RootId {
 
        self.protocol_descriptions.alloc_with_id(|id| f(id))
 
    }
 
}
 

	
 
impl Index<MemoryStatementId> for Heap {
 
    type Output = MemoryStatement;
 
    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)]
 
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() {
 
            if h[def].identifier().value == id {
 
                return Some(def);
 
            }
 
        }
 
        None
 
    }
 
}
 

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

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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)]
 
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'")
 
        }
 
    }
 
    pub(crate) fn as_symbols(&self) -> &ImportSymbols {
 
        match self {
 
            Import::Symbols(m) => m,
 
            _ => panic!("Unable to cast 'Import' to 'ImportSymbols'")
 
        }
 
    }
 
}
 

	
 
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)]
 
pub struct ImportModule {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub module_name: Vec<u8>,
 
    pub alias: Vec<u8>,
 
    // Phase 2: module resolving
 
    pub module_id: Option<RootId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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>,
 
@@ -719,967 +710,959 @@ impl Display for Identifier {
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum ParserTypeVariant {
 
    // Basic builtin
 
    Message,
 
    Bool,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
    String,
 
    // Literals (need to get concrete builtin type during typechecking)
 
    IntegerLiteral,
 
    Inferred,
 
    // Complex builtins
 
    Array(ParserTypeId), // array of a type
 
    Input(ParserTypeId), // typed input endpoint of a channel
 
    Output(ParserTypeId), // typed output endpoint of a channel
 
    Symbolic(SymbolicParserType), // symbolic type (definition or polyarg)
 
}
 

	
 
impl ParserTypeVariant {
 
    pub(crate) fn supports_polymorphic_args(&self) -> bool {
 
        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)]
 
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)]
 
pub struct SymbolicParserType {
 
    // Phase 1: parser
 
    pub identifier: NamespacedIdentifier,
 
    /// The user-specified polymorphic arguments. Zero-length implies that the
 
    /// user did not specify any of them, and they're either not needed or all
 
    /// need to be inferred. Otherwise the number of polymorphic arguments must
 
    /// match those of the corresponding definition
 
    pub poly_args: Vec<ParserTypeId>,
 
    // Phase 2: validation/linking (for types in function/component bodies) and
 
    //  type table construction (for embedded types of structs/unions)
 
    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)]
 
pub enum SymbolicParserTypeVariant {
 
    Definition(DefinitionId),
 
    // TODO: figure out if I need the DefinitionId here
 
    PolyArg(DefinitionId, usize), // index of polyarg in the definition
 
}
 

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

	
 
// TODO: @cleanup, remove PartialEq implementations
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct PrimitiveSymbolic {
 
    // Phase 1: parser
 
    pub(crate) identifier: NamespacedIdentifier,
 
    // Phase 2: typing
 
    pub(crate) definition: Option<DefinitionId>
 
}
 

	
 
impl PartialEq for PrimitiveSymbolic {
 
    fn eq(&self, other: &Self) -> bool {
 
        self.identifier == other.identifier
 
    }
 
}
 
impl Eq for PrimitiveSymbolic{}
 

	
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
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.
 
                if let Some(id) = &data.definition {
 
                    write!(
 
                        f, "Symbolic({}, id: {})", 
 
                        String::from_utf8_lossy(&data.identifier.value),
 
                        id.index
 
                    )?;
 
                } else {
 
                    write!(
 
                        f, "Symbolic({}, id: Unresolved)",
 
                        String::from_utf8_lossy(&data.identifier.value)
 
                    )?;
 
                }
 
            }
 
        }
 
        if self.array {
 
            write!(f, "[]")
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

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

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

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

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

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

	
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
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,
 
        }
 
    }
 
    pub fn to_block(&self) -> BlockStatementId {
 
        match &self {
 
            Scope::Regular(id) => *id,
 
            Scope::Synchronous((_, id)) => *id,
 
            _ => panic!("unable to get BlockStatement from Scope")
 
        }
 
    }
 
}
 

	
 
pub trait VariableScope {
 
    fn parent_scope(&self, h: &Heap) -> Option<Scope>;
 
    fn get_variable(&self, h: &Heap, id: &Identifier) -> 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::Regular(stmt) => h[*stmt].parent_scope(h),
 
            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)]
 
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,
 
        }
 
    }
 
    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 as_local_mut(&mut self) -> &mut Local {
 
        match self {
 
            Variable::Local(result) => result,
 
            _ => panic!("Unable to cast 'Variable' to 'Local'"),
 
        }
 
    }
 
}
 

	
 
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)]
 
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)]
 
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)]
 
pub enum Definition {
 
    Struct(StructDefinition),
 
    Enum(EnumDefinition),
 
    Component(Component),
 
    Function(Function),
 
}
 

	
 
impl Definition {
 
    pub fn is_struct(&self) -> bool {
 
        match self {
 
            Definition::Struct(_) => true,
 
            _ => false
 
        }
 
    }
 
    pub fn as_struct(&self) -> &StructDefinition {
 
        match self {
 
            Definition::Struct(result) => result,
 
            _ => panic!("Unable to cast 'Definition' to 'StructDefinition'"),
 
        }
 
    }
 
    pub fn is_enum(&self) -> bool {
 
        match self {
 
            Definition::Enum(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_enum(&self) -> &EnumDefinition {
 
        match self {
 
            Definition::Enum(result) => result,
 
            _ => panic!("Unable to cast 'Definition' to 'EnumDefinition'"),
 
        }
 
    }
 
    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 is_function(&self) -> bool {
 
        match self {
 
            Definition::Function(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_function(&self) -> &Function {
 
        match self {
 
            Definition::Function(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Function`"),
 
        }
 
    }
 
    pub fn identifier(&self) -> &Identifier {
 
        match self {
 
            Definition::Struct(def) => &def.identifier,
 
            Definition::Enum(def) => &def.identifier,
 
            Definition::Component(com) => &com.identifier,
 
            Definition::Function(fun) => &fun.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        // TODO: Fix this
 
        static EMPTY_VEC: Vec<ParameterId> = Vec::new();
 
        match self {
 
            Definition::Component(com) => &com.parameters,
 
            Definition::Function(fun) => &fun.parameters,
 
            _ => &EMPTY_VEC,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        // TODO: Fix this
 
        match self {
 
            Definition::Component(com) => com.body,
 
            Definition::Function(fun) => fun.body,
 
            _ => panic!("cannot retrieve body (for EnumDefinition or StructDefinition)")
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Definition {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Definition::Struct(def) => def.position,
 
            Definition::Enum(def) => def.position,
 
            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: &Identifier) -> Option<VariableId> {
 
        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)]
 
pub struct StructFieldDefinition {
 
    pub position: InputPosition,
 
    pub field: Identifier,
 
    pub parser_type: ParserTypeId,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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, PartialEq)]
 
pub enum EnumVariantValue {
 
    None,
 
    Integer(i64),
 
    Type(ParserTypeId),
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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, Copy, serde::Serialize, serde::Deserialize)]
 
pub enum ComponentVariant {
 
    Primitive,
 
    Composite,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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)]
 
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)]
 
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_if_mut(&mut self) -> &mut 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(_) => todo!(),
 
            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::EndIf(stmt) => stmt.next = Some(next),
 
            Statement::EndWhile(stmt) => stmt.next = Some(next),
 
            Statement::EndSynchronous(stmt) => stmt.next = Some(next),
 
            Statement::Assert(stmt) => stmt.next = Some(next),
 
            Statement::New(stmt) => stmt.next = Some(next),
 
            Statement::Put(stmt) => stmt.next = Some(next),
 
            Statement::Expression(stmt) => stmt.next = Some(next),
 
            Statement::Return(_)
 
            | Statement::Break(_)
 
            | Statement::Continue(_)
 
            | Statement::Synchronous(_)
 
            | Statement::Goto(_)
 
            | Statement::While(_)
 
            | Statement::Labeled(_)
 
            | Statement::If(_) => unreachable!(),
 
        }
 
    }
 
}
 

	
 
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, serde::Serialize, serde::Deserialize)]
 
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>,
 
}
 

	
 
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::Regular(parent) => {
 
                // A variable scope is either a definition, sync, or block.
 
                Some(parent)
 
            }
 
        }
 
    }
 
    pub fn first(&self) -> StatementId {
 
        // It is an invariant (guaranteed by the lexer) that block statements have at least one stmt
 
        *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.clone()
 
    }
 
    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.value == id.value {
 
                return Some(local_id.0);
 
            }
 
        }
 
        None
 
    }
 
}
 

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

	
 
/// 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)]
 
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)]
 
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)]
 
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)]
 
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
 
@@ -1694,541 +1677,530 @@ impl SyntaxElement for IfStatement {
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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)]
 
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)]
 
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)]
 
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)]
 
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)]
 
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 {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
impl VariableScope for SynchronousStatement {
 
    fn parent_scope(&self, _h: &Heap) -> Option<Scope> {
 
        self.parent_scope.clone()
 
    }
 
    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)]
 
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)]
 
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)]
 
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)]
 
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)]
 
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)]
 
pub struct PutStatement {
 
    pub this: PutStatementId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub port: ExpressionId,
 
    pub message: ExpressionId,
 
    // Phase 2: linker
 
    pub next: Option<StatementId>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
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)]
 
pub enum ExpressionParent {
 
    None, // only set during initial parsing
 
    Memory(MemoryStatementId),
 
    If(IfStatementId),
 
    While(WhileStatementId),
 
    Return(ReturnStatementId),
 
    Assert(AssertStatementId),
 
    New(NewStatementId),
 
    Put(PutStatementId, u32), // index of arg
 
    ExpressionStmt(ExpressionStatementId),
 
    Expression(ExpressionId, u32) // index within expression (e.g LHS or RHS of expression)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Expression {
 
    Assignment(AssignmentExpression),
 
    Conditional(ConditionalExpression),
 
    Binary(BinaryExpression),
 
    Unary(UnaryExpression),
 
    Indexing(IndexingExpression),
 
    Slicing(SlicingExpression),
 
    Select(SelectExpression),
 
    Array(ArrayExpression),
 
    Constant(ConstantExpression),
 
    Call(CallExpression),
 
    Variable(VariableExpression),
 
}
 

	
 
impl Expression {
 
    pub fn as_assignment(&self) -> &AssignmentExpression {
 
        match self {
 
            Expression::Assignment(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `AssignmentExpression`"),
 
        }
 
    }
 
    pub fn as_conditional(&self) -> &ConditionalExpression {
 
        match self {
 
            Expression::Conditional(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `ConditionalExpression`"),
 
        }
 
    }
 
    pub fn as_binary(&self) -> &BinaryExpression {
 
        match self {
 
            Expression::Binary(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `BinaryExpression`"),
 
        }
 
    }
 
    pub fn as_unary(&self) -> &UnaryExpression {
 
        match self {
 
            Expression::Unary(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `UnaryExpression`"),
 
        }
 
    }
 
    pub fn as_indexing(&self) -> &IndexingExpression {
 
        match self {
 
            Expression::Indexing(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `IndexingExpression`"),
 
        }
 
    }
 
    pub fn as_slicing(&self) -> &SlicingExpression {
 
        match self {
 
            Expression::Slicing(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `SlicingExpression`"),
 
        }
 
    }
 
    pub fn as_select(&self) -> &SelectExpression {
 
        match self {
 
            Expression::Select(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `SelectExpression`"),
 
        }
 
    }
 
    pub fn as_array(&self) -> &ArrayExpression {
 
        match self {
 
            Expression::Array(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `ArrayExpression`"),
 
        }
 
    }
 
    pub fn as_constant(&self) -> &ConstantExpression {
 
        match self {
 
            Expression::Constant(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `ConstantExpression`"),
 
        }
 
    }
 
    pub fn as_call(&self) -> &CallExpression {
 
        match self {
 
            Expression::Call(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `CallExpression`"),
 
        }
 
    }
 
    pub fn as_call_mut(&mut self) -> &mut CallExpression {
 
        match self {
 
            Expression::Call(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `CallExpression`"),
 
        }
 
    }
 
    pub fn as_variable(&self) -> &VariableExpression {
 
        match self {
 
            Expression::Variable(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `VariableExpression`"),
 
        }
 
    }
 
    pub fn as_variable_mut(&mut self) -> &mut VariableExpression {
 
        match self {
 
            Expression::Variable(result) => result,
 
            _ => panic!("Unable to cast `Expression` to `VariableExpression`"),
 
        }
 
    }
 
    // TODO: @cleanup
 
    pub fn parent(&self) -> &ExpressionParent {
 
        match self {
 
            Expression::Assignment(expr) => &expr.parent,
 
            Expression::Conditional(expr) => &expr.parent,
 
            Expression::Binary(expr) => &expr.parent,
 
            Expression::Unary(expr) => &expr.parent,
 
            Expression::Indexing(expr) => &expr.parent,
 
            Expression::Slicing(expr) => &expr.parent,
 
            Expression::Select(expr) => &expr.parent,
 
            Expression::Array(expr) => &expr.parent,
 
            Expression::Constant(expr) => &expr.parent,
 
            Expression::Call(expr) => &expr.parent,
 
            Expression::Variable(expr) => &expr.parent,
 
        }
 
    }
 
    pub fn parent_expr_id(&self) -> Option<ExpressionId> {
 
        if let ExpressionParent::Expression(id, _) = self.parent() {
 
            Some(*id)
 
        } else {
 
            None
 
        }
 
    }
 
    pub fn set_parent(&mut self, parent: ExpressionParent) {
 
        match self {
 
            Expression::Assignment(expr) => expr.parent = parent,
 
            Expression::Conditional(expr) => expr.parent = parent,
 
            Expression::Binary(expr) => expr.parent = parent,
 
            Expression::Unary(expr) => expr.parent = parent,
 
            Expression::Indexing(expr) => expr.parent = parent,
 
            Expression::Slicing(expr) => expr.parent = parent,
 
            Expression::Select(expr) => expr.parent = parent,
 
            Expression::Array(expr) => expr.parent = parent,
 
            Expression::Constant(expr) => expr.parent = parent,
 
            Expression::Call(expr) => expr.parent = parent,
 
            Expression::Variable(expr) => expr.parent = parent,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Expression {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Expression::Assignment(expr) => expr.position(),
 
            Expression::Conditional(expr) => expr.position(),
 
            Expression::Binary(expr) => expr.position(),
 
            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::Constant(expr) => expr.position(),
 
            Expression::Call(expr) => expr.position(),
 
            Expression::Variable(expr) => expr.position(),
 
        }
 
    }
 
}
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
src/protocol/ast_printer.rs
Show inline comments
 
@@ -296,461 +296,451 @@ impl ASTWriter {
 
            },
 
            Definition::Component(def) => {
 
                self.kv(indent).with_id(PREFIX_COMPONENT_ID,def.this.0.index)
 
                    .with_s_key("DefinitionComponent");
 

	
 
                self.kv(indent2).with_s_key("Name").with_ascii_val(&def.identifier.value);
 
                self.kv(indent2).with_s_key("Variant").with_debug_val(&def.variant);
 

	
 
                self.kv(indent2).with_s_key("PolymorphicVariables");
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar");
 
                    self.kv(indent4).with_s_key("Name").with_ascii_val(&poly_var_id.value);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parameters");
 
                for param_id in &def.parameters {
 
                    self.write_parameter(heap, *param_id, indent3)
 
                }
 

	
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, def.body, indent3);
 
            }
 
        }
 
    }
 

	
 
    fn write_parameter(&mut self, heap: &Heap, param_id: ParameterId, indent: usize) {
 
        let indent2 = indent + 1;
 
        let param = &heap[param_id];
 

	
 
        self.kv(indent).with_id(PREFIX_PARAMETER_ID, param_id.0.index)
 
            .with_s_key("Parameter");
 
        self.kv(indent2).with_s_key("Name").with_ascii_val(&param.identifier.value);
 
        self.kv(indent2).with_s_key("Type").with_custom_val(|w| write_type(w, heap, &heap[param.parser_type]));
 
    }
 

	
 
    fn write_stmt(&mut self, heap: &Heap, stmt_id: StatementId, indent: usize) {
 
        let stmt = &heap[stmt_id];
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 

	
 
        match stmt {
 
            Statement::Block(stmt) => {
 
                self.kv(indent).with_id(PREFIX_BLOCK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Block");
 

	
 
                for stmt_id in &stmt.statements {
 
                    self.write_stmt(heap, *stmt_id, indent2);
 
                }
 
            },
 
            Statement::Local(stmt) => {
 
                match stmt {
 
                    LocalStatement::Channel(stmt) => {
 
                        self.kv(indent).with_id(PREFIX_CHANNEL_STMT_ID, stmt.this.0.0.index)
 
                            .with_s_key("LocalChannel");
 

	
 
                        self.kv(indent2).with_s_key("From");
 
                        self.write_local(heap, stmt.from, indent3);
 
                        self.kv(indent2).with_s_key("To");
 
                        self.write_local(heap, stmt.to, indent3);
 
                        self.kv(indent2).with_s_key("Next")
 
                            .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
                    },
 
                    LocalStatement::Memory(stmt) => {
 
                        self.kv(indent).with_id(PREFIX_MEM_STMT_ID, stmt.this.0.0.index)
 
                            .with_s_key("LocalMemory");
 

	
 
                        self.kv(indent2).with_s_key("Variable");
 
                        self.write_local(heap, stmt.variable, indent3);
 
                        self.kv(indent2).with_s_key("initial");
 
                        self.write_expr(heap, stmt.initial, indent3);
 
                        self.kv(indent2).with_s_key("Next")
 
                            .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
                    }
 
                }
 
            },
 
            Statement::Skip(stmt) => {
 
                self.kv(indent).with_id(PREFIX_SKIP_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Skip");
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Labeled(stmt) => {
 
                self.kv(indent).with_id(PREFIX_LABELED_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Labeled");
 

	
 
                self.kv(indent2).with_s_key("Label").with_ascii_val(&stmt.label.value);
 
                self.kv(indent2).with_s_key("Statement");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::If(stmt) => {
 
                self.kv(indent).with_id(PREFIX_IF_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("If");
 

	
 
                self.kv(indent2).with_s_key("EndIf")
 
                    .with_opt_disp_val(stmt.end_if.as_ref().map(|v| &v.0.index));
 

	
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, stmt.test, indent3);
 

	
 
                self.kv(indent2).with_s_key("TrueBody");
 
                self.write_stmt(heap, stmt.true_body, indent3);
 

	
 
                self.kv(indent2).with_s_key("FalseBody");
 
                self.write_stmt(heap, stmt.false_body, indent3);
 
            },
 
            Statement::EndIf(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDIF_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndIf");
 
                self.kv(indent2).with_s_key("StartIf").with_disp_val(&stmt.start_if.0.index);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::While(stmt) => {
 
                self.kv(indent).with_id(PREFIX_WHILE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("While");
 

	
 
                self.kv(indent2).with_s_key("EndWhile")
 
                    .with_opt_disp_val(stmt.end_while.as_ref().map(|v| &v.0.index));
 
                self.kv(indent2).with_s_key("InSync")
 
                    .with_opt_disp_val(stmt.in_sync.as_ref().map(|v| &v.0.index));
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, stmt.test, indent3);
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::EndWhile(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDWHILE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndWhile");
 
                self.kv(indent2).with_s_key("StartWhile").with_disp_val(&stmt.start_while.0.index);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Break(stmt) => {
 
                self.kv(indent).with_id(PREFIX_BREAK_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Break");
 
                self.kv(indent2).with_s_key("Label")
 
                    .with_opt_ascii_val(stmt.label.as_ref().map(|v| v.value.as_slice()));
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.index));
 
            },
 
            Statement::Continue(stmt) => {
 
                self.kv(indent).with_id(PREFIX_CONTINUE_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Continue");
 
                self.kv(indent2).with_s_key("Label")
 
                    .with_opt_ascii_val(stmt.label.as_ref().map(|v| v.value.as_slice()));
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.index));
 
            },
 
            Statement::Synchronous(stmt) => {
 
                self.kv(indent).with_id(PREFIX_SYNC_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Synchronous");
 
                self.kv(indent2).with_s_key("EndSync")
 
                    .with_opt_disp_val(stmt.end_sync.as_ref().map(|v| &v.0.index));
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, stmt.body, indent3);
 
            },
 
            Statement::EndSynchronous(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ENDSYNC_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("EndSynchronous");
 
                self.kv(indent2).with_s_key("StartSync").with_disp_val(&stmt.start_sync.0.index);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Return(stmt) => {
 
                self.kv(indent).with_id(PREFIX_RETURN_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Return");
 
                self.kv(indent2).with_s_key("Expression");
 
                self.write_expr(heap, stmt.expression, indent3);
 
            },
 
            Statement::Assert(stmt) => {
 
                self.kv(indent).with_id(PREFIX_ASSERT_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Assert");
 
                self.kv(indent2).with_s_key("Expression");
 
                self.write_expr(heap, stmt.expression, indent3);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Goto(stmt) => {
 
                self.kv(indent).with_id(PREFIX_GOTO_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Goto");
 
                self.kv(indent2).with_s_key("Label").with_ascii_val(&stmt.label.value);
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_opt_disp_val(stmt.target.as_ref().map(|v| &v.0.index));
 
            },
 
            Statement::New(stmt) => {
 
                self.kv(indent).with_id(PREFIX_NEW_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("New");
 
                self.kv(indent2).with_s_key("Expression");
 
                self.write_expr(heap, stmt.expression.upcast(), indent3);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Put(stmt) => {
 
                self.kv(indent).with_id(PREFIX_PUT_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("Put");
 
                self.kv(indent2).with_s_key("Port");
 
                self.write_expr(heap, stmt.port, indent3);
 
                self.kv(indent2).with_s_key("Message");
 
                self.write_expr(heap, stmt.message, indent3);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            },
 
            Statement::Expression(stmt) => {
 
                self.kv(indent).with_id(PREFIX_EXPR_STMT_ID, stmt.this.0.index)
 
                    .with_s_key("ExpressionStatement");
 
                self.write_expr(heap, stmt.expression, indent2);
 
                self.kv(indent2).with_s_key("Next")
 
                    .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index));
 
            }
 
        }
 
    }
 

	
 
    fn write_expr(&mut self, heap: &Heap, expr_id: ExpressionId, indent: usize) {
 
        let expr = &heap[expr_id];
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 

	
 
        match expr {
 
            Expression::Assignment(expr) => {
 
                self.kv(indent).with_id(PREFIX_ASSIGNMENT_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("AssignmentExpr");
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Left");
 
                self.write_expr(heap, expr.left, indent3);
 
                self.kv(indent2).with_s_key("Right");
 
                self.write_expr(heap, expr.right, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Conditional(expr) => {
 
                self.kv(indent).with_id(PREFIX_CONDITIONAL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("ConditionalExpr");
 
                self.kv(indent2).with_s_key("Condition");
 
                self.write_expr(heap, expr.test, indent3);
 
                self.kv(indent2).with_s_key("TrueExpression");
 
                self.write_expr(heap, expr.true_expression, indent3);
 
                self.kv(indent2).with_s_key("FalseExpression");
 
                self.write_expr(heap, expr.false_expression, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Binary(expr) => {
 
                self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("BinaryExpr");
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Left");
 
                self.write_expr(heap, expr.left, indent3);
 
                self.kv(indent2).with_s_key("Right");
 
                self.write_expr(heap, expr.right, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Unary(expr) => {
 
                self.kv(indent).with_id(PREFIX_UNARY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("UnaryExpr");
 
                self.kv(indent2).with_s_key("Operation").with_debug_val(&expr.operation);
 
                self.kv(indent2).with_s_key("Argument");
 
                self.write_expr(heap, expr.expression, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Indexing(expr) => {
 
                self.kv(indent).with_id(PREFIX_INDEXING_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("IndexingExpr");
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 
                self.kv(indent2).with_s_key("Index");
 
                self.write_expr(heap, expr.index, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Slicing(expr) => {
 
                self.kv(indent).with_id(PREFIX_SLICING_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("SlicingExpr");
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 
                self.kv(indent2).with_s_key("FromIndex");
 
                self.write_expr(heap, expr.from_index, indent3);
 
                self.kv(indent2).with_s_key("ToIndex");
 
                self.write_expr(heap, expr.to_index, indent3);
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Select(expr) => {
 
                self.kv(indent).with_id(PREFIX_SELECT_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("SelectExpr");
 
                self.kv(indent2).with_s_key("Subject");
 
                self.write_expr(heap, expr.subject, indent3);
 

	
 
                match &expr.field {
 
                    Field::Length => {
 
                        self.kv(indent2).with_s_key("Field").with_s_val("length");
 
                    },
 
                    Field::Symbolic(field) => {
 
                        self.kv(indent2).with_s_key("Field").with_ascii_val(&field.value);
 
                    }
 
                }
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Array(expr) => {
 
                self.kv(indent).with_id(PREFIX_ARRAY_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("ArrayExpr");
 
                self.kv(indent2).with_s_key("Elements");
 
                for expr_id in &expr.elements {
 
                    self.write_expr(heap, *expr_id, indent3);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Constant(expr) => {
 
                self.kv(indent).with_id(PREFIX_CONST_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("ConstantExpr");
 

	
 
                let val = self.kv(indent2).with_s_key("Value");
 
                match &expr.value {
 
                    Constant::Null => { val.with_s_val("null"); },
 
                    Constant::True => { val.with_s_val("true"); },
 
                    Constant::False => { val.with_s_val("false"); },
 
                    Constant::Character(char) => { val.with_ascii_val(char); },
 
                    Constant::Integer(int) => { val.with_disp_val(int); },
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Call(expr) => {
 
                self.kv(indent).with_id(PREFIX_CALL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("CallExpr");
 

	
 
                // Method
 
                let method = self.kv(indent2).with_s_key("Method");
 
                match &expr.method {
 
                    Method::Get => { method.with_s_val("get"); },
 
                    Method::Put => { method.with_s_val("put"); },
 
                    Method::Fires => { method.with_s_val("fires"); },
 
                    Method::Create => { method.with_s_val("create"); },
 
                    Method::Symbolic(symbolic) => {
 
                        method.with_s_val("symbolic");
 
                        self.kv(indent3).with_s_key("Name").with_ascii_val(&symbolic.identifier.value);
 
                        self.kv(indent3).with_s_key("Definition")
 
                            .with_opt_disp_val(symbolic.definition.as_ref().map(|v| &v.index));
 
                    }
 
                }
 

	
 
                // Arguments
 
                self.kv(indent2).with_s_key("Arguments");
 
                for arg_id in &expr.arguments {
 
                    self.write_expr(heap, *arg_id, indent3);
 
                }
 

	
 
                // Parent
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Variable(expr) => {
 
                self.kv(indent).with_id(PREFIX_VARIABLE_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("VariableExpr");
 
                self.kv(indent2).with_s_key("Name").with_ascii_val(&expr.identifier.value);
 
                self.kv(indent2).with_s_key("Definition")
 
                    .with_opt_disp_val(expr.declaration.as_ref().map(|v| &v.index));
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            }
 
        }
 
    }
 

	
 
    fn write_local(&mut self, heap: &Heap, local_id: LocalId, indent: usize) {
 
        let local = &heap[local_id];
 
        let indent2 = indent + 1;
 

	
 
        self.kv(indent).with_id(PREFIX_LOCAL_ID, local_id.0.index)
 
            .with_s_key("Local");
 

	
 
        self.kv(indent2).with_s_key("Name").with_ascii_val(&local.identifier.value);
 
        self.kv(indent2).with_s_key("Type")
 
            .with_custom_val(|w| write_type(w, heap, &heap[local.parser_type]));
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Printing Utilities
 
    //--------------------------------------------------------------------------
 

	
 
    fn kv(&mut self, indent: usize) -> KV {
 
        KV::new(&mut self.buffer, &mut self.temp1, &mut self.temp2, indent)
 
    }
 

	
 
    fn flush<W: IOWrite>(&mut self, w: &mut W) {
 
        w.write(self.buffer.as_bytes()).unwrap();
 
        self.buffer.clear()
 
    }
 
}
 

	
 
fn write_option<V: Display>(target: &mut String, value: Option<V>) {
 
    target.clear();
 
    match &value {
 
        Some(v) => write!(target, "Some({})", v),
 
        None => target.write_str("None")
 
    };
 
}
 

	
 
fn write_type(target: &mut String, heap: &Heap, t: &ParserType) {
 
    use ParserTypeVariant as PTV;
 

	
 
    let mut embedded = Vec::new();
 
    match &t.variant {
 
        PTV::Input(id) => { target.write_str("in"); embedded.push(*id); }
 
        PTV::Output(id) => { target.write_str("out"); embedded.push(*id) }
 
        PTV::Array(id) => { target.write_str("array"); embedded.push(*id) }
 
        PTV::Message => { target.write_str("msg"); }
 
        PTV::Bool => { target.write_str("bool"); }
 
        PTV::Byte => { target.write_str("byte"); }
 
        PTV::Short => { target.write_str("short"); }
 
        PTV::Int => { target.write_str("int"); }
 
        PTV::Long => { target.write_str("long"); }
 
        PTV::String => { target.write_str("str"); }
 
        PTV::IntegerLiteral => { target.write_str("int_lit"); }
 
        PTV::Inferred => { target.write_str("auto"); }
 
        PTV::Symbolic(symbolic) => {
 
            target.write_str(&String::from_utf8_lossy(&symbolic.identifier.value));
 
            match symbolic.variant {
 
                Some(SymbolicParserTypeVariant::PolyArg(def_id, idx)) => {
 
                    target.write_str(&format!("{{def: {}, idx: {}}}", def_id.index, idx));
 
                },
 
                Some(SymbolicParserTypeVariant::Definition(def_id)) => {
 
                    target.write_str(&format!("{{def: {}}}", def_id.index));
 
                },
 
                None => {
 
                    target.write_str("{None}");
 
                }
 
            }
 
            embedded.extend(&symbolic.poly_args);
 
        }
 
    };
 

	
 
    if !embedded.is_empty() {
 
        target.write_str("<");
 
        for (idx, embedded_id) in embedded.into_iter().enumerate() {
 
            if idx != 0 { target.write_str(", "); }
 
            write_type(target, heap, &heap[embedded_id]);
 
        }
 
        target.write_str(">");
 
    }
 
}
 

	
 
fn write_expression_parent(target: &mut String, parent: &ExpressionParent) {
 
    use ExpressionParent as EP;
 

	
 
    *target = match parent {
 
        EP::None => String::from("None"),
 
        EP::Memory(id) => format!("MemoryStmt({})", id.0.0.index),
 
        EP::If(id) => format!("IfStmt({})", id.0.index),
 
        EP::While(id) => format!("WhileStmt({})", id.0.index),
 
        EP::Return(id) => format!("ReturnStmt({})", id.0.index),
 
        EP::Assert(id) => format!("AssertStmt({})", id.0.index),
 
        EP::New(id) => format!("NewStmt({})", id.0.index),
 
        EP::Put(id, idx) => format!("PutStmt({}, {})", id.0.index, idx),
 
        EP::ExpressionStmt(id) => format!("ExprStmt({})", id.0.index),
 
        EP::Expression(id, idx) => format!("Expr({}, {})", id.index, idx)
 
    };
 
}
 
\ No newline at end of file
src/protocol/eval.rs
Show inline comments
 
@@ -1310,467 +1310,469 @@ impl Store {
 
    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,
 
        };
 
        assert!(value.is_type_compatible(h, &h[parser_type]));
 
        // Overwrite mapping
 
        self.map.insert(var, value.clone());
 
    }
 
    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 parser_type_id = match &h[var] {
 
                    Variable::Local(v) => v.parser_type,
 
                    Variable::Parameter(v) => v.parser_type
 
                };
 
                let parser_type = &h[parser_type_id];
 
                assert!(value.is_type_compatible(h, parser_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),
 
                }
 
            }
 
            _ => unimplemented!("{:?}", h[lexpr]),
 
        }
 
    }
 
    fn get(&mut self, h: &Heap, ctx: &mut EvalContext, rexpr: ExpressionId) -> EvalResult {
 
        match &h[rexpr] {
 
            Expression::Variable(var) => {
 
                let var_id = var.declaration.unwrap();
 
                let value = self
 
                    .map
 
                    .get(&var_id)
 
                    .expect(&format!("Uninitialized variable {:?}", String::from_utf8_lossy(&var.identifier.value)));
 
                Ok(value.clone())
 
            }
 
            Expression::Indexing(indexing) => {
 
                // Evaluate index expression, which must be some integral type
 
                let index = self.eval(h, ctx, indexing.index)?;
 
                // Reference to subject
 
                let subject;
 
                match &h[indexing.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get(&var).unwrap();
 
                    }
 
                    q => unreachable!("Reached {:?}", q),
 
                }
 
                match subject.get(&index) {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            Expression::Select(selecting) => {
 
                // Reference to subject
 
                let subject;
 
                match &h[selecting.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get(&var).unwrap();
 
                    }
 
                    q => unreachable!("Reached {:?}", q),
 
                }
 
                match subject.length() {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            _ => 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, ctx, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.plus(&value))?;
 
                    }
 
                    AssignmentOperator::Subtracted => {
 
                        let old = self.get(h, ctx, 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;
 
                match expr.operation {
 
                    BinaryOperator::LogicalAnd => {
 
                        if left.as_boolean().0 == false {
 
                            return Ok(left);
 
                        }
 
                        right = self.eval(h, ctx, expr.right)?;
 
                        right.as_boolean(); // panics if not a boolean
 
                        return Ok(right);
 
                    }
 
                    BinaryOperator::LogicalOr => {
 
                        if left.as_boolean().0 == true {
 
                            return Ok(left);
 
                        }
 
                        right = self.eval(h, ctx, expr.right)?;
 
                        right.as_boolean(); // panics if not a boolean
 
                        return Ok(right);
 
                    }
 
                    _ => {}
 
                }
 
                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)),
 
                    BinaryOperator::Add => Ok(left.plus(&right)),
 
                    _ => unimplemented!("{:?}", expr.operation),
 
                }
 
            }
 
            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, ctx, expr.this.upcast()),
 
            Expression::Slicing(_expr) => unimplemented!(),
 
            Expression::Select(expr) => self.get(h, ctx, expr.this.upcast()),
 
            Expression::Array(expr) => {
 
                let mut elements = Vec::new();
 
                for &elem in expr.elements.iter() {
 
                    elements.push(self.eval(h, ctx, elem)?);
 
                }
 
                todo!()
 
            }
 
            Expression::Constant(expr) => Ok(Value::from_constant(&expr.value)),
 
            Expression::Call(expr) => match &expr.method {
 
                Method::Create => {
 
                Method::Get => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let length = self.eval(h, ctx, expr.arguments[0])?;
 
                    Ok(Value::create_message(length))
 
                    let value = self.eval(h, ctx, expr.arguments[0])?;
 
                    match ctx.get(value.clone()) {
 
                        None => Err(EvalContinuation::BlockGet(value)),
 
                        Some(result) => Ok(result),
 
                    }
 
                }
 
                Method::Put => {
 
                    assert_eq!(2, expr.arguments.len());
 
                    let port_value = self.eval(h, ctx, expr.arguments[0])?;
 
                    let msg_value = self.eval(h, ctx, expr.arguments[1])?;
 
                    if ctx.did_put(port_value.clone()) {
 
                        // Return bogus, replacing this at some point anyway
 
                        Ok(Value::Message(MessageValue(None)))
 
                    } else {
 
                        Err(EvalContinuation::Put(port_value, msg_value))
 
                    }
 
                }
 
                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 => {
 
                Method::Create => {
 
                    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),
 
                    }
 
                    let length = self.eval(h, ctx, expr.arguments[0])?;
 
                    Ok(Value::create_message(length))
 
                }
 
                Method::Symbolic(_symbol) => unimplemented!(),
 
            },
 
            Expression::Variable(expr) => self.get(h, ctx, expr.this.upcast()),
 
        }
 
    }
 
}
 

	
 
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)]
 
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
 
    }
 
    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 parser_type = &h[hparam.parser_type];
 
            assert!(value.is_type_compatible(h, parser_type));
 
            self.store.initialize(h, param.upcast(), value.clone());
 
        }
 
    }
 
    pub fn step(&mut self, h: &Heap, ctx: &mut EvalContext) -> EvalResult {
 
        if self.position.is_none() {
 
            return Err(EvalContinuation::Terminal);
 
        }
 

	
 
        let stmt = &h[self.position.unwrap()];
 
        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) => {
 
                        let [from, to] = ctx.new_channel();
 
                        // Store the values in the declared variables
 
                        self.store.initialize(h, stmt.from.upcast(), from);
 
                        self.store.initialize(h, stmt.to.upcast(), to);
 
                    }
 
                }
 
                // 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.end_while.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::Break(stmt) => {
 
                // Continue to end of while
 
                self.position = stmt.target.map(EndWhileStatementId::upcast);
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Continue(stmt) => {
 
                // Continue to beginning of while
 
                self.position = stmt.target.map(WhileStatementId::upcast);
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Assert(stmt) => {
 
                // Evaluate expression
 
                let value = self.store.eval(h, ctx, stmt.expression)?;
 
                if value.as_boolean().0 {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                } else {
 
                    // Assertion failed: inconsistent
 
                    Err(EvalContinuation::Inconsistent)
 
                }
 
            }
 
            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) => {
 
                let expr = &h[stmt.expression];
 
                let mut args = Vec::new();
 
                for &arg in expr.arguments.iter() {
 
                    let value = self.store.eval(h, ctx, arg)?;
 
                    args.push(value);
 
                }
 
                self.position = stmt.next;
 
                match &expr.method {
 
                    Method::Symbolic(symbolic) => {
 
                         Err(EvalContinuation::NewComponent(symbolic.definition.unwrap(), args))
 
                    },
 
                    _ => unreachable!("not a symbolic call expression")
 
                }
 
            }
 
            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)
 
            }
 
        }
 
    }
 
    // 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(_, _) => unreachable!(),
 
    //             EvalContinuation::BlockFires(val) => unreachable!(),
 
    //             EvalContinuation::BlockGet(val) => 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 def = heap[pd].get_definition_ident(&heap, b"test").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
 
@@ -1225,885 +1225,870 @@ impl Lexer<'_> {
 
                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,
 
                        parent: ExpressionParent::None,
 
                    })
 
                    .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,
 
                        parent: ExpressionParent::None,
 
                    })
 
                    .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,
 
                            parent: ExpressionParent::None,
 
                        })
 
                        .upcast();
 
                } else {
 
                    result = h
 
                        .alloc_indexing_expression(|this| IndexingExpression {
 
                            this,
 
                            position,
 
                            subject,
 
                            index,
 
                            parent: ExpressionParent::None,
 
                        })
 
                        .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()?);
 
                }
 
                result = h
 
                    .alloc_select_expression(|this| SelectExpression {
 
                        this,
 
                        position,
 
                        subject,
 
                        field,
 
                        parent: ExpressionParent::None,
 
                    })
 
                    .upcast();
 
            }
 
        }
 
        Ok(result)
 
    }
 
    fn consume_primary_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError2> {
 
        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, ParseError2> {
 
        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,
 
            parent: ExpressionParent::None,
 
        }))
 
    }
 
    fn has_constant(&self) -> bool {
 
        is_constant(self.source.next())
 
    }
 
    fn consume_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ConstantExpressionId, ParseError2> {
 
        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.is_empty() {
 
                return Err(self.error_at_pos("Expected character constant"));
 
            }
 
            self.source.consume();
 
            value = Constant::Character(data);
 
        } else {
 
            if !self.has_integer() {
 
                return Err(self.error_at_pos("Expected integer constant"));
 
            }
 

	
 
            value = Constant::Integer(self.consume_integer()?);
 
        }
 
        Ok(h.alloc_constant_expression(|this| ConstantExpression {
 
            this,
 
            position,
 
            value,
 
            parent: ExpressionParent::None,
 
        }))
 
    }
 
    fn has_call_expression(&mut self) -> bool {
 
        // We need to prevent ambiguity with various operators (because we may
 
        // be specifying polymorphic variables) and variables.
 
        if self.has_builtin_keyword() {
 
            return true;
 
        }
 

	
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 

	
 
        if self.consume_namespaced_identifier_spilled().is_ok() &&
 
            self.consume_whitespace(false).is_ok() &&
 
            self.maybe_consume_poly_args_spilled_without_pos_recovery().is_ok() &&
 
            self.maybe_consume_poly_args_spilled_without_pos_recovery() &&
 
            self.consume_whitespace(false).is_ok() &&
 
            self.source.next() == Some(b'(') {
 
            // Seems like we have a function call or an enum literal
 
            result = true;
 
        }
 

	
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_call_expression(&mut self, h: &mut Heap) -> Result<CallExpressionId, ParseError2> {
 
        let position = self.source.pos();
 

	
 
        // Consume method identifier
 
        let method;
 
        if self.has_keyword(b"get") {
 
            self.consume_keyword(b"get")?;
 
            method = Method::Get;
 
        } else if self.has_keyword(b"put") {
 
            self.consume_keyword(b"put")?;
 
            method = Method::Put;
 
        } 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_namespaced_identifier()?;
 
            method = Method::Symbolic(MethodSymbolic{
 
                identifier,
 
                definition: None
 
            })
 
        }
 

	
 
        // Consume polymorphic arguments
 
        self.consume_whitespace(false)?;
 
        let poly_args = self.consume_polymorphic_args(h, true)?;
 

	
 
        // Consume arguments to call
 
        self.consume_whitespace(false)?;
 
        let mut arguments = Vec::new();
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b")") {
 
            // TODO: allow trailing comma
 
            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,
 
            poly_args,
 
            parent: ExpressionParent::None,
 
        }))
 
    }
 
    fn consume_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<VariableExpressionId, ParseError2> {
 
        let position = self.source.pos();
 
        let identifier = self.consume_namespaced_identifier()?;
 
        Ok(h.alloc_variable_expression(|this| VariableExpression {
 
            this,
 
            position,
 
            identifier,
 
            declaration: None,
 
            parent: ExpressionParent::None,
 
        }))
 
    }
 

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

	
 
    /// Consumes any kind of statement from the source and will error if it
 
    /// did not encounter a statement. Will also return an error if the
 
    /// statement is nested too deeply.
 
    ///
 
    /// `wrap_in_block` may be set to true to ensure that the parsed statement
 
    /// will be wrapped in a block statement if it is not already a block
 
    /// statement. This is used to ensure that all `if`, `while` and `sync`
 
    /// statements have a block statement as body.
 
    fn consume_statement(&mut self, h: &mut Heap, wrap_in_block: bool) -> Result<StatementId, ParseError2> {
 
        if self.level >= MAX_LEVEL {
 
            return Err(self.error_at_pos("Too deeply nested statement"));
 
        }
 
        self.level += 1;
 
        let result = self.consume_statement_impl(h, wrap_in_block);
 
        self.level -= 1;
 
        result
 
    }
 
    fn has_label(&mut self) -> bool {
 
        // To prevent ambiguity with expression statements consisting only of an
 
        // identifier or a namespaced identifier, we look ahead and match on the
 
        // *single* colon that signals a labeled statement.
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        if self.consume_identifier_spilled().is_ok() {
 
            // next character is ':', second character is NOT ':'
 
            result = Some(b':') == self.source.next() && Some(b':') != self.source.lookahead(1)
 
        }
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_statement_impl(&mut self, h: &mut Heap, wrap_in_block: bool) -> Result<StatementId, ParseError2> {
 
        // Parse and allocate statement
 
        let mut must_wrap = true;
 
        let mut stmt_id = if self.has_string(b"{") {
 
            must_wrap = false;
 
            self.consume_block_statement(h)?
 
        } else if self.has_keyword(b"skip") {
 
            must_wrap = false;
 
            self.consume_skip_statement(h)?.upcast()
 
        } else if self.has_keyword(b"if") {
 
            self.consume_if_statement(h)?.upcast()
 
        } else if self.has_keyword(b"while") {
 
            self.consume_while_statement(h)?.upcast()
 
        } else if self.has_keyword(b"break") {
 
            self.consume_break_statement(h)?.upcast()
 
        } else if self.has_keyword(b"continue") {
 
            self.consume_continue_statement(h)?.upcast()
 
        } else if self.has_keyword(b"synchronous") {
 
            self.consume_synchronous_statement(h)?.upcast()
 
        } else if self.has_keyword(b"return") {
 
            self.consume_return_statement(h)?.upcast()
 
        } else if self.has_keyword(b"assert") {
 
            self.consume_assert_statement(h)?.upcast()
 
        } else if self.has_keyword(b"goto") {
 
            self.consume_goto_statement(h)?.upcast()
 
        } else if self.has_keyword(b"new") {
 
            self.consume_new_statement(h)?.upcast()
 
        } else if self.has_keyword(b"put") {
 
            self.consume_put_statement(h)?.upcast()
 
        } else if self.has_label() {
 
            self.consume_labeled_statement(h)?.upcast()
 
        } else {
 
            self.consume_expression_statement(h)?.upcast()
 
        };
 

	
 
        // Wrap if desired and if needed
 
        if must_wrap && wrap_in_block {
 
            let position = h[stmt_id].position();
 
            let block_wrapper = h.alloc_block_statement(|this| BlockStatement{
 
                this,
 
                position,
 
                statements: vec![stmt_id],
 
                parent_scope: None,
 
                relative_pos_in_parent: 0,
 
                locals: Vec::new(),
 
                labels: Vec::new()
 
            });
 

	
 
            stmt_id = block_wrapper.upcast();
 
        }
 

	
 
        Ok(stmt_id)
 
    }
 
    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_pos = self.source.pos();
 
        let mut result = false;
 
        if self.maybe_consume_type_spilled_without_pos_recovery() {
 
            // We seem to have a valid type, do we now have an identifier?
 
            if self.consume_whitespace(true).is_ok() {
 
                result = self.has_identifier();
 
            }
 
        }
 

	
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_block_statement(&mut self, h: &mut Heap) -> Result<StatementId, ParseError2> {
 
        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, false)?);
 
            self.consume_whitespace(false)?;
 
        }
 
        self.consume_string(b"}")?;
 
        if statements.is_empty() {
 
            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,
 
                relative_pos_in_parent: 0,
 
                locals: Vec::new(),
 
                labels: Vec::new(),
 
            })
 
            .upcast())
 
        }
 
    }
 
    fn consume_local_statement(&mut self, h: &mut Heap) -> Result<LocalStatementId, ParseError2> {
 
        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, ParseError2> {
 
        // Consume channel statement and polymorphic argument if specified
 
        let position = self.source.pos();
 
        self.consume_keyword(b"channel")?;
 

	
 
        let poly_args = self.consume_polymorphic_args(h, true)?;
 
        let poly_arg_id = match poly_args.len() {
 
            0 => h.alloc_parser_type(|this| ParserType{
 
                this, pos: position.clone(), variant: ParserTypeVariant::Inferred,
 
            }),
 
            1 => poly_args[0],
 
            _ => return Err(ParseError2::new_error(
 
                &self.source, self.source.pos(),
 
                "port construction using 'channel' accepts up to 1 polymorphic argument"
 
            ))
 
        };
 
        self.consume_whitespace(true)?;
 

	
 
        // Consume the output port
 
        let out_parser_type = h.alloc_parser_type(|this| ParserType{
 
            this, pos: position.clone(), variant: ParserTypeVariant::Output(poly_arg_id)
 
        });
 
        let out_identifier = self.consume_identifier()?;
 

	
 
        // Consume the "->" syntax
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"->")?;
 
        self.consume_whitespace(false)?;
 

	
 
        // Consume the input port
 
        // TODO: Unsure about this, both ports refer to the same ParserType, is this ok?
 
        let in_parser_type = h.alloc_parser_type(|this| ParserType{
 
            this, pos: position.clone(), variant: ParserTypeVariant::Input(poly_arg_id)
 
        });
 
        let in_identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        let out_port = h.alloc_local(|this| Local {
 
            this,
 
            position,
 
            parser_type: out_parser_type,
 
            identifier: out_identifier,
 
            relative_pos_in_block: 0
 
        });
 
        let in_port = h.alloc_local(|this| Local {
 
            this,
 
            position,
 
            parser_type: in_parser_type,
 
            identifier: in_identifier,
 
            relative_pos_in_block: 0
 
        });
 
        Ok(h.alloc_channel_statement(|this| ChannelStatement {
 
            this,
 
            position,
 
            from: out_port,
 
            to: in_port,
 
            relative_pos_in_block: 0,
 
            next: None,
 
        }))
 
    }
 
    fn consume_memory_statement(&mut self, h: &mut Heap) -> Result<MemoryStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        let parser_type = self.consume_type2(h, true)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier()?;
 
        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,
 
            parser_type,
 
            identifier,
 
            relative_pos_in_block: 0
 
        });
 
        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, ParseError2> {
 
        let position = self.source.pos();
 
        let label = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b":")?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_statement(h, false)?;
 
        Ok(h.alloc_labeled_statement(|this| LabeledStatement {
 
            this,
 
            position,
 
            label,
 
            body,
 
            relative_pos_in_block: 0,
 
            in_sync: None,
 
        }))
 
    }
 
    fn consume_skip_statement(&mut self, h: &mut Heap) -> Result<SkipStatementId, ParseError2> {
 
        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, ParseError2> {
 
        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, true)?;
 
        self.consume_whitespace(false)?;
 
        let false_body = if self.has_keyword(b"else") {
 
            self.consume_keyword(b"else")?;
 
            self.consume_whitespace(false)?;
 
            self.consume_statement(h, true)?
 
        } else {
 
            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, end_if: None }))
 
    }
 
    fn consume_while_statement(&mut self, h: &mut Heap) -> Result<WhileStatementId, ParseError2> {
 
        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, true)?;
 
        Ok(h.alloc_while_statement(|this| WhileStatement {
 
            this,
 
            position,
 
            test,
 
            body,
 
            end_while: None,
 
            in_sync: None,
 
        }))
 
    }
 
    fn consume_break_statement(&mut self, h: &mut Heap) -> Result<BreakStatementId, ParseError2> {
 
        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()?);
 
            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, ParseError2> {
 
        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()?);
 
            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, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"synchronous")?;
 
        self.consume_whitespace(false)?;
 
        // TODO: What was the purpose of this? Seems superfluous and confusing?
 
        // 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.error_at_pos("Expected block statement"));
 
        // }
 
        let body = self.consume_statement(h, true)?;
 
        Ok(h.alloc_synchronous_statement(|this| SynchronousStatement {
 
            this,
 
            position,
 
            body,
 
            end_sync: None,
 
            parent_scope: None,
 
        }))
 
    }
 
    fn consume_return_statement(&mut self, h: &mut Heap) -> Result<ReturnStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"return")?;
 
        self.consume_whitespace(false)?;
 
        let expression = if self.has_string(b"(") {
 
            self.consume_paren_expression(h)
 
        } else {
 
            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, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"assert")?;
 
        self.consume_whitespace(false)?;
 
        let expression = if self.has_string(b"(") {
 
            self.consume_paren_expression(h)
 
        } else {
 
            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, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"goto")?;
 
        self.consume_whitespace(false)?;
 
        let label = self.consume_identifier()?;
 
        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, ParseError2> {
 
        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, ParseError2> {
 
        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, ParseError2> {
 
        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, ParseError2> {
 
        if self.has_keyword(b"struct") {
 
            Ok(self.consume_struct_definition(h)?.upcast())
 
        } else if self.has_keyword(b"enum") {
 
            Ok(self.consume_enum_definition(h)?.upcast())
 
        } else 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_struct_definition(&mut self, h: &mut Heap) -> Result<StructId, ParseError2> {
 
        // Parse "struct" keyword, optional polyvars and its identifier
 
        let struct_pos = self.source.pos();
 
        self.consume_keyword(b"struct")?;
 
        self.consume_whitespace(true)?;
 
        let struct_ident = self.consume_identifier()?;
 
        let poly_vars = self.consume_polymorphic_vars()?;
 
        self.consume_whitespace(false)?;
 

	
 
        // Parse struct fields
 
        self.consume_string(b"{")?;
 
        let mut next = self.source.next();
 
        let mut fields = Vec::new();
 
        while next.is_some() {
 
            let char = next.unwrap();
 
            if char == b'}' {
 
                break;
 
            }
 

	
 
            // Consume field definition
 
            self.consume_whitespace(false)?;
 
            let field_position = self.source.pos();
 
            let field_parser_type = self.consume_type2(h, false)?;
 
            self.consume_whitespace(true)?;
 
            let field_ident = self.consume_identifier()?;
 
            self.consume_whitespace(false)?;
 

	
 
            fields.push(StructFieldDefinition{
 
                position: field_position,
 
                field: field_ident,
 
                parser_type: field_parser_type,
 
            });
 

	
 
            // If we have a comma, then we may or may not have another field
 
            // definition. Otherwise we expect the struct to be fully defined
 
            // and expect a closing brace
 
            next = self.source.next();
 
            if let Some(b',') = next {
 
                self.source.consume();
 
                self.consume_whitespace(false)?;
 
                next = self.source.next();
 
            } else {
 
                break;
 
            }
 
        }
 

	
 
        // End of struct definition, so we expect a closing brace
 
        self.consume_string(b"}")?;
 

	
 
        // Valid struct definition
 
        Ok(h.alloc_struct_definition(|this| StructDefinition{
 
            this,
 
            position: struct_pos,
 
            identifier: struct_ident,
 
            poly_vars,
 
            fields,
 
        }))
 
    }
 
    fn consume_enum_definition(&mut self, h: &mut Heap) -> Result<EnumId, ParseError2> {
 
        // Parse "enum" keyword, optional polyvars and its identifier
 
        let enum_pos = self.source.pos();
 
        self.consume_keyword(b"enum")?;
 
        self.consume_whitespace(true)?;
 
        let enum_ident = self.consume_identifier()?;
 
        let poly_vars = self.consume_polymorphic_vars()?;
 
        self.consume_whitespace(false)?;
 

	
 
        // Parse enum variants
 
        self.consume_string(b"{")?;
 
        let mut next = self.source.next();
 
        let mut variants = Vec::new();
 
        while next.is_some() {
 
            let char = next.unwrap();
 
            if char == b'}' {
 
                break;
 
            }
 

	
 
            // Consume variant identifier
 
            self.consume_whitespace(false)?;
 
            let variant_position = self.source.pos();
 
            let variant_ident = self.consume_identifier()?;
 
            self.consume_whitespace(false)?;
 

	
 
            // Consume variant (tag) value: may be nothing, in which case it is
 
            // assigned automatically, may be a constant integer, or an embedded
 
            // type as value, resulting in a tagged union
 
            next = self.source.next();
 
            let variant_value = if let Some(b',') = next {
 
                EnumVariantValue::None
 
            } else if let Some(b'=') = next {
 
                self.source.consume();
 
                self.consume_whitespace(false)?;
 
                if !self.has_integer() {
 
                    return Err(self.error_at_pos("expected integer"));
 
                }
 
                let variant_int = self.consume_integer()?;
 
                self.consume_whitespace(false)?;
 
                EnumVariantValue::Integer(variant_int)
 
            } else if let Some(b'(') = next {
 
                self.source.consume();
 
                self.consume_whitespace(false)?;
 
                let variant_type = self.consume_type2(h, false)?;
 
                self.consume_whitespace(false)?;
 
                self.consume_string(b")")?;
 
                self.consume_whitespace(false)?;
 
                EnumVariantValue::Type(variant_type)
 
            } else {
 
                return Err(self.error_at_pos("expected ',', '=', or '('"));
 
            };
 

	
 
            variants.push(EnumVariantDefinition{
 
                position: variant_position,
 
                identifier: variant_ident,
 
                value: variant_value
 
            });
 

	
 
            // If we have a comma, then we may or may not have another variant,
 
            // otherwise we expect the enum is fully defined
 
            next = self.source.next();
 
            if let Some(b',') = next {
 
                self.source.consume();
 
                self.consume_whitespace(false)?;
 
                next = self.source.next();
 
            } else {
 
                break;
 
            }
 
        }
 

	
 
        self.consume_string(b"}")?;
 

	
 
        // An enum without variants is somewhat valid, but completely useless
 
        // within the language
 
        if variants.is_empty() {
 
            return Err(ParseError2::new_error(self.source, enum_pos, "enum definition without variants"));
 
        }
 

	
 
        Ok(h.alloc_enum_definition(|this| EnumDefinition{
 
            this,
 
            position: enum_pos,
 
            identifier: enum_ident,
 
            poly_vars,
 
            variants,
 
        }))
 
    }
 
    fn consume_component_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        // TODO: Cleanup
 
        if self.has_keyword(b"composite") {
 
            Ok(self.consume_composite_definition(h)?)
 
        } else {
 
            Ok(self.consume_primitive_definition(h)?)
 
        }
 
    }
 
    fn consume_composite_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        // Parse keyword, optional polyvars and the identifier
 
        let position = self.source.pos();
src/protocol/mod.rs
Show inline comments
 
@@ -105,193 +105,205 @@ impl ProtocolDescription {
 
                unreachable!()
 
            }
 
        }
 
        Ok(result)
 
    }
 
    // expects port polarities to be correct
 
    pub(crate) fn new_component(&self, identifier: &[u8], ports: &[PortId]) -> ComponentState {
 
        let mut args = Vec::new();
 
        for (&x, y) in ports.iter().zip(self.component_polarities(identifier).unwrap()) {
 
            match y {
 
                Polarity::Getter => args.push(Value::Input(InputValue(x))),
 
                Polarity::Putter => args.push(Value::Output(OutputValue(x))),
 
            }
 
        }
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier).unwrap();
 
        ComponentState { prompt: Prompt::new(h, def, &args) }
 
    }
 
}
 
impl ComponentState {
 
    pub(crate) fn nonsync_run<'a: 'b, 'b>(
 
        &'a mut self,
 
        context: &'b mut NonsyncProtoContext<'b>,
 
        pd: &'a ProtocolDescription,
 
    ) -> NonsyncBlocker {
 
        let mut context = EvalContext::Nonsync(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 NonsyncBlocker::Inconsistent,
 
                    EvalContinuation::Terminal => return NonsyncBlocker::ComponentExit,
 
                    EvalContinuation::SyncBlockStart => return NonsyncBlocker::SyncBlockStart,
 
                    // Not possible to end sync block if never entered one
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(definition_id, args) => {
 
                        // Look up definition (TODO for now, assume it is a definition)
 
                        let h = &pd.heap;
 
                        let init_state = ComponentState { prompt: Prompt::new(h, definition_id, &args) };
 
                        context.new_component(&args, init_state);
 
                        // Continue stepping
 
                        continue;
 
                    }
 
                    // Outside synchronous blocks, no fires/get/put happens
 
                    EvalContinuation::BlockFires(_) => unreachable!(),
 
                    EvalContinuation::BlockGet(_) => unreachable!(),
 
                    EvalContinuation::Put(_, _) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    pub(crate) fn sync_run<'a: 'b, 'b>(
 
        &'a mut self,
 
        context: &'b mut SyncProtoContext<'b>,
 
        pd: &'a ProtocolDescription,
 
    ) -> SyncBlocker {
 
        let mut context = EvalContext::Sync(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 SyncBlocker::Inconsistent,
 
                    // First need to exit synchronous block before definition may end
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // No nested synchronous blocks
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => return SyncBlocker::SyncBlockEnd,
 
                    // Not possible to create component in sync block
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(port) => match port {
 
                        Value::Output(OutputValue(port)) => {
 
                            return SyncBlocker::CouldntCheckFiring(port);
 
                        }
 
                        Value::Input(InputValue(port)) => {
 
                            return SyncBlocker::CouldntCheckFiring(port);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::BlockGet(port) => match port {
 
                        Value::Output(OutputValue(port)) => {
 
                            return SyncBlocker::CouldntReadMsg(port);
 
                        }
 
                        Value::Input(InputValue(port)) => {
 
                            return SyncBlocker::CouldntReadMsg(port);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::Put(port, message) => {
 
                        let value;
 
                        match port {
 
                            Value::Output(OutputValue(port_value)) => {
 
                                value = port_value;
 
                            }
 
                            Value::Input(InputValue(port_value)) => {
 
                                value = port_value;
 
                            }
 
                            _ => unreachable!(),
 
                        }
 
                        let payload;
 
                        match message {
 
                            Value::Message(MessageValue(None)) => {
 
                                // Putting a null message is inconsistent
 
                                return SyncBlocker::Inconsistent;
 
                            }
 
                            Value::Message(MessageValue(Some(buffer))) => {
 
                                // Create a copy of the payload
 
                                payload = buffer;
 
                            }
 
                            _ => unreachable!(),
 
                        }
 
                        return SyncBlocker::PutMsg(value, payload);
 
                    }
 
                },
 
            }
 
        }
 
    }
 
}
 
impl EvalContext<'_> {
 
    // fn random(&mut self) -> LongValue {
 
    //     match self {
 
    //         // EvalContext::None => unreachable!(),
 
    //         EvalContext::Nonsync(_context) => todo!(),
 
    //         EvalContext::Sync(_) => unreachable!(),
 
    //     }
 
    // }
 
    fn new_component(&mut self, args: &[Value], init_state: ComponentState) -> () {
 
        match self {
 
            // EvalContext::None => unreachable!(),
 
            EvalContext::Nonsync(context) => {
 
                let mut moved_ports = HashSet::new();
 
                for arg in args.iter() {
 
                    match arg {
 
                        Value::Output(OutputValue(port)) => {
 
                            moved_ports.insert(*port);
 
                        }
 
                        Value::Input(InputValue(port)) => {
 
                            moved_ports.insert(*port);
 
                        }
 
                        _ => {}
 
                    }
 
                }
 
                context.new_component(moved_ports, init_state)
 
            }
 
            EvalContext::Sync(_) => unreachable!(),
 
        }
 
    }
 
    fn new_channel(&mut self) -> [Value; 2] {
 
        match self {
 
            // EvalContext::None => unreachable!(),
 
            EvalContext::Nonsync(context) => {
 
                let [from, to] = context.new_port_pair();
 
                let from = Value::Output(OutputValue(from));
 
                let to = Value::Input(InputValue(to));
 
                return [from, to];
 
            }
 
            EvalContext::Sync(_) => unreachable!(),
 
        }
 
    }
 
    fn fires(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            // EvalContext::None => unreachable!(),
 
            EvalContext::Nonsync(_) => unreachable!(),
 
            EvalContext::Sync(context) => match port {
 
                Value::Output(OutputValue(port)) => context.is_firing(port).map(Value::from),
 
                Value::Input(InputValue(port)) => context.is_firing(port).map(Value::from),
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
    fn get(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            // EvalContext::None => unreachable!(),
 
            EvalContext::Nonsync(_) => unreachable!(),
 
            EvalContext::Sync(context) => match port {
 
                Value::Output(OutputValue(port)) => {
 
                    context.read_msg(port).map(Value::receive_message)
 
                }
 
                Value::Input(InputValue(port)) => {
 
                    context.read_msg(port).map(Value::receive_message)
 
                }
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
    fn did_put(&mut self, port: Value) -> bool {
 
        match self {
 
            EvalContext::Nonsync(_) => unreachable!("did_put in nonsync context"),
 
            EvalContext::Sync(context) => match port {
 
                Value::Output(OutputValue(port)) => {
 
                    context.is_firing(port).unwrap_or(false)
 
                },
 
                Value::Input(_) => unreachable!("did_put on input port"),
 
                _ => unreachable!("did_put on non-port value")
 
            }
 
        }
 
    }
 
}
src/protocol/parser/depth_visitor.rs
Show inline comments
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 

	
 
// The following indirection is needed due to a bug in the cbindgen tool.
 
type Unit = ();
 
pub(crate) type VisitorError = (InputPosition, String); // TODO: Revise when multi-file compiling is in place
 
pub(crate) type VisitorResult = Result<Unit, VisitorError>;
 

	
 
pub(crate) trait Visitor: Sized {
 
    fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> VisitorResult {
 
        recursive_protocol_description(self, h, pd)
 
    }
 
    fn visit_pragma(&mut self, _h: &mut Heap, _pragma: PragmaId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_import(&mut self, _h: &mut Heap, _import: ImportId) -> VisitorResult {
 
        Ok(())
 
    }
 

	
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        recursive_symbol_definition(self, h, def)
 
    }
 
    fn visit_struct_definition(&mut self, _h: &mut Heap, _def: StructId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_enum_definition(&mut self, _h: &mut Heap, _def: EnumId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_component_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_component_definition(self, h, def)
 
    }
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_composite_definition(self, h, def)
 
    }
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_primitive_definition(self, h, def)
 
    }
 
    fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionId) -> VisitorResult {
 
        recursive_function_definition(self, h, def)
 
    }
 

	
 
    fn visit_variable_declaration(&mut self, h: &mut Heap, decl: VariableId) -> VisitorResult {
 
        recursive_variable_declaration(self, h, decl)
 
    }
 
    fn visit_parameter_declaration(&mut self, _h: &mut Heap, _decl: ParameterId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_local_declaration(&mut self, _h: &mut Heap, _decl: LocalId) -> VisitorResult {
 
        Ok(())
 
    }
 

	
 
    fn visit_statement(&mut self, h: &mut Heap, stmt: StatementId) -> VisitorResult {
 
        recursive_statement(self, h, stmt)
 
    }
 
    fn visit_local_statement(&mut self, h: &mut Heap, stmt: LocalStatementId) -> VisitorResult {
 
        recursive_local_statement(self, h, stmt)
 
    }
 
    fn visit_memory_statement(&mut self, h: &mut Heap, stmt: MemoryStatementId) -> VisitorResult {
 
        recursive_memory_statement(self, h, stmt)
 
    }
 
    fn visit_channel_statement(
 
        &mut self,
 
        _h: &mut Heap,
 
        _stmt: ChannelStatementId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        recursive_block_statement(self, h, stmt)
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_skip_statement(&mut self, _h: &mut Heap, _stmt: SkipStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult {
 
        recursive_if_statement(self, h, stmt)
 
    }
 
    fn visit_end_if_statement(&mut self, _h: &mut Heap, _stmt: EndIfStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        recursive_while_statement(self, h, stmt)
 
    }
 
    fn visit_end_while_statement(&mut self, _h: &mut Heap, _stmt: EndWhileStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_break_statement(&mut self, _h: &mut Heap, _stmt: BreakStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        _h: &mut Heap,
 
        _stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        recursive_synchronous_statement(self, h, stmt)
 
    }
 
    fn visit_end_synchronous_statement(&mut self, _h: &mut Heap, _stmt: EndSynchronousStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_return_statement(&mut self, h: &mut Heap, stmt: ReturnStatementId) -> VisitorResult {
 
        recursive_return_statement(self, h, stmt)
 
    }
 
    fn visit_assert_statement(&mut self, h: &mut Heap, stmt: AssertStatementId) -> VisitorResult {
 
        recursive_assert_statement(self, h, stmt)
 
    }
 
    fn visit_goto_statement(&mut self, _h: &mut Heap, _stmt: GotoStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        recursive_new_statement(self, h, stmt)
 
    }
 
    fn visit_put_statement(&mut self, h: &mut Heap, stmt: PutStatementId) -> VisitorResult {
 
        recursive_put_statement(self, h, stmt)
 
    }
 
    fn visit_expression_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ExpressionStatementId,
 
    ) -> VisitorResult {
 
        recursive_expression_statement(self, h, stmt)
 
    }
 

	
 
    fn visit_expression(&mut self, h: &mut Heap, expr: ExpressionId) -> VisitorResult {
 
        recursive_expression(self, h, expr)
 
    }
 
    fn visit_assignment_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: AssignmentExpressionId,
 
    ) -> VisitorResult {
 
        recursive_assignment_expression(self, h, expr)
 
    }
 
    fn visit_conditional_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConditionalExpressionId,
 
    ) -> VisitorResult {
 
        recursive_conditional_expression(self, h, expr)
 
    }
 
    fn visit_binary_expression(&mut self, h: &mut Heap, expr: BinaryExpressionId) -> VisitorResult {
 
        recursive_binary_expression(self, h, expr)
 
    }
 
    fn visit_unary_expression(&mut self, h: &mut Heap, expr: UnaryExpressionId) -> VisitorResult {
 
        recursive_unary_expression(self, h, expr)
 
    }
 
    fn visit_indexing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: IndexingExpressionId,
 
    ) -> VisitorResult {
 
        recursive_indexing_expression(self, h, expr)
 
    }
 
    fn visit_slicing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: SlicingExpressionId,
 
    ) -> VisitorResult {
 
        recursive_slicing_expression(self, h, expr)
 
    }
 
    fn visit_select_expression(&mut self, h: &mut Heap, expr: SelectExpressionId) -> VisitorResult {
 
        recursive_select_expression(self, h, expr)
 
    }
 
    fn visit_array_expression(&mut self, h: &mut Heap, expr: ArrayExpressionId) -> VisitorResult {
 
        recursive_array_expression(self, h, expr)
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        recursive_call_expression(self, h, expr)
 
    }
 
    fn visit_constant_expression(
 
        &mut self,
 
        _h: &mut Heap,
 
        _expr: ConstantExpressionId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_variable_expression(
 
        &mut self,
 
        _h: &mut Heap,
 
        _expr: VariableExpressionId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
// Bubble-up helpers
 
fn recursive_parameter_as_variable<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    param: ParameterId,
 
) -> VisitorResult {
 
    this.visit_variable_declaration(h, param.upcast())
 
}
 

	
 
fn recursive_local_as_variable<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    local: LocalId,
 
) -> VisitorResult {
 
    this.visit_variable_declaration(h, local.upcast())
 
}
 

	
 
fn recursive_call_expression_as_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    call: CallExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, call.upcast())
 
}
 

	
 
// Recursive procedures
 
fn recursive_protocol_description<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    pd: RootId,
 
) -> VisitorResult {
 
    for &pragma in h[pd].pragmas.clone().iter() {
 
        this.visit_pragma(h, pragma)?;
 
    }
 
    for &import in h[pd].imports.clone().iter() {
 
        this.visit_import(h, import)?;
 
    }
 
    for &def in h[pd].definitions.clone().iter() {
 
        this.visit_symbol_definition(h, def)?;
 
    }
 
    Ok(())
 
}
 

	
 
fn recursive_symbol_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: DefinitionId,
 
) -> VisitorResult {
 
    // We clone the definition in case it is modified
 
    // TODO: Fix me
 
    match h[def].clone() {
 
        Definition::Struct(def) => this.visit_struct_definition(h, def.this),
 
        Definition::Enum(def) => this.visit_enum_definition(h, def.this),
 
        Definition::Component(cdef) => this.visit_component_definition(h, cdef.this),
 
        Definition::Function(fdef) => this.visit_function_definition(h, fdef.this),
 
    }
 
}
 

	
 
fn recursive_component_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    let component_variant = h[def].variant;
 
    match component_variant {
 
        ComponentVariant::Primitive => this.visit_primitive_definition(h, def),
 
        ComponentVariant::Composite => this.visit_composite_definition(h, def),
 
    }
 
}
 

	
 
fn recursive_composite_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    for &param in h[def].parameters.clone().iter() {
 
        recursive_parameter_as_variable(this, h, param)?;
 
    }
 
    this.visit_statement(h, h[def].body)
 
}
 

	
 
fn recursive_primitive_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    for &param in h[def].parameters.clone().iter() {
 
        recursive_parameter_as_variable(this, h, param)?;
 
    }
 
    this.visit_statement(h, h[def].body)
 
}
 

	
 
fn recursive_function_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: FunctionId,
 
) -> VisitorResult {
 
    for &param in h[def].parameters.clone().iter() {
 
        recursive_parameter_as_variable(this, h, param)?;
 
    }
 
    this.visit_statement(h, h[def].body)
 
}
 

	
 
fn recursive_variable_declaration<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    decl: VariableId,
 
) -> VisitorResult {
 
    match h[decl].clone() {
 
        Variable::Parameter(decl) => this.visit_parameter_declaration(h, decl.this),
 
        Variable::Local(decl) => this.visit_local_declaration(h, decl.this),
 
    }
 
}
 

	
 
fn recursive_statement<T: Visitor>(this: &mut T, h: &mut Heap, stmt: StatementId) -> VisitorResult {
 
    match h[stmt].clone() {
 
        Statement::Block(stmt) => this.visit_block_statement(h, stmt.this),
 
        Statement::Local(stmt) => this.visit_local_statement(h, stmt.this()),
 
        Statement::Skip(stmt) => this.visit_skip_statement(h, stmt.this),
 
        Statement::Labeled(stmt) => this.visit_labeled_statement(h, stmt.this),
 
        Statement::If(stmt) => this.visit_if_statement(h, stmt.this),
 
        Statement::While(stmt) => this.visit_while_statement(h, stmt.this),
 
        Statement::Break(stmt) => this.visit_break_statement(h, stmt.this),
 
        Statement::Continue(stmt) => this.visit_continue_statement(h, stmt.this),
 
        Statement::Synchronous(stmt) => this.visit_synchronous_statement(h, stmt.this),
 
        Statement::Return(stmt) => this.visit_return_statement(h, stmt.this),
 
        Statement::Assert(stmt) => this.visit_assert_statement(h, stmt.this),
 
        Statement::Goto(stmt) => this.visit_goto_statement(h, stmt.this),
 
        Statement::New(stmt) => this.visit_new_statement(h, stmt.this),
 
        Statement::Put(stmt) => this.visit_put_statement(h, stmt.this),
 
        Statement::Expression(stmt) => this.visit_expression_statement(h, stmt.this),
 
        Statement::EndSynchronous(stmt) => this.visit_end_synchronous_statement(h, stmt.this),
 
        Statement::EndWhile(stmt) => this.visit_end_while_statement(h, stmt.this),
 
        Statement::EndIf(stmt) => this.visit_end_if_statement(h, stmt.this),
 
    }
 
}
 

	
 
fn recursive_block_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    block: BlockStatementId,
 
) -> VisitorResult {
 
    for &local in h[block].locals.clone().iter() {
 
        recursive_local_as_variable(this, h, local)?;
 
    }
 
    for &stmt in h[block].statements.clone().iter() {
 
        this.visit_statement(h, stmt)?;
 
    }
 
    Ok(())
 
}
 

	
 
fn recursive_local_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: LocalStatementId,
 
) -> VisitorResult {
 
    match h[stmt].clone() {
 
        LocalStatement::Channel(stmt) => this.visit_channel_statement(h, stmt.this),
 
        LocalStatement::Memory(stmt) => this.visit_memory_statement(h, stmt.this),
 
    }
 
}
 

	
 
fn recursive_memory_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: MemoryStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].initial)
 
}
 

	
 
fn recursive_labeled_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: LabeledStatementId,
 
) -> VisitorResult {
 
    this.visit_statement(h, h[stmt].body)
 
}
 

	
 
fn recursive_if_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: IfStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].test)?;
 
    this.visit_statement(h, h[stmt].true_body)?;
 
    this.visit_statement(h, h[stmt].false_body)
 
}
 

	
 
fn recursive_while_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: WhileStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].test)?;
 
    this.visit_statement(h, h[stmt].body)
 
}
 

	
 
fn recursive_synchronous_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: SynchronousStatementId,
 
) -> VisitorResult {
 
    // TODO: Check where this was used for
 
    // for &param in h[stmt].parameters.clone().iter() {
 
    //     recursive_parameter_as_variable(this, h, param)?;
 
    // }
 
    this.visit_statement(h, h[stmt].body)
 
}
 

	
 
fn recursive_return_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: ReturnStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].expression)
 
}
 

	
 
fn recursive_assert_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: AssertStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].expression)
 
}
 

	
 
fn recursive_new_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: NewStatementId,
 
) -> VisitorResult {
 
    recursive_call_expression_as_expression(this, h, h[stmt].expression)
 
}
 

	
 
fn recursive_put_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: PutStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].port)?;
 
    this.visit_expression(h, h[stmt].message)
 
}
 

	
 
fn recursive_expression_statement<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    stmt: ExpressionStatementId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[stmt].expression)
 
}
 

	
 
fn recursive_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: ExpressionId,
 
) -> VisitorResult {
 
    match h[expr].clone() {
 
        Expression::Assignment(expr) => this.visit_assignment_expression(h, expr.this),
 
        Expression::Conditional(expr) => this.visit_conditional_expression(h, expr.this),
 
        Expression::Binary(expr) => this.visit_binary_expression(h, expr.this),
 
        Expression::Unary(expr) => this.visit_unary_expression(h, expr.this),
 
        Expression::Indexing(expr) => this.visit_indexing_expression(h, expr.this),
 
        Expression::Slicing(expr) => this.visit_slicing_expression(h, expr.this),
 
        Expression::Select(expr) => this.visit_select_expression(h, expr.this),
 
        Expression::Array(expr) => this.visit_array_expression(h, expr.this),
 
        Expression::Constant(expr) => this.visit_constant_expression(h, expr.this),
 
        Expression::Call(expr) => this.visit_call_expression(h, expr.this),
 
        Expression::Variable(expr) => this.visit_variable_expression(h, expr.this),
 
    }
 
}
 

	
 
fn recursive_assignment_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: AssignmentExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].left)?;
 
    this.visit_expression(h, h[expr].right)
 
}
 

	
 
fn recursive_conditional_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: ConditionalExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].test)?;
 
    this.visit_expression(h, h[expr].true_expression)?;
 
    this.visit_expression(h, h[expr].false_expression)
 
}
 

	
 
fn recursive_binary_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: BinaryExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].left)?;
 
    this.visit_expression(h, h[expr].right)
 
}
 

	
 
fn recursive_unary_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: UnaryExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].expression)
 
}
 

	
 
fn recursive_indexing_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: IndexingExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].subject)?;
 
    this.visit_expression(h, h[expr].index)
 
}
 

	
 
fn recursive_slicing_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: SlicingExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].subject)?;
 
    this.visit_expression(h, h[expr].from_index)?;
 
    this.visit_expression(h, h[expr].to_index)
 
}
 

	
 
fn recursive_select_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: SelectExpressionId,
 
) -> VisitorResult {
 
    this.visit_expression(h, h[expr].subject)
 
}
 

	
 
fn recursive_array_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: ArrayExpressionId,
 
) -> VisitorResult {
 
    for &expr in h[expr].elements.clone().iter() {
 
        this.visit_expression(h, expr)?;
 
    }
 
    Ok(())
 
}
 

	
 
fn recursive_call_expression<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    expr: CallExpressionId,
 
) -> VisitorResult {
 
    for &expr in h[expr].arguments.clone().iter() {
 
        this.visit_expression(h, expr)?;
 
    }
 
    Ok(())
 
}
 

	
 
// ====================
 
// Grammar Rules
 
// ====================
 

	
 
pub(crate) struct NestedSynchronousStatements {
 
    illegal: bool,
 
}
 

	
 
impl NestedSynchronousStatements {
 
    pub(crate) fn new() -> Self {
 
        NestedSynchronousStatements { illegal: false }
 
    }
 
}
 

	
 
impl Visitor for NestedSynchronousStatements {
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_composite_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
    fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_function_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        if self.illegal {
 
            return Err((
 
                h[stmt].position(),
 
                "Illegal nested synchronous statement".to_string(),
 
            ));
 
        }
 
        self.illegal = true;
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct ChannelStatementOccurrences {
 
    illegal: bool,
 
}
 

	
 
impl ChannelStatementOccurrences {
 
    pub(crate) fn new() -> Self {
 
        ChannelStatementOccurrences { illegal: false }
 
    }
 
}
 

	
 
impl Visitor for ChannelStatementOccurrences {
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_primitive_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
    fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_function_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
    fn visit_channel_statement(&mut self, h: &mut Heap, stmt: ChannelStatementId) -> VisitorResult {
 
        if self.illegal {
 
            return Err((h[stmt].position(), "Illegal channel declaration".to_string()));
 
        }
 
@@ -780,388 +767,384 @@ impl Visitor for CheckBuiltinOccurrences {
 
}
 

	
 
pub(crate) struct BuildScope {
 
    scope: Option<Scope>,
 
}
 

	
 
impl BuildScope {
 
    pub(crate) fn new() -> Self {
 
        BuildScope { scope: None }
 
    }
 
}
 

	
 
impl Visitor for BuildScope {
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        assert!(self.scope.is_none());
 
        self.scope = Some(Scope::Definition(def));
 
        recursive_symbol_definition(self, h, def)?;
 
        self.scope = None;
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        // First store the current scope
 
        h[stmt].parent_scope = self.scope;
 
        // Then move scope down to current block
 
        self.scope = Some(Scope::Regular(stmt));
 
        recursive_block_statement(self, h, stmt)?;
 
        // Move scope back up
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        // First store the current scope
 
        h[stmt].parent_scope = self.scope;
 
        // Then move scope down to current sync
 
        // TODO: Should be legal-ish, but very wrong
 
        self.scope = Some(Scope::Synchronous((stmt, BlockStatementId(stmt.upcast()))));
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        // Move scope back up
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct UniqueStatementId(StatementId);
 

	
 
pub(crate) struct LinkStatements {
 
    prev: Option<UniqueStatementId>,
 
}
 

	
 
impl LinkStatements {
 
    pub(crate) fn new() -> Self {
 
        LinkStatements { prev: None }
 
    }
 
}
 

	
 
impl Visitor for LinkStatements {
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        assert!(self.prev.is_none());
 
        recursive_symbol_definition(self, h, def)?;
 
        // Clear out last statement
 
        self.prev = None;
 
        Ok(())
 
    }
 
    fn visit_statement(&mut self, h: &mut Heap, stmt: StatementId) -> VisitorResult {
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(stmt);
 
        }
 
        recursive_statement(self, h, stmt)
 
    }
 
    fn visit_local_statement(&mut self, _h: &mut Heap, stmt: LocalStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_skip_statement(&mut self, _h: &mut Heap, stmt: SkipStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult {
 
        // Link the two branches to the corresponding EndIf pseudo-statement
 
        let end_if_id = h[stmt].end_if;
 
        assert!(end_if_id.is_some());
 
        let end_if_id = end_if_id.unwrap();
 

	
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].true_body)?;
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(end_if_id.upcast());
 
        }
 

	
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].false_body)?;
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(end_if_id.upcast());
 
        }
 

	
 
        // Use the pseudo-statement as the statement where to update the next pointer
 
        // self.prev = Some(UniqueStatementId(end_if_id.upcast()));
 
        Ok(())
 
    }
 
    fn visit_end_if_statement(&mut self, _h: &mut Heap, stmt: EndIfStatementId) -> VisitorResult {
 
        assert!(self.prev.is_none());
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        // We allocate a pseudo-statement, to which the break statement finds its target
 
        // Update the while's next statement to point to the pseudo-statement
 
        let end_while_id = h[stmt].end_while;
 
        assert!(end_while_id.is_some());
 
        // let end_while_id = end_while_id.unwrap();
 

	
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].body)?;
 
        // The body's next statement loops back to the while statement itself
 
        // Note: continue statements also loop back to the while statement itself
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(stmt.upcast());
 
        }
 
        // Use the while statement as the statement where the next pointer is updated
 
        // self.prev = Some(UniqueStatementId(end_while_id.upcast()));
 
        Ok(())
 
    }
 
    fn visit_end_while_statement(&mut self, _h: &mut Heap, stmt: EndWhileStatementId) -> VisitorResult {
 
        assert!(self.prev.is_none());
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_break_statement(&mut self, _h: &mut Heap, _stmt: BreakStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        _h: &mut Heap,
 
        _stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        // Allocate a pseudo-statement, that is added for helping the evaluator to issue a command
 
        // that marks the end of the synchronous block. Every evaluation has to pause at this
 
        // point, only to resume later when the thread is selected as unique thread to continue.
 
        let end_sync_id = h[stmt].end_sync;
 
        assert!(end_sync_id.is_some());
 
        let end_sync_id = end_sync_id.unwrap();
 

	
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].body)?;
 
        // The body's next statement points to the pseudo element
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(end_sync_id.upcast());
 
        }
 
        // Use the pseudo-statement as the statement where the next pointer is updated
 
        // self.prev = Some(UniqueStatementId(end_sync_id.upcast()));
 
        Ok(())
 
    }
 
    fn visit_end_synchronous_statement(&mut self, _h: &mut Heap, stmt: EndSynchronousStatementId) -> VisitorResult {
 
        assert!(self.prev.is_none());
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_return_statement(&mut self, _h: &mut Heap, _stmt: ReturnStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_assert_statement(&mut self, _h: &mut Heap, stmt: AssertStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_goto_statement(&mut self, _h: &mut Heap, _stmt: GotoStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_new_statement(&mut self, _h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_put_statement(&mut self, _h: &mut Heap, stmt: PutStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_expression_statement(
 
        &mut self,
 
        _h: &mut Heap,
 
        stmt: ExpressionStatementId,
 
    ) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct BuildLabels {
 
    block: Option<BlockStatementId>,
 
    sync_enclosure: Option<SynchronousStatementId>,
 
}
 

	
 
impl BuildLabels {
 
    pub(crate) fn new() -> Self {
 
        BuildLabels { block: None, sync_enclosure: None }
 
    }
 
}
 

	
 
impl Visitor for BuildLabels {
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert_eq!(self.block, h[stmt].parent_block(h));
 
        let old = self.block;
 
        self.block = Some(stmt);
 
        recursive_block_statement(self, h, stmt)?;
 
        self.block = old;
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        assert!(!self.block.is_none());
 
        // Store label in current block (on the fly)
 
        h[self.block.unwrap()].labels.push(stmt);
 
        // Update synchronous scope of label
 
        h[stmt].in_sync = self.sync_enclosure;
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        h[stmt].in_sync = self.sync_enclosure;
 
        recursive_while_statement(self, h, stmt)
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(self.sync_enclosure.is_none());
 
        self.sync_enclosure = Some(stmt);
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.sync_enclosure = None;
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct ResolveLabels {
 
    block: Option<BlockStatementId>,
 
    while_enclosure: Option<WhileStatementId>,
 
    sync_enclosure: Option<SynchronousStatementId>,
 
}
 

	
 
impl ResolveLabels {
 
    pub(crate) fn new() -> Self {
 
        ResolveLabels { block: None, while_enclosure: None, sync_enclosure: None }
 
    }
 
    fn check_duplicate_impl(
 
        h: &Heap,
 
        block: Option<BlockStatementId>,
 
        stmt: LabeledStatementId,
 
    ) -> VisitorResult {
 
        if let Some(block) = block {
 
            // Checking the parent first is important. Otherwise, labels
 
            // overshadow previously defined labels: and this is illegal!
 
            ResolveLabels::check_duplicate_impl(h, h[block].parent_block(h), stmt)?;
 
            // For the current block, check for a duplicate.
 
            for &other_stmt in h[block].labels.iter() {
 
                if other_stmt == stmt {
 
                    continue;
 
                } else {
 
                    if h[other_stmt].label.value == h[stmt].label.value {
 
                        return Err((h[stmt].position, "Duplicate label".to_string()));
 
                    }
 
                }
 
            }
 
        }
 
        Ok(())
 
    }
 
    fn check_duplicate(&self, h: &Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        ResolveLabels::check_duplicate_impl(h, self.block, stmt)
 
    }
 
    fn get_target(
 
        &self,
 
        h: &Heap,
 
        id: &Identifier,
 
    ) -> Result<LabeledStatementId, VisitorError> {
 
        if let Some(stmt) = ResolveLabels::find_target(h, self.block, id) {
 
            Ok(stmt)
 
        } else {
 
            Err((id.position, "Unresolved label".to_string()))
 
        }
 
    }
 
    fn find_target(
 
        h: &Heap,
 
        block: Option<BlockStatementId>,
 
        id: &Identifier,
 
    ) -> Option<LabeledStatementId> {
 
        if let Some(block) = block {
 
            // It does not matter in what order we find the labels.
 
            // If there are duplicates: that is checked elsewhere.
 
            for &stmt in h[block].labels.iter() {
 
                if h[stmt].label.value == id.value {
 
                    return Some(stmt);
 
                }
 
            }
 
            if let Some(stmt) = ResolveLabels::find_target(h, h[block].parent_block(h), id) {
 
                return Some(stmt);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
impl Visitor for ResolveLabels {
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert_eq!(self.block, h[stmt].parent_block(h));
 
        let old = self.block;
 
        self.block = Some(stmt);
 
        recursive_block_statement(self, h, stmt)?;
 
        self.block = old;
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        assert!(!self.block.is_none());
 
        self.check_duplicate(h, stmt)?;
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        let old = self.while_enclosure;
 
        self.while_enclosure = Some(stmt);
 
        recursive_while_statement(self, h, stmt)?;
 
        self.while_enclosure = old;
 
        Ok(())
 
    }
 
    fn visit_break_statement(&mut self, h: &mut Heap, stmt: BreakStatementId) -> VisitorResult {
 
        let the_while;
 
        if let Some(label) = &h[stmt].label {
 
            let target = self.get_target(h, label)?;
 
            let target = &h[h[target].body];
 
            if !target.is_while() {
 
                return Err((
 
                    h[stmt].position,
 
                    "Illegal break: target not a while statement".to_string(),
 
                ));
 
            }
 
            the_while = target.as_while();
 
            // TODO: check if break is nested under while
 
        } else {
 
            if self.while_enclosure.is_none() {
 
                return Err((
 
                    h[stmt].position,
 
                    "Illegal break: no surrounding while statement".to_string(),
 
                ));
 
            }
 
            the_while = &h[self.while_enclosure.unwrap()];
 
            // break is always nested under while, by recursive vistor
 
        }
 
        if the_while.in_sync != self.sync_enclosure {
 
            return Err((
 
                h[stmt].position,
 
                "Illegal break: synchronous statement escape".to_string(),
 
            ));
 
        }
 
        h[stmt].target = the_while.end_while;
 
        Ok(())
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        let the_while;
 
        if let Some(label) = &h[stmt].label {
 
            let target = self.get_target(h, label)?;
 
            let target = &h[h[target].body];
 
            if !target.is_while() {
 
                return Err((

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

0 comments (0 inline, 0 general)