Changeset - d25df42a65d3
[Not reviewed]
1 6 0
MH - 4 years ago 2021-03-08 09:55:18
contact@maxhenger.nl
remove concept of declaration AST nodes
7 files changed with 1 insertions and 444 deletions:
0 comments (0 inline, 0 general)
src/protocol/ast.rs
Show inline comments
 
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 {
 
    ($name:ident, $parent:ty) => {
 
        pub type $name = $parent;
 
    }
 
}
 

	
 
/// Helper macro that defines a subtype for a particular variant of an AST 
 
/// element ID.
 
macro_rules! define_new_ast_id {
 
    ($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
 
            }
 
        }
 
    };
 
}
 

	
 
define_aliased_ast_id!(RootId, Id<Root>);
 
define_aliased_ast_id!(PragmaId, Id<Pragma>);
 
define_aliased_ast_id!(ImportId, Id<Import>);
 
define_aliased_ast_id!(TypeAnnotationId, Id<TypeAnnotation>);
 

	
 
define_aliased_ast_id!(VariableId, Id<Variable>);
 
define_new_ast_id!(ParameterId, VariableId);
 
define_new_ast_id!(LocalId, VariableId);
 

	
 
define_aliased_ast_id!(DefinitionId, Id<Definition>);
 
define_new_ast_id!(StructId, DefinitionId);
 
define_new_ast_id!(EnumId, DefinitionId);
 
define_new_ast_id!(ComponentId, DefinitionId);
 
define_new_ast_id!(FunctionId, DefinitionId);
 

	
 
define_aliased_ast_id!(StatementId, Id<Statement>);
 
define_new_ast_id!(BlockStatementId, StatementId);
 
define_new_ast_id!(LocalStatementId, StatementId);
 
define_new_ast_id!(MemoryStatementId, LocalStatementId);
 
define_new_ast_id!(ChannelStatementId, LocalStatementId);
 
define_new_ast_id!(SkipStatementId, StatementId);
 
define_new_ast_id!(LabeledStatementId, StatementId);
 
define_new_ast_id!(IfStatementId, StatementId);
 
define_new_ast_id!(EndIfStatementId, StatementId);
 
define_new_ast_id!(WhileStatementId, StatementId);
 
define_new_ast_id!(EndWhileStatementId, StatementId);
 
define_new_ast_id!(BreakStatementId, StatementId);
 
define_new_ast_id!(ContinueStatementId, StatementId);
 
define_new_ast_id!(SynchronousStatementId, StatementId);
 
define_new_ast_id!(EndSynchronousStatementId, StatementId);
 
define_new_ast_id!(ReturnStatementId, StatementId);
 
define_new_ast_id!(AssertStatementId, StatementId);
 
define_new_ast_id!(GotoStatementId, StatementId);
 
define_new_ast_id!(NewStatementId, StatementId);
 
define_new_ast_id!(PutStatementId, StatementId);
 
define_new_ast_id!(ExpressionStatementId, StatementId);
 

	
 
define_aliased_ast_id!(ExpressionId, Id<Expression>);
 
define_new_ast_id!(AssignmentExpressionId, ExpressionId);
 
define_new_ast_id!(ConditionalExpressionId, ExpressionId);
 
define_new_ast_id!(BinaryExpressionId, ExpressionId);
 
define_new_ast_id!(UnaryExpressionId, ExpressionId);
 
define_new_ast_id!(IndexingExpressionId, ExpressionId);
 
define_new_ast_id!(SlicingExpressionId, ExpressionId);
 
define_new_ast_id!(SelectExpressionId, ExpressionId);
 
define_new_ast_id!(ArrayExpressionId, ExpressionId);
 
define_new_ast_id!(ConstantExpressionId, ExpressionId);
 
define_new_ast_id!(CallExpressionId, ExpressionId);
 
define_new_ast_id!(VariableExpressionId, ExpressionId);
 

	
 
define_aliased_ast_id!(DeclarationId, Id<Declaration>); // TODO: @cleanup
 
define_new_ast_id!(DefinedDeclarationId, DeclarationId);
 
define_new_ast_id!(ImportedDeclarationId, DeclarationId);
 

	
 
// TODO: @cleanup - pub qualifiers can be removed once done
 
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 
pub struct Heap {
 
    // Allocators
 
    // #[serde(skip)] string_alloc: StringAllocator,
 
    // 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) type_annotations: Arena<TypeAnnotation>,
 
    pub(crate) variables: Arena<Variable>,
 
    pub(crate) definitions: Arena<Definition>,
 
    pub(crate) statements: Arena<Statement>,
 
    pub(crate) expressions: Arena<Expression>,
 
    declarations: Arena<Declaration>,
 
}
 

	
 
impl Heap {
 
    pub fn new() -> Heap {
 
        Heap {
 
            // string_alloc: StringAllocator::new(),
 
            protocol_descriptions: Arena::new(),
 
            pragmas: Arena::new(),
 
            imports: Arena::new(),
 
            identifiers: Arena::new(),
 
            type_annotations: Arena::new(),
 
            variables: Arena::new(),
 
            definitions: Arena::new(),
 
            statements: Arena::new(),
 
            expressions: Arena::new(),
 
            declarations: Arena::new(),
 
        }
 
    }
 
    pub fn alloc_type_annotation(
 
        &mut self,
 
        f: impl FnOnce(TypeAnnotationId) -> TypeAnnotation,
 
    ) -> TypeAnnotationId {
 
        self.type_annotations.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))
 
    }
 
    pub fn alloc_imported_declaration(
 
        &mut self,
 
        f: impl FnOnce(ImportedDeclarationId) -> ImportedDeclaration,
 
    ) -> ImportedDeclarationId {
 
        ImportedDeclarationId(self.declarations.alloc_with_id(|id| {
 
            Declaration::Imported(f(ImportedDeclarationId(id)))
 
        }))
 
    }
 
    pub fn alloc_defined_declaration(
 
        &mut self,
 
        f: impl FnOnce(DefinedDeclarationId) -> DefinedDeclaration,
 
    ) -> DefinedDeclarationId {
 
        DefinedDeclarationId(
 
            self.declarations.alloc_with_id(|id| {
 
                Declaration::Defined(f(DefinedDeclarationId(id)))
 
            }),
 
        )
 
    }
 
}
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 
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()
 
    }
 
}
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 
#[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>,
 
    // Pase 2: linker
 
    pub declarations: Vec<DeclarationId>,
 
}
 

	
 
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
 
    }
 
    pub fn get_declaration(&self, h: &Heap, id: &Identifier) -> Option<DeclarationId> {
 
        for declaration_id in self.declarations.iter() {
 
            let declaration = &h[*declaration_id];
 
            if declaration.identifier().value == id.value {
 
                return Some(*declaration_id);
 
            }
 
        }
 
        None
 
    }
 
    pub fn get_declaration_namespaced(&self, h: &Heap, id: &NamespacedIdentifier) -> Option<DeclarationId> {
 
        for declaration_id in self.declarations.iter() {
 
            let declaration = &h[*declaration_id];
 
            // TODO: @fixme
 
            if declaration.identifier().value == id.value {
 
                return Some(*declaration_id);
 
            }
 
        }
 
        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>,
 
}
 

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

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

	
 
impl NamespacedIdentifier {
 
    pub(crate) fn iter(&self) -> NamespacedIdentifierIter {
 
        NamespacedIdentifierIter{
 
            value: &self.value,
 
            cur_offset: 0,
 
            num_returned: 0,
 
            num_total: self.num_namespaces
 
        }
 
    }
 
}
 

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

	
 
// TODO: Just keep ref to NamespacedIdentifier
 
pub(crate) struct NamespacedIdentifierIter<'a> {
 
    value: &'a Vec<u8>,
 
    cur_offset: usize,
 
    num_returned: u8,
 
    num_total: u8,
 
}
 

	
 
impl<'a> NamespacedIdentifierIter<'a> {
 
    pub(crate) fn num_returned(&self) -> u8 {
 
        return self.num_returned;
 
    }
 
    pub(crate) fn num_remaining(&self) -> u8 {
 
        return self.num_total - self.num_returned
 
    }
 
}
 

	
 
impl<'a> Iterator for NamespacedIdentifierIter<'a> {
 
    type Item = &'a [u8];
 
    fn next(&mut self) -> Option<Self::Item> {
 
        if self.cur_offset >= self.value.len() {
 
            debug_assert_eq!(self.num_returned, self.num_total);
 
            None
 
        } else {
 
            debug_assert!(self.num_returned < self.num_total);
 
            let start = self.cur_offset;
 
            let mut end = start;
 
            while end < self.value.len() - 1 {
 
                if self.value[end] == b':' && self.value[end + 1] == b':' {
 
                    self.cur_offset = end + 2;
 
                    self.num_returned += 1;
 
                    return Some(&self.value[start..end]);
 
                }
 
                end += 1;
 
            }
 

	
 
            // If NamespacedIdentifier is constructed properly, then we cannot
 
            // end with "::" in the value, so
 
            debug_assert!(end == 0 || (self.value[end - 1] != b':' && self.value[end] != b':'));
 
            debug_assert_eq!(self.num_returned + 1, self.num_total);
 
            self.cur_offset = self.value.len();
 
            self.num_returned += 1;
 
            return Some(&self.value[start..]);
 
        }
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone, 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(())
 
        }
 
    }
 
}
 

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

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

	
 
type CharacterData = Vec<u8>;
 
