From 1d47d7b850e52ad7b5abba7b9b745c548ff79681 Mon Sep 17 00:00:00 2001 From: David Mak Date: Wed, 6 Dec 2023 15:26:37 +0800 Subject: [PATCH] core: Codegen for ellipsis expression --- nac3core/src/codegen/expr.rs | 45 ++++++++++++++----- nac3core/src/codegen/stmt.rs | 4 +- nac3core/src/typecheck/function_check.rs | 2 +- nac3core/src/typecheck/type_inferencer/mod.rs | 1 + 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 052e483..fe53657 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -207,12 +207,12 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { generator: &mut dyn CodeGenerator, value: &Constant, ty: Type, - ) -> BasicValueEnum<'ctx> { + ) -> Option> { match value { Constant::Bool(v) => { assert!(self.unifier.unioned(ty, self.primitives.bool)); 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) => { let ty = if self.unifier.unioned(ty, self.primitives.int32) @@ -226,28 +226,33 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } else { unreachable!(); }; - ty.const_int(*val as u64, false).into() + Some(ty.const_int(*val as u64, false).into()) } Constant::Float(v) => { assert!(self.unifier.unioned(ty, self.primitives.float)); let ty = self.ctx.f64_type(); - ty.const_float(*v).into() + Some(ty.const_float(*v).into()) } Constant::Tuple(v) => { let ty = self.unifier.get_ty(ty); let types = if let TypeEnum::TTuple { ty } = &*ty { ty.clone() } else { unreachable!() }; 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(); - let types = values.iter().map(BasicValueEnum::get_type).collect_vec(); - let ty = self.ctx.struct_type(&types, false); - ty.const_named_struct(&values).into() + + if values.len() == v.len() { + 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) => { assert!(self.unifier.unioned(ty, self.primitives.str)); if let Some(v) = self.const_strings.get(v) { - *v + Some(*v) } else { let str_ptr = self.builder.build_global_string_ptr(v, "const").as_pointer_value().into(); @@ -256,9 +261,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { let val = ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into(); 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!(), } } @@ -481,7 +499,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { generator: &mut dyn CodeGenerator, s: S, ) -> 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( @@ -1211,7 +1229,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>( Ok(Some(match &expr.node { ExprKind::Constant { value, .. } => { 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() => { match ( diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index 65b3dbb..f2b7f47 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -604,7 +604,7 @@ pub fn exn_constructor<'ctx, 'a>( let msg = if !args.is_empty() { args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)? } else { - empty_string + empty_string.unwrap() }; ctx.builder.build_store(ptr, msg); for i in [6, 7, 8].iter() { @@ -627,7 +627,7 @@ pub fn exn_constructor<'ctx, 'a>( &[zero, int32.const_int(*i, false)], "exn.str", ); - ctx.builder.build_store(ptr, empty_string); + ctx.builder.build_store(ptr, empty_string.unwrap()); } // set ints to zero for i in [2, 3].iter() { diff --git a/nac3core/src/typecheck/function_check.rs b/nac3core/src/typecheck/function_check.rs index 7ed0735..6d8e1b2 100644 --- a/nac3core/src/typecheck/function_check.rs +++ b/nac3core/src/typecheck/function_check.rs @@ -62,7 +62,7 @@ impl<'a> Inferencer<'a> { ) -> Result<(), String> { // there are some cases where the custom field is None 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!( "expected concrete type at {} but got {}", expr.location, diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index c72e199..60dea07 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -964,6 +964,7 @@ impl<'a> Inferencer<'a> { ast::Constant::Str(_) => Ok(self.primitives.str), ast::Constant::None => 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), } }