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::{
|
|
|
|
codegen::expr::gen_binop_expr,
|
|
|
|
typecheck::typedef::{Type, TypeEnum},
|
2021-12-27 22:55:51 +08:00
|
|
|
};
|
|
|
|
use inkwell::{
|
|
|
|
types::BasicTypeEnum,
|
|
|
|
values::{BasicValue, BasicValueEnum, PointerValue},
|
|
|
|
};
|
2021-11-03 17:11:00 +08:00
|
|
|
use nac3parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
2022-01-20 04:14:22 +08:00
|
|
|
use std::convert::TryFrom;
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_var<'ctx, 'a>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
ty: BasicTypeEnum<'ctx>,
|
|
|
|
) -> PointerValue<'ctx> {
|
2021-10-16 22:17:36 +08:00
|
|
|
// 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());
|
|
|
|
let ptr = ctx.builder.build_alloca(ty, "tmp");
|
|
|
|
ctx.builder.position_at_end(current);
|
|
|
|
ptr
|
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
pattern: &Expr<Option<Type>>,
|
|
|
|
) -> PointerValue<'ctx> {
|
|
|
|
// very similar to gen_expr, but we don't do an extra load at the end
|
|
|
|
// and we flatten nested tuples
|
|
|
|
match &pattern.node {
|
2021-11-20 19:50:25 +08:00
|
|
|
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).map(|v| v.0).unwrap_or_else(|| {
|
2021-12-27 22:55:51 +08:00
|
|
|
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
|
|
|
let ptr = generator.gen_var_alloc(ctx, ptr_ty);
|
2021-11-20 19:50:25 +08:00
|
|
|
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
2021-10-16 22:17:36 +08:00
|
|
|
ptr
|
|
|
|
}),
|
|
|
|
ExprKind::Attribute { value, attr, .. } => {
|
|
|
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
2021-12-27 22:55:51 +08:00
|
|
|
let val = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx, generator);
|
2021-10-16 22:17:36 +08:00
|
|
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
|
|
|
v
|
|
|
|
} else {
|
|
|
|
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),
|
|
|
|
],
|
|
|
|
"attr",
|
|
|
|
)
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
ExprKind::Subscript { value, slice, .. } => {
|
|
|
|
let i32_type = ctx.ctx.i32_type();
|
2021-11-20 19:50:25 +08:00
|
|
|
let v = generator
|
|
|
|
.gen_expr(ctx, value)
|
|
|
|
.unwrap()
|
2021-12-27 22:55:51 +08:00
|
|
|
.to_basic_value_enum(ctx, generator)
|
2021-11-20 19:50:25 +08:00
|
|
|
.into_pointer_value();
|
2021-12-27 22:55:51 +08:00
|
|
|
let index = generator
|
|
|
|
.gen_expr(ctx, slice)
|
|
|
|
.unwrap()
|
|
|
|
.to_basic_value_enum(ctx, generator)
|
|
|
|
.into_int_value();
|
2021-10-16 22:17:36 +08:00
|
|
|
unsafe {
|
2021-10-24 14:52:21 +08:00
|
|
|
let arr_ptr = ctx
|
2021-12-27 22:50:36 +08:00
|
|
|
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_zero()])
|
2021-10-24 14:52:21 +08:00
|
|
|
.into_pointer_value();
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_gep(arr_ptr, &[index], "loadarrgep")
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
target: &Expr<Option<Type>>,
|
2021-11-20 19:50:25 +08:00
|
|
|
value: ValueEnum<'ctx>,
|
2021-10-16 22:17:36 +08:00
|
|
|
) {
|
2022-02-07 02:18:56 +08:00
|
|
|
match &target.node {
|
|
|
|
ExprKind::Tuple { elts, .. } => {
|
|
|
|
if let BasicValueEnum::StructValue(v) = value.to_basic_value_enum(ctx, generator) {
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
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 { .. }) =>
|
|
|
|
{
|
|
|
|
if let ExprKind::Slice { lower, upper, step } = &slice.node {
|
|
|
|
let ls = generator
|
|
|
|
.gen_expr(ctx, ls)
|
|
|
|
.unwrap()
|
|
|
|
.to_basic_value_enum(ctx, generator)
|
|
|
|
.into_pointer_value();
|
|
|
|
let (start, end, step) =
|
|
|
|
handle_slice_indices(lower, upper, step, ctx, generator, ls);
|
|
|
|
let value = value.to_basic_value_enum(ctx, generator).into_pointer_value();
|
|
|
|
let ty = if let TypeEnum::TList { ty } =
|
|
|
|
&*ctx.unifier.get_ty(target.custom.unwrap())
|
|
|
|
{
|
|
|
|
ctx.get_llvm_type(generator, *ty)
|
2022-01-09 19:55:17 +08:00
|
|
|
} else {
|
|
|
|
unreachable!()
|
2022-02-07 02:18:56 +08:00
|
|
|
};
|
|
|
|
let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value);
|
|
|
|
list_slice_assignment(
|
|
|
|
ctx,
|
|
|
|
generator.get_size_type(ctx.ctx),
|
|
|
|
ty,
|
|
|
|
ls,
|
|
|
|
(start, end, step),
|
|
|
|
value,
|
|
|
|
src_ind,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
2022-01-09 19:55:17 +08:00
|
|
|
}
|
2022-02-07 02:18:56 +08:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let ptr = generator.gen_store_target(ctx, target);
|
|
|
|
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-02-07 02:18:56 +08:00
|
|
|
let val = value.to_basic_value_enum(ctx, generator);
|
|
|
|
ctx.builder.build_store(ptr, val);
|
2021-11-20 19:50:25 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
2021-10-23 23:53:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
stmt: &Stmt<Option<Type>>,
|
|
|
|
) {
|
|
|
|
if let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node {
|
2021-11-20 19:50:25 +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();
|
|
|
|
|
2021-10-24 14:39:50 +08:00
|
|
|
let int32 = ctx.ctx.i32_type();
|
2021-12-27 22:55:51 +08:00
|
|
|
let size_t = generator.get_size_type(ctx.ctx);
|
2021-10-24 14:39:50 +08:00
|
|
|
let zero = int32.const_zero();
|
2021-10-23 23:53:36 +08:00
|
|
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
|
|
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
|
|
|
// if there is no orelse, we just go to cont_bb
|
|
|
|
let orelse_bb =
|
|
|
|
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "orelse") };
|
|
|
|
// store loop bb information and restore it later
|
|
|
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx, generator);
|
2021-10-23 23:53:36 +08:00
|
|
|
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
|
|
|
// setup
|
|
|
|
let iter_val = iter_val.into_pointer_value();
|
|
|
|
let i = generator.gen_store_target(ctx, target);
|
2021-10-24 14:52:21 +08:00
|
|
|
let (start, end, step) = destructure_range(ctx, iter_val);
|
2021-10-23 23:53:36 +08:00
|
|
|
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
ctx.builder.position_at_end(test_bb);
|
|
|
|
let sign = ctx.builder.build_int_compare(
|
|
|
|
inkwell::IntPredicate::SGT,
|
|
|
|
step,
|
|
|
|
int32.const_zero(),
|
|
|
|
"sign",
|
|
|
|
);
|
|
|
|
// add and test
|
2021-10-24 14:39:50 +08:00
|
|
|
let tmp = ctx.builder.build_int_add(
|
|
|
|
ctx.builder.build_load(i, "i").into_int_value(),
|
|
|
|
step,
|
|
|
|
"start_loop",
|
|
|
|
);
|
2021-10-23 23:53:36 +08:00
|
|
|
ctx.builder.build_store(i, tmp);
|
|
|
|
// // if step > 0, continue when i < end
|
|
|
|
let cmp1 = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, end, "cmp1");
|
|
|
|
// if step < 0, continue when i > end
|
|
|
|
let cmp2 = ctx.builder.build_int_compare(inkwell::IntPredicate::SGT, tmp, end, "cmp2");
|
|
|
|
let pos = ctx.builder.build_and(sign, cmp1, "pos");
|
|
|
|
let neg = ctx.builder.build_and(ctx.builder.build_not(sign, "inv"), cmp2, "neg");
|
|
|
|
ctx.builder.build_conditional_branch(
|
|
|
|
ctx.builder.build_or(pos, neg, "or"),
|
|
|
|
body_bb,
|
|
|
|
orelse_bb,
|
|
|
|
);
|
2021-10-24 14:39:50 +08:00
|
|
|
ctx.builder.position_at_end(body_bb);
|
2021-10-23 23:53:36 +08:00
|
|
|
} else {
|
2021-12-27 22:55:51 +08:00
|
|
|
let counter = generator.gen_var_alloc(ctx, size_t.into());
|
2021-10-24 14:39:50 +08:00
|
|
|
// counter = -1
|
2021-12-27 22:55:51 +08:00
|
|
|
ctx.builder.build_store(counter, size_t.const_int(u64::max_value(), true));
|
2021-10-24 14:52:21 +08:00
|
|
|
let len = ctx
|
2021-12-27 22:55:51 +08:00
|
|
|
.build_gep_and_load(
|
|
|
|
iter_val.into_pointer_value(),
|
|
|
|
&[zero, int32.const_int(1, false)],
|
|
|
|
)
|
2021-10-24 14:52:21 +08:00
|
|
|
.into_int_value();
|
2021-10-24 14:39:50 +08:00
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
ctx.builder.position_at_end(test_bb);
|
|
|
|
let tmp = ctx.builder.build_load(counter, "i").into_int_value();
|
2021-12-27 22:55:51 +08:00
|
|
|
let tmp = ctx.builder.build_int_add(tmp, size_t.const_int(1, false), "inc");
|
2021-10-24 14:39:50 +08:00
|
|
|
ctx.builder.build_store(counter, tmp);
|
|
|
|
let cmp = ctx.builder.build_int_compare(inkwell::IntPredicate::SLT, tmp, len, "cmp");
|
|
|
|
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb);
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
2021-10-24 14:52:21 +08:00
|
|
|
let arr_ptr = ctx
|
2021-12-27 22:55:51 +08:00
|
|
|
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero])
|
2021-10-24 14:52:21 +08:00
|
|
|
.into_pointer_value();
|
|
|
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
2021-11-20 19:50:25 +08:00
|
|
|
generator.gen_assign(ctx, target, val.into());
|
2021-10-23 23:53:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for stmt in body.iter() {
|
|
|
|
generator.gen_stmt(ctx, stmt);
|
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
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
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
if !orelse.is_empty() {
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
for stmt in orelse.iter() {
|
|
|
|
generator.gen_stmt(ctx, stmt);
|
|
|
|
}
|
|
|
|
ctx.builder.build_unconditional_branch(cont_bb);
|
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
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
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
ctx.loop_bb = loop_bb;
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
stmt: &Stmt<Option<Type>>,
|
|
|
|
) {
|
2021-11-04 15:02:51 +08:00
|
|
|
if let StmtKind::While { test, body, orelse, .. } = &stmt.node {
|
2021-11-20 19:50:25 +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();
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
|
|
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
|
|
|
// if there is no orelse, we just go to cont_bb
|
|
|
|
let orelse_bb =
|
|
|
|
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "orelse") };
|
|
|
|
// store loop bb information and restore it later
|
|
|
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
ctx.builder.position_at_end(test_bb);
|
2021-12-27 22:55:51 +08:00
|
|
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx, generator);
|
2021-10-16 22:17:36 +08:00
|
|
|
if let BasicValueEnum::IntValue(test) = test {
|
|
|
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
2021-08-09 15:39:50 +08:00
|
|
|
} else {
|
2021-10-16 22:17:36 +08:00
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
|
|
|
for stmt in body.iter() {
|
|
|
|
generator.gen_stmt(ctx, stmt);
|
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
|
|
|
}
|
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
if !orelse.is_empty() {
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
for stmt in orelse.iter() {
|
|
|
|
generator.gen_stmt(ctx, stmt);
|
|
|
|
}
|
|
|
|
ctx.builder.build_unconditional_branch(cont_bb);
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
|
|
|
}
|
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
ctx.loop_bb = loop_bb;
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-08-09 15:39:50 +08:00
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
stmt: &Stmt<Option<Type>>,
|
|
|
|
) -> bool {
|
2021-11-04 15:02:51 +08:00
|
|
|
if let StmtKind::If { test, body, orelse, .. } = &stmt.node {
|
2021-11-20 19:50:25 +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();
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
|
|
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
|
|
|
let body_bb = ctx.ctx.append_basic_block(current, "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, "cont"));
|
|
|
|
cont_bb.unwrap()
|
|
|
|
} else {
|
|
|
|
ctx.ctx.append_basic_block(current, "orelse")
|
|
|
|
};
|
|
|
|
ctx.builder.build_unconditional_branch(test_bb);
|
|
|
|
ctx.builder.position_at_end(test_bb);
|
2021-12-27 22:55:51 +08:00
|
|
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx, generator);
|
2021-10-16 22:17:36 +08:00
|
|
|
if let BasicValueEnum::IntValue(test) = test {
|
|
|
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
ctx.builder.position_at_end(body_bb);
|
|
|
|
let mut exited = false;
|
|
|
|
for stmt in body.iter() {
|
|
|
|
exited = generator.gen_stmt(ctx, stmt);
|
|
|
|
if exited {
|
|
|
|
break;
|
2021-08-09 16:10:17 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
if !exited {
|
|
|
|
if cont_bb.is_none() {
|
|
|
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
2021-08-19 15:30:15 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap());
|
|
|
|
}
|
|
|
|
let then_exited = exited;
|
|
|
|
let else_exited = if !orelse.is_empty() {
|
|
|
|
exited = false;
|
|
|
|
ctx.builder.position_at_end(orelse_bb);
|
|
|
|
for stmt in orelse.iter() {
|
|
|
|
exited = generator.gen_stmt(ctx, stmt);
|
|
|
|
if exited {
|
|
|
|
break;
|
2021-08-27 11:46:12 +08:00
|
|
|
}
|
2021-08-09 16:10:17 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
if !exited {
|
|
|
|
if cont_bb.is_none() {
|
|
|
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
2021-08-09 16:10:17 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_unconditional_branch(cont_bb.unwrap());
|
2021-08-09 16:10:17 +08:00
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
exited
|
|
|
|
} else {
|
|
|
|
false
|
2021-08-19 15:30:15 +08:00
|
|
|
};
|
2021-10-16 22:17:36 +08:00
|
|
|
if let Some(cont_bb) = cont_bb {
|
|
|
|
ctx.builder.position_at_end(cont_bb);
|
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
|
|
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
|
|
|
if counter != counter2 {
|
|
|
|
*static_val = None;
|
|
|
|
}
|
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
then_exited && else_exited
|
2022-02-12 21:09:23 +08:00
|
|
|
pub fn exn_constructor<'ctx, 'a>(
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
|
|
|
_fun: (&FunSignature, DefinitionId),
|
|
|
|
mut args: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
|
|
|
generator: &mut dyn CodeGenerator
|
|
|
|
) -> Option<BasicValueEnum<'ctx>> {
|
|
|
|
let (zelf_ty, zelf) = obj.unwrap();
|
|
|
|
let zelf = zelf.to_basic_value_enum(ctx, generator).into_pointer_value();
|
|
|
|
let int32 = ctx.ctx.i32_type();
|
|
|
|
let zero = int32.const_zero();
|
|
|
|
let zelf_id = {
|
|
|
|
if let TypeEnum::TObj { obj_id, .. } = &*ctx.unifier.get_ty(zelf_ty) {
|
|
|
|
obj_id.0
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let defs = ctx.top_level.definitions.read();
|
|
|
|
let def = defs[zelf_id].read();
|
|
|
|
let zelf_name = if let TopLevelDef::Class { name, .. } = &*def {
|
|
|
|
*name
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
let exception_name = format!("0:{}", zelf_name);
|
|
|
|
unsafe {
|
|
|
|
let id_ptr = ctx.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id");
|
|
|
|
let id = ctx.resolver.get_string_id(&exception_name);
|
|
|
|
ctx.builder.build_store(id_ptr, int32.const_int(id as u64, false));
|
|
|
|
let empty_string = ctx.gen_const(generator, &Constant::Str("".into()), ctx.primitives.str);
|
|
|
|
let ptr = ctx.builder.build_in_bounds_gep(
|
|
|
|
zelf, &[zero, int32.const_int(5, false)], "exn.msg");
|
|
|
|
let msg = if !args.is_empty() {
|
|
|
|
args.remove(0).1.to_basic_value_enum(ctx, generator)
|
|
|
|
} else {
|
|
|
|
empty_string
|
|
|
|
};
|
|
|
|
ctx.builder.build_store(ptr, msg);
|
|
|
|
for i in [6, 7, 8].iter() {
|
|
|
|
let value = if !args.is_empty() {
|
|
|
|
args.remove(0).1.to_basic_value_enum(ctx, generator)
|
|
|
|
} else {
|
|
|
|
ctx.ctx.i64_type().const_zero().into()
|
|
|
|
};
|
|
|
|
let ptr = ctx.builder.build_in_bounds_gep(
|
|
|
|
zelf, &[zero, int32.const_int(*i, false)], "exn.param");
|
|
|
|
ctx.builder.build_store(ptr, value);
|
|
|
|
}
|
|
|
|
// set file, func to empty string
|
|
|
|
for i in [1, 4].iter() {
|
|
|
|
let ptr = ctx.builder.build_in_bounds_gep(
|
|
|
|
zelf, &[zero, int32.const_int(*i, false)], "exn.str");
|
|
|
|
ctx.builder.build_store(ptr, empty_string);
|
|
|
|
}
|
|
|
|
// set ints to zero
|
|
|
|
for i in [2, 3].iter() {
|
|
|
|
let ptr = ctx.builder.build_in_bounds_gep(
|
|
|
|
zelf, &[zero, int32.const_int(*i, false)], "exn.ints");
|
|
|
|
ctx.builder.build_store(ptr, zero);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(zelf.into())
|
|
|
|
}
|
|
|
|
|
2021-10-16 22:17:36 +08:00
|
|
|
} else {
|
|
|
|
unreachable!()
|
2021-08-09 15:39:50 +08:00
|
|
|
}
|
|
|
|
}
|
2021-10-16 22:17:36 +08:00
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
|
2021-10-31 17:16:21 +08:00
|
|
|
_: &mut G,
|
|
|
|
_: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
_: &Stmt<Option<Type>>,
|
|
|
|
) -> bool {
|
|
|
|
// TODO: Implement with statement after finishing exceptions
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
|
2021-12-27 22:55:51 +08:00
|
|
|
pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
2021-10-16 22:17:36 +08:00
|
|
|
generator: &mut G,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
stmt: &Stmt<Option<Type>>,
|
|
|
|
) -> bool {
|
|
|
|
match &stmt.node {
|
2021-11-20 19:50:25 +08:00
|
|
|
StmtKind::Pass { .. } => {}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Expr { value, .. } => {
|
2021-10-16 22:17:36 +08:00
|
|
|
generator.gen_expr(ctx, value);
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Return { value, .. } => {
|
2021-11-20 19:50:25 +08:00
|
|
|
let value = value
|
|
|
|
.as_ref()
|
2021-12-27 22:55:51 +08:00
|
|
|
.map(|v| generator.gen_expr(ctx, v).unwrap().to_basic_value_enum(ctx, generator));
|
2021-10-16 22:17:36 +08:00
|
|
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
|
|
|
ctx.builder.build_return(value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
StmtKind::AnnAssign { target, value, .. } => {
|
|
|
|
if let Some(value) = value {
|
|
|
|
let value = generator.gen_expr(ctx, value).unwrap();
|
|
|
|
generator.gen_assign(ctx, target, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
StmtKind::Assign { targets, value, .. } => {
|
|
|
|
let value = generator.gen_expr(ctx, value).unwrap();
|
|
|
|
for target in targets.iter() {
|
2021-11-20 19:50:25 +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 { .. } => {
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().0);
|
|
|
|
return true;
|
|
|
|
}
|
2021-11-20 19:50:25 +08:00
|
|
|
StmtKind::Break { .. } => {
|
2021-10-16 22:17:36 +08:00
|
|
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
StmtKind::If { .. } => return generator.gen_if(ctx, stmt),
|
|
|
|
StmtKind::While { .. } => return generator.gen_while(ctx, stmt),
|
2021-10-23 23:53:36 +08:00
|
|
|
StmtKind::For { .. } => return generator.gen_for(ctx, stmt),
|
2021-10-31 17:16:21 +08:00
|
|
|
StmtKind::With { .. } => return generator.gen_with(ctx, stmt),
|
2021-11-12 01:44:12 +08:00
|
|
|
StmtKind::AugAssign { target, op, value, .. } => {
|
2022-01-08 22:16:55 +08:00
|
|
|
let value = gen_binop_expr(generator, ctx, target, op, value);
|
|
|
|
generator.gen_assign(ctx, target, value);
|
2021-11-12 01:44:12 +08:00
|
|
|
}
|
2021-10-23 23:53:36 +08:00
|
|
|
_ => unimplemented!(),
|
2021-10-16 22:17:36 +08:00
|
|
|
};
|
|
|
|
false
|
|
|
|
}
|