type IntegerData = 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,
 
    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'"),
 
        }
 
    }
 
    pub fn the_type<'b>(&self, h: &'b Heap) -> &'b Type {
 
        match self {
 
            Variable::Parameter(param) => &h[param.type_annotation].the_type,
 
            Variable::Local(local) => &h[local.type_annotation].the_type,
 
        }
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Parameter {
 
    pub this: ParameterId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub type_annotation: TypeAnnotationId,
 
    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 type_annotation: TypeAnnotationId,
 
    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 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 the_type: TypeAnnotationId,
 
}
 

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

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

	
 
#[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 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 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: TypeAnnotationId,
 
    pub identifier: 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 Declaration {
 
    Defined(DefinedDeclaration),
 
    Imported(ImportedDeclaration),
 
}
 

	
 
impl Declaration {
 
    pub fn signature(&self) -> &Signature {
 
        match self {
 
            Declaration::Defined(decl) => &decl.signature,
 
            Declaration::Imported(decl) => &decl.signature,
 
        }
 
    }
 
    pub fn identifier(&self) -> &Identifier {
 
        self.signature().identifier()
 
    }
 
    pub fn is_component(&self) -> bool {
 
        self.signature().is_component()
 
    }
 
    pub fn is_function(&self) -> bool {
 
        self.signature().is_function()
 
    }
 
    pub fn as_defined(&self) -> &DefinedDeclaration {
 
        match self {
 
            Declaration::Defined(result) => result,
 
            _ => panic!("Unable to cast `Declaration` to `DefinedDeclaration`"),
 
        }
 
    }
 
}
 

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

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

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

	
 
impl Signature {
 
    pub fn from_definition(h: &Heap, def: DefinitionId) -> Signature {
 
        // TODO: Fix this
 
        match &h[def] {
 
            Definition::Component(com) => Signature::Component(ComponentSignature {
 
                identifier: com.identifier.clone(), // TODO: @fix
 
                arity: Signature::convert_parameters(h, &com.parameters),
 
            }),
 
            Definition::Function(fun) => Signature::Function(FunctionSignature {
 
                return_type: h[fun.return_type].the_type.clone(),
 
                identifier: fun.identifier.clone(), // TODO: @fix
 
                arity: Signature::convert_parameters(h, &fun.parameters),
 
            }),
 
            _ => panic!("cannot retrieve signature (for StructDefinition or EnumDefinition)")
 
        }
 
    }
 
    fn convert_parameters(h: &Heap, params: &Vec<ParameterId>) -> Vec<Type> {
 
        let mut result = Vec::new();
 
        for &param in params.iter() {
 
            result.push(h[h[param].type_annotation].the_type.clone());
 
        }
 
        result
 
    }
 
    fn identifier(&self) -> &Identifier {
 
        match self {
 
            Signature::Component(com) => &com.identifier,
 
            Signature::Function(fun) => &fun.identifier,
 
        }
 
    }
 
    pub fn is_component(&self) -> bool {
 
        match self {
 
            Signature::Component(_) => true,
 
            Signature::Function(_) => false,
 
        }
 
    }
 
    pub fn is_function(&self) -> bool {
 
        match self {
 
            Signature::Component(_) => false,
 
            Signature::Function(_) => true,
 
        }
 
    }
 
}
 

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

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

	
 
#[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,
src/protocol/ast_printer.rs
Show inline comments
 
use std::fmt::{Debug, Display, Write};
 
use std::io::Write as IOWrite;
 

	
 
use super::ast::*;
 
use std::borrow::Borrow;
 

	
 
const INDENT: usize = 2;
 

	
 
const PREFIX_EMPTY: &'static str = "    ";
 
const PREFIX_ROOT_ID: &'static str = "Root";
 
const PREFIX_PRAGMA_ID: &'static str = "Prag";
 
const PREFIX_IMPORT_ID: &'static str = "Imp ";
 
const PREFIX_TYPE_ANNOT_ID: &'static str = "TyAn";
 
const PREFIX_VARIABLE_ID: &'static str = "Var ";
 
const PREFIX_PARAMETER_ID: &'static str = "Par ";
 
const PREFIX_LOCAL_ID: &'static str = "Loc ";
 
const PREFIX_DEFINITION_ID: &'static str = "Def ";
 
const PREFIX_STRUCT_ID: &'static str = "DefS";
 
const PREFIX_ENUM_ID: &'static str = "DefE";
 
const PREFIX_COMPONENT_ID: &'static str = "DefC";
 
const PREFIX_FUNCTION_ID: &'static str = "DefF";
 
const PREFIX_STMT_ID: &'static str = "Stmt";
 
const PREFIX_BLOCK_STMT_ID: &'static str = "SBl ";
 
const PREFIX_LOCAL_STMT_ID: &'static str = "SLoc";
 
const PREFIX_MEM_STMT_ID: &'static str = "SMem";
 
const PREFIX_CHANNEL_STMT_ID: &'static str = "SCha";
 
const PREFIX_SKIP_STMT_ID: &'static str = "SSki";
 
const PREFIX_LABELED_STMT_ID: &'static str = "SLab";
 
const PREFIX_IF_STMT_ID: &'static str = "SIf ";
 
const PREFIX_ENDIF_STMT_ID: &'static str = "SEIf";
 
const PREFIX_WHILE_STMT_ID: &'static str = "SWhi";
 
const PREFIX_ENDWHILE_STMT_ID: &'static str = "SEWh";
 
const PREFIX_BREAK_STMT_ID: &'static str = "SBre";
 
const PREFIX_CONTINUE_STMT_ID: &'static str = "SCon";
 
const PREFIX_SYNC_STMT_ID: &'static str = "SSyn";
 
const PREFIX_ENDSYNC_STMT_ID: &'static str = "SESy";
 
const PREFIX_RETURN_STMT_ID: &'static str = "SRet";
 
const PREFIX_ASSERT_STMT_ID: &'static str = "SAsr";
 
const PREFIX_GOTO_STMT_ID: &'static str = "SGot";
 
const PREFIX_NEW_STMT_ID: &'static str = "SNew";
 
const PREFIX_PUT_STMT_ID: &'static str = "SPut";
 
const PREFIX_EXPR_STMT_ID: &'static str = "SExp";
 
const PREFIX_ASSIGNMENT_EXPR_ID: &'static str = "EAsi";
 
const PREFIX_CONDITIONAL_EXPR_ID: &'static str = "ECnd";
 
const PREFIX_BINARY_EXPR_ID: &'static str = "EBin";
 
const PREFIX_UNARY_EXPR_ID: &'static str = "EUna";
 
const PREFIX_INDEXING_EXPR_ID: &'static str = "EIdx";
 
const PREFIX_SLICING_EXPR_ID: &'static str = "ESli";
 
const PREFIX_SELECT_EXPR_ID: &'static str = "ESel";
 
const PREFIX_ARRAY_EXPR_ID: &'static str = "EArr";
 
const PREFIX_CONST_EXPR_ID: &'static str = "ECns";
 
const PREFIX_CALL_EXPR_ID: &'static str = "ECll";
 
const PREFIX_VARIABLE_EXPR_ID: &'static str = "EVar";
 

	
 
struct KV<'a> {
 
    buffer: &'a mut String,
 
    prefix: Option<(&'static str, u32)>,
 
    indent: usize,
 
    temp_key: &'a mut String,
 
    temp_val: &'a mut String,
 
}
 

	
 
impl<'a> KV<'a> {
 
    fn new(buffer: &'a mut String, temp_key: &'a mut String, temp_val: &'a mut String, indent: usize) -> Self {
 
        temp_key.clear();
 
        temp_val.clear();
 
        KV{
 
            buffer,
 
            prefix: None,
 
            indent,
 
            temp_key,
 
            temp_val
 
        }
 
    }
 

	
 
    fn with_id(mut self, prefix: &'static str, id: u32) -> Self {
 
        self.prefix = Some((prefix, id));
 
        self
 
    }
 

	
 
    fn with_s_key(self, key: &str) -> Self {
 
        self.temp_key.push_str(key);
 
        self
 
    }
 

	
 
    fn with_d_key<D: Display>(mut self, key: &D) -> Self {
 
        write!(&mut self.temp_key, "{}", key);
 
        self
 
    }
 

	
 
    fn with_s_val(self, val: &str) -> Self {
 
        self.temp_val.push_str(val);
 
        self
 
    }
 

	
 
    fn with_disp_val<D: Display>(mut self, val: &D) -> Self {
 
        write!(&mut self.temp_val, "{}", val);
 
        self
 
    }
 

	
 
    fn with_debug_val<D: Debug>(mut self, val: &D) -> Self {
 
        write!(&mut self.temp_val, "{:?}", val);
 
        self
 
    }
 

	
 
    fn with_ascii_val(self, val: &[u8]) -> Self {
 
        self.temp_val.write_str(&*String::from_utf8_lossy(val));
 
        self
 
    }
 

	
 
    fn with_opt_disp_val<D: Display>(mut self, val: Option<&D>) -> Self {
 
        match val {
 
            Some(v) => { write!(&mut self.temp_val, "Some({})", v); },
 
            None => { self.temp_val.write_str("None"); }
 
        }
 
        self
 
    }
 

	
 
    fn with_opt_ascii_val(self, val: Option<&[u8]>) -> Self {
 
        match val {
 
            Some(v) => {
 
                self.temp_val.write_str("Some(");
 
                self.temp_val.write_str(&*String::from_utf8_lossy(v));
 
                self.temp_val.write_char(')');
 
            },
 
            None => {
 
                self.temp_val.write_str("None");
 
            }
 
        }
 
        self
 
    }
 

	
 
