2021-12-27 22:55:51 +08:00
|
|
|
use super::{
|
2022-01-09 19:55:17 +08:00
|
|
|
super::symbol_resolver::ValueEnum,
|
|
|
|
expr::destructure_range,
|
|
|
|
irrt::{handle_slice_indices, list_slice_assignment},
|
|
|
|
CodeGenContext, CodeGenerator,
|
|
|
|
};
|
|
|
|
use crate::{
|
2023-10-06 12:11:57 +08:00
|
|
|
codegen::{
|
2024-03-19 00:20:09 +08:00
|
|
|
classes::{ArrayLikeIndexer, ArraySliceValue, ListValue, RangeValue},
|
2023-10-06 12:11:57 +08:00
|
|
|
expr::gen_binop_expr,
|
|
|
|
gen_in_range_check,
|
|
|
|
},
|
2024-06-12 15:01:01 +08:00
|
|
|
toplevel::{helper::PrimDef, numpy::unpack_ndarray_var_tys, DefinitionId, TopLevelDef},
|
2022-02-21 18:27:46 +08:00
|
|
|
typecheck::typedef::{FunSignature, Type, TypeEnum},
|
2021-12-27 22:55:51 +08:00
|
|
|
};
|
|
|
|
use inkwell::{
|
2022-02-12 21:13:16 +08:00
|
|
|
attributes::{Attribute, AttributeLoc},
|
|
|
|
basic_block::BasicBlock,
|
2023-11-27 13:25:53 +08:00
|
|
|
types::{BasicType, BasicTypeEnum},
|
2023-11-17 17:30:27 +08:00
|
|
|
values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue},
|
2023-09-05 12:10:52 +08:00
|
|
|
IntPredicate,
|
2021-12-27 22:55:51 +08:00
|
|
|
};
|
2022-02-21 18:27:46 +08:00
|
|
|
use nac3parser::ast::{
|
|
|
|
Constant, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind, StrRef,
|
|
|
|
};
|
2022-01-20 04:14:22 +08:00
|
|
|
use std::convert::TryFrom;
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_var_alloc`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_var<'ctx>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2021-12-27 22:55:51 +08:00
|
|
|
ty: BasicTypeEnum<'ctx>,
|
2023-09-06 11:00:02 +08:00
|
|
|
name: Option<&str>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<PointerValue<'ctx>, String> {
|
2023-10-06 11:11:38 +08:00
|
|
|
// Restore debug location
|
|
|
|
let di_loc = ctx.debug_info.0.create_debug_location(
|
|
|
|
ctx.ctx,
|
|
|
|
ctx.current_loc.row as u32,
|
|
|
|
ctx.current_loc.column as u32,
|
|
|
|
ctx.debug_info.2,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
// put the alloca in init block
|
|
|
|
let current = ctx.builder.get_insert_block().unwrap();
|
2023-10-06 11:11:38 +08:00
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
// position before the last branching instruction...
|
|
|
|
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
2023-10-06 11:11:38 +08:00
|
|
|
ctx.builder.set_current_debug_location(di_loc);
|
|
|
|
|
2024-02-19 19:30:25 +08:00
|
|
|
let ptr = ctx.builder.build_alloca(ty, name.unwrap_or("")).unwrap();
|
2023-10-06 11:11:38 +08:00
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.position_at_end(current);
|
2023-10-06 11:11:38 +08:00
|
|
|
ctx.builder.set_current_debug_location(di_loc);
|
2023-11-27 13:25:53 +08:00
|
|
|
|
|
|
|
Ok(ptr)
|
|
|
|
}
|
|
|
|
|
2024-02-20 18:07:55 +08:00
|
|
|
/// See [`CodeGenerator::gen_array_var_alloc`].
|
2023-11-27 13:25:53 +08:00
|
|
|
pub fn gen_array_var<'ctx, 'a, T: BasicType<'ctx>>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
ty: T,
|
|
|
|
size: IntValue<'ctx>,
|
2024-03-19 00:20:09 +08:00
|
|
|
name: Option<&'ctx str>,
|
|
|
|
) -> Result<ArraySliceValue<'ctx>, String> {
|
2023-11-27 13:25:53 +08:00
|
|
|
// Restore debug location
|
|
|
|
let di_loc = ctx.debug_info.0.create_debug_location(
|
|
|
|
ctx.ctx,
|
|
|
|
ctx.current_loc.row as u32,
|
|
|
|
ctx.current_loc.column as u32,
|
|
|
|
ctx.debug_info.2,
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
|
|
|
|
// put the alloca in init block
|
|
|
|
let current = ctx.builder.get_insert_block().unwrap();
|
|
|
|
|
|
|
|
// position before the last branching instruction...
|
|
|
|
ctx.builder.position_before(&ctx.init_bb.get_last_instruction().unwrap());
|
|
|
|
ctx.builder.set_current_debug_location(di_loc);
|
|
|
|
|
2024-02-19 19:30:25 +08:00
|
|
|
let ptr = ctx.builder.build_array_alloca(ty, size, name.unwrap_or("")).unwrap();
|
2024-03-19 00:20:09 +08:00
|
|
|
let ptr = ArraySliceValue::from_ptr_val(ptr, size, name);
|
2023-11-27 13:25:53 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(current);
|
|
|
|
ctx.builder.set_current_debug_location(di_loc);
|
2023-10-06 11:11:38 +08:00
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(ptr)
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_store_target`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_store_target<'ctx, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2021-10-16 22:17:36 +08:00
|
|
|
pattern: &Expr<Option<Type>>,
|
2023-09-06 11:00:02 +08:00
|
|
|
name: Option<&str>,
|
2023-12-06 15:26:37 +08:00
|
|
|
) -> Result<Option<PointerValue<'ctx>>, String> {
|
2024-01-23 17:21:24 +08:00
|
|
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
// very similar to gen_expr, but we don't do an extra load at the end
|
|
|
|
// and we flatten nested tuples
|
2023-12-06 15:26:37 +08:00
|
|
|
Ok(Some(match &pattern.node {
|
2022-05-14 02:30:08 +08:00
|
|
|
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
|
|
|
None => {
|
|
|
|
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
2023-09-06 11:00:02 +08:00
|
|
|
let ptr = generator.gen_var_alloc(ctx, ptr_ty, name)?;
|
2022-05-14 02:30:08 +08:00
|
|
|
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
|
|
|
ptr
|
|
|
|
}
|
|
|
|
Some(v) => {
|
|
|
|
let (ptr, counter) = (v.0, v.2);
|
|
|
|
ctx.var_assignment.insert(*id, (ptr, None, counter));
|
|
|
|
ptr
|
|
|
|
}
|
2024-06-12 14:45:03 +08:00
|
|
|
},
|
2021-10-16 22:17:36 +08:00
|
|
|
ExprKind::Attribute { value, attr, .. } => {
|
2024-06-19 17:19:55 +08:00
|
|
|
let (index, _) = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
2023-12-06 15:26:37 +08:00
|
|
|
let val = if let Some(v) = generator.gen_expr(ctx, value)? {
|
|
|
|
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
|
|
|
} else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(None);
|
2023-12-06 15:26:37 +08:00
|
|
|
};
|
2023-12-08 17:43:32 +08:00
|
|
|
let BasicValueEnum::PointerValue(ptr) = val else {
|
2021-10-16 22:17:36 +08:00
|
|
|
unreachable!();
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
ctx.builder.build_in_bounds_gep(
|
|
|
|
ptr,
|
|
|
|
&[
|
|
|
|
ctx.ctx.i32_type().const_zero(),
|
|
|
|
ctx.ctx.i32_type().const_int(index as u64, false),
|
|
|
|
],
|
2023-09-06 11:09:15 +08:00
|
|
|
name.unwrap_or(""),
|
2021-10-16 22:17:36 +08:00
|
|
|
)
|
2024-06-12 14:45:03 +08:00
|
|
|
}
|
|
|
|
.unwrap()
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
ExprKind::Subscript { value, slice, .. } => {
|
2023-11-06 18:03:52 +08:00
|
|
|
match ctx.unifier.get_ty_immutable(value.custom.unwrap()).as_ref() {
|
2024-07-02 11:05:05 +08:00
|
|
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::List.id() => {
|
2023-11-06 18:03:52 +08:00
|
|
|
let v = generator
|
|
|
|
.gen_expr(ctx, value)?
|
|
|
|
.unwrap()
|
|
|
|
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
|
|
|
.into_pointer_value();
|
2024-01-23 17:21:24 +08:00
|
|
|
let v = ListValue::from_ptr_val(v, llvm_usize, None);
|
|
|
|
let len = v.load_size(ctx, Some("len"));
|
2023-11-06 18:03:52 +08:00
|
|
|
let raw_index = generator
|
|
|
|
.gen_expr(ctx, slice)?
|
|
|
|
.unwrap()
|
|
|
|
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
|
|
|
.into_int_value();
|
2024-06-12 14:45:03 +08:00
|
|
|
let raw_index = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_int_s_extend(raw_index, generator.get_size_type(ctx.ctx), "sext")
|
|
|
|
.unwrap();
|
2023-11-06 18:03:52 +08:00
|
|
|
// handle negative index
|
2024-06-12 14:45:03 +08:00
|
|
|
let is_negative = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_int_compare(
|
|
|
|
IntPredicate::SLT,
|
|
|
|
raw_index,
|
|
|
|
generator.get_size_type(ctx.ctx).const_zero(),
|
|
|
|
"is_neg",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let adjusted = ctx.builder.build_int_add(raw_index, len, "adjusted").unwrap();
|
2023-11-06 18:03:52 +08:00
|
|
|
let index = ctx
|
|
|
|
.builder
|
|
|
|
.build_select(is_negative, adjusted, raw_index, "index")
|
2024-02-19 19:30:25 +08:00
|
|
|
.map(BasicValueEnum::into_int_value)
|
|
|
|
.unwrap();
|
2023-11-06 18:03:52 +08:00
|
|
|
// unsigned less than is enough, because negative index after adjustment is
|
|
|
|
// bigger than the length (for unsigned cmp)
|
2024-06-12 14:45:03 +08:00
|
|
|
let bound_check = ctx
|
|
|
|
.builder
|
|
|
|
.build_int_compare(IntPredicate::ULT, index, len, "inbound")
|
2024-02-19 19:30:25 +08:00
|
|
|
.unwrap();
|
2023-11-06 18:03:52 +08:00
|
|
|
ctx.make_assert(
|
|
|
|
generator,
|
|
|
|
bound_check,
|
|
|
|
"0:IndexError",
|
|
|
|
"index {0} out of bounds 0:{1}",
|
|
|
|
[Some(raw_index), Some(len), None],
|
|
|
|
slice.location,
|
|
|
|
);
|
2024-04-16 17:20:24 +08:00
|
|
|
v.data().ptr_offset(ctx, generator, &index, name)
|
2023-11-06 18:03:52 +08:00
|
|
|
}
|
|
|
|
|
2024-06-12 15:01:01 +08:00
|
|
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
2023-11-06 18:03:52 +08:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => unreachable!(),
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
2023-12-06 15:26:37 +08:00
|
|
|
}))
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_assign`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_assign<'ctx, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2021-10-16 22:17:36 +08:00
|
|
|
target: &Expr<Option<Type>>,
|
2021-11-20 19:50:25 +08:00
|
|
|
value: ValueEnum<'ctx>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2024-01-23 17:21:24 +08:00
|
|
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
match &target.node {
|
2022-02-07 02:18:56 +08:00
|
|
|
ExprKind::Tuple { elts, .. } => {
|
2023-12-12 13:38:27 +08:00
|
|
|
let BasicValueEnum::StructValue(v) =
|
2024-06-12 14:45:03 +08:00
|
|
|
value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
|
|
|
else {
|
2022-02-07 02:18:56 +08:00
|
|
|
unreachable!()
|
2023-12-12 13:38:27 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
for (i, elt) in elts.iter().enumerate() {
|
|
|
|
let v = ctx
|
|
|
|
.builder
|
|
|
|
.build_extract_value(v, u32::try_from(i).unwrap(), "struct_elem")
|
|
|
|
.unwrap();
|
|
|
|
generator.gen_assign(ctx, elt, v.into())?;
|
2021-08-19 17:14:38 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2022-02-07 02:18:56 +08:00
|
|
|
ExprKind::Subscript { value: ls, slice, .. }
|
|
|
|
if matches!(&slice.node, ExprKind::Slice { .. }) =>
|
|
|
|
{
|
2024-06-12 14:45:03 +08:00
|
|
|
let ExprKind::Slice { lower, upper, step } = &slice.node else { unreachable!() };
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
let ls = generator
|
|
|
|
.gen_expr(ctx, ls)?
|
|
|
|
.unwrap()
|
|
|
|
.to_basic_value_enum(ctx, generator, ls.custom.unwrap())?
|
|
|
|
.into_pointer_value();
|
2024-01-23 17:21:24 +08:00
|
|
|
let ls = ListValue::from_ptr_val(ls, llvm_usize, None);
|
2024-06-12 14:45:03 +08:00
|
|
|
let Some((start, end, step)) =
|
|
|
|
handle_slice_indices(lower, upper, step, ctx, generator, ls.load_size(ctx, None))?
|
|
|
|
else {
|
|
|
|
return Ok(());
|
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
let value = value
|
|
|
|
.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
|
|
|
.into_pointer_value();
|
2024-01-23 17:21:24 +08:00
|
|
|
let value = ListValue::from_ptr_val(value, llvm_usize, None);
|
2024-02-27 13:39:05 +08:00
|
|
|
let ty = match &*ctx.unifier.get_ty_immutable(target.custom.unwrap()) {
|
2024-07-02 11:05:05 +08:00
|
|
|
TypeEnum::TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
|
|
|
|
*params.iter().next().unwrap().1
|
|
|
|
}
|
2024-06-12 15:01:01 +08:00
|
|
|
TypeEnum::TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
2024-03-26 19:14:56 +08:00
|
|
|
unpack_ndarray_var_tys(&mut ctx.unifier, target.custom.unwrap()).0
|
2024-02-27 13:39:05 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
2024-01-23 17:21:24 +08:00
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
|
2024-02-27 13:39:05 +08:00
|
|
|
let ty = ctx.get_llvm_type(generator, ty);
|
2024-05-29 15:07:28 +08:00
|
|
|
let Some(src_ind) = handle_slice_indices(
|
|
|
|
&None,
|
|
|
|
&None,
|
|
|
|
&None,
|
|
|
|
ctx,
|
|
|
|
generator,
|
|
|
|
value.load_size(ctx, None),
|
2024-06-12 14:45:03 +08:00
|
|
|
)?
|
|
|
|
else {
|
|
|
|
return Ok(());
|
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind);
|
2022-02-07 02:18:56 +08:00
|
|
|
}
|
|
|
|
_ => {
|
2023-09-05 15:15:47 +08:00
|
|
|
let name = if let ExprKind::Name { id, .. } = &target.node {
|
2023-12-08 17:43:32 +08:00
|
|
|
format!("{id}.addr")
|
2023-09-05 15:15:47 +08:00
|
|
|
} else {
|
|
|
|
String::from("target.addr")
|
|
|
|
};
|
2023-12-06 15:26:37 +08:00
|
|
|
let Some(ptr) = generator.gen_store_target(ctx, target, Some(name.as_str()))? else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-06 15:26:37 +08:00
|
|
|
};
|
2023-09-05 15:15:47 +08:00
|
|
|
|
2022-02-07 02:18:56 +08:00
|
|
|
if let ExprKind::Name { id, .. } = &target.node {
|
|
|
|
let (_, static_value, counter) = ctx.var_assignment.get_mut(id).unwrap();
|
|
|
|
*counter += 1;
|
|
|
|
if let ValueEnum::Static(s) = &value {
|
|
|
|
*static_value = Some(s.clone());
|
2022-01-09 19:55:17 +08:00
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2022-04-08 03:26:42 +08:00
|
|
|
let val = value.to_basic_value_enum(ctx, generator, target.custom.unwrap())?;
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(ptr, val).unwrap();
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2022-02-21 18:27:46 +08:00
|
|
|
};
|
|
|
|
Ok(())
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_for`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_for<G: CodeGenerator>(
|
2021-10-23 23:53:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2021-10-23 23:53:36 +08:00
|
|
|
stmt: &Stmt<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2024-06-12 14:45:03 +08:00
|
|
|
let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node else { unreachable!() };
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// var_assignment static values may be changed in another branch
|
|
|
|
// if so, remove the static value as it may not be correct in this branch
|
|
|
|
let var_assignment = ctx.var_assignment.clone();
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let int32 = ctx.ctx.i32_type();
|
|
|
|
let size_t = generator.get_size_type(ctx.ctx);
|
|
|
|
let zero = int32.const_zero();
|
|
|
|
let current = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "for.body");
|
|
|
|
let cont_bb = ctx.ctx.append_basic_block(current, "for.end");
|
|
|
|
// if there is no orelse, we just go to cont_bb
|
2024-06-12 14:45:03 +08:00
|
|
|
let orelse_bb =
|
|
|
|
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "for.orelse") };
|
2021-10-23 23:53:36 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// Whether the iterable is a range() expression
|
|
|
|
let is_iterable_range_expr = ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range);
|
2023-09-05 17:07:48 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// The BB containing the increment expression
|
|
|
|
let incr_bb = ctx.ctx.append_basic_block(current, "for.incr");
|
|
|
|
// The BB containing the loop condition check
|
|
|
|
let cond_bb = ctx.ctx.append_basic_block(current, "for.cond");
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// store loop bb information and restore it later
|
|
|
|
let loop_bb = ctx.loop_target.replace((incr_bb, cont_bb));
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let iter_val = if let Some(v) = generator.gen_expr(ctx, iter)? {
|
2024-06-12 14:45:03 +08:00
|
|
|
v.to_basic_value_enum(ctx, generator, iter.custom.unwrap())?
|
2023-12-12 13:38:27 +08:00
|
|
|
} else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-12 13:38:27 +08:00
|
|
|
};
|
|
|
|
if is_iterable_range_expr {
|
2024-01-23 18:27:00 +08:00
|
|
|
let iter_val = RangeValue::from_ptr_val(iter_val.into_pointer_value(), Some("range"));
|
2023-12-12 13:38:27 +08:00
|
|
|
// Internal variable for loop; Cannot be assigned
|
|
|
|
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
|
|
|
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
2024-06-12 14:45:03 +08:00
|
|
|
let Some(target_i) = generator.gen_store_target(ctx, target, Some("for.target.addr"))?
|
|
|
|
else {
|
2023-12-12 13:38:27 +08:00
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
let (start, stop, step) = destructure_range(ctx, iter_val);
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(i, start).unwrap();
|
2023-09-05 17:07:48 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// Check "If step is zero, ValueError is raised."
|
2024-06-12 14:45:03 +08:00
|
|
|
let rangenez =
|
|
|
|
ctx.builder.build_int_compare(IntPredicate::NE, step, int32.const_zero(), "").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.make_assert(
|
|
|
|
generator,
|
|
|
|
rangenez,
|
|
|
|
"ValueError",
|
|
|
|
"range() arg 3 must not be zero",
|
|
|
|
[None, None, None],
|
2024-06-12 14:45:03 +08:00
|
|
|
ctx.current_loc,
|
2023-12-12 13:38:27 +08:00
|
|
|
);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
{
|
2023-10-30 13:59:20 +08:00
|
|
|
ctx.builder.position_at_end(cond_bb);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_conditional_branch(
|
|
|
|
gen_in_range_check(
|
|
|
|
ctx,
|
|
|
|
ctx.builder.build_load(i, "").map(BasicValueEnum::into_int_value).unwrap(),
|
|
|
|
stop,
|
|
|
|
step,
|
|
|
|
),
|
|
|
|
body_bb,
|
|
|
|
orelse_bb,
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-10-23 23:53:36 +08:00
|
|
|
}
|
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(incr_bb);
|
2024-06-12 14:45:03 +08:00
|
|
|
let next_i = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_int_add(
|
|
|
|
ctx.builder.build_load(i, "").map(BasicValueEnum::into_int_value).unwrap(),
|
|
|
|
step,
|
|
|
|
"inc",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(i, next_i).unwrap();
|
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_store(
|
|
|
|
target_i,
|
|
|
|
ctx.builder.build_load(i, "").map(BasicValueEnum::into_int_value).unwrap(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
} else {
|
|
|
|
let index_addr = generator.gen_var_alloc(ctx, size_t.into(), Some("for.index.addr"))?;
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(index_addr, size_t.const_zero()).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
let len = ctx
|
|
|
|
.build_gep_and_load(
|
|
|
|
iter_val.into_pointer_value(),
|
|
|
|
&[zero, int32.const_int(1, false)],
|
2024-06-12 14:45:03 +08:00
|
|
|
Some("len"),
|
2023-12-12 13:38:27 +08:00
|
|
|
)
|
|
|
|
.into_int_value();
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(cond_bb);
|
2024-06-12 14:45:03 +08:00
|
|
|
let index = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_load(index_addr, "for.index")
|
|
|
|
.map(BasicValueEnum::into_int_value)
|
|
|
|
.unwrap();
|
|
|
|
let cmp = ctx.builder.build_int_compare(IntPredicate::SLT, index, len, "cond").unwrap();
|
|
|
|
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(incr_bb);
|
2024-06-12 14:45:03 +08:00
|
|
|
let index =
|
|
|
|
ctx.builder.build_load(index_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
2024-02-19 19:30:25 +08:00
|
|
|
let inc = ctx.builder.build_int_add(index, size_t.const_int(1, true), "inc").unwrap();
|
|
|
|
ctx.builder.build_store(index_addr, inc).unwrap();
|
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
|
|
|
let arr_ptr = ctx
|
|
|
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero], Some("arr.addr"))
|
|
|
|
.into_pointer_value();
|
2024-06-12 14:45:03 +08:00
|
|
|
let index = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_load(index_addr, "for.index")
|
|
|
|
.map(BasicValueEnum::into_int_value)
|
|
|
|
.unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
let val = ctx.build_gep_and_load(arr_ptr, &[index], Some("val"));
|
|
|
|
generator.gen_assign(ctx, target, val.into())?;
|
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(incr_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if !orelse.is_empty() {
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
generator.gen_block(ctx, orelse.iter())?;
|
2022-02-12 21:13:16 +08:00
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb).unwrap();
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2021-10-23 23:53:36 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
ctx.loop_target = loop_bb;
|
2023-09-05 12:10:52 +08:00
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2021-10-23 23:53:36 +08:00
|
|
|
}
|
|
|
|
|
2024-07-02 19:05:00 +08:00
|
|
|
#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)]
|
|
|
|
pub struct BreakContinueHooks<'ctx> {
|
|
|
|
/// The [exit block][`BasicBlock`] to branch to when `break`-ing out of a loop.
|
|
|
|
pub exit_bb: BasicBlock<'ctx>,
|
|
|
|
|
|
|
|
/// The [latch basic block][`BasicBlock`] to branch to for `continue`-ing to the next iteration
|
|
|
|
/// of the loop.
|
|
|
|
pub latch_bb: BasicBlock<'ctx>,
|
|
|
|
}
|
|
|
|
|
2023-11-17 17:30:27 +08:00
|
|
|
/// Generates a C-style `for` construct using lambdas, similar to the following C code:
|
|
|
|
///
|
|
|
|
/// ```c
|
|
|
|
/// for (x... = init(); cond(x...); update(x...)) {
|
|
|
|
/// body(x...);
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// * `init` - A lambda containing IR statements declaring and initializing loop variables. The
|
|
|
|
/// return value is a [Clone] value which will be passed to the other lambdas.
|
|
|
|
/// * `cond` - A lambda containing IR statements checking whether the loop should continue
|
|
|
|
/// executing. The result value must be an `i1` indicating if the loop should continue.
|
|
|
|
/// * `body` - A lambda containing IR statements within the loop body.
|
|
|
|
/// * `update` - A lambda containing IR statements updating loop variables.
|
2024-03-19 18:24:30 +08:00
|
|
|
pub fn gen_for_callback<'ctx, 'a, G, I, InitFn, CondFn, BodyFn, UpdateFn>(
|
|
|
|
generator: &mut G,
|
2023-11-17 17:30:27 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
init: InitFn,
|
|
|
|
cond: CondFn,
|
|
|
|
body: BodyFn,
|
|
|
|
update: UpdateFn,
|
|
|
|
) -> Result<(), String>
|
2024-06-12 14:45:03 +08:00
|
|
|
where
|
|
|
|
G: CodeGenerator + ?Sized,
|
|
|
|
I: Clone,
|
|
|
|
InitFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<I, String>,
|
|
|
|
CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<IntValue<'ctx>, String>,
|
2024-07-02 19:05:00 +08:00
|
|
|
BodyFn:
|
|
|
|
FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, BreakContinueHooks, I) -> Result<(), String>,
|
2024-06-12 14:45:03 +08:00
|
|
|
UpdateFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>,
|
2023-11-17 17:30:27 +08:00
|
|
|
{
|
2024-04-19 19:00:07 +08:00
|
|
|
let current_bb = ctx.builder.get_insert_block().unwrap();
|
|
|
|
let init_bb = ctx.ctx.insert_basic_block_after(current_bb, "for.init");
|
2023-11-17 17:30:27 +08:00
|
|
|
// The BB containing the loop condition check
|
2024-04-19 19:00:07 +08:00
|
|
|
let cond_bb = ctx.ctx.insert_basic_block_after(init_bb, "for.cond");
|
|
|
|
let body_bb = ctx.ctx.insert_basic_block_after(cond_bb, "for.body");
|
2023-11-17 17:30:27 +08:00
|
|
|
// The BB containing the increment expression
|
2024-04-19 19:00:07 +08:00
|
|
|
let update_bb = ctx.ctx.insert_basic_block_after(body_bb, "for.update");
|
|
|
|
let cont_bb = ctx.ctx.insert_basic_block_after(update_bb, "for.end");
|
2023-11-17 17:30:27 +08:00
|
|
|
|
|
|
|
// store loop bb information and restore it later
|
|
|
|
let loop_bb = ctx.loop_target.replace((update_bb, cont_bb));
|
|
|
|
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(init_bb).unwrap();
|
2023-11-17 17:30:27 +08:00
|
|
|
|
2024-04-12 18:59:18 +08:00
|
|
|
ctx.builder.position_at_end(init_bb);
|
|
|
|
let loop_var = init(generator, ctx)?;
|
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
2024-04-12 18:59:18 +08:00
|
|
|
}
|
2023-11-17 17:30:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(cond_bb);
|
|
|
|
let cond = cond(generator, ctx, loop_var.clone())?;
|
|
|
|
assert_eq!(cond.get_type().get_bit_width(), ctx.ctx.bool_type().get_bit_width());
|
2024-04-12 18:59:18 +08:00
|
|
|
if !ctx.is_terminated() {
|
2024-06-12 14:45:03 +08:00
|
|
|
ctx.builder.build_conditional_branch(cond, body_bb, cont_bb).unwrap();
|
2024-04-12 18:59:18 +08:00
|
|
|
}
|
2023-11-17 17:30:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
2024-07-02 19:05:00 +08:00
|
|
|
let hooks = BreakContinueHooks { exit_bb: cont_bb, latch_bb: update_bb };
|
|
|
|
body(generator, ctx, hooks, loop_var.clone())?;
|
2024-04-12 18:59:18 +08:00
|
|
|
if !ctx.is_terminated() {
|
|
|
|
ctx.builder.build_unconditional_branch(update_bb).unwrap();
|
|
|
|
}
|
2023-11-17 17:30:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(update_bb);
|
|
|
|
update(generator, ctx, loop_var)?;
|
2024-04-12 18:59:18 +08:00
|
|
|
if !ctx.is_terminated() {
|
|
|
|
ctx.builder.build_unconditional_branch(cond_bb).unwrap();
|
|
|
|
}
|
2023-11-17 17:30:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
ctx.loop_target = loop_bb;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
/// Generates a C-style monotonically-increasing `for` construct using lambdas, similar to the
|
2024-03-08 13:13:18 +08:00
|
|
|
/// following C code:
|
|
|
|
///
|
|
|
|
/// ```c
|
|
|
|
/// for (int x = init_val; x /* < or <= ; see `max_val` */ max_val; x += incr_val) {
|
|
|
|
/// body(x);
|
|
|
|
/// }
|
|
|
|
/// ```
|
2024-03-13 11:16:23 +08:00
|
|
|
///
|
2024-06-12 14:45:03 +08:00
|
|
|
/// * `init_val` - The initial value of the loop variable. The type of this value will also be used
|
2024-03-08 13:13:18 +08:00
|
|
|
/// as the type of the loop variable.
|
|
|
|
/// * `max_val` - A tuple containing the maximum value of the loop variable, and whether the maximum
|
|
|
|
/// value should be treated as inclusive (as opposed to exclusive).
|
|
|
|
/// * `body` - A lambda containing IR statements within the loop body.
|
|
|
|
/// * `incr_val` - The value to increment the loop variable on each iteration.
|
2024-03-19 18:24:30 +08:00
|
|
|
pub fn gen_for_callback_incrementing<'ctx, 'a, G, BodyFn>(
|
|
|
|
generator: &mut G,
|
2024-03-08 13:13:18 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
init_val: IntValue<'ctx>,
|
|
|
|
max_val: (IntValue<'ctx>, bool),
|
|
|
|
body: BodyFn,
|
|
|
|
incr_val: IntValue<'ctx>,
|
|
|
|
) -> Result<(), String>
|
2024-06-12 14:45:03 +08:00
|
|
|
where
|
|
|
|
G: CodeGenerator + ?Sized,
|
2024-07-02 19:05:00 +08:00
|
|
|
BodyFn: FnOnce(
|
|
|
|
&mut G,
|
|
|
|
&mut CodeGenContext<'ctx, 'a>,
|
|
|
|
BreakContinueHooks,
|
|
|
|
IntValue<'ctx>,
|
|
|
|
) -> Result<(), String>,
|
2024-03-08 13:13:18 +08:00
|
|
|
{
|
|
|
|
let init_val_t = init_val.get_type();
|
|
|
|
|
|
|
|
gen_for_callback(
|
|
|
|
generator,
|
|
|
|
ctx,
|
|
|
|
|generator, ctx| {
|
|
|
|
let i_addr = generator.gen_var_alloc(ctx, init_val_t.into(), None)?;
|
|
|
|
ctx.builder.build_store(i_addr, init_val).unwrap();
|
|
|
|
|
|
|
|
Ok(i_addr)
|
|
|
|
},
|
|
|
|
|_, ctx, i_addr| {
|
2024-06-12 14:45:03 +08:00
|
|
|
let cmp_op = if max_val.1 { IntPredicate::ULE } else { IntPredicate::ULT };
|
2024-03-08 13:13:18 +08:00
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
|
|
|
let max_val =
|
|
|
|
ctx.builder.build_int_z_extend_or_bit_cast(max_val.0, init_val_t, "").unwrap();
|
2024-03-08 13:13:18 +08:00
|
|
|
|
|
|
|
Ok(ctx.builder.build_int_compare(cmp_op, i, max_val, "").unwrap())
|
|
|
|
},
|
2024-07-02 19:05:00 +08:00
|
|
|
|generator, ctx, hooks, i_addr| {
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
2024-03-08 13:13:18 +08:00
|
|
|
|
2024-07-02 19:05:00 +08:00
|
|
|
body(generator, ctx, hooks, i)
|
2024-03-08 13:13:18 +08:00
|
|
|
},
|
|
|
|
|_, ctx, i_addr| {
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
|
|
|
let incr_val =
|
|
|
|
ctx.builder.build_int_z_extend_or_bit_cast(incr_val, init_val_t, "").unwrap();
|
2024-03-08 13:13:18 +08:00
|
|
|
let i = ctx.builder.build_int_add(i, incr_val, "").unwrap();
|
|
|
|
ctx.builder.build_store(i_addr, i).unwrap();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-05-27 15:11:14 +08:00
|
|
|
/// Generates a `for` construct over a `range`-like iterable using lambdas, similar to the following
|
|
|
|
/// C code:
|
2024-06-12 14:45:03 +08:00
|
|
|
///
|
2024-05-27 15:11:14 +08:00
|
|
|
/// ```c
|
|
|
|
/// bool incr = start_fn() <= end_fn();
|
|
|
|
/// for (int i = start_fn(); i /* < or > */ end_fn(); i += step_fn()) {
|
|
|
|
/// body_fn(i);
|
|
|
|
/// }
|
|
|
|
/// ```
|
2024-06-12 14:45:03 +08:00
|
|
|
///
|
2024-05-27 15:11:14 +08:00
|
|
|
/// - `is_unsigned`: Whether to treat the values of the `range` as unsigned.
|
2024-06-12 14:45:03 +08:00
|
|
|
/// - `start_fn`: A lambda of IR statements that retrieves the `start` value of the `range`-like
|
2024-05-27 15:11:14 +08:00
|
|
|
/// iterable.
|
|
|
|
/// - `stop_fn`: A lambda of IR statements that retrieves the `stop` value of the `range`-like
|
|
|
|
/// iterable. This value will be extended to the size of `start`.
|
|
|
|
/// - `stop_inclusive`: Whether the stop value should be treated as inclusive.
|
2024-06-12 14:45:03 +08:00
|
|
|
/// - `step_fn`: A lambda of IR statements that retrieves the `step` value of the `range`-like
|
2024-05-27 15:11:14 +08:00
|
|
|
/// iterable. This value will be extended to the size of `start`.
|
|
|
|
/// - `body_fn`: A lambda of IR statements within the loop body.
|
|
|
|
pub fn gen_for_range_callback<'ctx, 'a, G, StartFn, StopFn, StepFn, BodyFn>(
|
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
is_unsigned: bool,
|
|
|
|
start_fn: StartFn,
|
|
|
|
(stop_fn, stop_inclusive): (StopFn, bool),
|
|
|
|
step_fn: StepFn,
|
|
|
|
body_fn: BodyFn,
|
|
|
|
) -> Result<(), String>
|
2024-06-12 14:45:03 +08:00
|
|
|
where
|
|
|
|
G: CodeGenerator + ?Sized,
|
|
|
|
StartFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<IntValue<'ctx>, String>,
|
|
|
|
StopFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<IntValue<'ctx>, String>,
|
|
|
|
StepFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<IntValue<'ctx>, String>,
|
|
|
|
BodyFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, IntValue<'ctx>) -> Result<(), String>,
|
2024-05-27 15:11:14 +08:00
|
|
|
{
|
2024-06-12 14:45:03 +08:00
|
|
|
let init_val_t = start_fn(generator, ctx).map(IntValue::get_type).unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
|
|
|
|
gen_for_callback(
|
|
|
|
generator,
|
|
|
|
ctx,
|
|
|
|
|generator, ctx| {
|
|
|
|
let i_addr = generator.gen_var_alloc(ctx, init_val_t.into(), None)?;
|
|
|
|
|
|
|
|
let start = start_fn(generator, ctx)?;
|
|
|
|
ctx.builder.build_store(i_addr, start).unwrap();
|
|
|
|
|
|
|
|
let start = start_fn(generator, ctx)?;
|
|
|
|
let stop = stop_fn(generator, ctx)?;
|
2024-05-29 14:19:12 +08:00
|
|
|
let stop = if stop.get_type().get_bit_width() == start.get_type().get_bit_width() {
|
2024-05-27 15:11:14 +08:00
|
|
|
stop
|
2024-05-29 14:19:12 +08:00
|
|
|
} else if is_unsigned {
|
|
|
|
ctx.builder.build_int_z_extend(stop, start.get_type(), "").unwrap()
|
|
|
|
} else {
|
|
|
|
ctx.builder.build_int_s_extend(stop, start.get_type(), "").unwrap()
|
2024-05-27 15:11:14 +08:00
|
|
|
};
|
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
let incr = ctx
|
|
|
|
.builder
|
|
|
|
.build_int_compare(
|
|
|
|
if is_unsigned { IntPredicate::ULE } else { IntPredicate::SLE },
|
|
|
|
start,
|
|
|
|
stop,
|
|
|
|
"",
|
|
|
|
)
|
|
|
|
.unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
|
|
|
|
Ok((i_addr, incr))
|
|
|
|
},
|
|
|
|
|generator, ctx, (i_addr, incr)| {
|
|
|
|
let (lt_cmp_op, gt_cmp_op) = match (is_unsigned, stop_inclusive) {
|
|
|
|
(true, true) => (IntPredicate::ULE, IntPredicate::UGE),
|
|
|
|
(true, false) => (IntPredicate::ULT, IntPredicate::UGT),
|
|
|
|
(false, true) => (IntPredicate::SLE, IntPredicate::SGE),
|
|
|
|
(false, false) => (IntPredicate::SLT, IntPredicate::SGT),
|
|
|
|
};
|
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
let stop = stop_fn(generator, ctx)?;
|
2024-05-29 14:19:12 +08:00
|
|
|
let stop = if stop.get_type().get_bit_width() == i.get_type().get_bit_width() {
|
2024-05-27 15:11:14 +08:00
|
|
|
stop
|
2024-05-29 14:19:12 +08:00
|
|
|
} else if is_unsigned {
|
|
|
|
ctx.builder.build_int_z_extend(stop, i.get_type(), "").unwrap()
|
|
|
|
} else {
|
|
|
|
ctx.builder.build_int_s_extend(stop, i.get_type(), "").unwrap()
|
2024-05-27 15:11:14 +08:00
|
|
|
};
|
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
let i_lt_end = ctx.builder.build_int_compare(lt_cmp_op, i, stop, "").unwrap();
|
|
|
|
let i_gt_end = ctx.builder.build_int_compare(gt_cmp_op, i, stop, "").unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
let cond = ctx
|
|
|
|
.builder
|
2024-05-27 15:11:14 +08:00
|
|
|
.build_select(incr, i_lt_end, i_gt_end, "")
|
|
|
|
.map(BasicValueEnum::into_int_value)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
Ok(cond)
|
|
|
|
},
|
2024-07-02 19:05:00 +08:00
|
|
|
|generator, ctx, _, (i_addr, _)| {
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
|
|
|
|
body_fn(generator, ctx, i)
|
|
|
|
},
|
|
|
|
|generator, ctx, (i_addr, _)| {
|
2024-06-12 14:45:03 +08:00
|
|
|
let i = ctx.builder.build_load(i_addr, "").map(BasicValueEnum::into_int_value).unwrap();
|
2024-05-27 15:11:14 +08:00
|
|
|
|
|
|
|
let incr_val = step_fn(generator, ctx)?;
|
2024-05-29 14:19:12 +08:00
|
|
|
let incr_val = if incr_val.get_type().get_bit_width() == i.get_type().get_bit_width() {
|
2024-05-27 15:11:14 +08:00
|
|
|
incr_val
|
2024-05-29 14:19:12 +08:00
|
|
|
} else if is_unsigned {
|
|
|
|
ctx.builder.build_int_z_extend(incr_val, i.get_type(), "").unwrap()
|
|
|
|
} else {
|
|
|
|
ctx.builder.build_int_s_extend(incr_val, i.get_type(), "").unwrap()
|
2024-05-27 15:11:14 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
let i = ctx.builder.build_int_add(i, incr_val, "").unwrap();
|
|
|
|
ctx.builder.build_store(i_addr, i).unwrap();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_while`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_while<G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2021-10-16 22:17:36 +08:00
|
|
|
stmt: &Stmt<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2024-06-12 14:45:03 +08:00
|
|
|
let StmtKind::While { test, body, orelse, .. } = &stmt.node else { unreachable!() };
|
2023-12-06 15:26:37 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// var_assignment static values may be changed in another branch
|
|
|
|
// if so, remove the static value as it may not be correct in this branch
|
|
|
|
let var_assignment = ctx.var_assignment.clone();
|
|
|
|
|
|
|
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let test_bb = ctx.ctx.append_basic_block(current, "while.test");
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "while.body");
|
|
|
|
let cont_bb = ctx.ctx.append_basic_block(current, "while.cont");
|
|
|
|
// if there is no orelse, we just go to cont_bb
|
2024-06-12 14:45:03 +08:00
|
|
|
let orelse_bb = if orelse.is_empty() {
|
|
|
|
cont_bb
|
|
|
|
} else {
|
|
|
|
ctx.ctx.append_basic_block(current, "while.orelse")
|
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
// store loop bb information and restore it later
|
|
|
|
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(test_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(test_bb);
|
|
|
|
let test = if let Some(v) = generator.gen_expr(ctx, test)? {
|
|
|
|
v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
|
|
|
} else {
|
|
|
|
for bb in [body_bb, cont_bb] {
|
|
|
|
ctx.builder.position_at_end(bb);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unreachable().unwrap();
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-12 13:38:27 +08:00
|
|
|
};
|
2024-06-12 14:45:03 +08:00
|
|
|
let BasicValueEnum::IntValue(test) = test else { unreachable!() };
|
2023-12-12 13:38:27 +08:00
|
|
|
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb)
|
|
|
|
.unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(test_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
if !orelse.is_empty() {
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
generator.gen_block(ctx, orelse.iter())?;
|
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb).unwrap();
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
ctx.loop_target = loop_bb;
|
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2024-04-13 01:13:40 +08:00
|
|
|
/// Generates a C-style chained-`if` construct using lambdas, similar to the following C code:
|
2024-04-16 16:30:18 +08:00
|
|
|
///
|
2024-04-13 01:13:40 +08:00
|
|
|
/// ```c
|
|
|
|
/// T val;
|
2024-04-16 16:30:18 +08:00
|
|
|
/// if (cond_fn()) {
|
|
|
|
/// val = then_fn();
|
|
|
|
/// } else {
|
|
|
|
/// val = else_fn();
|
2024-04-13 01:13:40 +08:00
|
|
|
/// }
|
|
|
|
/// ```
|
2024-04-16 16:30:18 +08:00
|
|
|
pub fn gen_if_else_expr_callback<'ctx, 'a, G, CondFn, ThenFn, ElseFn, R>(
|
2024-04-13 01:13:40 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
2024-04-16 16:30:18 +08:00
|
|
|
cond_fn: CondFn,
|
|
|
|
then_fn: ThenFn,
|
|
|
|
else_fn: ElseFn,
|
2024-04-13 01:13:40 +08:00
|
|
|
) -> Result<Option<BasicValueEnum<'ctx>>, String>
|
2024-06-12 14:45:03 +08:00
|
|
|
where
|
|
|
|
G: CodeGenerator + ?Sized,
|
|
|
|
CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<IntValue<'ctx>, String>,
|
|
|
|
ThenFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<Option<R>, String>,
|
|
|
|
ElseFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<Option<R>, String>,
|
|
|
|
R: BasicValue<'ctx>,
|
2024-04-13 01:13:40 +08:00
|
|
|
{
|
|
|
|
let current_bb = ctx.builder.get_insert_block().unwrap();
|
|
|
|
|
2024-04-16 16:30:18 +08:00
|
|
|
let then_bb = ctx.ctx.insert_basic_block_after(current_bb, "if.then");
|
2024-04-19 19:00:07 +08:00
|
|
|
let else_bb = ctx.ctx.insert_basic_block_after(then_bb, "if.else");
|
|
|
|
let end_bb = ctx.ctx.insert_basic_block_after(else_bb, "if.end");
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-04-16 16:30:18 +08:00
|
|
|
let cond = cond_fn(generator, ctx)?;
|
|
|
|
assert_eq!(cond.get_type().get_bit_width(), ctx.ctx.bool_type().get_bit_width());
|
|
|
|
ctx.builder.build_conditional_branch(cond, then_bb, else_bb).unwrap();
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-04-16 16:30:18 +08:00
|
|
|
ctx.builder.position_at_end(then_bb);
|
|
|
|
let then_val = then_fn(generator, ctx)?;
|
2024-06-07 16:38:12 +08:00
|
|
|
let then_end_bb = ctx.builder.get_insert_block().unwrap();
|
2024-04-16 16:30:18 +08:00
|
|
|
if !ctx.is_terminated() {
|
|
|
|
ctx.builder.build_unconditional_branch(end_bb).unwrap();
|
|
|
|
}
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-04-16 16:30:18 +08:00
|
|
|
ctx.builder.position_at_end(else_bb);
|
|
|
|
let else_val = else_fn(generator, ctx)?;
|
2024-06-07 16:38:12 +08:00
|
|
|
let else_end_bb = ctx.builder.get_insert_block().unwrap();
|
2024-04-16 16:30:18 +08:00
|
|
|
if !ctx.is_terminated() {
|
|
|
|
ctx.builder.build_unconditional_branch(end_bb).unwrap();
|
|
|
|
}
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-04-19 19:00:07 +08:00
|
|
|
ctx.builder.position_at_end(end_bb);
|
2024-04-16 16:30:18 +08:00
|
|
|
let phi = match (then_val, else_val) {
|
|
|
|
(Some(tv), Some(ev)) => {
|
|
|
|
let tv_ty = tv.as_basic_value_enum().get_type();
|
|
|
|
assert_eq!(tv_ty, ev.as_basic_value_enum().get_type());
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-04-16 16:30:18 +08:00
|
|
|
let phi = ctx.builder.build_phi(tv_ty, "").unwrap();
|
2024-06-07 16:38:12 +08:00
|
|
|
phi.add_incoming(&[(&tv, then_end_bb), (&ev, else_end_bb)]);
|
2024-04-13 01:13:40 +08:00
|
|
|
|
2024-06-12 14:45:03 +08:00
|
|
|
Some(phi.as_basic_value())
|
|
|
|
}
|
2024-04-16 16:30:18 +08:00
|
|
|
(Some(tv), None) => Some(tv.as_basic_value_enum()),
|
|
|
|
(None, Some(ev)) => Some(ev.as_basic_value_enum()),
|
|
|
|
(None, None) => None,
|
2024-04-13 01:13:40 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(phi)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generates a C-style chained-`if` construct using lambdas, similar to the following C code:
|
|
|
|
///
|
|
|
|
/// ```c
|
|
|
|
/// if (cond_fn()) {
|
|
|
|
/// then_fn();
|
|
|
|
/// } else {
|
2024-04-16 16:30:18 +08:00
|
|
|
/// else_fn();
|
2024-04-13 01:13:40 +08:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
pub fn gen_if_callback<'ctx, 'a, G, CondFn, ThenFn, ElseFn>(
|
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
cond_fn: CondFn,
|
|
|
|
then_fn: ThenFn,
|
2024-04-16 16:30:18 +08:00
|
|
|
else_fn: ElseFn,
|
2024-04-13 01:13:40 +08:00
|
|
|
) -> Result<(), String>
|
2024-06-12 14:45:03 +08:00
|
|
|
where
|
|
|
|
G: CodeGenerator + ?Sized,
|
|
|
|
CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<IntValue<'ctx>, String>,
|
|
|
|
ThenFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<(), String>,
|
|
|
|
ElseFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result<(), String>,
|
2024-04-13 01:13:40 +08:00
|
|
|
{
|
2024-04-16 16:30:18 +08:00
|
|
|
gen_if_else_expr_callback(
|
2024-04-13 01:13:40 +08:00
|
|
|
generator,
|
|
|
|
ctx,
|
2024-04-16 16:30:18 +08:00
|
|
|
cond_fn,
|
|
|
|
|generator, ctx| {
|
|
|
|
then_fn(generator, ctx)?;
|
|
|
|
Ok(None::<BasicValueEnum<'ctx>>)
|
|
|
|
},
|
|
|
|
|generator, ctx| {
|
|
|
|
else_fn(generator, ctx)?;
|
|
|
|
Ok(None)
|
2024-06-12 14:45:03 +08:00
|
|
|
},
|
2024-04-16 16:30:18 +08:00
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
2024-04-13 01:13:40 +08:00
|
|
|
}
|
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_if`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_if<G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2021-10-16 22:17:36 +08:00
|
|
|
stmt: &Stmt<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2024-06-12 14:45:03 +08:00
|
|
|
let StmtKind::If { test, body, orelse, .. } = &stmt.node else { unreachable!() };
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
// var_assignment static values may be changed in another branch
|
|
|
|
// if so, remove the static value as it may not be correct in this branch
|
|
|
|
let var_assignment = ctx.var_assignment.clone();
|
|
|
|
|
|
|
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let test_bb = ctx.ctx.append_basic_block(current, "if.test");
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "if.body");
|
|
|
|
let mut cont_bb = None;
|
|
|
|
// if there is no orelse, we just go to cont_bb
|
|
|
|
let orelse_bb = if orelse.is_empty() {
|
|
|
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "if.cont"));
|
|
|
|
cont_bb.unwrap()
|
|
|
|
} else {
|
|
|
|
ctx.ctx.append_basic_block(current, "if.orelse")
|
|
|
|
};
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(test_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(test_bb);
|
2024-06-12 14:45:03 +08:00
|
|
|
let test = generator.gen_expr(ctx, test).and_then(|v| {
|
|
|
|
v.map(|v| v.to_basic_value_enum(ctx, generator, test.custom.unwrap())).transpose()
|
|
|
|
})?;
|
2023-12-12 13:38:27 +08:00
|
|
|
if let Some(BasicValueEnum::IntValue(test)) = test {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb)
|
|
|
|
.unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
};
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
if !ctx.is_terminated() {
|
|
|
|
if cont_bb.is_none() {
|
|
|
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
|
|
|
}
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap()).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
if !orelse.is_empty() {
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
generator.gen_block(ctx, orelse.iter())?;
|
2022-02-12 21:13:16 +08:00
|
|
|
if !ctx.is_terminated() {
|
2021-10-16 22:17:36 +08:00
|
|
|
if cont_bb.is_none() {
|
|
|
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
2021-08-19 15:30:15 +08:00
|
|
|
}
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap()).unwrap();
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
if let Some(cont_bb) = cont_bb {
|
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
}
|
|
|
|
for (k, (_, _, counter)) in &var_assignment {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
|
|
|
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn final_proxy<'ctx>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2022-02-12 21:15:50 +08:00
|
|
|
target: BasicBlock<'ctx>,
|
|
|
|
block: BasicBlock<'ctx>,
|
2022-02-25 13:59:53 +08:00
|
|
|
final_data: &mut (PointerValue, Vec<BasicBlock<'ctx>>, Vec<BasicBlock<'ctx>>),
|
2022-02-12 21:15:50 +08:00
|
|
|
) {
|
2022-02-25 13:59:53 +08:00
|
|
|
let (final_state, final_targets, final_paths) = final_data;
|
2022-02-12 21:15:50 +08:00
|
|
|
let prev = ctx.builder.get_insert_block().unwrap();
|
|
|
|
ctx.builder.position_at_end(block);
|
|
|
|
unsafe {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(*final_state, target.get_address().unwrap()).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
ctx.builder.position_at_end(prev);
|
|
|
|
final_targets.push(target);
|
|
|
|
final_paths.push(block);
|
|
|
|
}
|
|
|
|
|
2023-09-20 16:59:47 +08:00
|
|
|
/// Inserts the declaration of the builtin function with the specified `symbol` name, and returns
|
|
|
|
/// the function.
|
2024-03-19 18:24:30 +08:00
|
|
|
pub fn get_builtins<'ctx, G: CodeGenerator + ?Sized>(
|
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2022-02-12 21:15:50 +08:00
|
|
|
symbol: &str,
|
|
|
|
) -> FunctionValue<'ctx> {
|
|
|
|
ctx.module.get_function(symbol).unwrap_or_else(|| {
|
|
|
|
let ty = match symbol {
|
2022-02-23 11:04:35 +08:00
|
|
|
"__nac3_raise" => ctx
|
2022-02-21 18:27:46 +08:00
|
|
|
.ctx
|
|
|
|
.void_type()
|
|
|
|
.fn_type(&[ctx.get_llvm_type(generator, ctx.primitives.exception).into()], false),
|
2023-12-08 17:43:32 +08:00
|
|
|
"__nac3_resume" | "__nac3_end_catch" => ctx.ctx.void_type().fn_type(&[], false),
|
2022-02-12 21:15:50 +08:00
|
|
|
_ => unimplemented!(),
|
|
|
|
};
|
|
|
|
let fun = ctx.module.add_function(symbol, ty, None);
|
2022-02-23 11:04:35 +08:00
|
|
|
if symbol == "__nac3_raise" || symbol == "__nac3_resume" {
|
2022-02-12 21:15:50 +08:00
|
|
|
fun.add_attribute(
|
|
|
|
AttributeLoc::Function,
|
2022-04-18 18:47:20 +08:00
|
|
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("noreturn"), 0),
|
2022-02-12 21:15:50 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
fun
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn exn_constructor<'ctx>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2022-02-12 21:09:23 +08:00
|
|
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
|
|
|
_fun: (&FunSignature, DefinitionId),
|
|
|
|
mut args: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
2022-02-21 18:27:46 +08:00
|
|
|
generator: &mut dyn CodeGenerator,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
2022-02-12 21:09:23 +08:00
|
|
|
let (zelf_ty, zelf) = obj.unwrap();
|
2022-04-08 03:26:42 +08:00
|
|
|
let zelf = zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
2022-02-12 21:09:23 +08:00
|
|
|
let int32 = ctx.ctx.i32_type();
|
|
|
|
let zero = int32.const_zero();
|
2023-12-13 18:15:22 +08:00
|
|
|
let zelf_id = if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(zelf_ty) {
|
2023-12-12 13:38:27 +08:00
|
|
|
obj_id.0
|
2023-12-13 18:15:22 +08:00
|
|
|
} else {
|
|
|
|
unreachable!()
|
2022-02-12 21:09:23 +08:00
|
|
|
};
|
|
|
|
let defs = ctx.top_level.definitions.read();
|
|
|
|
let def = defs[zelf_id].read();
|
2024-06-12 14:45:03 +08:00
|
|
|
let TopLevelDef::Class { name: zelf_name, .. } = &*def else { unreachable!() };
|
2022-03-05 00:26:35 +08:00
|
|
|
let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(zelf_id), zelf_name);
|
2022-02-12 21:09:23 +08:00
|
|
|
unsafe {
|
2024-02-19 19:30:25 +08:00
|
|
|
let id_ptr = ctx.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id").unwrap();
|
2022-02-12 21:09:23 +08:00
|
|
|
let id = ctx.resolver.get_string_id(&exception_name);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(id_ptr, int32.const_int(id as u64, false)).unwrap();
|
2024-06-12 14:45:03 +08:00
|
|
|
let empty_string =
|
|
|
|
ctx.gen_const(generator, &Constant::Str(String::new()), ctx.primitives.str);
|
|
|
|
let ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg")
|
|
|
|
.unwrap();
|
2023-12-08 17:43:32 +08:00
|
|
|
let msg = if args.is_empty() {
|
2023-12-06 15:26:37 +08:00
|
|
|
empty_string.unwrap()
|
2023-12-08 17:43:32 +08:00
|
|
|
} else {
|
|
|
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
2022-02-12 21:09:23 +08:00
|
|
|
};
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(ptr, msg).unwrap();
|
2023-12-08 17:43:32 +08:00
|
|
|
for i in &[6, 7, 8] {
|
|
|
|
let value = if args.is_empty() {
|
2022-02-12 21:09:23 +08:00
|
|
|
ctx.ctx.i64_type().const_zero().into()
|
2023-12-08 17:43:32 +08:00
|
|
|
} else {
|
|
|
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.int64)?
|
2022-02-12 21:09:23 +08:00
|
|
|
};
|
2024-06-12 14:45:03 +08:00
|
|
|
let ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(zelf, &[zero, int32.const_int(*i, false)], "exn.param")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(ptr, value).unwrap();
|
2022-02-12 21:09:23 +08:00
|
|
|
}
|
|
|
|
// set file, func to empty string
|
2023-12-08 17:43:32 +08:00
|
|
|
for i in &[1, 4] {
|
2024-06-12 14:45:03 +08:00
|
|
|
let ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(zelf, &[zero, int32.const_int(*i, false)], "exn.str")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(ptr, empty_string.unwrap()).unwrap();
|
2022-02-12 21:09:23 +08:00
|
|
|
}
|
|
|
|
// set ints to zero
|
2023-12-08 17:43:32 +08:00
|
|
|
for i in &[2, 3] {
|
2024-06-12 14:45:03 +08:00
|
|
|
let ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(zelf, &[zero, int32.const_int(*i, false)], "exn.ints")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(ptr, zero).unwrap();
|
2022-02-12 21:09:23 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(Some(zelf.into()))
|
2022-02-12 21:09:23 +08:00
|
|
|
}
|
|
|
|
|
2023-09-20 16:59:47 +08:00
|
|
|
/// Generates IR for a `raise` statement.
|
|
|
|
///
|
|
|
|
/// * `exception` - The exception thrown by the `raise` statement.
|
|
|
|
/// * `loc` - The location where the exception is raised from.
|
2024-03-19 18:24:30 +08:00
|
|
|
pub fn gen_raise<'ctx, G: CodeGenerator + ?Sized>(
|
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
2022-02-12 21:15:50 +08:00
|
|
|
exception: Option<&BasicValueEnum<'ctx>>,
|
|
|
|
loc: Location,
|
|
|
|
) {
|
|
|
|
if let Some(exception) = exception {
|
|
|
|
unsafe {
|
|
|
|
let int32 = ctx.ctx.i32_type();
|
|
|
|
let zero = int32.const_zero();
|
|
|
|
let exception = exception.into_pointer_value();
|
2024-06-12 14:45:03 +08:00
|
|
|
let file_ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(exception, &[zero, int32.const_int(1, false)], "file_ptr")
|
|
|
|
.unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
let filename = ctx.gen_string(generator, loc.file.0);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(file_ptr, filename).unwrap();
|
2024-06-12 14:45:03 +08:00
|
|
|
let row_ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(exception, &[zero, int32.const_int(2, false)], "row_ptr")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(row_ptr, int32.const_int(loc.row as u64, false)).unwrap();
|
2024-06-12 14:45:03 +08:00
|
|
|
let col_ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(exception, &[zero, int32.const_int(3, false)], "col_ptr")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(col_ptr, int32.const_int(loc.column as u64, false)).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
|
|
|
|
let current_fun = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let fun_name = ctx.gen_string(generator, current_fun.get_name().to_str().unwrap());
|
2024-06-12 14:45:03 +08:00
|
|
|
let name_ptr = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_in_bounds_gep(exception, &[zero, int32.const_int(4, false)], "name_ptr")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_store(name_ptr, fun_name).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
|
2022-02-23 11:04:35 +08:00
|
|
|
let raise = get_builtins(generator, ctx, "__nac3_raise");
|
2022-02-12 21:15:50 +08:00
|
|
|
let exception = *exception;
|
|
|
|
ctx.build_call_or_invoke(raise, &[exception], "raise");
|
|
|
|
} else {
|
2022-02-23 11:04:35 +08:00
|
|
|
let resume = get_builtins(generator, ctx, "__nac3_resume");
|
2022-02-12 21:15:50 +08:00
|
|
|
ctx.build_call_or_invoke(resume, &[], "resume");
|
|
|
|
}
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unreachable().unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
|
2023-09-20 16:59:47 +08:00
|
|
|
/// Generates IR for a `try` statement.
|
2022-02-12 21:15:50 +08:00
|
|
|
pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
target: &Stmt<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2023-12-12 13:38:27 +08:00
|
|
|
let StmtKind::Try { body, handlers, orelse, finalbody, .. } = &target.node else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2023-12-08 17:43:32 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
// if we need to generate anything related to exception, we must have personality defined
|
|
|
|
let personality_symbol = ctx.top_level.personality_symbol.as_ref().unwrap();
|
|
|
|
let personality = ctx.module.get_function(personality_symbol).unwrap_or_else(|| {
|
|
|
|
let ty = ctx.ctx.i32_type().fn_type(&[], true);
|
|
|
|
ctx.module.add_function(personality_symbol, ty, None)
|
|
|
|
});
|
|
|
|
let exception_type = ctx.get_llvm_type(generator, ctx.primitives.exception);
|
|
|
|
let ptr_type = ctx.ctx.i8_type().ptr_type(inkwell::AddressSpace::default());
|
|
|
|
let current_block = ctx.builder.get_insert_block().unwrap();
|
|
|
|
let current_fun = current_block.get_parent().unwrap();
|
|
|
|
let landingpad = ctx.ctx.append_basic_block(current_fun, "try.landingpad");
|
|
|
|
let dispatcher = ctx.ctx.append_basic_block(current_fun, "try.dispatch");
|
|
|
|
let mut dispatcher_end = dispatcher;
|
|
|
|
ctx.builder.position_at_end(dispatcher);
|
2024-02-19 19:30:25 +08:00
|
|
|
let exn = ctx.builder.build_phi(exception_type, "exn").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(current_block);
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let mut cleanup = None;
|
|
|
|
let mut old_loop_target = None;
|
|
|
|
let mut old_return = None;
|
|
|
|
let mut final_data = None;
|
|
|
|
let has_cleanup = !finalbody.is_empty();
|
|
|
|
if has_cleanup {
|
2024-06-12 14:45:03 +08:00
|
|
|
let final_state =
|
|
|
|
generator.gen_var_alloc(ctx, ptr_type.into(), Some("try.final_state.addr"))?;
|
2023-12-12 13:38:27 +08:00
|
|
|
final_data = Some((final_state, Vec::new(), Vec::new()));
|
|
|
|
if let Some((continue_target, break_target)) = ctx.loop_target {
|
2022-02-12 21:15:50 +08:00
|
|
|
let break_proxy = ctx.ctx.append_basic_block(current_fun, "try.break");
|
|
|
|
let continue_proxy = ctx.ctx.append_basic_block(current_fun, "try.continue");
|
2023-12-12 13:38:27 +08:00
|
|
|
final_proxy(ctx, break_target, break_proxy, final_data.as_mut().unwrap());
|
|
|
|
final_proxy(ctx, continue_target, continue_proxy, final_data.as_mut().unwrap());
|
|
|
|
old_loop_target = ctx.loop_target.replace((continue_proxy, break_proxy));
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
let return_proxy = ctx.ctx.append_basic_block(current_fun, "try.return");
|
2023-12-12 13:38:27 +08:00
|
|
|
if let Some(return_target) = ctx.return_target {
|
|
|
|
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
|
|
|
|
} else {
|
|
|
|
let return_target = ctx.ctx.append_basic_block(current_fun, "try.return_target");
|
|
|
|
ctx.builder.position_at_end(return_target);
|
2024-06-12 14:45:03 +08:00
|
|
|
let return_value =
|
|
|
|
ctx.return_buffer.map(|v| ctx.builder.build_load(v, "$ret").unwrap());
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_return(return_value.as_ref().map(|v| v as &dyn BasicValue)).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(current_block);
|
|
|
|
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
|
|
|
|
}
|
|
|
|
old_return = ctx.return_target.replace(return_proxy);
|
|
|
|
cleanup = Some(ctx.ctx.append_basic_block(current_fun, "try.cleanup"));
|
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let mut clauses = Vec::new();
|
|
|
|
let mut found_catch_all = false;
|
|
|
|
for handler_node in handlers {
|
|
|
|
let ExcepthandlerKind::ExceptHandler { type_, .. } = &handler_node.node;
|
|
|
|
// none or Exception
|
|
|
|
if type_.is_none()
|
|
|
|
|| ctx
|
|
|
|
.unifier
|
|
|
|
.unioned(type_.as_ref().unwrap().custom.unwrap(), ctx.primitives.exception)
|
|
|
|
{
|
|
|
|
clauses.push(None);
|
|
|
|
found_catch_all = true;
|
|
|
|
break;
|
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let type_ = type_.as_ref().unwrap();
|
|
|
|
let exn_name = ctx.resolver.get_type_name(
|
|
|
|
&ctx.top_level.definitions.read(),
|
|
|
|
&mut ctx.unifier,
|
|
|
|
type_.custom.unwrap(),
|
|
|
|
);
|
2024-06-12 14:45:03 +08:00
|
|
|
let obj_id =
|
|
|
|
if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(type_.custom.unwrap()) {
|
|
|
|
*obj_id
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
let exception_name = format!("{}:{}", ctx.resolver.get_exception_id(obj_id.0), exn_name);
|
|
|
|
let exn_id = ctx.resolver.get_string_id(&exception_name);
|
|
|
|
let exn_id_global =
|
|
|
|
ctx.module.add_global(ctx.ctx.i32_type(), None, &format!("exn.{exn_id}"));
|
|
|
|
exn_id_global.set_initializer(&ctx.ctx.i32_type().const_int(exn_id as u64, false));
|
|
|
|
clauses.push(Some(exn_id_global.as_pointer_value().as_basic_value_enum()));
|
|
|
|
}
|
|
|
|
let mut all_clauses = clauses.clone();
|
|
|
|
if let Some(old_clauses) = &ctx.outer_catch_clauses {
|
|
|
|
if !found_catch_all {
|
|
|
|
all_clauses.extend_from_slice(&old_clauses.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let old_clauses = ctx.outer_catch_clauses.replace((all_clauses, dispatcher, exn));
|
|
|
|
let old_unwind = ctx.unwind_target.replace(landingpad);
|
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
if ctx.builder.get_insert_block().unwrap().get_terminator().is_none() {
|
|
|
|
generator.gen_block(ctx, orelse.iter())?;
|
|
|
|
}
|
|
|
|
let body = ctx.builder.get_insert_block().unwrap();
|
|
|
|
// reset old_clauses and old_unwind
|
|
|
|
let (all_clauses, _, _) = ctx.outer_catch_clauses.take().unwrap();
|
|
|
|
ctx.outer_catch_clauses = old_clauses;
|
|
|
|
ctx.unwind_target = old_unwind;
|
|
|
|
ctx.return_target = old_return;
|
|
|
|
ctx.loop_target = old_loop_target.or(ctx.loop_target).take();
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
let old_unwind = if finalbody.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let final_landingpad = ctx.ctx.append_basic_block(current_fun, "try.catch.final");
|
|
|
|
ctx.builder.position_at_end(final_landingpad);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_landing_pad(
|
|
|
|
ctx.ctx.struct_type(&[ptr_type.into(), exception_type], false),
|
|
|
|
personality,
|
|
|
|
&[],
|
|
|
|
true,
|
|
|
|
"try.catch.final",
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_unconditional_branch(cleanup.unwrap()).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(body);
|
|
|
|
ctx.unwind_target.replace(final_landingpad)
|
|
|
|
};
|
|
|
|
|
|
|
|
// run end_catch before continue/break/return
|
|
|
|
let mut final_proxy_lambda =
|
2024-06-12 14:45:03 +08:00
|
|
|
|ctx: &mut CodeGenContext<'ctx, 'a>, target: BasicBlock<'ctx>, block: BasicBlock<'ctx>| {
|
2024-06-12 12:27:35 +08:00
|
|
|
final_proxy(ctx, target, block, final_data.as_mut().unwrap());
|
2024-06-12 14:45:03 +08:00
|
|
|
};
|
|
|
|
let mut redirect_lambda =
|
|
|
|
|ctx: &mut CodeGenContext<'ctx, 'a>, target: BasicBlock<'ctx>, block: BasicBlock<'ctx>| {
|
|
|
|
ctx.builder.position_at_end(block);
|
|
|
|
ctx.builder.build_unconditional_branch(target).unwrap();
|
|
|
|
ctx.builder.position_at_end(body);
|
|
|
|
};
|
2023-12-12 13:38:27 +08:00
|
|
|
let redirect = if has_cleanup {
|
|
|
|
&mut final_proxy_lambda
|
|
|
|
as &mut dyn FnMut(&mut CodeGenContext<'ctx, 'a>, BasicBlock<'ctx>, BasicBlock<'ctx>)
|
|
|
|
} else {
|
|
|
|
&mut redirect_lambda
|
|
|
|
as &mut dyn FnMut(&mut CodeGenContext<'ctx, 'a>, BasicBlock<'ctx>, BasicBlock<'ctx>)
|
|
|
|
};
|
|
|
|
let resume = get_builtins(generator, ctx, "__nac3_resume");
|
|
|
|
let end_catch = get_builtins(generator, ctx, "__nac3_end_catch");
|
|
|
|
if let Some((continue_target, break_target)) = ctx.loop_target.take() {
|
|
|
|
let break_proxy = ctx.ctx.append_basic_block(current_fun, "try.break");
|
|
|
|
let continue_proxy = ctx.ctx.append_basic_block(current_fun, "try.continue");
|
|
|
|
ctx.builder.position_at_end(break_proxy);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(continue_proxy);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(body);
|
|
|
|
redirect(ctx, break_target, break_proxy);
|
|
|
|
redirect(ctx, continue_target, continue_proxy);
|
|
|
|
ctx.loop_target = Some((continue_proxy, break_proxy));
|
|
|
|
old_loop_target = Some((continue_target, break_target));
|
|
|
|
}
|
|
|
|
let return_proxy = ctx.ctx.append_basic_block(current_fun, "try.return");
|
|
|
|
ctx.builder.position_at_end(return_proxy);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
let return_target = ctx.return_target.take().unwrap_or_else(|| {
|
|
|
|
let doreturn = ctx.ctx.append_basic_block(current_fun, "try.doreturn");
|
|
|
|
ctx.builder.position_at_end(doreturn);
|
2024-02-19 19:30:25 +08:00
|
|
|
let return_value = ctx.return_buffer.map(|v| ctx.builder.build_load(v, "$ret").unwrap());
|
|
|
|
ctx.builder.build_return(return_value.as_ref().map(|v| v as &dyn BasicValue)).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
doreturn
|
|
|
|
});
|
|
|
|
redirect(ctx, return_target, return_proxy);
|
|
|
|
ctx.return_target = Some(return_proxy);
|
|
|
|
old_return = Some(return_target);
|
|
|
|
|
|
|
|
let mut post_handlers = Vec::new();
|
|
|
|
|
|
|
|
let exnid = if handlers.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
ctx.builder.position_at_end(dispatcher);
|
|
|
|
unsafe {
|
|
|
|
let zero = ctx.ctx.i32_type().const_zero();
|
2024-06-12 14:45:03 +08:00
|
|
|
let exnid_ptr = ctx
|
|
|
|
.builder
|
|
|
|
.build_gep(exn.as_basic_value().into_pointer_value(), &[zero, zero], "exnidptr")
|
2024-02-19 19:30:25 +08:00
|
|
|
.unwrap();
|
|
|
|
Some(ctx.builder.build_load(exnid_ptr, "exnid").unwrap())
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
};
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
for (handler_node, exn_type) in handlers.iter().zip(clauses.iter()) {
|
|
|
|
let ExcepthandlerKind::ExceptHandler { type_, name, body } = &handler_node.node;
|
|
|
|
let handler_bb = ctx.ctx.append_basic_block(current_fun, "try.handler");
|
|
|
|
ctx.builder.position_at_end(handler_bb);
|
|
|
|
if let Some(name) = name {
|
|
|
|
let exn_ty = ctx.get_llvm_type(generator, type_.as_ref().unwrap().custom.unwrap());
|
|
|
|
let exn_store = generator.gen_var_alloc(ctx, exn_ty, Some("try.exn_store.addr"))?;
|
|
|
|
ctx.var_assignment.insert(*name, (exn_store, None, 0));
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(exn_store, exn.as_basic_value()).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
generator.gen_block(ctx, body.iter())?;
|
|
|
|
let current = ctx.builder.get_insert_block().unwrap();
|
|
|
|
// only need to call end catch if not terminated
|
|
|
|
// otherwise, we already handled in return/break/continue/raise
|
|
|
|
if current.get_terminator().is_none() {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
post_handlers.push(current);
|
|
|
|
ctx.builder.position_at_end(dispatcher_end);
|
|
|
|
if let Some(exn_type) = exn_type {
|
2024-06-12 14:45:03 +08:00
|
|
|
let dispatcher_cont = ctx.ctx.append_basic_block(current_fun, "try.dispatcher_cont");
|
2023-12-12 13:38:27 +08:00
|
|
|
let actual_id = exnid.unwrap().into_int_value();
|
|
|
|
let expected_id = ctx
|
|
|
|
.builder
|
|
|
|
.build_load(exn_type.into_pointer_value(), "expected_id")
|
2024-02-19 19:30:25 +08:00
|
|
|
.map(BasicValueEnum::into_int_value)
|
|
|
|
.unwrap();
|
2024-06-12 14:45:03 +08:00
|
|
|
let result = ctx
|
|
|
|
.builder
|
2024-02-19 19:30:25 +08:00
|
|
|
.build_int_compare(IntPredicate::EQ, actual_id, expected_id, "exncheck")
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder.build_conditional_branch(result, handler_bb, dispatcher_cont).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
dispatcher_end = dispatcher_cont;
|
|
|
|
} else {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(handler_bb).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
break;
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.unwind_target = old_unwind;
|
|
|
|
ctx.loop_target = old_loop_target.or(ctx.loop_target).take();
|
|
|
|
ctx.return_target = old_return;
|
|
|
|
|
|
|
|
ctx.builder.position_at_end(landingpad);
|
|
|
|
let clauses: Vec<_> = if finalbody.is_empty() { &all_clauses } else { &clauses }
|
|
|
|
.iter()
|
|
|
|
.map(|v| v.unwrap_or(ptr_type.const_zero().into()))
|
|
|
|
.collect();
|
|
|
|
let landingpad_value = ctx
|
|
|
|
.builder
|
|
|
|
.build_landing_pad(
|
|
|
|
ctx.ctx.struct_type(&[ptr_type.into(), exception_type], false),
|
|
|
|
personality,
|
|
|
|
&clauses,
|
|
|
|
has_cleanup,
|
|
|
|
"try.landingpad",
|
|
|
|
)
|
2024-02-19 19:30:25 +08:00
|
|
|
.map(BasicValueEnum::into_struct_value)
|
|
|
|
.unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
let exn_val = ctx.builder.build_extract_value(landingpad_value, 1, "exn").unwrap();
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(dispatcher).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
exn.add_incoming(&[(&exn_val, landingpad)]);
|
|
|
|
|
|
|
|
if dispatcher_end.get_terminator().is_none() {
|
|
|
|
ctx.builder.position_at_end(dispatcher_end);
|
|
|
|
if let Some(cleanup) = cleanup {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cleanup).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
} else if let Some((_, outer_dispatcher, phi)) = ctx.outer_catch_clauses {
|
|
|
|
phi.add_incoming(&[(&exn_val, dispatcher_end)]);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(outer_dispatcher).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
} else {
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.build_call_or_invoke(resume, &[], "resume");
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unreachable().unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
|
2023-12-12 13:38:27 +08:00
|
|
|
if finalbody.is_empty() {
|
|
|
|
let tail = ctx.ctx.append_basic_block(current_fun, "try.tail");
|
|
|
|
if body.get_terminator().is_none() {
|
|
|
|
ctx.builder.position_at_end(body);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(tail).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
if matches!(cleanup, Some(cleanup) if cleanup.get_terminator().is_none()) {
|
|
|
|
ctx.builder.position_at_end(cleanup.unwrap());
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(tail).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
for post_handler in post_handlers {
|
|
|
|
if post_handler.get_terminator().is_none() {
|
|
|
|
ctx.builder.position_at_end(post_handler);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(tail).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
ctx.builder.position_at_end(tail);
|
|
|
|
} else {
|
|
|
|
// exception path
|
|
|
|
let cleanup = cleanup.unwrap();
|
|
|
|
ctx.builder.position_at_end(cleanup);
|
|
|
|
generator.gen_block(ctx, finalbody.iter())?;
|
|
|
|
if !ctx.is_terminated() {
|
|
|
|
ctx.build_call_or_invoke(resume, &[], "resume");
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unreachable().unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// normal path
|
|
|
|
let (final_state, mut final_targets, final_paths) = final_data.unwrap();
|
|
|
|
let tail = ctx.ctx.append_basic_block(current_fun, "try.tail");
|
|
|
|
final_targets.push(tail);
|
|
|
|
let finalizer = ctx.ctx.append_basic_block(current_fun, "try.finally");
|
|
|
|
ctx.builder.position_at_end(finalizer);
|
|
|
|
generator.gen_block(ctx, finalbody.iter())?;
|
|
|
|
if !ctx.is_terminated() {
|
2024-02-19 19:30:25 +08:00
|
|
|
let dest = ctx.builder.build_load(final_state, "final_dest").unwrap();
|
|
|
|
ctx.builder.build_indirect_branch(dest, &final_targets).unwrap();
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
for block in &final_paths {
|
|
|
|
if block.get_terminator().is_none() {
|
|
|
|
ctx.builder.position_at_end(*block);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(finalizer).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
}
|
|
|
|
for block in [body].iter().chain(post_handlers.iter()) {
|
|
|
|
if block.get_terminator().is_none() {
|
|
|
|
ctx.builder.position_at_end(*block);
|
|
|
|
unsafe {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(final_state, tail.get_address().unwrap()).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(finalizer).unwrap();
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
ctx.builder.position_at_end(tail);
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2023-12-12 13:38:27 +08:00
|
|
|
|
|
|
|
Ok(())
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_with`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_with<G: CodeGenerator>(
|
2021-10-31 17:16:21 +08:00
|
|
|
_: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
_: &mut CodeGenContext<'_, '_>,
|
2022-02-21 17:52:34 +08:00
|
|
|
stmt: &Stmt<Option<Type>>,
|
|
|
|
) -> Result<(), String> {
|
2021-10-31 17:16:21 +08:00
|
|
|
// TODO: Implement with statement after finishing exceptions
|
2022-02-21 17:52:34 +08:00
|
|
|
Err(format!("With statement with custom types is not yet supported (at {})", stmt.location))
|
2021-10-31 17:16:21 +08:00
|
|
|
}
|
|
|
|
|
2023-09-20 16:59:47 +08:00
|
|
|
/// Generates IR for a `return` statement.
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_return<G: CodeGenerator>(
|
2022-02-12 21:13:16 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2022-02-12 21:13:16 +08:00
|
|
|
value: &Option<Box<Expr<Option<Type>>>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2023-12-08 17:43:32 +08:00
|
|
|
let func = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
|
2023-12-06 15:26:37 +08:00
|
|
|
let value = if let Some(v_expr) = value.as_ref() {
|
|
|
|
if let Some(v) = generator.gen_expr(ctx, v_expr).transpose() {
|
2024-06-12 14:45:03 +08:00
|
|
|
Some(v.and_then(|v| v.to_basic_value_enum(ctx, generator, v_expr.custom.unwrap()))?)
|
2023-12-06 15:26:37 +08:00
|
|
|
} else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-06 15:26:37 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2022-02-12 21:13:16 +08:00
|
|
|
if let Some(return_target) = ctx.return_target {
|
|
|
|
if let Some(value) = value {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(ctx.return_buffer.unwrap(), value).unwrap();
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(return_target).unwrap();
|
2022-03-09 22:09:36 +08:00
|
|
|
} else if ctx.need_sret {
|
|
|
|
// sret
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_store(ctx.return_buffer.unwrap(), value.unwrap()).unwrap();
|
|
|
|
ctx.builder.build_return(None).unwrap();
|
2022-02-12 21:13:16 +08:00
|
|
|
} else {
|
2023-09-20 13:34:50 +08:00
|
|
|
// Remap boolean return type into i1
|
|
|
|
let value = value.map(|v| {
|
|
|
|
let expected_ty = func.get_type().get_return_type().unwrap();
|
|
|
|
let ret_val = v.as_basic_value_enum();
|
|
|
|
|
|
|
|
if expected_ty.is_int_type() && ret_val.is_int_value() {
|
|
|
|
let ret_type = expected_ty.into_int_type();
|
|
|
|
let ret_val = ret_val.into_int_value();
|
|
|
|
|
|
|
|
if ret_type.get_bit_width() == 1 && ret_val.get_type().get_bit_width() != 1 {
|
|
|
|
generator.bool_to_i1(ctx, ret_val)
|
|
|
|
} else {
|
|
|
|
ret_val
|
2024-06-12 14:45:03 +08:00
|
|
|
}
|
|
|
|
.into()
|
2023-09-20 13:34:50 +08:00
|
|
|
} else {
|
|
|
|
ret_val
|
|
|
|
}
|
|
|
|
});
|
2022-02-12 21:13:16 +08:00
|
|
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_return(value).unwrap();
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2022-02-12 21:13:16 +08:00
|
|
|
}
|
|
|
|
|
2023-12-08 17:43:32 +08:00
|
|
|
/// See [`CodeGenerator::gen_stmt`].
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_stmt<G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2021-10-16 22:17:36 +08:00
|
|
|
stmt: &Stmt<Option<Type>>,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2022-04-04 23:21:00 +08:00
|
|
|
ctx.current_loc = stmt.location;
|
2022-04-14 15:40:12 +08:00
|
|
|
|
|
|
|
let loc = ctx.debug_info.0.create_debug_location(
|
|
|
|
ctx.ctx,
|
|
|
|
ctx.current_loc.row as u32,
|
|
|
|
ctx.current_loc.column as u32,
|
|
|
|
ctx.debug_info.2,
|
|
|
|
None,
|
|
|
|
);
|
2023-03-08 15:19:09 +08:00
|
|
|
ctx.builder.set_current_debug_location(loc);
|
2022-04-14 15:40:12 +08:00
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
match &stmt.node {
|
2021-11-20 19:50:25 +08:00
|
|
|
StmtKind::Pass { .. } => {}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Expr { value, .. } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
generator.gen_expr(ctx, value)?;
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Return { value, .. } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
gen_return(generator, ctx, value)?;
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
StmtKind::AnnAssign { target, value, .. } => {
|
|
|
|
if let Some(value) = value {
|
2024-06-12 14:45:03 +08:00
|
|
|
let Some(value) = generator.gen_expr(ctx, value)? else { return Ok(()) };
|
2022-02-21 17:52:34 +08:00
|
|
|
generator.gen_assign(ctx, target, value)?;
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
StmtKind::Assign { targets, value, .. } => {
|
2024-06-12 14:45:03 +08:00
|
|
|
let Some(value) = generator.gen_expr(ctx, value)? else { return Ok(()) };
|
2023-12-08 17:43:32 +08:00
|
|
|
for target in targets {
|
2022-02-21 17:52:34 +08:00
|
|
|
generator.gen_assign(ctx, target, value.clone())?;
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Continue { .. } => {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(ctx.loop_target.unwrap().0).unwrap();
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
StmtKind::Break { .. } => {
|
2024-02-19 19:30:25 +08:00
|
|
|
ctx.builder.build_unconditional_branch(ctx.loop_target.unwrap().1).unwrap();
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
StmtKind::If { .. } => generator.gen_if(ctx, stmt)?,
|
|
|
|
StmtKind::While { .. } => generator.gen_while(ctx, stmt)?,
|
|
|
|
StmtKind::For { .. } => generator.gen_for(ctx, stmt)?,
|
|
|
|
StmtKind::With { .. } => generator.gen_with(ctx, stmt)?,
|
2021-11-12 01:44:12 +08:00
|
|
|
StmtKind::AugAssign { target, op, value, .. } => {
|
2024-06-12 15:13:09 +08:00
|
|
|
let value = gen_binop_expr(generator, ctx, target, *op, value, stmt.location, true)?;
|
2022-04-13 12:25:52 +08:00
|
|
|
generator.gen_assign(ctx, target, value.unwrap())?;
|
2021-11-12 01:44:12 +08:00
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
|
2022-02-12 21:15:50 +08:00
|
|
|
StmtKind::Raise { exc, .. } => {
|
2022-02-21 17:52:34 +08:00
|
|
|
if let Some(exc) = exc {
|
2023-12-06 15:26:37 +08:00
|
|
|
let exc = if let Some(v) = generator.gen_expr(ctx, exc)? {
|
|
|
|
v.to_basic_value_enum(ctx, generator, exc.custom.unwrap())?
|
|
|
|
} else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-06 15:26:37 +08:00
|
|
|
};
|
2022-02-21 17:52:34 +08:00
|
|
|
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
|
|
|
} else {
|
|
|
|
gen_raise(generator, ctx, None, stmt.location);
|
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
2022-03-29 00:13:47 +08:00
|
|
|
StmtKind::Assert { test, msg, .. } => {
|
2023-12-06 15:26:37 +08:00
|
|
|
let test = if let Some(v) = generator.gen_expr(ctx, test)? {
|
|
|
|
v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
|
|
|
} else {
|
2024-06-12 14:45:03 +08:00
|
|
|
return Ok(());
|
2023-12-06 15:26:37 +08:00
|
|
|
};
|
2022-03-29 00:13:47 +08:00
|
|
|
let err_msg = match msg {
|
2024-06-12 14:45:03 +08:00
|
|
|
Some(msg) => {
|
|
|
|
if let Some(v) = generator.gen_expr(ctx, msg)? {
|
|
|
|
v.to_basic_value_enum(ctx, generator, msg.custom.unwrap())?
|
|
|
|
} else {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
2022-03-29 00:13:47 +08:00
|
|
|
None => ctx.gen_string(generator, ""),
|
|
|
|
};
|
|
|
|
ctx.make_assert_impl(
|
|
|
|
generator,
|
|
|
|
test.into_int_value(),
|
|
|
|
"0:AssertionError",
|
|
|
|
err_msg,
|
|
|
|
[None, None, None],
|
|
|
|
stmt.location,
|
2023-12-08 17:43:32 +08:00
|
|
|
);
|
2022-03-29 00:13:47 +08:00
|
|
|
}
|
2024-06-12 14:45:03 +08:00
|
|
|
_ => unimplemented!(),
|
2021-10-16 22:17:36 +08:00
|
|
|
};
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2022-02-12 21:15:50 +08:00
|
|
|
}
|
|
|
|
|
2023-09-20 16:59:47 +08:00
|
|
|
/// Generates IR for a block statement contains `stmts`.
|
2023-12-06 11:49:02 +08:00
|
|
|
pub fn gen_block<'a, G: CodeGenerator, I: Iterator<Item = &'a Stmt<Option<Type>>>>(
|
2022-02-12 21:13:16 +08:00
|
|
|
generator: &mut G,
|
2023-12-06 11:49:02 +08:00
|
|
|
ctx: &mut CodeGenContext<'_, '_>,
|
2022-02-12 21:13:16 +08:00
|
|
|
stmts: I,
|
2022-02-21 17:52:34 +08:00
|
|
|
) -> Result<(), String> {
|
2022-02-12 21:13:16 +08:00
|
|
|
for stmt in stmts {
|
2022-02-21 17:52:34 +08:00
|
|
|
generator.gen_stmt(ctx, stmt)?;
|
2022-02-12 21:13:16 +08:00
|
|
|
if ctx.is_terminated() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-02-21 17:52:34 +08:00
|
|
|
Ok(())
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|