From 120857c659916d67564cb5b3dcbcb21b17b1f41d 2021-05-27 18:17:47 From: MH Date: 2021-05-27 18:17:47 Subject: [PATCH] Second round of dead code removal --- diff --git a/src/collections/scoped_buffer.rs b/src/collections/scoped_buffer.rs index 1416a1634df2816c4b7127dcec1ded5ec63a6a64..4827b030ab01d643a3d8d98e4b2d38894fdbec09 100644 --- a/src/collections/scoped_buffer.rs +++ b/src/collections/scoped_buffer.rs @@ -43,12 +43,12 @@ impl ScopedBuffer { impl ScopedBuffer { pub(crate) fn start_section_initialized(&mut self, initialize_with: &[T]) -> ScopedSection { let start_size = self.inner.len() as u32; - let data_size = initialize_with.len() as u32; + let _data_size = initialize_with.len() as u32; self.inner.extend_from_slice(initialize_with); ScopedSection{ inner: &mut self.inner, start_size, - #[cfg(debug_assertions)] cur_size: start_size + data_size, + #[cfg(debug_assertions)] cur_size: start_size + _data_size, } } } diff --git a/src/protocol/arena.rs b/src/protocol/arena.rs index 10c90a1186f6bcb9d75f73502bc6b69fc305cb0d..6afdc88e49dc4a56b392a9dc204d7a664cb8713d 100644 --- a/src/protocol/arena.rs +++ b/src/protocol/arena.rs @@ -10,9 +10,9 @@ pub struct Id { } impl Id { - pub(crate) fn new_invalid() -> Self { Self{ index: -1, _phantom: Default::default() } } - pub(crate) fn new(index: i32) -> Self { Self{ index, _phantom: Default::default() } } - pub(crate) fn is_invalid(&self) -> bool { self.index < 0 } + #[inline] pub(crate) fn new_invalid() -> Self { Self{ index: -1, _phantom: Default::default() } } + #[inline] pub(crate) fn new(index: i32) -> Self { Self{ index, _phantom: Default::default() } } + #[inline] pub(crate) fn is_invalid(&self) -> bool { self.index < 0 } } #[derive(Debug)] diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 43e2694f36c3442237d9133e20e31adb791933ab..2ec91950cccab65a5a367f7f582b1ee9bb61a25a 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -931,7 +931,7 @@ impl Statement { } pub fn link_next(&mut self, next: StatementId) { match self { - Statement::Block(_) => todo!(), + Statement::Block(stmt) => stmt.next = next, Statement::EndBlock(stmt) => stmt.next = next, Statement::Local(stmt) => match stmt { LocalStatement::Channel(stmt) => stmt.next = next, @@ -969,6 +969,7 @@ pub struct BlockStatement { pub relative_pos_in_parent: u32, pub locals: Vec, pub labels: Vec, + pub next: StatementId, } #[derive(Debug, Clone)] diff --git a/src/protocol/eval/executor.rs b/src/protocol/eval/executor.rs index 298d1c01b01250e1db3213df35d670c4dbd44485..bece26924d9c6faf15c3b1a2ca1aefb44f8d28ed 100644 --- a/src/protocol/eval/executor.rs +++ b/src/protocol/eval/executor.rs @@ -737,7 +737,8 @@ impl Prompt { let stmt = &heap[cur_frame.position]; let return_value = match stmt { Statement::Block(stmt) => { - cur_frame.position = stmt.statements[0]; + debug_assert!(stmt.statements.is_empty() || stmt.next == stmt.statements[0]); + cur_frame.position = stmt.next; Ok(EvalContinuation::Stepping) }, Statement::EndBlock(stmt) => { diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 0a4427df8bd9cc7fe1bc6395f40b123590c8049b..94c743fbabfdc823d4619417d0a7897909e944a7 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -35,6 +35,8 @@ pub struct ProtocolDescription { pub(crate) struct ComponentState { prompt: Prompt, } + +#[allow(dead_code)] pub(crate) enum EvalContext<'a> { Nonsync(&'a mut NonsyncProtoContext<'a>), Sync(&'a mut SyncProtoContext<'a>), diff --git a/src/protocol/parser/depth_visitor.rs b/src/protocol/parser/depth_visitor.rs deleted file mode 100644 index e389f1f067803286589ce3407d5aae42b0a0ec10..0000000000000000000000000000000000000000 --- a/src/protocol/parser/depth_visitor.rs +++ /dev/null @@ -1,652 +0,0 @@ -use crate::protocol::ast::*; -use crate::protocol::input_source::*; - -// 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; - -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: StructDefinitionId) -> VisitorResult { - Ok(()) - } - fn visit_enum_definition(&mut self, _h: &mut Heap, _def: EnumDefinitionId) -> VisitorResult { - Ok(()) - } - fn visit_union_definition(&mut self, _h: &mut Heap, _def: UnionDefinitionId) -> VisitorResult { - Ok(()) - } - fn visit_component_definition(&mut self, h: &mut Heap, def: ComponentDefinitionId) -> VisitorResult { - recursive_component_definition(self, h, def) - } - fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentDefinitionId) -> VisitorResult { - recursive_composite_definition(self, h, def) - } - fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentDefinitionId) -> VisitorResult { - recursive_primitive_definition(self, h, def) - } - fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionDefinitionId) -> VisitorResult { - recursive_function_definition(self, h, def) - } - - fn visit_variable_declaration(&mut self, h: &mut Heap, decl: VariableId) -> 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 { - Ok(()) - } - 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_end_block_statement(&mut self, h: &mut Heap, stmt: EndBlockStatementId) -> VisitorResult { - Ok(()) - } - fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult { - recursive_labeled_statement(self, h, stmt) - } - 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_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult { - recursive_new_statement(self, h, stmt) - } - fn visit_goto_statement(&mut self, _h: &mut Heap, _stmt: GotoStatementId) -> VisitorResult { - Ok(()) - } - 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_binding_expression( - &mut self, - h: &mut Heap, - expr: BindingExpressionId - ) -> VisitorResult { - recursive_binding_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_cast_expression(&mut self, h: &mut Heap, expr: CastExpressionId) -> VisitorResult { - let subject = h[expr].subject; - self.visit_expression(h, subject) - } - 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: LiteralExpressionId, - ) -> VisitorResult { - Ok(()) - } - fn visit_variable_expression( - &mut self, - _h: &mut Heap, - _expr: VariableExpressionId, - ) -> VisitorResult { - Ok(()) - } -} - -fn recursive_call_expression_as_expression( - this: &mut T, - h: &mut Heap, - call: CallExpressionId, -) -> VisitorResult { - this.visit_expression(h, call.upcast()) -} - -// Recursive procedures -fn recursive_protocol_description( - 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( - 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::Union(def) => this.visit_union_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( - this: &mut T, - h: &mut Heap, - def: ComponentDefinitionId, -) -> 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( - this: &mut T, - h: &mut Heap, - def: ComponentDefinitionId, -) -> VisitorResult { - for ¶m in h[def].parameters.clone().iter() { - this.visit_variable_declaration(h, param)?; - } - this.visit_block_statement(h, h[def].body) -} - -fn recursive_primitive_definition( - this: &mut T, - h: &mut Heap, - def: ComponentDefinitionId, -) -> VisitorResult { - for ¶m in h[def].parameters.clone().iter() { - this.visit_variable_declaration(h, param)?; - } - this.visit_block_statement(h, h[def].body) -} - -fn recursive_function_definition( - this: &mut T, - h: &mut Heap, - def: FunctionDefinitionId, -) -> VisitorResult { - for ¶m in h[def].parameters.clone().iter() { - this.visit_variable_declaration(h, param)?; - } - this.visit_block_statement(h, h[def].body) -} - -fn recursive_statement(this: &mut T, h: &mut Heap, stmt: StatementId) -> VisitorResult { - match h[stmt].clone() { - Statement::Block(stmt) => this.visit_block_statement(h, stmt.this), - Statement::EndBlock(stmt) => this.visit_end_block_statement(h, stmt.this), - Statement::Local(stmt) => this.visit_local_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::Goto(stmt) => this.visit_goto_statement(h, stmt.this), - Statement::New(stmt) => this.visit_new_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( - this: &mut T, - h: &mut Heap, - block: BlockStatementId, -) -> VisitorResult { - for &local in h[block].locals.clone().iter() { - this.visit_variable_declaration(h, local)?; - } - for &stmt in h[block].statements.clone().iter() { - this.visit_statement(h, stmt)?; - } - Ok(()) -} - -fn recursive_local_statement( - 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_labeled_statement( - this: &mut T, - h: &mut Heap, - stmt: LabeledStatementId, -) -> VisitorResult { - this.visit_statement(h, h[stmt].body) -} - -fn recursive_if_statement( - this: &mut T, - h: &mut Heap, - stmt: IfStatementId, -) -> VisitorResult { - this.visit_expression(h, h[stmt].test)?; - this.visit_block_statement(h, h[stmt].true_body)?; - if let Some(false_body) = h[stmt].false_body { - this.visit_block_statement(h, false_body)?; - } - Ok(()) -} - -fn recursive_while_statement( - this: &mut T, - h: &mut Heap, - stmt: WhileStatementId, -) -> VisitorResult { - this.visit_expression(h, h[stmt].test)?; - this.visit_block_statement(h, h[stmt].body) -} - -fn recursive_synchronous_statement( - this: &mut T, - h: &mut Heap, - stmt: SynchronousStatementId, -) -> VisitorResult { - // TODO: Check where this was used for - // for ¶m in h[stmt].parameters.clone().iter() { - // recursive_parameter_as_variable(this, h, param)?; - // } - this.visit_block_statement(h, h[stmt].body) -} - -fn recursive_return_statement( - this: &mut T, - h: &mut Heap, - stmt: ReturnStatementId, -) -> VisitorResult { - debug_assert_eq!(h[stmt].expressions.len(), 1); - this.visit_expression(h, h[stmt].expressions[0]) -} - -fn recursive_new_statement( - this: &mut T, - h: &mut Heap, - stmt: NewStatementId, -) -> VisitorResult { - recursive_call_expression_as_expression(this, h, h[stmt].expression) -} - -fn recursive_expression_statement( - this: &mut T, - h: &mut Heap, - stmt: ExpressionStatementId, -) -> VisitorResult { - this.visit_expression(h, h[stmt].expression) -} - -fn recursive_expression( - this: &mut T, - h: &mut Heap, - expr: ExpressionId, -) -> VisitorResult { - match h[expr].clone() { - Expression::Assignment(expr) => this.visit_assignment_expression(h, expr.this), - Expression::Binding(expr) => this.visit_binding_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::Literal(expr) => this.visit_constant_expression(h, expr.this), - Expression::Cast(expr) => this.visit_cast_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( - 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_binding_expression( - this: &mut T, - h: &mut Heap, - expr: BindingExpressionId, -) -> VisitorResult { - this.visit_expression(h, h[expr].bound_from)?; - this.visit_expression(h, h[expr].bound_to) -} - -fn recursive_conditional_expression( - 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( - 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( - this: &mut T, - h: &mut Heap, - expr: UnaryExpressionId, -) -> VisitorResult { - this.visit_expression(h, h[expr].expression) -} - -fn recursive_indexing_expression( - 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( - 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( - this: &mut T, - h: &mut Heap, - expr: SelectExpressionId, -) -> VisitorResult { - this.visit_expression(h, h[expr].subject) -} - -fn recursive_call_expression( - 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 UniqueStatementId(StatementId); - -pub(crate) struct LinkStatements { - prev: Option, -} - -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_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult { - if let Some(prev) = self.prev.take() { - h[prev.0].link_next(stmt.upcast()); - } - let end_block = h[stmt].end_block; - recursive_block_statement(self, h, stmt)?; - if let Some(prev) = self.prev.take() { - h[prev.0].link_next(end_block.upcast()); - } - self.prev = Some(UniqueStatementId(end_block.upcast())); - Ok(()) - } - 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_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_invalid()); - - assert!(self.prev.is_none()); - self.visit_block_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()); - if let Some(false_body) = h[stmt].false_body { - self.visit_block_statement(h, 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_invalid()); - - assert!(self.prev.is_none()); - self.visit_block_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_invalid()); - - assert!(self.prev.is_none()); - self.visit_block_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_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_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(()) - } -} \ No newline at end of file diff --git a/src/protocol/parser/mod.rs b/src/protocol/parser/mod.rs index a9f8ea8a948cce14f0dded45d58f1240bdac95ce..9e85d0599835b082b977ad5e9cab6f38286e9ff5 100644 --- a/src/protocol/parser/mod.rs +++ b/src/protocol/parser/mod.rs @@ -1,4 +1,3 @@ -mod depth_visitor; pub(crate) mod symbol_table; pub(crate) mod type_table; pub(crate) mod tokens; @@ -11,10 +10,9 @@ pub(crate) mod pass_validation_linking; pub(crate) mod pass_typing; mod visitor; -use depth_visitor::*; use tokens::*; use crate::collections::*; -use visitor::Visitor2; +use visitor::Visitor; use pass_tokenizer::PassTokenizer; use pass_symbols::PassSymbols; use pass_imports::PassImport; @@ -37,7 +35,8 @@ pub enum ModuleCompilationPhase { DefinitionsParsed, // produced the AST for the entire module TypesAddedToTable, // added all definitions to the type table ValidatedAndLinked, // AST is traversed and has linked the required AST nodes - Typed, // Type inference and checking has been performed + // When we continue with the compiler: + // Typed, // Type inference and checking has been performed } pub struct Module { @@ -222,15 +221,7 @@ impl Parser { self.pass_typing.handle_module_definition(&mut ctx, &mut queue, top)?; } - // Perform remaining steps - // TODO: Phase out at some point - for module in &self.modules { - let root_id = module.root_id; - if let Err((position, message)) = Self::parse_inner(&mut self.heap, root_id) { - return Err(ParseError::new_error_str_at_pos(&self.modules[0].source, position, &message)) - } - } - + // Write out desired information if let Some(filename) = &self.write_ast_to { let mut writer = ASTWriter::new(); let mut file = std::fs::File::create(std::path::Path::new(filename)).unwrap(); @@ -239,27 +230,6 @@ impl Parser { Ok(()) } - - 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(()) - } } // Note: args and return type need to be a function because we need to know the function ID. diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index fe2d9987f3574bfeadab97f9ba488a261122ac89..4214c9c89221f9ae45203396b927e1e5d205a2cd 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -362,7 +362,8 @@ impl PassDefinitions { next_unique_id_in_scope: -1, relative_pos_in_parent: 0, locals: Vec::new(), - labels: Vec::new() + labels: Vec::new(), + next: StatementId::new_invalid(), }); let end_block = ctx.heap.alloc_end_block_statement(|this| EndBlockStatement{ @@ -501,6 +502,7 @@ impl PassDefinitions { relative_pos_in_parent: 0, locals: Vec::new(), labels: Vec::new(), + next: StatementId::new_invalid(), }); let end_block = ctx.heap.alloc_end_block_statement(|this| EndBlockStatement{ diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 5bb7e41f992484673c1511184ce7d95a750fe4a5..98447a5af22fccfc472f6774102b6ed0d051fced 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -59,7 +59,7 @@ use super::visitor::{ STMT_BUFFER_INIT_CAPACITY, EXPR_BUFFER_INIT_CAPACITY, Ctx, - Visitor2, + Visitor, VisitorResult }; @@ -999,7 +999,7 @@ impl PassTyping { } } -impl Visitor2 for PassTyping { +impl Visitor for PassTyping { // Definitions fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentDefinitionId) -> VisitorResult { diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index 99a7ea702e46371d4a3e8ce1834deeb2f53bb9c4..3c18ce687700956f4f63212a2d903d9622e5be18 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -7,8 +7,8 @@ use crate::protocol::parser::type_table::*; use super::visitor::{ STMT_BUFFER_INIT_CAPACITY, EXPR_BUFFER_INIT_CAPACITY, - Ctx, - Visitor2, + Ctx, + Visitor, VisitorResult }; use crate::protocol::parser::ModuleCompilationPhase; @@ -51,12 +51,12 @@ pub(crate) struct PassValidationLinking { in_test_expr: StatementId, // wrapping if/while stmt id in_binding_expr: BindingExpressionId, // to resolve variable expressions in_binding_expr_lhs: bool, - // Traversal state: current scope (which can be used to find the parent + // Traversal state, current scope (which can be used to find the parent // scope) and the definition variant we are considering. cur_scope: Scope, def_type: DefinitionType, - // Parent expression (the previous stmt/expression we visited that could be - // used as an expression parent) + // "Trailing" traversal state, set be child/prev stmt/expr used by next one + prev_stmt: StatementId, expr_parent: ExpressionParent, // Set by parent to indicate that child expression must be assignable. The // child will throw an error if it is not assignable. The stored span is @@ -83,6 +83,7 @@ impl PassValidationLinking { in_binding_expr: BindingExpressionId::new_invalid(), in_binding_expr_lhs: false, cur_scope: Scope::Definition(DefinitionId::new_invalid()), + prev_stmt: StatementId::new_invalid(), expr_parent: ExpressionParent::None, def_type: DefinitionType::Function(FunctionDefinitionId::new_invalid()), must_be_assignable: None, @@ -103,6 +104,7 @@ impl PassValidationLinking { self.in_binding_expr_lhs = false; self.cur_scope = Scope::Definition(DefinitionId::new_invalid()); self.def_type = DefinitionType::Function(FunctionDefinitionId::new_invalid()); + self.prev_stmt = StatementId::new_invalid(); self.expr_parent = ExpressionParent::None; self.must_be_assignable = None; self.relative_pos_in_block = 0; @@ -110,7 +112,25 @@ impl PassValidationLinking { } } -impl Visitor2 for PassValidationLinking { +macro_rules! assign_then_erase_next_stmt { + ($self:ident, $ctx:ident, $stmt_id:expr) => { + if !$self.prev_stmt.is_invalid() { + $ctx.heap[$self.prev_stmt].link_next($stmt_id); + $self.prev_stmt = StatementId::new_invalid(); + } + } +} + +macro_rules! assign_and_replace_next_stmt { + ($self:ident, $ctx:ident, $stmt_id:expr) => { + if !$self.prev_stmt.is_invalid() { + $ctx.heap[$self.prev_stmt].link_next($stmt_id); + } + $self.prev_stmt = $stmt_id; + } +} + +impl Visitor for PassValidationLinking { fn visit_module(&mut self, ctx: &mut Ctx) -> VisitorResult { debug_assert_eq!(ctx.module.phase, ModuleCompilationPhase::TypesAddedToTable); @@ -199,11 +219,13 @@ impl Visitor2 for PassValidationLinking { self.visit_block_stmt_with_hint(ctx, id, None) } - fn visit_local_memory_stmt(&mut self, _ctx: &mut Ctx, _id: MemoryStatementId) -> VisitorResult { + fn visit_local_memory_stmt(&mut self, ctx: &mut Ctx, id: MemoryStatementId) -> VisitorResult { + assign_and_replace_next_stmt!(self, ctx, id.upcast().upcast()); Ok(()) } - fn visit_local_channel_stmt(&mut self, _ctx: &mut Ctx, _id: ChannelStatementId) -> VisitorResult { + fn visit_local_channel_stmt(&mut self, ctx: &mut Ctx, id: ChannelStatementId) -> VisitorResult { + assign_and_replace_next_stmt!(self, ctx, id.upcast().upcast()); Ok(()) } @@ -216,6 +238,7 @@ impl Visitor2 for PassValidationLinking { fn visit_if_stmt(&mut self, ctx: &mut Ctx, id: IfStatementId) -> VisitorResult { let if_stmt = &ctx.heap[id]; + let end_if_id = if_stmt.end_if; let test_expr_id = if_stmt.test; let true_stmt_id = if_stmt.true_body; let false_stmt_id = if_stmt.false_body; @@ -223,6 +246,7 @@ impl Visitor2 for PassValidationLinking { // Visit test expression debug_assert_eq!(self.expr_parent, ExpressionParent::None); debug_assert!(self.in_test_expr.is_invalid()); + self.in_test_expr = id.upcast(); self.expr_parent = ExpressionParent::If(id); self.visit_expr(ctx, test_expr_id)?; @@ -230,19 +254,27 @@ impl Visitor2 for PassValidationLinking { self.expr_parent = ExpressionParent::None; + // Visit true and false branch. Executor chooses next statement based on + // test expression, not on if-statement itself. + assign_then_erase_next_stmt!(self, ctx, id.upcast()); self.visit_block_stmt(ctx, true_stmt_id)?; + assign_then_erase_next_stmt!(self, ctx, end_if_id.upcast()); + if let Some(false_id) = false_stmt_id { self.visit_block_stmt(ctx, false_id)?; + assign_then_erase_next_stmt!(self, ctx, end_if_id.upcast()); } + self.prev_stmt = end_if_id.upcast(); Ok(()) } fn visit_while_stmt(&mut self, ctx: &mut Ctx, id: WhileStatementId) -> VisitorResult { - let (test_id, body_id) = { - let stmt = &ctx.heap[id]; - (stmt.test, stmt.body) - }; + let stmt = &ctx.heap[id]; + let end_while_id = stmt.end_while; + let test_expr_id = stmt.test; + let body_stmt_id = stmt.body; + let old_while = self.in_while; self.in_while = id; @@ -251,13 +283,22 @@ impl Visitor2 for PassValidationLinking { debug_assert!(self.in_test_expr.is_invalid()); self.in_test_expr = id.upcast(); self.expr_parent = ExpressionParent::While(id); - self.visit_expr(ctx, test_id)?; + self.visit_expr(ctx, test_expr_id)?; self.in_test_expr = StatementId::new_invalid(); + // Link up to body statement + assign_then_erase_next_stmt!(self, ctx, id.upcast()); + self.expr_parent = ExpressionParent::None; - self.visit_block_stmt(ctx, body_id)?; + self.visit_block_stmt(ctx, body_stmt_id)?; self.in_while = old_while; + // Link final entry in while's block statement back to the while. The + // executor will go to the end-while statement if the test expression + // is false, so put that in as the new previous stmt + assign_then_erase_next_stmt!(self, ctx, id.upcast()); + self.prev_stmt = end_while_id.upcast(); + Ok(()) } @@ -272,6 +313,7 @@ impl Visitor2 for PassValidationLinking { target_while.end_while }; + assign_then_erase_next_stmt!(self, ctx, id.upcast()); let stmt = &mut ctx.heap[id]; stmt.target = Some(target_end_while); @@ -285,6 +327,7 @@ impl Visitor2 for PassValidationLinking { self.resolve_break_or_continue_target(ctx, stmt.span, &stmt.label)? }; + assign_then_erase_next_stmt!(self, ctx, id.upcast()); let stmt = &mut ctx.heap[id]; stmt.target = Some(target_while_id); @@ -293,7 +336,9 @@ impl Visitor2 for PassValidationLinking { fn visit_synchronous_stmt(&mut self, ctx: &mut Ctx, id: SynchronousStatementId) -> VisitorResult { // Check for validity of synchronous statement - let cur_sync_span = ctx.heap[id].span; + let sync_stmt = &ctx.heap[id]; + let end_sync_id = sync_stmt.end_sync; + let cur_sync_span = sync_stmt.span; if !self.in_sync.is_invalid() { // Nested synchronous statement let old_sync_span = ctx.heap[self.in_sync].span; @@ -311,10 +356,14 @@ impl Visitor2 for PassValidationLinking { )); } + // Synchronous statement implicitly moves to its block + assign_then_erase_next_stmt!(self, ctx, id.upcast()); + let sync_body = ctx.heap[id].body; debug_assert!(self.in_sync.is_invalid()); self.in_sync = id; self.visit_block_stmt_with_hint(ctx, sync_body, Some(id))?; + assign_and_replace_next_stmt!(self, ctx, end_sync_id.upcast()); self.in_sync = SynchronousStatementId::new_invalid(); @@ -332,6 +381,7 @@ impl Visitor2 for PassValidationLinking { } // If here then we are within a function + assign_then_erase_next_stmt!(self, ctx, id.upcast()); debug_assert_eq!(self.expr_parent, ExpressionParent::None); debug_assert_eq!(ctx.heap[id].expressions.len(), 1); self.expr_parent = ExpressionParent::Return(id); @@ -360,6 +410,8 @@ impl Visitor2 for PassValidationLinking { ); } + assign_then_erase_next_stmt!(self, ctx, id.upcast()); + Ok(()) } @@ -377,6 +429,7 @@ impl Visitor2 for PassValidationLinking { // to ensure that the "new" statment instantiates a component) let call_expr_id = ctx.heap[id].expression; + assign_and_replace_next_stmt!(self, ctx, id.upcast()); debug_assert_eq!(self.expr_parent, ExpressionParent::None); self.expr_parent = ExpressionParent::New(id); self.visit_call_expr(ctx, call_expr_id)?; @@ -388,6 +441,7 @@ impl Visitor2 for PassValidationLinking { fn visit_expr_stmt(&mut self, ctx: &mut Ctx, id: ExpressionStatementId) -> VisitorResult { let expr_id = ctx.heap[id].expression; + assign_and_replace_next_stmt!(self, ctx, id.upcast()); debug_assert_eq!(self.expr_parent, ExpressionParent::None); self.expr_parent = ExpressionParent::ExpressionStmt(id); self.visit_expr(ctx, expr_id)?; @@ -1182,6 +1236,7 @@ impl PassValidationLinking { let body = &mut ctx.heap[id]; body.scope_node.parent = old_scope; body.relative_pos_in_parent = self.relative_pos_in_block; + let end_block_id = body.end_block; let old_relative_pos = self.relative_pos_in_block; @@ -1197,10 +1252,12 @@ impl PassValidationLinking { } // Perform the depth-first traversal + assign_and_replace_next_stmt!(self, ctx, id.upcast()); for stmt_idx in 0..statement_section.len() { self.relative_pos_in_block = stmt_idx as u32; self.visit_stmt(ctx, statement_section[stmt_idx])?; } + assign_and_replace_next_stmt!(self, ctx, end_block_id.upcast()); self.cur_scope = old_scope; self.relative_pos_in_block = old_relative_pos; diff --git a/src/protocol/parser/visitor.rs b/src/protocol/parser/visitor.rs index b758cf493f60aeeee202fbc7ffd569960c54b0ca..7fe2688704ed60a76c8c5e4ec21ac200cc3d2e37 100644 --- a/src/protocol/parser/visitor.rs +++ b/src/protocol/parser/visitor.rs @@ -25,7 +25,7 @@ pub(crate) struct Ctx<'p> { /// implementation of the visitors is to not recurse. The exception is the /// top-level `visit_definition`, `visit_stmt` and `visit_expr` methods, which /// call the appropriate visitor function. -pub(crate) trait Visitor2 { +pub(crate) trait Visitor { // Entry point fn visit_module(&mut self, ctx: &mut Ctx) -> VisitorResult { let mut def_index = 0; diff --git a/src/protocol/tests/eval_calls.rs b/src/protocol/tests/eval_calls.rs index c3539167f93d2e02f0b126181fa688d26a8be9b6..f9a1e3c7ff545504193df16b75442b85270fcb6e 100644 --- a/src/protocol/tests/eval_calls.rs +++ b/src/protocol/tests/eval_calls.rs @@ -25,4 +25,17 @@ fn test_function_call() { }").for_function("foo", |f| { f.call_ok(Some(Value::Bool(true))); }); +} + +#[test] +fn test_empty_blocks() { + // Yes this is silly, but I managed to make this a bug before + Tester::new_single_source_expect_ok("traversing empty statements", " + func foo() -> u32 { + auto val = 128; + if (true) {} + while (false) {} + return val; + } + ").for_function("foo", |f| { f.call_ok(Some(Value::UInt32(128))); }); } \ No newline at end of file diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index 072e3601ba67992e8ee3874a49f4f94f6130f906..479a6cc52847075f06be1c25988721c14c95ea39 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -120,6 +120,7 @@ impl AstTesterResult { // Interface for successful compilation //------------------------------------------------------------------------------ +#[allow(dead_code)] pub(crate) struct AstOkTester { test_name: String, modules: Vec, @@ -949,11 +950,6 @@ fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph fn serialize_parser_type(buffer: &mut String, heap: &Heap, parser_type: &ParserType) { use ParserTypeVariant as PTV; - fn write_bytes(buffer: &mut String, bytes: &[u8]) { - let utf8 = String::from_utf8_lossy(bytes); - buffer.push_str(&utf8); - } - fn serialize_variant(buffer: &mut String, heap: &Heap, parser_type: &ParserType, mut idx: usize) -> usize { match &parser_type.elements[idx].variant { PTV::Void => buffer.push_str("void"),