    fn with_custom_val<F: Fn(&mut String)>(mut self, val_fn: F) -> Self {
 
        val_fn(&mut self.temp_val);
 
        self
 
    }
 
}
 

	
 
impl<'a> Drop for KV<'a> {
 
    fn drop(&mut self) {
 
        // Prefix and indent
 
        if let Some((prefix, id)) = &self.prefix {
 
            write!(&mut self.buffer, "{}[{:04}] ", prefix, id);
 
        } else {
 
            write!(&mut self.buffer, "           ");
 
        }
 

	
 
        for _ in 0..self.indent * INDENT {
 
            self.buffer.push(' ');
 
        }
 

	
 
        // Leading dash
 
        self.buffer.write_str("- ");
 

	
 
        // Key and value
 
        self.buffer.write_str(self.temp_key);
 
        if self.temp_val.is_empty() {
 
            self.buffer.push(':');
 
        } else {
 
            self.buffer.push_str(": ");
 
            self.buffer.push_str(&self.temp_val);
 
        }
 
        self.buffer.push('\n');
 
    }
 
}
 

	
 
pub(crate) struct ASTWriter {
 
    buffer: String,
 
    temp1: String,
 
    temp2: String,
 
}
 

	
 
impl ASTWriter {
 
    pub(crate) fn new() -> Self {
 
        Self{
 
            buffer: String::with_capacity(4096),
 
            temp1: String::with_capacity(256),
 
            temp2: String::with_capacity(256),
 
        }
 
    }
 
    pub(crate) fn write_ast<W: IOWrite>(&mut self, w: &mut W, heap: &Heap) {
 
        for root_id in heap.protocol_descriptions.iter().map(|v| v.this) {
 
            self.write_module(heap, root_id);
 
            w.write_all(self.buffer.as_bytes()).expect("flush buffer");
 
            self.buffer.clear();
 
        }
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Top-level module writing
 
    //--------------------------------------------------------------------------
 

	
 
    fn write_module(&mut self, heap: &Heap, root_id: RootId) {
 
        self.kv(0).with_id(PREFIX_ROOT_ID, root_id.index)
 
            .with_s_key("Module");
 

	
 
        let root = &heap[root_id];
 
        self.kv(1).with_s_key("Pragmas");
 
        for pragma_id in &root.pragmas {
 
            self.write_pragma(heap, *pragma_id, 2);
 
        }
 

	
 
        self.kv(1).with_s_key("Imports");
 
        for import_id in &root.imports {
 
            self.write_import(heap, *import_id, 2);
 
        }
 

	
 
        self.kv(1).with_s_key("Definitions");
 
        for def_id in &root.definitions {
 
            self.write_definition(heap, *def_id, 2);
 
        }
 
    }
 

	
 
    fn write_pragma(&mut self, heap: &Heap, pragma_id: PragmaId, indent: usize) {
 
        match &heap[pragma_id] {
 
            Pragma::Version(pragma) => {
 
                self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.index)
 
                    .with_s_key("PragmaVersion")
 
                    .with_disp_val(&pragma.version);
 
            },
 
            Pragma::Module(pragma) => {
 
                self.kv(indent).with_id(PREFIX_PRAGMA_ID, pragma.this.index)
 
                    .with_s_key("PragmaModule")
 
                    .with_ascii_val(&pragma.value);
 
            }
 
        }
 
    }
 

	
 
