🔧 Fix peek expression terminator issues and add ternary operator support
- Fix LLVM IR terminator missing in peek expression entry blocks - Add proper jump instructions between peek blocks - Implement ternary operator (? :) as syntactic sugar for peek - Update Python LLVM externcall handling for improved compatibility - Add comprehensive test cases for peek and ternary expressions - Update language guide with ternary operator documentation ChatGPTが頑張って修正してくれたにゃ!🐱 Co-Authored-By: ChatGPT <noreply@openai.com>
This commit is contained in:
@ -9,42 +9,81 @@ impl super::MirBuilder {
|
||||
arms: Vec<(LiteralValue, ASTNode)>,
|
||||
else_expr: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
// Evaluate scrutinee in the current block
|
||||
let scr_val = self.build_expression_impl(scrutinee)?;
|
||||
|
||||
// Prepare merge and result
|
||||
let merge_block: BasicBlockId = self.block_gen.next();
|
||||
let result_val = self.value_gen.next();
|
||||
let mut phi_inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
|
||||
let mut next_block = self.block_gen.next();
|
||||
self.start_new_block(next_block)?;
|
||||
|
||||
// Create dispatch block where we start comparing arms
|
||||
let dispatch_block = self.block_gen.next();
|
||||
// Jump from current block to dispatch (ensure terminator exists)
|
||||
let need_jump = {
|
||||
let cur = self.current_block;
|
||||
if let (Some(cb), Some(ref func)) = (cur, &self.current_function) {
|
||||
if let Some(bb) = func.blocks.get(&cb) { !bb.is_terminated() } else { true }
|
||||
} else { true }
|
||||
};
|
||||
if need_jump {
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: dispatch_block })?;
|
||||
}
|
||||
self.start_new_block(dispatch_block)?;
|
||||
|
||||
// If there are no arms, fall through to else directly
|
||||
if arms.is_empty() {
|
||||
let else_block = self.block_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: else_block })?;
|
||||
self.start_new_block(else_block)?;
|
||||
let else_val = self.build_expression_impl(else_expr)?;
|
||||
phi_inputs.push((else_block, else_val));
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: merge_block })?;
|
||||
self.start_new_block(merge_block)?;
|
||||
self.emit_instruction(super::MirInstruction::Phi { dst: result_val, inputs: phi_inputs })?;
|
||||
return Ok(result_val);
|
||||
}
|
||||
|
||||
// Else block to handle default case
|
||||
let else_block = self.block_gen.next();
|
||||
|
||||
// Chain dispatch blocks for each arm
|
||||
let mut cur_dispatch = dispatch_block;
|
||||
for (i, (label, arm_expr)) in arms.iter().cloned().enumerate() {
|
||||
let then_block = self.block_gen.next();
|
||||
// Only string labels handled here (behavior unchanged)
|
||||
// Next dispatch (only for non-last arm)
|
||||
let next_dispatch = if i + 1 < arms.len() { Some(self.block_gen.next()) } else { None };
|
||||
let else_target = next_dispatch.unwrap_or(else_block);
|
||||
|
||||
// In current dispatch block, compare and branch
|
||||
self.start_new_block(cur_dispatch)?;
|
||||
if let LiteralValue::String(s) = label {
|
||||
let lit_id = self.value_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Const { dst: lit_id, value: super::ConstValue::String(s) })?;
|
||||
let cond_id = self.value_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Compare { dst: cond_id, op: super::CompareOp::Eq, lhs: scr_val, rhs: lit_id })?;
|
||||
self.emit_instruction(super::MirInstruction::Branch { condition: cond_id, then_bb: then_block, else_bb: next_block })?;
|
||||
self.start_new_block(then_block)?;
|
||||
let then_val = self.build_expression_impl(arm_expr)?;
|
||||
phi_inputs.push((then_block, then_val));
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: merge_block })?;
|
||||
if i < arms.len() - 1 {
|
||||
let b = self.block_gen.next();
|
||||
self.start_new_block(b)?;
|
||||
next_block = b;
|
||||
}
|
||||
self.emit_instruction(super::MirInstruction::Branch { condition: cond_id, then_bb: then_block, else_bb: else_target })?;
|
||||
}
|
||||
|
||||
// then arm
|
||||
self.start_new_block(then_block)?;
|
||||
let then_val = self.build_expression_impl(arm_expr)?;
|
||||
phi_inputs.push((then_block, then_val));
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: merge_block })?;
|
||||
|
||||
// Move to next dispatch or else block
|
||||
cur_dispatch = else_target;
|
||||
}
|
||||
|
||||
let else_block_id = next_block;
|
||||
self.start_new_block(else_block_id)?;
|
||||
// Lower else expression in else_block
|
||||
self.start_new_block(else_block)?;
|
||||
let else_val = self.build_expression_impl(else_expr)?;
|
||||
phi_inputs.push((else_block_id, else_val));
|
||||
phi_inputs.push((else_block, else_val));
|
||||
self.emit_instruction(super::MirInstruction::Jump { target: merge_block })?;
|
||||
|
||||
// Merge and yield result
|
||||
self.start_new_block(merge_block)?;
|
||||
self.emit_instruction(super::MirInstruction::Phi { dst: result_val, inputs: phi_inputs })?;
|
||||
Ok(result_val)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user