forked from M-Labs/nac3
core: Codegen for ellipsis expression as NotImplemented
A lot of refactoring was performed, specifically with relaxing expression codegen to return Option in case where ellipsis are used within a subexpression.
This commit is contained in:
parent
68b97347b1
commit
c93ad152d7
@ -145,7 +145,8 @@ impl<'a> ArtiqCodeGenerator<'a> {
|
|||||||
let end_store = self.gen_store_target(
|
let end_store = self.gen_store_target(
|
||||||
ctx,
|
ctx,
|
||||||
&end,
|
&end,
|
||||||
store_name.map(|name| format!("{name}.addr")).as_deref())?;
|
store_name.map(|name| format!("{name}.addr")).as_deref())?
|
||||||
|
.unwrap();
|
||||||
ctx.builder.build_store(end_store, max);
|
ctx.builder.build_store(end_store, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +262,9 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||||||
node: ExprKind::Name { id: start, ctx: name_ctx.clone() },
|
node: ExprKind::Name { id: start, ctx: name_ctx.clone() },
|
||||||
custom: Some(ctx.primitives.int64),
|
custom: Some(ctx.primitives.int64),
|
||||||
};
|
};
|
||||||
let start = self.gen_store_target(ctx, &start_expr, Some("start.addr"))?;
|
let start = self
|
||||||
|
.gen_store_target(ctx, &start_expr, Some("start.addr"))?
|
||||||
|
.unwrap();
|
||||||
ctx.builder.build_store(start, now);
|
ctx.builder.build_store(start, now);
|
||||||
Ok(Some(start_expr)) as Result<_, String>
|
Ok(Some(start_expr)) as Result<_, String>
|
||||||
},
|
},
|
||||||
@ -274,7 +277,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||||||
node: ExprKind::Name { id: end, ctx: name_ctx.clone() },
|
node: ExprKind::Name { id: end, ctx: name_ctx.clone() },
|
||||||
custom: Some(ctx.primitives.int64),
|
custom: Some(ctx.primitives.int64),
|
||||||
};
|
};
|
||||||
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?;
|
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?.unwrap();
|
||||||
ctx.builder.build_store(end, now);
|
ctx.builder.build_store(end, now);
|
||||||
self.end = Some(end_expr);
|
self.end = Some(end_expr);
|
||||||
self.name_counter += 1;
|
self.name_counter += 1;
|
||||||
|
@ -207,12 +207,12 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
value: &Constant,
|
value: &Constant,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
match value {
|
match value {
|
||||||
Constant::Bool(v) => {
|
Constant::Bool(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
||||||
let ty = self.ctx.i8_type();
|
let ty = self.ctx.i8_type();
|
||||||
ty.const_int(if *v { 1 } else { 0 }, false).into()
|
Some(ty.const_int(if *v { 1 } else { 0 }, false).into())
|
||||||
}
|
}
|
||||||
Constant::Int(val) => {
|
Constant::Int(val) => {
|
||||||
let ty = if self.unifier.unioned(ty, self.primitives.int32)
|
let ty = if self.unifier.unioned(ty, self.primitives.int32)
|
||||||
@ -226,28 +226,33 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
ty.const_int(*val as u64, false).into()
|
Some(ty.const_int(*val as u64, false).into())
|
||||||
}
|
}
|
||||||
Constant::Float(v) => {
|
Constant::Float(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.float));
|
assert!(self.unifier.unioned(ty, self.primitives.float));
|
||||||
let ty = self.ctx.f64_type();
|
let ty = self.ctx.f64_type();
|
||||||
ty.const_float(*v).into()
|
Some(ty.const_float(*v).into())
|
||||||
}
|
}
|
||||||
Constant::Tuple(v) => {
|
Constant::Tuple(v) => {
|
||||||
let ty = self.unifier.get_ty(ty);
|
let ty = self.unifier.get_ty(ty);
|
||||||
let types =
|
let types =
|
||||||
if let TypeEnum::TTuple { ty } = &*ty { ty.clone() } else { unreachable!() };
|
if let TypeEnum::TTuple { ty } = &*ty { ty.clone() } else { unreachable!() };
|
||||||
let values = zip(types.into_iter(), v.iter())
|
let values = zip(types.into_iter(), v.iter())
|
||||||
.map(|(ty, v)| self.gen_const(generator, v, ty))
|
.map_while(|(ty, v)| self.gen_const(generator, v, ty))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let types = values.iter().map(BasicValueEnum::get_type).collect_vec();
|
|
||||||
let ty = self.ctx.struct_type(&types, false);
|
if values.len() == v.len() {
|
||||||
ty.const_named_struct(&values).into()
|
let types = values.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
|
let ty = self.ctx.struct_type(&types, false);
|
||||||
|
Some(ty.const_named_struct(&values).into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Constant::Str(v) => {
|
Constant::Str(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.str));
|
assert!(self.unifier.unioned(ty, self.primitives.str));
|
||||||
if let Some(v) = self.const_strings.get(v) {
|
if let Some(v) = self.const_strings.get(v) {
|
||||||
*v
|
Some(*v)
|
||||||
} else {
|
} else {
|
||||||
let str_ptr =
|
let str_ptr =
|
||||||
self.builder.build_global_string_ptr(v, "const").as_pointer_value().into();
|
self.builder.build_global_string_ptr(v, "const").as_pointer_value().into();
|
||||||
@ -256,9 +261,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
let val =
|
let val =
|
||||||
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
||||||
self.const_strings.insert(v.to_string(), val);
|
self.const_strings.insert(v.to_string(), val);
|
||||||
val
|
Some(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Constant::Ellipsis => {
|
||||||
|
let msg = self.gen_string(generator, "NotImplementedError");
|
||||||
|
|
||||||
|
self.raise_exn(
|
||||||
|
generator,
|
||||||
|
"0:NotImplementedError",
|
||||||
|
msg,
|
||||||
|
[None, None, None],
|
||||||
|
self.current_loc,
|
||||||
|
);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,7 +499,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
|||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
s: S,
|
s: S,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str)
|
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_exn(
|
pub fn raise_exn(
|
||||||
@ -935,7 +953,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
if let ExprKind::ListComp { elt, generators } = &expr.node {
|
if let ExprKind::ListComp { elt, generators } = &expr.node {
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
|
|
||||||
@ -949,9 +967,16 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx.builder.position_at_end(init_bb);
|
ctx.builder.position_at_end(init_bb);
|
||||||
|
|
||||||
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
||||||
let iter_val = generator.gen_expr(ctx, iter)?
|
let iter_val = if let Some(v) = generator.gen_expr(ctx, iter)? {
|
||||||
.unwrap()
|
v.to_basic_value_enum(ctx, generator, iter.custom.unwrap())?
|
||||||
.to_basic_value_enum(ctx, generator, iter.custom.unwrap())?;
|
} else {
|
||||||
|
for bb in [test_bb, body_bb, cont_bb] {
|
||||||
|
ctx.builder.position_at_end(bb);
|
||||||
|
ctx.builder.build_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = generator.get_size_type(ctx.ctx);
|
||||||
let zero_size_t = size_t.const_zero();
|
let zero_size_t = size_t.const_zero();
|
||||||
@ -994,7 +1019,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
list_content = ctx.build_gep_and_load(list, &[zero_size_t, zero_32], Some("listcomp.data.addr"))
|
list_content = ctx.build_gep_and_load(list, &[zero_size_t, zero_32], Some("listcomp.data.addr"))
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?;
|
let i = generator.gen_store_target(ctx, target, Some("i.addr"))?.unwrap();
|
||||||
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
ctx.builder.build_store(i, ctx.builder.build_int_sub(start, step, "start_init"));
|
||||||
|
|
||||||
ctx.builder.build_conditional_branch(
|
ctx.builder.build_conditional_branch(
|
||||||
@ -1049,12 +1074,25 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
generator.gen_assign(ctx, target, val.into())?;
|
generator.gen_assign(ctx, target, val.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emits the content of `cont_bb`
|
||||||
|
let emit_cont_bb = |ctx: &CodeGenContext| {
|
||||||
|
ctx.builder.position_at_end(cont_bb);
|
||||||
|
let len_ptr = unsafe {
|
||||||
|
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
|
||||||
|
};
|
||||||
|
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
||||||
|
};
|
||||||
|
|
||||||
for cond in ifs.iter() {
|
for cond in ifs.iter() {
|
||||||
let result = generator
|
let result = if let Some(v) = generator.gen_expr(ctx, cond)? {
|
||||||
.gen_expr(ctx, cond)?
|
v.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?.into_int_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, cond.custom.unwrap())?
|
// Bail if the predicate is an ellipsis - Emit cont_bb contents in case the
|
||||||
.into_int_value();
|
// no element matches the predicate
|
||||||
|
emit_cont_bb(ctx);
|
||||||
|
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
let result = generator.bool_to_i1(ctx, result);
|
let result = generator.bool_to_i1(ctx, result);
|
||||||
let succ = ctx.ctx.append_basic_block(current, "then");
|
let succ = ctx.ctx.append_basic_block(current, "then");
|
||||||
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
||||||
@ -1062,7 +1100,12 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx.builder.position_at_end(succ);
|
ctx.builder.position_at_end(succ);
|
||||||
}
|
}
|
||||||
|
|
||||||
let elem = generator.gen_expr(ctx, elt)?.unwrap();
|
let Some(elem) = generator.gen_expr(ctx, elt)? else {
|
||||||
|
// Similarly, bail if the generator expression is an ellipsis, but keep cont_bb contents
|
||||||
|
emit_cont_bb(ctx);
|
||||||
|
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
let i = ctx.builder.build_load(index, "i").into_int_value();
|
let i = ctx.builder.build_load(index, "i").into_int_value();
|
||||||
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
||||||
let val = elem.to_basic_value_enum(ctx, generator, elt.custom.unwrap())?;
|
let val = elem.to_basic_value_enum(ctx, generator, elt.custom.unwrap())?;
|
||||||
@ -1071,13 +1114,9 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
.build_store(index, ctx.builder.build_int_add(i, size_t.const_int(1, false), "inc"));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(cont_bb);
|
emit_cont_bb(ctx);
|
||||||
let len_ptr = unsafe {
|
|
||||||
ctx.builder.build_gep(list, &[zero_size_t, int32.const_int(1, false)], "length")
|
|
||||||
};
|
|
||||||
ctx.builder.build_store(len_ptr, ctx.builder.build_load(index, "index"));
|
|
||||||
|
|
||||||
Ok(list.into())
|
Ok(Some(list.into()))
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -1101,14 +1140,16 @@ pub fn gen_binop_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
||||||
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
||||||
let left_val = generator
|
let left_val = if let Some(v) = generator.gen_expr(ctx, left)? {
|
||||||
.gen_expr(ctx, left)?
|
v.to_basic_value_enum(ctx, generator, left.custom.unwrap())?
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, left.custom.unwrap())?;
|
return Ok(None)
|
||||||
let right_val = generator
|
};
|
||||||
.gen_expr(ctx, right)?
|
let right_val = if let Some(v) = generator.gen_expr(ctx, right)? {
|
||||||
.unwrap()
|
v.to_basic_value_enum(ctx, generator, right.custom.unwrap())?
|
||||||
.to_basic_value_enum(ctx, generator, right.custom.unwrap())?;
|
} else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
|
|
||||||
// we can directly compare the types, because we've got their representatives
|
// we can directly compare the types, because we've got their representatives
|
||||||
// which would be unchanged until further unification, which we would never do
|
// which would be unchanged until further unification, which we would never do
|
||||||
@ -1211,7 +1252,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
Ok(Some(match &expr.node {
|
Ok(Some(match &expr.node {
|
||||||
ExprKind::Constant { value, .. } => {
|
ExprKind::Constant { value, .. } => {
|
||||||
let ty = expr.custom.unwrap();
|
let ty = expr.custom.unwrap();
|
||||||
ctx.gen_const(generator, value, ty).into()
|
let Some(const_val) = ctx.gen_const(generator, value, ty) else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
|
const_val.into()
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } if id == &"none".into() => {
|
ExprKind::Name { id, .. } if id == &"none".into() => {
|
||||||
match (
|
match (
|
||||||
@ -1242,15 +1286,17 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
// we should use memcpy for that instead of generating thousands of stores
|
// we should use memcpy for that instead of generating thousands of stores
|
||||||
let elements = elts
|
let elements = elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| generator.gen_expr(ctx, x))
|
||||||
generator
|
.take_while(|v| !matches!(v, Ok(None)))
|
||||||
.gen_expr(ctx, x)
|
|
||||||
.map_or_else(
|
|
||||||
Err,
|
|
||||||
|v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap())
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
let elements = elements.into_iter().zip(elts)
|
||||||
|
.map(|(v, x)| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
if elements.len() < elts.len() {
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
let ty = if elements.is_empty() {
|
let ty = if elements.is_empty() {
|
||||||
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(expr.custom.unwrap()) {
|
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(expr.custom.unwrap()) {
|
||||||
ctx.get_llvm_type(generator, *ty)
|
ctx.get_llvm_type(generator, *ty)
|
||||||
@ -1277,14 +1323,19 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
arr_str_ptr.into()
|
arr_str_ptr.into()
|
||||||
}
|
}
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
let element_val = elts
|
let elements_val = elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| generator.gen_expr(ctx, x))
|
||||||
generator
|
.take_while(|v| !matches!(v, Ok(None)))
|
||||||
.gen_expr(ctx, x)
|
|
||||||
.map_or_else(Err, |v| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()))
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
let element_val = elements_val.into_iter().zip(elts)
|
||||||
|
.map(|(v, x)| v.unwrap().to_basic_value_enum(ctx, generator, x.custom.unwrap()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
if element_val.len() < elts.len() {
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
||||||
let tuple_ptr = ctx.builder.build_alloca(tuple_ty, "tuple");
|
let tuple_ptr = ctx.builder.build_alloca(tuple_ty, "tuple");
|
||||||
@ -1302,8 +1353,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
// note that we would handle class methods directly in calls
|
// note that we would handle class methods directly in calls
|
||||||
match generator.gen_expr(ctx, value)?.unwrap() {
|
match generator.gen_expr(ctx, value)? {
|
||||||
ValueEnum::Static(v) => v.get_field(*attr, ctx).map_or_else(|| {
|
Some(ValueEnum::Static(v)) => v.get_field(*attr, ctx).map_or_else(|| {
|
||||||
let v = v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?;
|
let v = v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?;
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
Ok(ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
@ -1312,7 +1363,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
None,
|
None,
|
||||||
))) as Result<_, String>
|
))) as Result<_, String>
|
||||||
}, Ok)?,
|
}, Ok)?,
|
||||||
ValueEnum::Dynamic(v) => {
|
Some(ValueEnum::Dynamic(v)) => {
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
v.into_pointer_value(),
|
v.into_pointer_value(),
|
||||||
@ -1320,15 +1371,16 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
None => return Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::BoolOp { op, values } => {
|
ExprKind::BoolOp { op, values } => {
|
||||||
// requires conditional branches for short-circuiting...
|
// requires conditional branches for short-circuiting...
|
||||||
let left = generator
|
let left = if let Some(v) = generator.gen_expr(ctx, &values[0])? {
|
||||||
.gen_expr(ctx, &values[0])?
|
v.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?.into_int_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, values[0].custom.unwrap())?
|
return Ok(None)
|
||||||
.into_int_value();
|
};
|
||||||
let left = generator.bool_to_i1(ctx, left);
|
let left = generator.bool_to_i1(ctx, left);
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
@ -1340,45 +1392,62 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = ctx.ctx.i8_type().const_int(1, false);
|
let a = ctx.ctx.i8_type().const_int(1, false);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = generator
|
let b = if let Some(v) = generator.gen_expr(ctx, &values[1])? {
|
||||||
.gen_expr(ctx, &values[1])?
|
let b = v.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?.into_int_value();
|
||||||
.unwrap()
|
let b = generator.bool_to_i8(ctx, b);
|
||||||
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
.into_int_value();
|
|
||||||
let b = generator.bool_to_i8(ctx, b);
|
Some(b)
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
} else {
|
||||||
(a, b)
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
(Some(a), b)
|
||||||
}
|
}
|
||||||
Boolop::And => {
|
Boolop::And => {
|
||||||
ctx.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = generator
|
let a = if let Some(v) = generator.gen_expr(ctx, &values[1])? {
|
||||||
.gen_expr(ctx, &values[1])?
|
let a = v.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?.into_int_value();
|
||||||
.unwrap()
|
let a = generator.bool_to_i8(ctx, a);
|
||||||
.to_basic_value_enum(ctx, generator, values[1].custom.unwrap())?
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
.into_int_value();
|
|
||||||
let a = generator.bool_to_i8(ctx, a);
|
Some(a)
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = ctx.ctx.i8_type().const_zero();
|
let b = ctx.ctx.i8_type().const_zero();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
|
||||||
|
(a, Some(b))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(ctx.ctx.i8_type(), "");
|
match (a, b) {
|
||||||
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
(Some(a), Some(b)) => {
|
||||||
phi.as_basic_value().into()
|
let phi = ctx.builder.build_phi(ctx.ctx.i8_type(), "");
|
||||||
|
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
||||||
|
phi.as_basic_value().into()
|
||||||
|
}
|
||||||
|
(Some(a), None) => a.into(),
|
||||||
|
(None, Some(b)) => b.into(),
|
||||||
|
(None, None) => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::BinOp { op, left, right } => {
|
ExprKind::BinOp { op, left, right } => {
|
||||||
return gen_binop_expr(generator, ctx, left, op, right, expr.location, false);
|
return gen_binop_expr(generator, ctx, left, op, right, expr.location, false);
|
||||||
}
|
}
|
||||||
ExprKind::UnaryOp { op, operand } => {
|
ExprKind::UnaryOp { op, operand } => {
|
||||||
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
||||||
let val =
|
let val = if let Some(v) = generator.gen_expr(ctx, operand)? {
|
||||||
generator.gen_expr(ctx, operand)?
|
v.to_basic_value_enum(ctx, generator, operand.custom.unwrap())?
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, operand.custom.unwrap())?;
|
return Ok(None)
|
||||||
|
};
|
||||||
if ty == ctx.primitives.bool {
|
if ty == ctx.primitives.bool {
|
||||||
let val = val.into_int_value();
|
let val = val.into_int_value();
|
||||||
match op {
|
match op {
|
||||||
@ -1415,7 +1484,7 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Compare { left, ops, comparators } => {
|
ExprKind::Compare { left, ops, comparators } => {
|
||||||
izip!(chain(once(left.as_ref()), comparators.iter()), comparators.iter(), ops.iter(),)
|
let cmp_val = izip!(chain(once(left.as_ref()), comparators.iter()), comparators.iter(), ops.iter(),)
|
||||||
.fold(Ok(None), |prev: Result<Option<_>, String>, (lhs, rhs, op)| {
|
.fold(Ok(None), |prev: Result<Option<_>, String>, (lhs, rhs, op)| {
|
||||||
let ty = ctx.unifier.get_representative(lhs.custom.unwrap());
|
let ty = ctx.unifier.get_representative(lhs.custom.unwrap());
|
||||||
let current =
|
let current =
|
||||||
@ -1427,23 +1496,15 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx.primitives.uint64,
|
ctx.primitives.uint64,
|
||||||
].contains(&ty);
|
].contains(&ty);
|
||||||
|
|
||||||
let (lhs, rhs) = if let (
|
let BasicValueEnum::IntValue(lhs) = (match generator.gen_expr(ctx, lhs)? {
|
||||||
BasicValueEnum::IntValue(lhs),
|
Some(v) => v.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
||||||
BasicValueEnum::IntValue(rhs),
|
None => return Ok(None),
|
||||||
) = (
|
}) else { unreachable!() };
|
||||||
generator
|
|
||||||
.gen_expr(ctx, lhs)?
|
let BasicValueEnum::IntValue(rhs) = (match generator.gen_expr(ctx, rhs)? {
|
||||||
.unwrap()
|
Some(v) => v.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
||||||
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
None => return Ok(None),
|
||||||
generator
|
}) else { unreachable!() };
|
||||||
.gen_expr(ctx, rhs)?
|
|
||||||
.unwrap()
|
|
||||||
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
|
||||||
) {
|
|
||||||
(lhs, rhs)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let op = match op {
|
let op = match op {
|
||||||
ast::Cmpop::Eq | ast::Cmpop::Is => IntPredicate::EQ,
|
ast::Cmpop::Eq | ast::Cmpop::Is => IntPredicate::EQ,
|
||||||
@ -1474,23 +1535,16 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
|
|
||||||
ctx.builder.build_int_compare(op, lhs, rhs, "cmp")
|
ctx.builder.build_int_compare(op, lhs, rhs, "cmp")
|
||||||
} else if ty == ctx.primitives.float {
|
} else if ty == ctx.primitives.float {
|
||||||
let (lhs, rhs) = if let (
|
let BasicValueEnum::FloatValue(lhs) = (match generator.gen_expr(ctx, lhs)? {
|
||||||
BasicValueEnum::FloatValue(lhs),
|
Some(v) => v.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
||||||
BasicValueEnum::FloatValue(rhs),
|
None => return Ok(None),
|
||||||
) = (
|
}) else { unreachable!() };
|
||||||
generator
|
|
||||||
.gen_expr(ctx, lhs)?
|
let BasicValueEnum::FloatValue(rhs) = (match generator.gen_expr(ctx, rhs)? {
|
||||||
.unwrap()
|
Some(v) => v.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
||||||
.to_basic_value_enum(ctx, generator, lhs.custom.unwrap())?,
|
None => return Ok(None),
|
||||||
generator
|
}) else { unreachable!() };
|
||||||
.gen_expr(ctx, rhs)?
|
|
||||||
.unwrap()
|
|
||||||
.to_basic_value_enum(ctx, generator, rhs.custom.unwrap())?,
|
|
||||||
) {
|
|
||||||
(lhs, rhs)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
let op = match op {
|
let op = match op {
|
||||||
ast::Cmpop::Eq | ast::Cmpop::Is => inkwell::FloatPredicate::OEQ,
|
ast::Cmpop::Eq | ast::Cmpop::Is => inkwell::FloatPredicate::OEQ,
|
||||||
ast::Cmpop::NotEq => inkwell::FloatPredicate::ONE,
|
ast::Cmpop::NotEq => inkwell::FloatPredicate::ONE,
|
||||||
@ -1505,16 +1559,18 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
};
|
};
|
||||||
Ok(prev?.map(|v| ctx.builder.build_and(v, current, "cmp")).or(Some(current)))
|
Ok(prev?.map(|v| ctx.builder.build_and(v, current, "cmp")).or(Some(current)))
|
||||||
})?
|
})?;
|
||||||
.unwrap()
|
|
||||||
.into() // as there should be at least 1 element, it should never be none
|
match cmp_val {
|
||||||
|
Some(v) => v.into(),
|
||||||
|
None => return Ok(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::IfExp { test, body, orelse } => {
|
ExprKind::IfExp { test, body, orelse } => {
|
||||||
let test = generator
|
let test = match generator.gen_expr(ctx, test)? {
|
||||||
.gen_expr(ctx, test)?
|
Some(v) => v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?.into_int_value(),
|
||||||
.unwrap()
|
None => return Ok(None),
|
||||||
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
};
|
||||||
.into_int_value();
|
|
||||||
let test = generator.bool_to_i1(ctx, test);
|
let test = generator.bool_to_i1(ctx, test);
|
||||||
let body_ty = body.custom.unwrap();
|
let body_ty = body.custom.unwrap();
|
||||||
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
let is_none = ctx.unifier.get_representative(body_ty) == ctx.primitives.none;
|
||||||
@ -1529,37 +1585,52 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
||||||
|
|
||||||
ctx.builder.position_at_end(then_bb);
|
ctx.builder.position_at_end(then_bb);
|
||||||
let a = generator.gen_expr(ctx, body)?;
|
let a = generator.gen_expr(ctx, body)?;
|
||||||
match result {
|
if let Some(a) = a {
|
||||||
None => None,
|
match result {
|
||||||
Some(v) => {
|
None => None,
|
||||||
let a = a.unwrap().to_basic_value_enum(ctx, generator, body.custom.unwrap())?;
|
Some(v) => {
|
||||||
Some(ctx.builder.build_store(v, a))
|
let a = a.to_basic_value_enum(ctx, generator, body.custom.unwrap())?;
|
||||||
}
|
Some(ctx.builder.build_store(v, a))
|
||||||
};
|
}
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
};
|
||||||
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.builder.position_at_end(else_bb);
|
ctx.builder.position_at_end(else_bb);
|
||||||
let b = generator.gen_expr(ctx, orelse)?;
|
let b = generator.gen_expr(ctx, orelse)?;
|
||||||
match result {
|
if let Some(b) = b {
|
||||||
None => None,
|
match result {
|
||||||
Some(v) => {
|
None => None,
|
||||||
let b = b.unwrap().to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
|
Some(v) => {
|
||||||
Some(ctx.builder.build_store(v, b))
|
let b = b.to_basic_value_enum(ctx, generator, orelse.custom.unwrap())?;
|
||||||
}
|
Some(ctx.builder.build_store(v, b))
|
||||||
};
|
}
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
};
|
||||||
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
match result {
|
if let Some(v) = result {
|
||||||
None => return Ok(None),
|
ctx.builder.build_load(v, "if_exp_val_load").into()
|
||||||
Some(v) => return Ok(Some(ctx.builder.build_load(v, "if_exp_val_load").into()))
|
} else {
|
||||||
|
return Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Call { func, args, keywords } => {
|
ExprKind::Call { func, args, keywords } => {
|
||||||
let mut params = args
|
let mut params = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| Ok((None, generator.gen_expr(ctx, arg)?.unwrap())) as Result<_, String>)
|
.map(|arg| generator.gen_expr(ctx, arg))
|
||||||
|
.take_while(|expr| !matches!(expr, Ok(None)))
|
||||||
|
.map(|expr| Ok((None, expr?.unwrap())) as Result<_, String>)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
if params.len() < args.len() {
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
let kw_iter = keywords.iter().map(|kw| {
|
let kw_iter = keywords.iter().map(|kw| {
|
||||||
Ok((
|
Ok((
|
||||||
Some(*kw.node.arg.as_ref().unwrap()),
|
Some(*kw.node.arg.as_ref().unwrap()),
|
||||||
@ -1593,7 +1664,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.map(|v| v.into()));
|
.map(|v| v.into()));
|
||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let val = generator.gen_expr(ctx, value)?.unwrap();
|
let val = match generator.gen_expr(ctx, value)? {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
let id = if let TypeEnum::TObj { obj_id, .. } =
|
let id = if let TypeEnum::TObj { obj_id, .. } =
|
||||||
&*ctx.unifier.get_ty(value.custom.unwrap())
|
&*ctx.unifier.get_ty(value.custom.unwrap())
|
||||||
{
|
{
|
||||||
@ -1691,18 +1766,20 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
if let TypeEnum::TList { ty } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||||
let v = generator
|
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
|
||||||
.gen_expr(ctx, value)?
|
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?.into_pointer_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
return Ok(None)
|
||||||
.into_pointer_value();
|
};
|
||||||
let ty = ctx.get_llvm_type(generator, *ty);
|
let ty = ctx.get_llvm_type(generator, *ty);
|
||||||
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero], Some("arr.addr"))
|
let arr_ptr = ctx.build_gep_and_load(v, &[zero, zero], Some("arr.addr"))
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
if let ExprKind::Slice { lower, upper, step } = &slice.node {
|
if let ExprKind::Slice { lower, upper, step } = &slice.node {
|
||||||
let one = int32.const_int(1, false);
|
let one = int32.const_int(1, false);
|
||||||
let (start, end, step) =
|
let Some((start, end, step)) =
|
||||||
handle_slice_indices(lower, upper, step, ctx, generator, v)?;
|
handle_slice_indices(lower, upper, step, ctx, generator, v)? else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
let length = calculate_len_for_slice_range(
|
let length = calculate_len_for_slice_range(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
@ -1723,8 +1800,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
step,
|
step,
|
||||||
);
|
);
|
||||||
let res_array_ret = allocate_list(generator, ctx, ty, length, Some("ret"));
|
let res_array_ret = allocate_list(generator, ctx, ty, length, Some("ret"));
|
||||||
let res_ind =
|
let Some(res_ind) =
|
||||||
handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)?;
|
handle_slice_indices(&None, &None, &None, ctx, generator, res_array_ret)? else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
list_slice_assignment(
|
list_slice_assignment(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
@ -1739,11 +1818,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
let len = ctx
|
let len = ctx
|
||||||
.build_gep_and_load(v, &[zero, int32.const_int(1, false)], Some("len"))
|
.build_gep_and_load(v, &[zero, int32.const_int(1, false)], Some("len"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let raw_index = generator
|
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
|
||||||
.gen_expr(ctx, slice)?
|
v.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
return Ok(None)
|
||||||
.into_int_value();
|
};
|
||||||
let raw_index = ctx.builder.build_int_s_extend(
|
let raw_index = ctx.builder.build_int_s_extend(
|
||||||
raw_index,
|
raw_index,
|
||||||
generator.get_size_type(ctx.ctx),
|
generator.get_size_type(ctx.ctx),
|
||||||
@ -1786,15 +1865,12 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
unreachable!("tuple subscript must be const int after type check");
|
unreachable!("tuple subscript must be const int after type check");
|
||||||
};
|
};
|
||||||
let v = generator
|
match generator.gen_expr(ctx, value)? {
|
||||||
.gen_expr(ctx, value)?
|
Some(ValueEnum::Dynamic(v)) => {
|
||||||
.unwrap();
|
|
||||||
match v {
|
|
||||||
ValueEnum::Dynamic(v) => {
|
|
||||||
let v = v.into_struct_value();
|
let v = v.into_struct_value();
|
||||||
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into()
|
ctx.builder.build_extract_value(v, index, "tup_elem").unwrap().into()
|
||||||
}
|
}
|
||||||
ValueEnum::Static(v) => {
|
Some(ValueEnum::Static(v)) => {
|
||||||
match v.get_tuple_element(index) {
|
match v.get_tuple_element(index) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
@ -1805,12 +1881,19 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None => return Ok(None),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("should not be other subscriptable types after type check");
|
unreachable!("should not be other subscriptable types after type check");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr)?.into(),
|
ExprKind::ListComp { .. } => {
|
||||||
|
if let Some(v) = gen_comprehension(generator, ctx, expr)? {
|
||||||
|
v.into()
|
||||||
|
} else {
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ pub trait CodeGenerator {
|
|||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
pattern: &Expr<Option<Type>>,
|
pattern: &Expr<Option<Type>>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> Result<PointerValue<'ctx>, String>
|
) -> Result<Option<PointerValue<'ctx>>, String>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -158,33 +158,41 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
|||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
list: PointerValue<'ctx>,
|
list: PointerValue<'ctx>,
|
||||||
) -> Result<(IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>), String> {
|
) -> Result<Option<(IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>)>, String> {
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let one = int32.const_int(1, false);
|
let one = int32.const_int(1, false);
|
||||||
let length = ctx.build_gep_and_load(list, &[zero, one], Some("length")).into_int_value();
|
let length = ctx.build_gep_and_load(list, &[zero, one], Some("length")).into_int_value();
|
||||||
let length = ctx.builder.build_int_truncate_or_bit_cast(length, int32, "leni32");
|
let length = ctx.builder.build_int_truncate_or_bit_cast(length, int32, "leni32");
|
||||||
Ok(match (start, end, step) {
|
Ok(Some(match (start, end, step) {
|
||||||
(s, e, None) => (
|
(s, e, None) => (
|
||||||
s.as_ref().map_or_else(
|
if let Some(s) = s.as_ref() {
|
||||||
|| Ok(int32.const_zero()),
|
match handle_slice_index_bound(s, ctx, generator, length)? {
|
||||||
|s| handle_slice_index_bound(s, ctx, generator, length),
|
Some(v) => v,
|
||||||
)?,
|
None => return Ok(None),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int32.const_zero()
|
||||||
|
},
|
||||||
{
|
{
|
||||||
let e = e.as_ref().map_or_else(
|
let e = if let Some(s) = e.as_ref() {
|
||||||
|| Ok(length),
|
match handle_slice_index_bound(s, ctx, generator, length)? {
|
||||||
|e| handle_slice_index_bound(e, ctx, generator, length),
|
Some(v) => v,
|
||||||
)?;
|
None => return Ok(None),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
length
|
||||||
|
};
|
||||||
ctx.builder.build_int_sub(e, one, "final_end")
|
ctx.builder.build_int_sub(e, one, "final_end")
|
||||||
},
|
},
|
||||||
one,
|
one,
|
||||||
),
|
),
|
||||||
(s, e, Some(step)) => {
|
(s, e, Some(step)) => {
|
||||||
let step = generator
|
let step = if let Some(v) = generator.gen_expr(ctx, step)? {
|
||||||
.gen_expr(ctx, step)?
|
v.to_basic_value_enum(ctx, generator, ctx.primitives.int32)?.into_int_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, ctx.primitives.int32)?
|
return Ok(None)
|
||||||
.into_int_value();
|
};
|
||||||
// assert step != 0, throw exception if not
|
// assert step != 0, throw exception if not
|
||||||
let not_zero = ctx.builder.build_int_compare(
|
let not_zero = ctx.builder.build_int_compare(
|
||||||
IntPredicate::NE,
|
IntPredicate::NE,
|
||||||
@ -205,7 +213,9 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
|||||||
(
|
(
|
||||||
match s {
|
match s {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let s = handle_slice_index_bound(s, ctx, generator, length)?;
|
let Some(s) = handle_slice_index_bound(s, ctx, generator, length)? else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_select(
|
.build_select(
|
||||||
ctx.builder.build_and(
|
ctx.builder.build_and(
|
||||||
@ -228,7 +238,9 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
|||||||
},
|
},
|
||||||
match e {
|
match e {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
let e = handle_slice_index_bound(e, ctx, generator, length)?;
|
let Some(e) = handle_slice_index_bound(e, ctx, generator, length)? else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_select(
|
.build_select(
|
||||||
neg,
|
neg,
|
||||||
@ -243,7 +255,7 @@ pub fn handle_slice_indices<'a, 'ctx, G: CodeGenerator>(
|
|||||||
step,
|
step,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this function allows index out of range, since python
|
/// this function allows index out of range, since python
|
||||||
@ -253,7 +265,7 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
|
|||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
length: IntValue<'ctx>,
|
length: IntValue<'ctx>,
|
||||||
) -> Result<IntValue<'ctx>, String> {
|
) -> Result<Option<IntValue<'ctx>>, String> {
|
||||||
const SYMBOL: &str = "__nac3_slice_index_bound";
|
const SYMBOL: &str = "__nac3_slice_index_bound";
|
||||||
let func = ctx.module.get_function(SYMBOL).unwrap_or_else(|| {
|
let func = ctx.module.get_function(SYMBOL).unwrap_or_else(|| {
|
||||||
let i32_t = ctx.ctx.i32_type();
|
let i32_t = ctx.ctx.i32_type();
|
||||||
@ -261,14 +273,18 @@ pub fn handle_slice_index_bound<'a, 'ctx, G: CodeGenerator>(
|
|||||||
ctx.module.add_function(SYMBOL, fn_t, None)
|
ctx.module.add_function(SYMBOL, fn_t, None)
|
||||||
});
|
});
|
||||||
|
|
||||||
let i = generator.gen_expr(ctx, i)?.unwrap().to_basic_value_enum(ctx, generator, i.custom.unwrap())?;
|
let i = if let Some(v) = generator.gen_expr(ctx, i)? {
|
||||||
Ok(ctx
|
v.to_basic_value_enum(ctx, generator, i.custom.unwrap())?
|
||||||
|
} else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
|
Ok(Some(ctx
|
||||||
.builder
|
.builder
|
||||||
.build_call(func, &[i.into(), length.into()], "bounded_ind")
|
.build_call(func, &[i.into(), length.into()], "bounded_ind")
|
||||||
.try_as_basic_value()
|
.try_as_basic_value()
|
||||||
.left()
|
.left()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_int_value())
|
.into_int_value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function handles 'end' **inclusively**.
|
/// This function handles 'end' **inclusively**.
|
||||||
|
@ -60,10 +60,10 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
pattern: &Expr<Option<Type>>,
|
pattern: &Expr<Option<Type>>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> Result<PointerValue<'ctx>, String> {
|
) -> Result<Option<PointerValue<'ctx>>, String> {
|
||||||
// very similar to gen_expr, but we don't do an extra load at the end
|
// very similar to gen_expr, but we don't do an extra load at the end
|
||||||
// and we flatten nested tuples
|
// and we flatten nested tuples
|
||||||
Ok(match &pattern.node {
|
Ok(Some(match &pattern.node {
|
||||||
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
||||||
None => {
|
None => {
|
||||||
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
||||||
@ -79,11 +79,11 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = generator.gen_expr(ctx, value)?.unwrap().to_basic_value_enum(
|
let val = if let Some(v) = generator.gen_expr(ctx, value)? {
|
||||||
ctx,
|
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
||||||
generator,
|
} else {
|
||||||
value.custom.unwrap(),
|
return Ok(None)
|
||||||
)?;
|
};
|
||||||
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
@ -107,19 +107,19 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
));
|
));
|
||||||
let i32_type = ctx.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
let zero = i32_type.const_zero();
|
let zero = i32_type.const_zero();
|
||||||
let v = generator
|
let v = if let Some(v) = generator.gen_expr(ctx, value)? {
|
||||||
.gen_expr(ctx, value)?
|
v.to_basic_value_enum(ctx, generator, value.custom.unwrap())?.into_pointer_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, value.custom.unwrap())?
|
return Ok(None)
|
||||||
.into_pointer_value();
|
};
|
||||||
let len = ctx
|
let len = ctx
|
||||||
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)], Some("len"))
|
.build_gep_and_load(v, &[zero, i32_type.const_int(1, false)], Some("len"))
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let raw_index = generator
|
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
|
||||||
.gen_expr(ctx, slice)?
|
v.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value()
|
||||||
.unwrap()
|
} else {
|
||||||
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
return Ok(None)
|
||||||
.into_int_value();
|
};
|
||||||
let raw_index = ctx.builder.build_int_s_extend(
|
let raw_index = ctx.builder.build_int_s_extend(
|
||||||
raw_index,
|
raw_index,
|
||||||
generator.get_size_type(ctx.ctx),
|
generator.get_size_type(ctx.ctx),
|
||||||
@ -161,7 +161,7 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [CodeGenerator::gen_assign].
|
/// See [CodeGenerator::gen_assign].
|
||||||
@ -196,8 +196,10 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, ls.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, ls.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let (start, end, step) =
|
let Some((start, end, step)) =
|
||||||
handle_slice_indices(lower, upper, step, ctx, generator, ls)?;
|
handle_slice_indices(lower, upper, step, ctx, generator, ls)? else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
let value = value
|
let value = value
|
||||||
.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
.to_basic_value_enum(ctx, generator, target.custom.unwrap())?
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
@ -207,7 +209,9 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let src_ind = handle_slice_indices(&None, &None, &None, ctx, generator, value)?;
|
let Some(src_ind) = handle_slice_indices(&None, &None, &None, ctx, generator, value)? else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind)
|
list_slice_assignment(generator, ctx, ty, ls, (start, end, step), value, src_ind)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@ -219,7 +223,9 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
String::from("target.addr")
|
String::from("target.addr")
|
||||||
};
|
};
|
||||||
let ptr = generator.gen_store_target(ctx, target, Some(name.as_str()))?;
|
let Some(ptr) = generator.gen_store_target(ctx, target, Some(name.as_str()))? else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
if let ExprKind::Name { id, .. } = &target.node {
|
if let ExprKind::Name { id, .. } = &target.node {
|
||||||
let (_, static_value, counter) = ctx.var_assignment.get_mut(id).unwrap();
|
let (_, static_value, counter) = ctx.var_assignment.get_mut(id).unwrap();
|
||||||
@ -270,17 +276,23 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||||||
// store loop bb information and restore it later
|
// store loop bb information and restore it later
|
||||||
let loop_bb = ctx.loop_target.replace((incr_bb, cont_bb));
|
let loop_bb = ctx.loop_target.replace((incr_bb, cont_bb));
|
||||||
|
|
||||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(
|
let iter_val = if let Some(v) = generator.gen_expr(ctx, iter)? {
|
||||||
ctx,
|
v.to_basic_value_enum(
|
||||||
generator,
|
ctx,
|
||||||
iter.custom.unwrap(),
|
generator,
|
||||||
)?;
|
iter.custom.unwrap(),
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
if is_iterable_range_expr {
|
if is_iterable_range_expr {
|
||||||
let iter_val = iter_val.into_pointer_value();
|
let iter_val = iter_val.into_pointer_value();
|
||||||
// Internal variable for loop; Cannot be assigned
|
// Internal variable for loop; Cannot be assigned
|
||||||
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
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
|
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
||||||
let target_i = generator.gen_store_target(ctx, target, Some("for.target.addr"))?;
|
let Some(target_i) = generator.gen_store_target(ctx, target, Some("for.target.addr"))? else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
let (start, stop, step) = destructure_range(ctx, iter_val);
|
let (start, stop, step) = destructure_range(ctx, iter_val);
|
||||||
|
|
||||||
ctx.builder.build_store(i, start);
|
ctx.builder.build_store(i, start);
|
||||||
@ -412,11 +424,16 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator>(
|
|||||||
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_target.replace((test_bb, cont_bb));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
let test = if let Some(v) = generator.gen_expr(ctx, test)? {
|
||||||
ctx,
|
v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
||||||
generator,
|
} else {
|
||||||
test.custom.unwrap(),
|
for bb in [body_bb, cont_bb] {
|
||||||
)?;
|
ctx.builder.position_at_end(bb);
|
||||||
|
ctx.builder.build_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
@ -478,13 +495,11 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator>(
|
|||||||
};
|
};
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test)?
|
let test = generator
|
||||||
.unwrap()
|
.gen_expr(ctx, test)
|
||||||
.to_basic_value_enum(ctx, generator, test.custom.unwrap())?;
|
.and_then(|v| v.map(|v| v.to_basic_value_enum(ctx, generator, test.custom.unwrap())).transpose())?;
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let Some(BasicValueEnum::IntValue(test)) = test {
|
||||||
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(generator.bool_to_i1(ctx, test), body_bb, orelse_bb);
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
};
|
||||||
ctx.builder.position_at_end(body_bb);
|
ctx.builder.position_at_end(body_bb);
|
||||||
generator.gen_block(ctx, body.iter())?;
|
generator.gen_block(ctx, body.iter())?;
|
||||||
@ -604,7 +619,7 @@ pub fn exn_constructor<'ctx, 'a>(
|
|||||||
let msg = if !args.is_empty() {
|
let msg = if !args.is_empty() {
|
||||||
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
||||||
} else {
|
} else {
|
||||||
empty_string
|
empty_string.unwrap()
|
||||||
};
|
};
|
||||||
ctx.builder.build_store(ptr, msg);
|
ctx.builder.build_store(ptr, msg);
|
||||||
for i in [6, 7, 8].iter() {
|
for i in [6, 7, 8].iter() {
|
||||||
@ -627,7 +642,7 @@ pub fn exn_constructor<'ctx, 'a>(
|
|||||||
&[zero, int32.const_int(*i, false)],
|
&[zero, int32.const_int(*i, false)],
|
||||||
"exn.str",
|
"exn.str",
|
||||||
);
|
);
|
||||||
ctx.builder.build_store(ptr, empty_string);
|
ctx.builder.build_store(ptr, empty_string.unwrap());
|
||||||
}
|
}
|
||||||
// set ints to zero
|
// set ints to zero
|
||||||
for i in [2, 3].iter() {
|
for i in [2, 3].iter() {
|
||||||
@ -1036,14 +1051,17 @@ pub fn gen_return<'ctx, 'a, G: CodeGenerator>(
|
|||||||
value: &Option<Box<Expr<Option<Type>>>>,
|
value: &Option<Box<Expr<Option<Type>>>>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let func = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap();
|
let func = ctx.builder.get_insert_block().and_then(|bb| bb.get_parent()).unwrap();
|
||||||
let value = value
|
let value = if let Some(v_expr) = value.as_ref() {
|
||||||
.as_ref()
|
if let Some(v) = generator.gen_expr(ctx, v_expr).transpose() {
|
||||||
.map(|v_expr| {
|
Some(
|
||||||
generator.gen_expr(ctx, v_expr).and_then(|v| {
|
v.and_then(|v| v.to_basic_value_enum(ctx, generator, v_expr.custom.unwrap()))?
|
||||||
v.unwrap().to_basic_value_enum(ctx, generator, v_expr.custom.unwrap())
|
)
|
||||||
})
|
} else {
|
||||||
})
|
return Ok(())
|
||||||
.transpose()?;
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
if let Some(return_target) = ctx.return_target {
|
if let Some(return_target) = ctx.return_target {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
ctx.builder.build_store(ctx.return_buffer.unwrap(), value);
|
ctx.builder.build_store(ctx.return_buffer.unwrap(), value);
|
||||||
@ -1105,12 +1123,16 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
StmtKind::AnnAssign { target, value, .. } => {
|
StmtKind::AnnAssign { target, value, .. } => {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
let value = generator.gen_expr(ctx, value)?.unwrap();
|
let Some(value) = generator.gen_expr(ctx, value)? else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
generator.gen_assign(ctx, target, value)?;
|
generator.gen_assign(ctx, target, value)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Assign { targets, value, .. } => {
|
StmtKind::Assign { targets, value, .. } => {
|
||||||
let value = generator.gen_expr(ctx, value)?.unwrap();
|
let Some(value) = generator.gen_expr(ctx, value)? else {
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
for target in targets.iter() {
|
for target in targets.iter() {
|
||||||
generator.gen_assign(ctx, target, value.clone())?;
|
generator.gen_assign(ctx, target, value.clone())?;
|
||||||
}
|
}
|
||||||
@ -1132,28 +1154,28 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>(
|
|||||||
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
|
StmtKind::Try { .. } => gen_try(generator, ctx, stmt)?,
|
||||||
StmtKind::Raise { exc, .. } => {
|
StmtKind::Raise { exc, .. } => {
|
||||||
if let Some(exc) = exc {
|
if let Some(exc) = exc {
|
||||||
let exc = generator.gen_expr(ctx, exc)?.unwrap().to_basic_value_enum(
|
let exc = if let Some(v) = generator.gen_expr(ctx, exc)? {
|
||||||
ctx,
|
v.to_basic_value_enum(ctx, generator, exc.custom.unwrap())?
|
||||||
generator,
|
} else {
|
||||||
exc.custom.unwrap(),
|
return Ok(())
|
||||||
)?;
|
};
|
||||||
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
gen_raise(generator, ctx, Some(&exc), stmt.location);
|
||||||
} else {
|
} else {
|
||||||
gen_raise(generator, ctx, None, stmt.location);
|
gen_raise(generator, ctx, None, stmt.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Assert { test, msg, .. } => {
|
StmtKind::Assert { test, msg, .. } => {
|
||||||
let test = generator.gen_expr(ctx, test)?.unwrap().to_basic_value_enum(
|
let test = if let Some(v) = generator.gen_expr(ctx, test)? {
|
||||||
ctx,
|
v.to_basic_value_enum(ctx, generator, test.custom.unwrap())?
|
||||||
generator,
|
} else {
|
||||||
test.custom.unwrap(),
|
return Ok(())
|
||||||
)?;
|
};
|
||||||
let err_msg = match msg {
|
let err_msg = match msg {
|
||||||
Some(msg) => generator.gen_expr(ctx, msg)?.unwrap().to_basic_value_enum(
|
Some(msg) => if let Some(v) = generator.gen_expr(ctx, msg)? {
|
||||||
ctx,
|
v.to_basic_value_enum(ctx, generator, msg.custom.unwrap())?
|
||||||
generator,
|
} else {
|
||||||
msg.custom.unwrap(),
|
return Ok(())
|
||||||
)?,
|
},
|
||||||
None => ctx.gen_string(generator, ""),
|
None => ctx.gen_string(generator, ""),
|
||||||
};
|
};
|
||||||
ctx.make_assert_impl(
|
ctx.make_assert_impl(
|
||||||
|
@ -62,7 +62,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// there are some cases where the custom field is None
|
// there are some cases where the custom field is None
|
||||||
if let Some(ty) = &expr.custom {
|
if let Some(ty) = &expr.custom {
|
||||||
if !self.unifier.is_concrete(*ty, &self.function_data.bound_variables) {
|
if !matches!(&expr.node, ExprKind::Constant { value: Constant::Ellipsis, .. }) && !self.unifier.is_concrete(*ty, &self.function_data.bound_variables) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"expected concrete type at {} but got {}",
|
"expected concrete type at {} but got {}",
|
||||||
expr.location,
|
expr.location,
|
||||||
|
@ -964,6 +964,7 @@ impl<'a> Inferencer<'a> {
|
|||||||
ast::Constant::Str(_) => Ok(self.primitives.str),
|
ast::Constant::Str(_) => Ok(self.primitives.str),
|
||||||
ast::Constant::None
|
ast::Constant::None
|
||||||
=> report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc),
|
=> report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc),
|
||||||
|
ast::Constant::Ellipsis => Ok(self.unifier.get_fresh_var(None, None).0),
|
||||||
_ => report_error("not supported", *loc),
|
_ => report_error("not supported", *loc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user