    fn write_import(&mut self, heap: &Heap, import_id: ImportId, indent: usize) {
 
        let import = &heap[import_id];
 
        let indent2 = indent + 1;
 

	
 
        match import {
 
            Import::Module(import) => {
 
                self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.index)
 
                    .with_s_key("ImportModule");
 

	
 
                self.kv(indent2).with_s_key("Name").with_ascii_val(&import.module_name);
 
                self.kv(indent2).with_s_key("Alias").with_ascii_val(&import.alias);
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.index));
 
            },
 
            Import::Symbols(import) => {
 
                self.kv(indent).with_id(PREFIX_IMPORT_ID, import.this.index)
 
                    .with_s_key("ImportSymbol");
 

	
 
                self.kv(indent2).with_s_key("Name").with_ascii_val(&import.module_name);
 
                self.kv(indent2).with_s_key("Target")
 
                    .with_opt_disp_val(import.module_id.as_ref().map(|v| &v.index));
 

	
 
                self.kv(indent2).with_s_key("Symbols");
 

	
 
                let indent3 = indent2 + 1;
 
                let indent4 = indent3 + 1;
 
                for symbol in &import.symbols {
 
                    self.kv(indent3).with_s_key("AliasedSymbol");
 
                    self.kv(indent4).with_s_key("Name").with_ascii_val(&symbol.name);
 
                    self.kv(indent4).with_s_key("Alias").with_ascii_val(&symbol.alias);
 
                    self.kv(indent4).with_s_key("Definition")
 
                        .with_opt_disp_val(symbol.definition_id.as_ref().map(|v| &v.index));
 
                }
 
            }
 
        }
 
    }
 

	
 
    //--------------------------------------------------------------------------
 
    // Top-level definition writing
 
    //--------------------------------------------------------------------------
 

	
 
    fn write_definition(&mut self, heap: &Heap, def_id: DefinitionId, indent: usize) {
 
        let indent2 = indent + 1;
 
        let indent3 = indent2 + 1;
 
        let indent4 = indent3 + 1;
 

	
 
        match &heap[def_id] {
 
            Definition::Struct(_) => todo!("implement Definition::Struct"),
 
            Definition::Enum(_) => todo!("implement Definition::Enum"),
 
            Definition::Function(_) => todo!("implement Definition::Function"),
 
            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("Parameters");
 
                for param_id in &def.parameters {
 
                    let param = &heap[*param_id];
 
                    self.kv(indent3).with_id(PREFIX_PARAMETER_ID, param_id.0.index)
 
                        .with_s_key("Parameter");
 

	
 
                    self.kv(indent4).with_s_key("Name").with_ascii_val(&param.identifier.value);
 
                    self.kv(indent4).with_s_key("Type").with_custom_val(|w| write_type(w, &heap[param.type_annotation]));
 
                }
 

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

	
 
    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");
src/protocol/lexer.rs
Show inline comments
 
@@ -1669,717 +1669,716 @@ impl Lexer<'_> {
 
            // 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,
 
            fields,
 
        }))
 
    }
 
    fn consume_enum_definition(&mut self, h: &mut Heap) -> Result<EnumId, ParseError2> {
 
        // Parse "enum" keyword and its identifier
 
        let enum_pos = self.source.pos();
 
        self.consume_keyword(b"enum")?;
 
        self.consume_whitespace(true)?;
 
        let enum_ident = self.consume_identifier()?;
 
        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_type_annotation(h)?;
 
                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,
 
            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> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"composite")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_component(|this| Component { 
 
            this, variant: ComponentVariant::Composite, position, identifier, parameters, body 
 
        }))
 
    }
 
    fn consume_primitive_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"primitive")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_component(|this| Component { 
 
            this, variant: ComponentVariant::Primitive, position, identifier, parameters, body 
 
        }))
 
    }
 
    fn consume_function_definition(&mut self, h: &mut Heap) -> Result<FunctionId, ParseError2> {
 
        let position = self.source.pos();
 
        let return_type = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_function(|this| Function {
 
            this,
 
            position,
 
            return_type,
 
            identifier,
 
            parameters,
 
            body,
 
        }))
 
    }
 
    fn has_pragma(&self) -> bool {
 
        if let Some(c) = self.source.next() {
 
            c == b'#'
 
        } else {
 
            false
 
        }
 
    }
 
    fn consume_pragma(&mut self, h: &mut Heap) -> Result<PragmaId, ParseError2> {
 
        let position = self.source.pos();
 
        let next = self.source.next();
 
        if next != Some(b'#') {
 
            return Err(self.error_at_pos("Expected pragma"));
 
        }
 
        self.source.consume();
 
        if !is_vchar(self.source.next()) {
 
            return Err(self.error_at_pos("Expected pragma"));
 
        }
 
        if self.has_string(b"version") {
 
            self.consume_string(b"version")?;
 
            self.consume_whitespace(true)?;
 
            if !self.has_integer() {
 
                return Err(self.error_at_pos("Expected integer constant"));
 
            }
 
            let version = self.consume_integer()?;
 
            debug_assert!(version >= 0);
 
            return Ok(h.alloc_pragma(|this| Pragma::Version(PragmaVersion{
 
                this, position, version: version as u64
 
            })))
 
        } else if self.has_string(b"module") {
 
            self.consume_string(b"module")?;
 
            self.consume_whitespace(true)?;
 
            if !self.has_identifier() {
 
                return Err(self.error_at_pos("Expected identifier"));
 
            }
 
            let mut value = Vec::new();
 
            let mut ident = self.consume_ident()?;
 
            value.append(&mut ident);
 
            while self.has_string(b".") {
 
                self.consume_string(b".")?;
 
                value.push(b'.');
 
                ident = self.consume_ident()?;
 
                value.append(&mut ident);
 
            }
 
            return Ok(h.alloc_pragma(|this| Pragma::Module(PragmaModule{
 
                this, position, value
 
            })));
 
        } else {
 
            return Err(self.error_at_pos("Unknown pragma"));
 
        }
 
    }
 

	
 
    fn has_import(&self) -> bool {
 
        self.has_keyword(b"import")
 
    }
 
    fn consume_import(&mut self, h: &mut Heap) -> Result<ImportId, ParseError2> {
 
        // Parse the word "import" and the name of the module
 
        let position = self.source.pos();
 
        self.consume_keyword(b"import")?;
 
        self.consume_whitespace(true)?;
 
        let mut value = Vec::new();
 
        let mut ident = self.consume_ident()?;
 
        value.append(&mut ident);
 
        let mut last_ident_start = 0;
 

	
 
        while self.has_string(b".") {
 
            self.consume_string(b".")?;
 
            value.push(b'.');
 
            ident = self.consume_ident()?;
 
            last_ident_start = value.len();
 
            value.append(&mut ident);
 
        }
 

	
 

	
 
        self.consume_whitespace(false)?;
 

	
 
        // Check for the potential aliasing or specific module imports
 
        let import = if self.has_string(b"as") {
 
            self.consume_string(b"as")?;
 
            self.consume_whitespace(true)?;
 
            let alias = self.consume_ident()?;
 

	
 
            h.alloc_import(|this| Import::Module(ImportModule{
 
                this,
 
                position,
 
                module_name: value,
 
                alias,
 
                module_id: None,
 
            }))
 
        } else if self.has_string(b"::") {
 
            self.consume_string(b"::")?;
 
            self.consume_whitespace(false)?;
 

	
 
            if let Some(b'{') = self.source.next() {
 
                // Import specific symbols, optionally with an alias
 
                self.source.consume();
 
                self.consume_whitespace(false)?;
 

	
 
                let mut symbols = Vec::new();
 
                let mut next = self.source.next();
 

	
 
                while next.is_some() {
 
                    let char = next.unwrap();
 
                    if char == b'}' {
 
                        break;
 
                    }
 

	
 
                    let symbol_position = self.source.pos();
 
                    let symbol_name = self.consume_ident()?;
 
                    self.consume_whitespace(false)?;
 
                    if self.has_string(b"as") {
 
                        // Symbol has an alias
 
                        self.consume_string(b"as")?;
 
                        self.consume_whitespace(true)?;
 
                        let symbol_alias = self.consume_ident()?;
 

	
 
                        symbols.push(AliasedSymbol{
 
                            position: symbol_position,
 
                            name: symbol_name,
 
                            alias: symbol_alias,
 
                            definition_id: None,
 
                        });
 
                    } else {
 
                        // Symbol does not have an alias
 
                        symbols.push(AliasedSymbol{
 
                            position: symbol_position,
 
                            name: symbol_name.clone(),
 
                            alias: symbol_name,
 
                            definition_id: None,
 
                        });
 
                    }
 

	
 
                    // A comma indicates that we may have another symbol coming
 
                    // up (not necessary), but if not present then we expect the
 
                    // end of the symbol list
 
                    self.consume_whitespace(false)?;
 

	
 
                    next = self.source.next();
 
                    if let Some(b',') = next {
 
                        self.source.consume();
 
                        self.consume_whitespace(false)?;
 
                        next = self.source.next();
 
                    } else {
 
                        break;
 
                    }
 
                }
 

	
 
                if let Some(b'}') = next {
 
                    // We are fine, push the imported symbols
 
                    self.source.consume();
 
                    if symbols.is_empty() {
 
                        return Err(ParseError2::new_error(self.source, position, "empty symbol import list"));
 
                    }
 

	
 
                    h.alloc_import(|this| Import::Symbols(ImportSymbols{
 
                        this,
 
                        position,
 
                        module_name: value,
 
                        module_id: None,
 
                        symbols,
 
                    }))
 
                } else {
 
                    return Err(self.error_at_pos("Expected '}'"));
 
                }
 
            } else if let Some(b'*') = self.source.next() {
 
                // Import all symbols without alias
 
                self.source.consume();
 
                h.alloc_import(|this| Import::Symbols(ImportSymbols{
 
                    this,
 
                    position,
 
                    module_name: value,
 
                    module_id: None,
 
                    symbols: Vec::new()
 
                }))
 
            } else {
 
                return Err(self.error_at_pos("Expected '*' or '{'"));
 
            }
 
        } else {
 
            // No explicit alias or subimports, so implicit alias
 
            let alias = Vec::from(&value[last_ident_start..]);
 
            h.alloc_import(|this| Import::Module(ImportModule{
 
                this,
 
                position,
 
                module_name: value,
 
                alias,
 
                module_id: None,
 
            }))
 
        };
 

	
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(import)
 
    }
 
    pub fn consume_protocol_description(&mut self, h: &mut Heap) -> Result<RootId, ParseError2> {
 
        let position = self.source.pos();
 
        let mut pragmas = Vec::new();
 
        let mut imports = Vec::new();
 
        let mut definitions = Vec::new();
 
        self.consume_whitespace(false)?;
 
        while self.has_pragma() {
 
            let pragma = self.consume_pragma(h)?;
 
            pragmas.push(pragma);
 
            self.consume_whitespace(false)?;
 
        }
 
        while self.has_import() {
 
            let import = self.consume_import(h)?;
 
            imports.push(import);
 
            self.consume_whitespace(false)?;
 
        }
 
        while self.has_symbol_definition() {
 
            let def = self.consume_symbol_definition(h)?;
 
            definitions.push(def);
 
            self.consume_whitespace(false)?;
 
        }
 
        // end of file
 
        if !self.source.is_eof() {
 
            return Err(self.error_at_pos("Expected end of file"));
 
        }
 
        Ok(h.alloc_protocol_description(|this| Root {
 
            this,
 
            position,
 
            pragmas,
 
            imports,
 
            definitions,
 
            declarations: Vec::new(),
 
        }))
 
    }
 
}
 

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

	
 
    #[test]
 
    fn test_pragmas() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
        #version 0o7777
 
        #module something.dot.separated
 
        ").expect("new InputSource");
 
        let mut lex = Lexer::new(&mut input);
 
        let lexed = lex.consume_protocol_description(&mut h)
 
            .expect("lex input source");
 
        let root = &h[lexed];
 
        assert_eq!(root.pragmas.len(), 2);
 
        let pv = &h[root.pragmas[0]];
 
        let pm = &h[root.pragmas[1]];
 

	
 
        if let Pragma::Version(v) = pv {
 
            assert_eq!(v.version, 0o7777)
 
        } else {
 
            assert!(false, "first pragma not version");
 
        }
 
        if let Pragma::Module(m) = pm {
 
            assert_eq!(m.value, b"something.dot.separated");
 
        } else {
 
            assert!(false, "second pragma not module");
 
        }
 
    }
 

	
 
    #[test]
 
    fn test_import() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
        // Module imports, with optional and explicit aliasing
 
        import single_module;
 
        import std.reo;
 
        import something.other as alias;
 
        // Symbol imports
 
        import some_module::*;
 
        import some_module::{Foo as Bar, Qux, Dix as Flu};
 
        import std.reo::{
 
            Foo as Bar, // because thing
 
            Qux as Mox, // more explanations
 
            Dix, /* yesh, import me */
 
        };
 
        ").unwrap();
 
        let mut lex = Lexer::new(&mut input);
 
        let lexed = lex.consume_protocol_description(&mut h).unwrap();
 
        let root = &h[lexed];
 
        assert_eq!(root.imports.len(), 6);
 
        let no_alias_single = h[root.imports[0]].as_module();
 
        let no_alias_multi = h[root.imports[1]].as_module();
 
        let with_alias = h[root.imports[2]].as_module();
 

	
 
        assert_eq!(no_alias_single.module_name, b"single_module");
 
        assert_eq!(no_alias_single.alias, b"single_module");
 
        assert_eq!(no_alias_multi.module_name, b"std.reo");
 
        assert_eq!(no_alias_multi.alias, b"reo");
 
        assert_eq!(with_alias.module_name, b"something.other");
 
        assert_eq!(with_alias.alias, b"alias");
 

	
 
        let all_symbols = h[root.imports[3]].as_symbols();
 
        let single_line_symbols = h[root.imports[4]].as_symbols();
 
        let multi_line_symbols = h[root.imports[5]].as_symbols();
 

	
 
        assert_eq!(all_symbols.module_name, b"some_module");
 
        assert!(all_symbols.symbols.is_empty());
 
        assert_eq!(single_line_symbols.module_name, b"some_module");
 
        assert_eq!(single_line_symbols.symbols.len(), 3);
 
        assert_eq!(single_line_symbols.symbols[0].name, b"Foo");
 
        assert_eq!(single_line_symbols.symbols[0].alias, b"Bar");
 
        assert_eq!(single_line_symbols.symbols[1].name, b"Qux");
 
        assert_eq!(single_line_symbols.symbols[1].alias, b"Qux");
 
        assert_eq!(single_line_symbols.symbols[2].name, b"Dix");
 
        assert_eq!(single_line_symbols.symbols[2].alias, b"Flu");
 
        assert_eq!(multi_line_symbols.module_name, b"std.reo");
 
        assert_eq!(multi_line_symbols.symbols.len(), 3);
 
        assert_eq!(multi_line_symbols.symbols[0].name, b"Foo");
 
        assert_eq!(multi_line_symbols.symbols[0].alias, b"Bar");
 
        assert_eq!(multi_line_symbols.symbols[1].name, b"Qux");
 
        assert_eq!(multi_line_symbols.symbols[1].alias, b"Mox");
 
        assert_eq!(multi_line_symbols.symbols[2].name, b"Dix");
 
        assert_eq!(multi_line_symbols.symbols[2].alias, b"Dix");
 
    }
 

	
 
    #[test]
 
    fn test_struct_definition() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
        struct Foo {
 
            byte one,
 
            short two,
 
            Bar three,
 
        }
 
        struct Bar{int[] one, int[] two, Qux[] three}
 
        ").unwrap();
 
        let mut lex = Lexer::new(&mut input);
 
        let lexed = lex.consume_protocol_description(&mut h);
 
        if let Err(err) = &lexed {
 
            println!("{}", err);
 
        }
 
        let lexed = lexed.unwrap();
 
        let root = &h[lexed];
 

	
 
        assert_eq!(root.definitions.len(), 2);
 

	
 
        let symbolic_type = |v: &PrimitiveType| -> Vec<u8> {
 
            if let PrimitiveType::Symbolic(v) = v {
 
                v.identifier.value.clone()
 
            } else {
 
                assert!(false);
 
                unreachable!();
 
            }
 
        };
 

	
 
        let foo_def = h[root.definitions[0]].as_struct();
 
        assert_eq!(foo_def.identifier.value, b"Foo");
 
        assert_eq!(foo_def.fields.len(), 3);
 
        assert_eq!(foo_def.fields[0].field.value, b"one");
 
        assert_eq!(h[foo_def.fields[0].the_type].the_type, Type::BYTE);
 
        assert_eq!(foo_def.fields[1].field.value, b"two");
 
        assert_eq!(h[foo_def.fields[1].the_type].the_type, Type::SHORT);
 
        assert_eq!(foo_def.fields[2].field.value, b"three");
 
        assert_eq!(
 
            symbolic_type(&h[foo_def.fields[2].the_type].the_type.primitive), 
 
            Vec::from("Bar".as_bytes())
 
        );
 

	
 
        let bar_def = h[root.definitions[1]].as_struct();
 
        assert_eq!(bar_def.identifier.value, b"Bar");
 
        assert_eq!(bar_def.fields.len(), 3);
 
        assert_eq!(bar_def.fields[0].field.value, b"one");
 
        assert_eq!(h[bar_def.fields[0].the_type].the_type, Type::INT_ARRAY);
 
        assert_eq!(bar_def.fields[1].field.value, b"two");
 
        assert_eq!(h[bar_def.fields[1].the_type].the_type, Type::INT_ARRAY);
 
        assert_eq!(bar_def.fields[2].field.value, b"three");
 
        assert_eq!(h[bar_def.fields[2].the_type].the_type.array, true);
 
        assert_eq!(
 
            symbolic_type(&h[bar_def.fields[2].the_type].the_type.primitive), 
 
            Vec::from("Qux".as_bytes())
 
        );
 
    }
 

	
 
    #[test]
 
    fn test_enum_definition() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
        enum Foo {
 
            A = 0,
 
            B = 5,
 
            C,
 
            D = 0xFF,
 
        }
 
        enum Bar { Ayoo, Byoo, Cyoo,}
 
        enum Qux { A(byte[]), B(Bar[]), C(byte)
 
        }
 
        ").unwrap();
 
        let mut lex = Lexer::new(&mut input);
 
        let lexed = lex.consume_protocol_description(&mut h).unwrap();
 
        let root = &h[lexed];
 

	
 
        assert_eq!(root.definitions.len(), 3);
 

	
 
        let foo_def = h[root.definitions[0]].as_enum();
 
        assert_eq!(foo_def.identifier.value, b"Foo");
 
        assert_eq!(foo_def.variants.len(), 4);
 
        assert_eq!(foo_def.variants[0].identifier.value, b"A");
 
        assert_eq!(foo_def.variants[0].value, EnumVariantValue::Integer(0));
 
        assert_eq!(foo_def.variants[1].identifier.value, b"B");
 
        assert_eq!(foo_def.variants[1].value, EnumVariantValue::Integer(5));
 
        assert_eq!(foo_def.variants[2].identifier.value, b"C");
 
        assert_eq!(foo_def.variants[2].value, EnumVariantValue::None);
 
        assert_eq!(foo_def.variants[3].identifier.value, b"D");
 
        assert_eq!(foo_def.variants[3].value, EnumVariantValue::Integer(0xFF));
 

	
 
        let bar_def = h[root.definitions[1]].as_enum();
 
        assert_eq!(bar_def.identifier.value, b"Bar");
 
        assert_eq!(bar_def.variants.len(), 3);
 
        assert_eq!(bar_def.variants[0].identifier.value, b"Ayoo");
 
        assert_eq!(bar_def.variants[0].value, EnumVariantValue::None);
 
        assert_eq!(bar_def.variants[1].identifier.value, b"Byoo");
 
        assert_eq!(bar_def.variants[1].value, EnumVariantValue::None);
 
        assert_eq!(bar_def.variants[2].identifier.value, b"Cyoo");
 
        assert_eq!(bar_def.variants[2].value, EnumVariantValue::None);
 

	
 
        let qux_def = h[root.definitions[2]].as_enum();
 
        let enum_type = |value: &EnumVariantValue| -> &TypeAnnotation {
 
            if let EnumVariantValue::Type(t) = value {
 
                &h[*t]
 
            } else {
 
                assert!(false);
 
                unreachable!();
 
            }
 
        };
 
        assert_eq!(qux_def.identifier.value, b"Qux");
 
        assert_eq!(qux_def.variants.len(), 3);
 
        assert_eq!(qux_def.variants[0].identifier.value, b"A");
 
        assert_eq!(enum_type(&qux_def.variants[0].value).the_type, Type::BYTE_ARRAY);
 
        assert_eq!(qux_def.variants[1].identifier.value, b"B");
 
        assert_eq!(enum_type(&qux_def.variants[1].value).the_type.array, true);
 
        if let PrimitiveType::Symbolic(t) = &enum_type(&qux_def.variants[1].value).the_type.primitive {
 
            assert_eq!(t.identifier.value, Vec::from("Bar".as_bytes()));
 
        } else { assert!(false) }
 

	
 
        assert_eq!(qux_def.variants[2].identifier.value, b"C");
 
        assert_eq!(enum_type(&qux_def.variants[2].value).the_type, Type::BYTE);
 
    }
 

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

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

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

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

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

	
 
