diff --git a/src/mir/basic_block.rs b/src/mir/basic_block.rs index fa4c0fa6..681200d9 100644 --- a/src/mir/basic_block.rs +++ b/src/mir/basic_block.rs @@ -103,7 +103,8 @@ impl BasicBlock { matches!(instruction, MirInstruction::Branch { .. } | MirInstruction::Jump { .. } | - MirInstruction::Return { .. } + MirInstruction::Return { .. } | + MirInstruction::Throw { .. } ) } @@ -123,6 +124,10 @@ impl BasicBlock { MirInstruction::Return { .. } => { // No successors for return }, + MirInstruction::Throw { .. } => { + // No normal successors for throw - control goes to exception handlers + // Exception edges are handled separately from normal control flow + }, _ => unreachable!("Non-terminator instruction in terminator position"), } } diff --git a/src/mir/builder.rs b/src/mir/builder.rs index bd46fcc8..18e25b84 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -175,6 +175,10 @@ impl MirBuilder { self.build_throw_statement(*expression.clone()) }, + ASTNode::Local { variables, initial_values, .. } => { + self.build_local_statement(variables.clone(), initial_values.clone()) + }, + _ => { Err(format!("Unsupported AST node type: {:?}", ast)) } @@ -467,6 +471,18 @@ impl MirBuilder { let finally_block = if finally_body.is_some() { Some(self.block_gen.next()) } else { None }; let exit_block = self.block_gen.next(); + // Set up exception handler for the try block (before we enter it) + if let Some(catch_clause) = catch_clauses.first() { + let exception_value = self.value_gen.next(); + + // Register catch handler for exceptions that may occur in try block + self.emit_instruction(MirInstruction::Catch { + exception_type: catch_clause.exception_type.clone(), + exception_value, + handler_bb: catch_block, + })?; + } + // Jump to try block self.emit_instruction(MirInstruction::Jump { target: try_block })?; @@ -477,26 +493,19 @@ impl MirBuilder { statements: try_body, span: crate::ast::Span::unknown(), }; - let try_result = self.build_expression(try_ast)?; + let _try_result = self.build_expression(try_ast)?; - // Jump to finally or exit - let next_target = finally_block.unwrap_or(exit_block); - self.emit_instruction(MirInstruction::Jump { target: next_target })?; + // Normal completion of try block - jump to finally or exit (if not already terminated) + if !self.is_current_block_terminated() { + let next_target = finally_block.unwrap_or(exit_block); + self.emit_instruction(MirInstruction::Jump { target: next_target })?; + } - // Build catch block + // Build catch block (reachable via exception handling) self.start_new_block(catch_block)?; - // For now, handle first catch clause only (simplified) + // Handle catch clause if let Some(catch_clause) = catch_clauses.first() { - let exception_value = self.value_gen.next(); - - // Set up catch handler - self.emit_instruction(MirInstruction::Catch { - exception_type: catch_clause.exception_type.clone(), - exception_value, - handler_bb: catch_block, - })?; - // Build catch body let catch_ast = ASTNode::Program { statements: catch_clause.body.clone(), @@ -505,9 +514,11 @@ impl MirBuilder { self.build_expression(catch_ast)?; } - // Jump to finally or exit - let next_target = finally_block.unwrap_or(exit_block); - self.emit_instruction(MirInstruction::Jump { target: next_target })?; + // Catch completion - jump to finally or exit (if not already terminated) + if !self.is_current_block_terminated() { + let next_target = finally_block.unwrap_or(exit_block); + self.emit_instruction(MirInstruction::Jump { target: next_target })?; + } // Build finally block if present if let (Some(finally_block_id), Some(finally_statements)) = (finally_block, finally_body) { @@ -525,28 +536,65 @@ impl MirBuilder { // Create exit block self.start_new_block(exit_block)?; - // Return the try result (simplified - in real implementation would need phi node) - Ok(try_result) + // Return void for now (in a complete implementation, would use phi for try/catch values) + let result = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: result, + value: ConstValue::Void, + })?; + + Ok(result) } /// Build a throw statement fn build_throw_statement(&mut self, expression: ASTNode) -> Result { let exception_value = self.build_expression(expression)?; - // Emit throw instruction with PANIC effect + // Emit throw instruction with PANIC effect (this is a terminator) self.emit_instruction(MirInstruction::Throw { exception: exception_value, effects: EffectMask::PANIC, })?; // Throw doesn't return normally, but we need to return a value for the type system - let void_dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_dst, - value: ConstValue::Void, - })?; + // We can't add more instructions after throw, so just return the exception value + Ok(exception_value) + } + + /// Build local variable declarations with optional initial values + fn build_local_statement(&mut self, variables: Vec, initial_values: Vec>>) -> Result { + let mut last_value = None; - Ok(void_dst) + // Process each variable declaration + for (i, var_name) in variables.iter().enumerate() { + let value_id = if i < initial_values.len() && initial_values[i].is_some() { + // Variable has initial value - evaluate it + let init_expr = initial_values[i].as_ref().unwrap(); + self.build_expression(*init_expr.clone())? + } else { + // No initial value - assign void (uninitialized) + let void_dst = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: void_dst, + value: ConstValue::Void, + })?; + void_dst + }; + + // Register variable in SSA form + self.variable_map.insert(var_name.clone(), value_id); + last_value = Some(value_id); + } + + // Return the last assigned value, or void if no variables + Ok(last_value.unwrap_or_else(|| { + let void_val = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: void_val, + value: ConstValue::Void, + }).unwrap(); + void_val + })) } /// Start a new basic block @@ -560,6 +608,16 @@ impl MirBuilder { } } + /// Check if the current basic block is terminated + fn is_current_block_terminated(&self) -> bool { + if let (Some(block_id), Some(ref function)) = (self.current_block, &self.current_function) { + if let Some(block) = function.get_block(block_id) { + return block.is_terminated(); + } + } + false + } + /// Convert AST binary operator to MIR operator fn convert_binary_operator(&self, op: BinaryOperator) -> Result { match op { diff --git a/src/mir/verification.rs b/src/mir/verification.rs index 5bdec015..a24dcf48 100644 --- a/src/mir/verification.rs +++ b/src/mir/verification.rs @@ -228,11 +228,30 @@ impl MirVerifier { while let Some(current) = worklist.pop() { if reachable.insert(current) { if let Some(block) = function.blocks.get(¤t) { + // Add normal successors for successor in &block.successors { if !reachable.contains(successor) { worklist.push(*successor); } } + + // Add exception handler blocks as reachable + for instruction in &block.instructions { + if let super::MirInstruction::Catch { handler_bb, .. } = instruction { + if !reachable.contains(handler_bb) { + worklist.push(*handler_bb); + } + } + } + + // Also check terminator for exception handlers + if let Some(ref terminator) = block.terminator { + if let super::MirInstruction::Catch { handler_bb, .. } = terminator { + if !reachable.contains(handler_bb) { + worklist.push(*handler_bb); + } + } + } } } }