diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index 885c5aa4a83626d35fed98fa687fed9be50e92ff..94de9499c7f17bf17a73332551296924f9d7953d 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -487,10 +487,9 @@ impl PassDefinitions { // Two fallback possibilities: the first one is a memory // declaration, the other one is to parse it as a normal // expression. This is a bit ugly. - if let Some((memory_stmt_id, assignment_stmt_id)) = self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { + if let Some(memory_stmt_id) = self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { consume_token(&module.source, iter, TokenKind::SemiColon)?; section.push(memory_stmt_id.upcast().upcast()); - section.push(assignment_stmt_id.upcast()); } else { let id = self.consume_expression_statement(module, iter, ctx)?; section.push(id.upcast()); @@ -498,10 +497,9 @@ impl PassDefinitions { } } else if next == TokenKind::OpenParen { // Same as above: memory statement or normal expression - if let Some((memory_stmt_id, assignment_stmt_id)) = self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { + if let Some(memory_stmt_id) = self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { consume_token(&module.source, iter, TokenKind::SemiColon); section.push(memory_stmt_id.upcast().upcast()); - section.push(assignment_stmt_id.upcast()); } else { let id = self.consume_expression_statement(module, iter, ctx)?; section.push(id.upcast()); @@ -696,26 +694,26 @@ impl PassDefinitions { let mut next = iter.next(); while Some(TokenKind::CloseCurly) != next { - let (guard_var, guard_expr) = match self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { - Some(guard_var_and_expr) => guard_var_and_expr, + let guard = match self.maybe_consume_memory_statement_without_semicolon(module, iter, ctx)? { + Some(guard_mem_stmt) => guard_mem_stmt.upcast().upcast(), None => { let start_pos = iter.last_valid_pos(); let expr = self.consume_expression(module, iter, ctx)?; let end_pos = iter.last_valid_pos(); - let guard_expr = ctx.heap.alloc_expression_statement(|this| ExpressionStatement{ + let guard_expr_stmt = ctx.heap.alloc_expression_statement(|this| ExpressionStatement{ this, span: InputSpan::from_positions(start_pos, end_pos), expression: expr, next: StatementId::new_invalid(), }); - (MemoryStatementId::new_invalid(), guard_expr) + guard_expr_stmt.upcast() }, }; consume_token(&module.source, iter, TokenKind::ArrowRight)?; let block = self.consume_block_or_wrapped_statement(module, iter, ctx)?; - cases.push(SelectCase{ guard_var, guard_expr, block }); + cases.push(SelectCase{ guard, block }); next = iter.next(); } @@ -925,9 +923,14 @@ impl PassDefinitions { Ok(()) } + /// Attempts to consume a memory statement (a statement along the lines of + /// `type var_name = initial_expr`). Will return `Ok(None)` if it didn't + /// seem like there was a memory statement, `Ok(Some(...))` if there was + /// one, and `Err(...)` if its reasonable to assume that there was a memory + /// statement, but we failed to parse it. fn maybe_consume_memory_statement_without_semicolon( &mut self, module: &Module, iter: &mut TokenIter, ctx: &mut PassCtx - ) -> Result, ParseError> { + ) -> Result, ParseError> { // This is a bit ugly. It would be nicer if we could somehow // consume the expression with a type hint if we do get a valid // type, but we don't get an identifier following it @@ -947,11 +950,10 @@ impl PassDefinitions { let memory_span = InputSpan::from_positions(parser_type.full_span.begin, identifier.span.end); let assign_span = consume_token(&module.source, iter, TokenKind::Equal)?; - let initial_expr_begin_pos = iter.last_valid_pos(); let initial_expr_id = self.consume_expression(module, iter, ctx)?; let initial_expr_end_pos = iter.last_valid_pos(); - // Allocate the memory statement with the variable + // Create the AST variable let local_id = ctx.heap.alloc_variable(|this| Variable{ this, kind: VariableKind::Local, @@ -960,18 +962,13 @@ impl PassDefinitions { relative_pos_in_block: 0, unique_id_in_scope: -1, }); - let memory_stmt_id = ctx.heap.alloc_memory_statement(|this| MemoryStatement{ - this, - span: memory_span, - variable: local_id, - next: StatementId::new_invalid() - }); - // Allocate the initial assignment + // Create the initial assignment expression + // Note: we set the initial variable declaration here let variable_expr_id = ctx.heap.alloc_variable_expression(|this| VariableExpression{ this, identifier, - declaration: None, + declaration: Some(local_id), used_as_binding_target: false, parent: ExpressionParent::None, unique_id_in_definition: -1, @@ -986,14 +983,17 @@ impl PassDefinitions { parent: ExpressionParent::None, unique_id_in_definition: -1, }); - let assignment_stmt_id = ctx.heap.alloc_expression_statement(|this| ExpressionStatement{ + + // Put both together in the memory statement + let memory_stmt_id = ctx.heap.alloc_memory_statement(|this| MemoryStatement{ this, - span: InputSpan::from_positions(initial_expr_begin_pos, initial_expr_end_pos), - expression: assignment_expr_id.upcast(), - next: StatementId::new_invalid(), + span: memory_span, + variable: local_id, + initial_expr: assignment_expr_id, + next: StatementId::new_invalid() }); - return Ok(Some((memory_stmt_id, assignment_stmt_id))) + return Ok(Some(memory_stmt_id)); } }