//     #[test]
 
//     fn test_statement() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string(
 
//             "label: while (true) { if (x++ > y[0]) break label; else continue; }\n",
 
//         )
 
//         .unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_statement(&mut h) {
 
//             Ok(stmt) => {
 
//                 println!("{:#?}", stmt);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 
}
src/protocol/library.rs
Show inline comments
 
deleted file
src/protocol/mod.rs
Show inline comments
 
mod arena;
 
// mod ast;
 
mod eval;
 
pub(crate) mod inputsource;
 
// mod lexer;
 
mod library;
 
mod parser;
 

	
 
// TODO: Remove when not benchmarking
 
pub(crate) mod ast;
 
pub(crate) mod ast_printer;
 
pub(crate) mod lexer;
 

	
 
lazy_static::lazy_static! {
 
    /// Conveniently-provided protocol description initialized with a zero-length PDL string.
 
    /// Exposed to minimize repeated initializations of this common protocol description.
 
    pub static ref TRIVIAL_PD: std::sync::Arc<ProtocolDescription> = {
 
        std::sync::Arc::new(ProtocolDescription::parse(b"").unwrap())
 
    };
 
}
 

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

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

	
 
impl std::fmt::Debug for ProtocolDescription {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 
        write!(f, "(An opaque protocol description)")
 
    }
 
}
 
impl ProtocolDescription {
 
    pub fn parse(buffer: &[u8]) -> Result<Self, String> {
 
        // TODO: @fixme, keep code compilable, but needs support for multiple
 
        //  input files.
 
        let source = InputSource::from_buffer(buffer).unwrap();
 
        let mut parser = Parser::new();
 
        parser.feed(source).expect("failed to parse source");
 
        match parser.parse() {
 
            Ok(root) => {
 
                return Ok(ProtocolDescription { heap: parser.heap, source: parser.modules[0].source.clone(), root });
 
            }
 
            Err(err) => {
 
                println!("ERROR:\n{}", err);
 
                Err(format!("{}", err))
 
            }
 
        }
 
    }
 
    pub(crate) fn component_polarities(
 
        &self,
 
        identifier: &[u8],
 
    ) -> Result<Vec<Polarity>, AddComponentError> {
 
        use AddComponentError::*;
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier);
 
        if def.is_none() {
 
            return Err(NoSuchComponent);
 
        }
 
        let def = &h[def.unwrap()];
 
        if !def.is_component() {
 
            return Err(NoSuchComponent);
 
        }
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            if type_annot.the_type.array {
 
                return Err(NonPortTypeParameters);
 
            }
 
            match type_annot.the_type.primitive {
 
                PrimitiveType::Input | PrimitiveType::Output => continue,
 
                _ => {
 
                    return Err(NonPortTypeParameters);
 
                }
 
            }
 
        }
 
        let mut result = Vec::new();
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            let ptype = &type_annot.the_type.primitive;
 
            if ptype == &PrimitiveType::Input {
 
                result.push(Polarity::Getter)
 
            } else if ptype == &PrimitiveType::Output {
 
                result.push(Polarity::Putter)
 
            } else {
 
                unreachable!()
 
            }
 
        }
 
        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!(),
 
            },
 
        }
 
    }
 
}
src/protocol/parser/depth_visitor.rs
Show inline comments
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::library;
 

	
 
