core: Codegen for ellipsis expression

This commit is contained in:
David Mak 2023-12-06 15:26:37 +08:00
parent 61624cd339
commit 1d47d7b850
4 changed files with 37 additions and 15 deletions

View File

@ -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, "");
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(
@ -1211,7 +1229,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 (

View File

@ -604,7 +604,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 +627,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() {

View File

@ -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,

View File

@ -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),
} }
} }