// 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 {
 
@@ -399,1095 +398,820 @@ fn recursive_synchronous_statement<T: Visitor>(
 
    //     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()));
 
        }
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct FunctionStatementReturns {}
 

	
 
impl FunctionStatementReturns {
 
    pub(crate) fn new() -> Self {
 
        FunctionStatementReturns {}
 
    }
 
    fn function_error(&self, position: InputPosition) -> VisitorResult {
 
        Err((position, "Function definition must return".to_string()))
 
    }
 
}
 

	
 
impl Visitor for FunctionStatementReturns {
 
    fn visit_component_definition(&mut self, _h: &mut Heap, _def: ComponentId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_variable_declaration(&mut self, _h: &mut Heap, _decl: VariableId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, block: BlockStatementId) -> VisitorResult {
 
        let len = h[block].statements.len();
 
        assert!(len > 0);
 
        self.visit_statement(h, h[block].statements[len - 1])
 
    }
 
    fn visit_skip_statement(&mut self, h: &mut Heap, stmt: SkipStatementId) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_break_statement(&mut self, h: &mut Heap, stmt: BreakStatementId) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_assert_statement(&mut self, h: &mut Heap, stmt: AssertStatementId) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_expression_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ExpressionStatementId,
 
    ) -> VisitorResult {
 
        self.function_error(h[stmt].position)
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct ComponentStatementReturnNew {
 
    illegal_new: bool,
 
    illegal_return: bool,
 
}
 

	
 
impl ComponentStatementReturnNew {
 
    pub(crate) fn new() -> Self {
 
        ComponentStatementReturnNew { illegal_new: false, illegal_return: false }
 
    }
 
}
 

	
 
impl Visitor for ComponentStatementReturnNew {
 
    fn visit_component_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!(self.illegal_new || self.illegal_return));
 
        self.illegal_return = true;
 
        recursive_component_definition(self, h, def)?;
 
        self.illegal_return = false;
 
        Ok(())
 
    }
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal_new);
 
        self.illegal_new = true;
 
        recursive_primitive_definition(self, h, def)?;
 
        self.illegal_new = false;
 
        Ok(())
 
    }
 
    fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionId) -> VisitorResult {
 
        assert!(!(self.illegal_new || self.illegal_return));
 
        self.illegal_new = true;
 
        recursive_function_definition(self, h, def)?;
 
        self.illegal_new = false;
 
        Ok(())
 
    }
 
    fn visit_variable_declaration(&mut self, _h: &mut Heap, _decl: VariableId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_return_statement(&mut self, h: &mut Heap, stmt: ReturnStatementId) -> VisitorResult {
 
        if self.illegal_return {
 
            Err((h[stmt].position, "Component definition must not return".to_string()))
 
        } else {
 
            recursive_return_statement(self, h, stmt)
 
        }
 
    }
 
    fn visit_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        if self.illegal_new {
 
            Err((
 
                h[stmt].position,
 
                "Symbol definition contains illegal new statement".to_string(),
 
            ))
 
        } else {
 
            recursive_new_statement(self, h, stmt)
 
        }
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct CheckBuiltinOccurrences {
 
    legal: bool,
 
}
 

	
 
impl CheckBuiltinOccurrences {
 
    pub(crate) fn new() -> Self {
 
        CheckBuiltinOccurrences { legal: false }
 
    }
 
}
 

	
 
impl Visitor for CheckBuiltinOccurrences {
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(!self.legal);
 
        self.legal = true;
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.legal = false;
 
        Ok(())
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        match h[expr].method {
 
            Method::Get | Method::Fires => {
 
                if !self.legal {
 
                    return Err((h[expr].position, "Illegal built-in occurrence".to_string()));
 
                }
 
            }
 
            _ => {}
 
        }
 
        recursive_call_expression(self, h, expr)
 
    }
 
}
 

	
 
pub(crate) struct BuildSymbolDeclarations {
 
    declarations: Vec<DeclarationId>,
 
}
 

	
 
impl BuildSymbolDeclarations {
 
    pub(crate) fn new() -> Self {
 
        BuildSymbolDeclarations { declarations: Vec::new() }
 
    }
 
    fn checked_add(&mut self, h: &mut Heap, decl: DeclarationId) -> VisitorResult {
 
        for &old in self.declarations.iter() {
 
            let id = h[decl].identifier();
 
            if id.value == h[old].identifier().value {
 
                return match h[decl].clone() {
 
                    Declaration::Defined(defined) => Err((
 
                        h[defined.definition].position(),
 
                        format!("Defined symbol clash: {}", String::from_utf8_lossy(&id.value)),
 
                    )),
 
                    Declaration::Imported(imported) => Err((
 
                        h[imported.import].position(),
 
                        format!("Imported symbol clash: {}", String::from_utf8_lossy(&id.value)),
 
                    )),
 
                };
 
            }
 
        }
 
        self.declarations.push(decl);
 
        Ok(())
 
    }
 
}
 

	
 
impl Visitor for BuildSymbolDeclarations {
 
    fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> VisitorResult {
 
        recursive_protocol_description(self, h, pd)?;
 
        // Move all collected declarations to the protocol description
 
        h[pd].declarations.append(&mut self.declarations);
 
        Ok(())
 
    }
 
    fn visit_import(&mut self, h: &mut Heap, import: ImportId) -> VisitorResult {
 
        // println!("DEBUG: Warning (at {}:{}), import actually not yet implemented", file!(), line!());
 
        // TODO: Implement
 
        let vec = library::get_declarations(h, import);
 
        if let Err(_err)= vec {
 
            return Err((h[import].position(), "Failed to perform import".to_string()))
 
        }
 

	
 
        // Destructively iterate over the vector
 
        for decl in vec.unwrap() {
 
            self.checked_add(h, decl)?;
 
        }
 
        Ok(())
 
    }
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, definition: DefinitionId) -> VisitorResult {
 
        let signature = Signature::from_definition(h, definition);
 
        let decl = h
 
            .alloc_defined_declaration(|this| DefinedDeclaration { this, definition, signature })
 
            .upcast();
 
        self.checked_add(h, decl)?;
 
        Ok(())
 
    }
 
}
 

	
 
pub(crate) struct LinkCallExpressions {
 
    pd: Option<RootId>,
 
    composite: bool,
 
    new_statement: bool,
 
}
 

	
 
impl LinkCallExpressions {
 
    pub(crate) fn new() -> Self {
 
        LinkCallExpressions { pd: None, composite: false, new_statement: false }
 
    }
 
    fn get_declaration(
 
        &self,
 
        h: &Heap,
 
        id: &Identifier,
 
    ) -> Result<DeclarationId, VisitorError> {
 
        match h[self.pd.unwrap()].get_declaration(h, &id) {
 
            Some(id) => Ok(id),
 
            None => Err((id.position, "Unresolved method".to_string())),
 
        }
 
    }
 
    fn get_declaration_namespaced(
 
        &self, h: &Heap, id: &NamespacedIdentifier
 
    ) -> Result<DeclarationId, VisitorError> {
 
        // TODO: @fixme
 
        match h[self.pd.unwrap()].get_declaration_namespaced(h, id) {
 
            Some(id) => Ok(id),
 
            None => Err((id.position, "Unresolved method".to_string()))
 
        }
 
    }
 
}
 

	
 
impl Visitor for LinkCallExpressions {
 
    fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> VisitorResult {
 
        self.pd = Some(pd);
 
        recursive_protocol_description(self, h, pd)?;
 
        self.pd = None;
 
        Ok(())
 
    }
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.composite);
 
        self.composite = true;
 
        recursive_composite_definition(self, h, def)?;
 
        self.composite = false;
 
        Ok(())
 
    }
 
    fn visit_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        assert!(self.composite);
 
        assert!(!self.new_statement);
 
        self.new_statement = true;
 
        recursive_new_statement(self, h, stmt)?;
 
        self.new_statement = false;
 
        Ok(())
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        if let Method::Symbolic(id) = &h[expr].method {
 
            // TODO: @symbol_table
 
            let decl = self.get_declaration_namespaced(h, &id.identifier)?;
 
            if self.new_statement && h[decl].is_function() {
 
                return Err((id.identifier.position, "Illegal call expression".to_string()));
 
            }
 
            if !self.new_statement && h[decl].is_component() {
 
                return Err((id.identifier.position, "Illegal call expression".to_string()));
 
            }
 
            // Set the corresponding declaration of the call
 
            // TODO: This should not be necessary anymore once parser is rewritten
 
            // h[expr]. = Some(decl);
 
        }
 
        // A new statement's call expression may have as arguments function calls
 
        let old = self.new_statement;
 
        self.new_statement = false;
 
        recursive_call_expression(self, h, expr)?;
 
        self.new_statement = old;
 
        Ok(())
 
    }
 
}
 

	
 
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 ResolveVariables {
 
    scope: Option<Scope>,
 
}
 

	
 
impl ResolveVariables {
 
    pub(crate) fn new() -> Self {
 
        ResolveVariables { scope: None }
 
    }
 
    fn get_variable(&self, h: &Heap, id: &Identifier) -> Result<VariableId, VisitorError> {
 
        if let Some(var) = self.find_variable(h, id) {
 
            Ok(var)
 
        } else {
 
            Err((id.position, "Unresolved variable".to_string()))
 
        }
 
    }
 
    fn find_variable(&self, h: &Heap, id: &Identifier) -> Option<VariableId> {
 
        ResolveVariables::find_variable_impl(h, self.scope, id)
 
    }
 
    fn find_variable_impl(
 
        h: &Heap,
 
        scope: Option<Scope>,
 
        id: &Identifier,
 
    ) -> Option<VariableId> {
 
        if let Some(scope) = scope {
 
            // The order in which we check for variables is important:
 
            // otherwise, two variables with the same name are shadowed.
 
            if let Some(var) = ResolveVariables::find_variable_impl(h, scope.parent_scope(h), id) {
 
                Some(var)
 
            } else {
 
                scope.get_variable(h, id)
 
            }
 
        } else {
 
            None
 
        }
 
    }
 
}
 

	
 
impl Visitor for ResolveVariables {
 
    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_variable_declaration(&mut self, h: &mut Heap, decl: VariableId) -> VisitorResult {
 
        // This is only called for parameters of definitions and synchronous statements,
 
        // since the local variables of block statements are still empty
 
        // the moment it is traversed. After resolving variables, this
 
        // function is also called for every local variable declaration.
 

	
 
        // We want to make sure that the resolved variable is the variable declared itself;
 
        // otherwise, there is some variable defined in the parent scope. This check
 
        // imposes that the order in which find_variable looks is significant!
 
        let id = h[decl].identifier();
 
        let check_same = self.find_variable(h, id);
 
        if let Some(check_same) = check_same {
 
            if check_same != decl {
 
                return Err((id.position, "Declared variable clash".to_string()));
 
            }
 
        }
 
        recursive_variable_declaration(self, h, decl)
 
    }
 
    fn visit_memory_statement(&mut self, h: &mut Heap, stmt: MemoryStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let var = h[stmt].variable;
 
        let id = &h[var].identifier;
 
        // First check whether variable with same identifier is in scope
 
        let check_duplicate = self.find_variable(h, id);
 
        if check_duplicate.is_some() {
 
            return Err((id.position, "Declared variable clash".to_string()));
 
        }
 
        // Then check the expression's variables (this should not refer to own variable)
 
        recursive_memory_statement(self, h, stmt)?;
 
        // Finally, we may add the variable to the scope, which is guaranteed to be a block
 
        {
 
            let block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        Ok(())
 
    }
 
    fn visit_channel_statement(&mut self, h: &mut Heap, stmt: ChannelStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        // First handle the from variable
 
        {
 
            let var = h[stmt].from;
 
            let id = &h[var].identifier;
 
            let check_duplicate = self.find_variable(h, id);
 
            if check_duplicate.is_some() {
 
                return Err((id.position, "Declared variable clash".to_string()));
 
            }
 
            let block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        // Then handle the to variable (which may not be the same as the from)
 
        {
 
            let var = h[stmt].to;
 
            let id = &h[var].identifier;
 
            let check_duplicate = self.find_variable(h, id);
 
            if check_duplicate.is_some() {
 
                return Err((id.position, "Declared variable clash".to_string()));
 
            }
 
            let block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        self.scope = Some(Scope::Regular(stmt));
 
        recursive_block_statement(self, h, stmt)?;
 
        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;
 
        self.scope = Some(Scope::Synchronous((stmt, BlockStatementId(stmt.upcast())))); // TODO: WRONG!
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: VariableExpressionId,
 
    ) -> VisitorResult {
 
        let ident = Identifier{ position: Default::default(), value: h[expr].identifier.value.clone() };
 
        let var = self.get_variable(h, &ident)?;
 
        h[expr].declaration = Some(var);
 
        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((
 
                    h[stmt].position,
 
                    "Illegal continue: target not a while statement".to_string(),
 
                ));
 
            }
 
            the_while = target.as_while();
 
            // TODO: check if continue is nested under while
 
        } else {
 
            if self.while_enclosure.is_none() {
 
                return Err((
 
                    h[stmt].position,
 
                    "Illegal continue: no surrounding while statement".to_string(),
 
                ));
 
            }
 
            the_while = &h[self.while_enclosure.unwrap()];
 
            // continue is always nested under while, by recursive vistor
 
        }
 
        if the_while.in_sync != self.sync_enclosure {
 
            return Err((
 
                h[stmt].position,
 
                "Illegal continue: synchronous statement escape".to_string(),
 
            ));
 
        }
 
        h[stmt].target = Some(the_while.this);
 
        Ok(())
 
    }
 
    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_goto_statement(&mut self, h: &mut Heap, stmt: GotoStatementId) -> VisitorResult {
 
        let target = self.get_target(h, &h[stmt].label)?;
 
        if h[target].in_sync != self.sync_enclosure {
 
            return Err((
 
                h[stmt].position,
 
                "Illegal goto: synchronous statement escape".to_string(),
 
            ));
 
        }
 
        h[stmt].target = Some(target);
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, _h: &mut Heap, _expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
src/protocol/parser/mod.rs
Show inline comments
 
mod depth_visitor;
 
mod symbol_table;
 
mod type_table;
 
mod type_resolver;
 
mod visitor;
 
mod visitor_linker;
 

	
 
use depth_visitor::*;
 
use symbol_table::SymbolTable;
 
use visitor::Visitor2;
 
use visitor_linker::ValidityAndLinkerVisitor;
 
use type_table::TypeTable;
 

	
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::lexer::*;
 

	
 
use std::collections::HashMap;
 
use crate::protocol::parser::visitor::Ctx;
 
use crate::protocol::ast_printer::ASTWriter;
 

	
 
// TODO: @fixme, pub qualifier
 
pub(crate) struct LexedModule {
 
    pub(crate) source: InputSource,
 
    module_name: Vec<u8>,
 
    version: Option<u64>,
 
    root_id: RootId,
 
}
 

	
 
pub struct Parser {
 
    pub(crate) heap: Heap,
 
    pub(crate) modules: Vec<LexedModule>,
 
    pub(crate) module_lookup: HashMap<Vec<u8>, usize>, // from (optional) module name to `modules` idx
 
}
 

	
 
impl Parser {
 
    pub fn new() -> Self {
 
        Parser{
 
            heap: Heap::new(),
 
            modules: Vec::new(),
 
            module_lookup: HashMap::new()
 
        }
 
    }
 

	
 
    // TODO: @fix, temporary implementation to keep code compilable
 
    pub fn new_with_source(source: InputSource) -> Result<Self, ParseError2> {
 
        let mut parser = Parser::new();
 
        parser.feed(source)?;
 
        Ok(parser)
 
    }
 

	
 
    pub fn feed(&mut self, mut source: InputSource) -> Result<RootId, ParseError2> {
 
        // Lex the input source
 
        let mut lex = Lexer::new(&mut source);
 
        let pd = lex.consume_protocol_description(&mut self.heap)?;
 

	
 
        // Seek the module name and version
 
        let root = &self.heap[pd];
 
        let mut module_name_pos = InputPosition::default();
 
        let mut module_name = Vec::new();
 
        let mut module_version_pos = InputPosition::default();
 
        let mut module_version = None;
 

	
 
        for pragma in &root.pragmas {
 
            match &self.heap[*pragma] {
 
                Pragma::Module(module) => {
 
                    if !module_name.is_empty() {
 
                        return Err(
 
                            ParseError2::new_error(&source, module.position, "Double definition of module name in the same file")
 
                                .with_postfixed_info(&source, module_name_pos, "Previous definition was here")
 
                        )
 
                    }
 

	
 
                    module_name_pos = module.position.clone();
 
                    module_name = module.value.clone();
 
                },
 
                Pragma::Version(version) => {
 
                    if module_version.is_some() {
 
                        return Err(
 
                            ParseError2::new_error(&source, version.position, "Double definition of module version")
 
                                .with_postfixed_info(&source, module_version_pos, "Previous definition was here")
 
                        )
 
                    }
 

	
 
                    module_version_pos = version.position.clone();
 
                    module_version = Some(version.version);
 
                },
 
            }
 
        }
 

	
 
        // Add module to list of modules and prevent naming conflicts
 
        let cur_module_idx = self.modules.len();
 
        if let Some(prev_module_idx) = self.module_lookup.get(&module_name) {
 
            // Find `#module` statement in other module again
 
            let prev_module = &self.modules[*prev_module_idx];
 
            let prev_module_pos = self.heap[prev_module.root_id].pragmas
 
                .iter()
 
                .find_map(|p| {
 
                    match &self.heap[*p] {
 
                        Pragma::Module(module) => Some(module.position.clone()),
 
                        _ => None
 
                    }
 
                })
 
                .unwrap_or(InputPosition::default());
 

	
 
            let module_name_msg = if module_name.is_empty() {
 
                format!("a nameless module")
 
            } else {
 
                format!("module '{}'", String::from_utf8_lossy(&module_name))
 
            };
 

	
 
            return Err(
 
                ParseError2::new_error(&source, module_name_pos, &format!("Double definition of {} across files", module_name_msg))
 
                    .with_postfixed_info(&prev_module.source, prev_module_pos, "Other definition was here")
 
            );
 
        }
 

	
 
        self.modules.push(LexedModule{
 
            source,
 
            module_name: module_name.clone(),
 
            version: module_version,
 
            root_id: pd
 
        });
 
        self.module_lookup.insert(module_name, cur_module_idx);
 
        Ok(pd)
 
    }
 

	
 
    pub fn compile(&mut self) {
 
        // Build module lookup
 
    }
 

	
 
    fn resolve_symbols_and_types(&mut self) -> Result<(SymbolTable, TypeTable), ParseError2> {
 
        // Construct the symbol table to resolve any imports and/or definitions,
 
        // then use the symbol table to actually annotate all of the imports.
 
        // If the type table is constructed correctly then all imports MUST be
 
        // resolvable.
 
        // TODO: Update once namespaced identifiers are implemented
 
        let symbol_table = SymbolTable::new(&self.heap, &self.modules)?;
 

	
 
        // Not pretty, but we need to work around rust's borrowing rules, it is
 
        // totally safe to mutate the contents of an AST element that we are
 
        // not borrowing anywhere else.
 
        // TODO: Maybe directly access heap's members to allow borrowing from
 
        //  mutliple members of Heap? Not pretty though...
 
        let mut module_index = 0;
 
        let mut import_index = 0;
 
        loop {
 
            if module_index >= self.modules.len() {
 
                break;
 
            }
 

	
 
            let module_root_id = self.modules[module_index].root_id;
 
            let import_id = {
 
                let root = &self.heap[module_root_id];
 
                if import_index >= root.imports.len() {
 
                    module_index += 1;
 
                    import_index = 0;
 
                    continue
 
                }
 
                root.imports[import_index]
 
            };
 

	
 
            let import = &mut self.heap[import_id];
 
            match import {
 
                Import::Module(import) => {
 
                    debug_assert!(import.module_id.is_none(), "module import already resolved");
 
                    let target_module_id = symbol_table.resolve_module(&import.module_name)
 
                        .expect("module import is resolved by symbol table");
 
                    import.module_id = Some(target_module_id)
 
                },
 
                Import::Symbols(import) => {
 
                    debug_assert!(import.module_id.is_none(), "module of symbol import already resolved");
 
                    let target_module_id = symbol_table.resolve_module(&import.module_name)
 
                        .expect("symbol import's module is resolved by symbol table");
 
                    import.module_id = Some(target_module_id);
 

	
 
                    for symbol in &mut import.symbols {
 
                        debug_assert!(symbol.definition_id.is_none(), "symbol import already resolved");
 
                        let (_, target_definition_id) = symbol_table.resolve_symbol(module_root_id, &symbol.alias)
 
                            .expect("symbol import is resolved by symbol table")
 
                            .as_definition()
 
                            .expect("symbol import does not resolve to namespace symbol");
 
                        symbol.definition_id = Some(target_definition_id);
 
                    }
 
                }
 
            }
 
        }
 

	
 
        // All imports in the AST are now annotated. We now use the symbol table
 
        // to construct the type table.
 
        let type_table = TypeTable::new(&symbol_table, &self.heap, &self.modules)?;
 

	
 
        Ok((symbol_table, type_table))
 
    }
 

	
 
    // TODO: @fix, temporary impl to keep code compilable
 
    pub fn parse(&mut self) -> Result<RootId, ParseError2> {
 
        assert_eq!(self.modules.len(), 1, "Fix meeeee");
 
        let root_id = self.modules[0].root_id;
 

	
 
        let (mut symbol_table, mut type_table) = self.resolve_symbols_and_types()?;
 

	
 
        // TODO: @cleanup
 
        let mut ctx = visitor::Ctx{
 
            heap: &mut self.heap,
 
            module: &self.modules[0],
 
            symbols: &mut symbol_table,
 
            types: &mut type_table,
 
        };
 
        let mut visit = ValidityAndLinkerVisitor::new();
 
        visit.visit_module(&mut ctx)?;
 

	
 
        if let Err((position, message)) = Self::parse_inner(&mut self.heap, root_id) {
 
            return Err(ParseError2::new_error(&self.modules[0].source, position, &message))
 
        }
 

	
 
        // let mut writer = ASTWriter::new();
 
        // let mut file = std::fs::File::create(std::path::Path::new("ast.txt")).unwrap();
 
        // writer.write_ast(&mut file, &self.heap);
 

	
 
        Ok(root_id)
 
    }
 

	
 
    pub fn parse_inner(h: &mut Heap, pd: RootId) -> VisitorResult {
 
        // TODO: @cleanup, slowly phasing out old compiler
 
        // NestedSynchronousStatements::new().visit_protocol_description(h, pd)?;
 
        // ChannelStatementOccurrences::new().visit_protocol_description(h, pd)?;
 
        // FunctionStatementReturns::new().visit_protocol_description(h, pd)?;
 
        // ComponentStatementReturnNew::new().visit_protocol_description(h, pd)?;
 
        // CheckBuiltinOccurrences::new().visit_protocol_description(h, pd)?;
 
        // BuildSymbolDeclarations::new().visit_protocol_description(h, pd)?;
 
        // LinkCallExpressions::new().visit_protocol_description(h, pd)?;
 
        // BuildScope::new().visit_protocol_description(h, pd)?;
 
        // ResolveVariables::new().visit_protocol_description(h, pd)?;
 
        LinkStatements::new().visit_protocol_description(h, pd)?;
 
        // BuildLabels::new().visit_protocol_description(h, pd)?;
 
        // ResolveLabels::new().visit_protocol_description(h, pd)?;
 
        AssignableExpressions::new().visit_protocol_description(h, pd)?;
 
        IndexableExpressions::new().visit_protocol_description(h, pd)?;
 
        SelectableExpressions::new().visit_protocol_description(h, pd)?;
 

	
 
        Ok(())
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    use std::fs::File;
 
    use std::io::Read;
 
    use std::path::Path;
 

	
 
    use super::*;
 

	
 
    // #[test]
 
    fn positive_tests() {
 
        for resource in TestFileIter::new("testdata/parser/positive", "pdl") {
 
            let resource = resource.expect("read testdata filepath");
 
            // println!(" * running: {}", &resource);
 
            let path = Path::new(&resource);
 
            let source = InputSource::from_file(&path).unwrap();
 
            // println!("DEBUG -- input:\n{}", String::from_utf8_lossy(&source.input));
 
            let mut parser = Parser::new_with_source(source).expect("parse source");
 
            match parser.parse() {
 
                Ok(_) => {}
 
                Err(err) => {
 
                    println!(" > file: {}", &resource);
 
                    println!("{}", err);
 
                    assert!(false);
 
                }
 
            }
 
        }
 
    }
 

	
 
    // #[test]
 
    fn negative_tests() {
 
        for resource in TestFileIter::new("testdata/parser/negative", "pdl") {
 
            let resource = resource.expect("read testdata filepath");
 
            let path = Path::new(&resource);
 
            let expect = path.with_extension("txt");
 
            let mut source = InputSource::from_file(&path).unwrap();
 
            let mut parser = Parser::new_with_source(source).expect("construct parser");
 
            match parser.parse() {
 
                Ok(pd) => {
 
                    println!("Expected parse error:");
 

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

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

	
 
                    assert_eq!(expected.as_bytes(), cev);
 
                }
 
            }
 
        }
 
    }
 

	
 
    // #[test]
 
    fn counterexample_tests() {
 
        for resource in TestFileIter::new("testdata/parser/counterexamples", "pdl") {
 
            let resource = resource.expect("read testdata filepath");
 
            let path = Path::new(&resource);
 
            let source = InputSource::from_file(&path).unwrap();
 
            let mut parser = Parser::new_with_source(source).expect("construct parser");
 

	
 
            fn print_header(s: &str) {
 
                println!("{}", "=".repeat(80));
 
                println!(" > File: {}", s);
 
                println!("{}", "=".repeat(80));
 
            }
 

	
 
            match parser.parse() {
 
                Ok(parsed) => {
 
                    print_header(&resource);
 
                    println!("\n  SUCCESS\n\n --- source:\n{}", String::from_utf8_lossy(&parser.modules[0].source.input));
 
                },
 
                Err(err) => {
 
                    print_header(&resource);
 
                    println!(
 
                        "\n  FAILURE\n\n --- error:\n{}\n --- source:\n{}",
 
                        err,
 
                        String::from_utf8_lossy(&parser.modules[0].source.input)
 
                    )
 
                }
 
            }
 
        }
 
    }
 

	
 
    struct TestFileIter {
 
        iter: std::fs::ReadDir,
 
        root: String,
 
        extension: String
 
    }
 

	
 
    impl TestFileIter {
 
        fn new(root_dir: &str, extension: &str) -> Self {
 
            let path = Path::new(root_dir);
 
            assert!(path.is_dir(), "root '{}' is not a directory", root_dir);
 

	
 
            let iter = std::fs::read_dir(path).expect("list dir contents");
 

	
 
            Self {
 
                iter,
 
                root: root_dir.to_string(),
 
                extension: extension.to_string(),
 
            }
 
        }
 
    }
 

	
 
    impl Iterator for TestFileIter {
 
        type Item = Result<String, String>;
 

	
 
        fn next(&mut self) -> Option<Self::Item> {
 
            while let Some(entry) = self.iter.next() {
 
                if let Err(e) = entry {
 
                    return Some(Err(format!("failed to read dir entry, because: {}", e)));
 
                }
 
                let entry = entry.unwrap();
 

	
 
                let path = entry.path();
 
                if !path.is_file() { continue; }
 

	
 
                let extension = path.extension();
 
                if extension.is_none() { continue; }
 
                let extension = extension.unwrap().to_string_lossy();
 
                if extension != self.extension { continue; }
 

	
 
                return Some(Ok(path.to_string_lossy().to_string()));
 
            }
 

	
 
            None
 
        }
 
    }
 
}
0 comments (0 inline, 0 general)