From 8015ffd332fb41d92b288d7a51390075eb0dd181 Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Fri, 5 Apr 2024 11:17:03 -0400 Subject: [PATCH 01/10] add parsing and HIR pass --- src/cache/mod.rs | 3 +++ src/cranelift_backend/mod.rs | 27 +++++++++++++++++++++++ src/error/mod.rs | 7 ++++++ src/hir/closures.rs | 5 +++++ src/hir/mod.rs | 10 +++++++++ src/hir/monomorphisation.rs | 9 ++++++++ src/hir/printer.rs | 10 +++++++++ src/llvm/mod.rs | 41 +++++++++++++++++++++++++++++++++++ src/nameresolution/builtin.rs | 5 ++++- src/nameresolution/mod.rs | 12 ++++++++++ src/parser/ast.rs | 15 +++++++++++++ src/parser/pretty_printer.rs | 6 +++++ src/types/typechecker.rs | 22 +++++++++++++++++++ src/types/typed.rs | 1 + 14 files changed, 172 insertions(+), 1 deletion(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 01d84529..6852f75d 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -131,6 +131,8 @@ pub struct ModuleCache<'a> { pub error_count: usize, pub file_cache: FileCache, + + pub maybe_type: TypeInfoId, } pub type FileCache = HashMap; @@ -417,6 +419,7 @@ impl<'a> ModuleCache<'a> { global_dependency_graph: DependencyGraph::default(), diagnostics: Vec::new(), error_count: 0, + maybe_type: TypeInfoId(0), // sentinel value file_cache, } } diff --git a/src/cranelift_backend/mod.rs b/src/cranelift_backend/mod.rs index a8bbdb57..707c88ca 100644 --- a/src/cranelift_backend/mod.rs +++ b/src/cranelift_backend/mod.rs @@ -163,6 +163,33 @@ impl CodeGen for hir::If { } } +impl CodeGen for hir::Else { + fn codegen<'a>(&'a self, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> Value { + let expr = builder.create_block(); + let then_values = context.eval_all_in_block(&self.expr, expr, builder); + + let end = context.new_block_with_arg(&self.result_type, builder); + + let else_none = builder.create_block(); + builder.ins().jump(else_none, &[]); + + let else_values = context.eval_all_in_block(&self.otherwise, else_none, builder); + + if let Some(else_values) = else_values { + builder.ins().jump(end, &else_values); + } + + builder.seal_block(end); + builder.switch_to_block(end); + let end_values = builder.block_params(end); + let ret = context.array_to_value(end_values, &self.result_type); + + builder.seal_block(expr); + builder.seal_block(else_none); + ret + } +} + impl CodeGen for hir::Match { fn codegen<'a>(&'a self, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> Value { context.codegen_match(self, builder) diff --git a/src/error/mod.rs b/src/error/mod.rs index a1b3efbe..206406fd 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -104,6 +104,7 @@ pub enum TypeErrorKind { ArgumentTypeMismatch, NonBoolInCondition, IfBranchMismatch, + ElseBranchMismatch, MatchPatternTypeDiffers, MatchReturnTypeDiffers, DoesNotMatchAnnotatedType, @@ -278,6 +279,12 @@ impl Display for DiagnosticKind { "Expected 'then' and 'else' branch types to match, but found {expected} and {actual} respectively" ) }, + DiagnosticKind::TypeError(TypeErrorKind::ElseBranchMismatch, expected, actual) => { + write!( + f, + "Expected 'expr' and 'else' branch types to match, but found {expected} and {actual} respectively" + ) + }, DiagnosticKind::TypeError(TypeErrorKind::MatchPatternTypeDiffers, expected, actual) => { write!(f, "This pattern of type {actual} does not match the type {expected} that is being matched on") }, diff --git a/src/hir/closures.rs b/src/hir/closures.rs index 01a45eca..42bc81ac 100644 --- a/src/hir/closures.rs +++ b/src/hir/closures.rs @@ -90,6 +90,11 @@ fn replace_env(expr: Ast, env: &Ast, definition_id: hir::DefinitionId, f: &hir:: if_expr.otherwise = Box::new(replace_env(*if_expr.otherwise, env, definition_id, f)); Ast::If(if_expr) }, + Ast::Else(mut else_expr) => { + else_expr.expr = Box::new(replace_env(*else_expr.expr, env, definition_id, f)); + else_expr.otherwise = Box::new(replace_env(*else_expr.otherwise, env, definition_id, f)); + Ast::Else(else_expr) + }, Ast::Sequence(mut seq) => { seq.statements = fmap(seq.statements, |stmt| replace_env(stmt, env, definition_id, f)); Ast::Sequence(seq) diff --git a/src/hir/mod.rs b/src/hir/mod.rs index eb4d4dd5..2f8c2c27 100644 --- a/src/hir/mod.rs +++ b/src/hir/mod.rs @@ -108,6 +108,13 @@ pub struct If { pub result_type: Type, } +#[derive(Debug, Clone)] +pub struct Else { + pub expr: Box, + pub otherwise: Box, + pub result_type: Type, +} + #[derive(Debug, Clone)] pub struct Match { // Unlike ast::Match this only contains the parts of the @@ -262,6 +269,7 @@ pub enum Ast { FunctionCall(FunctionCall), Definition(Definition), If(If), + Else(Else), Match(Match), Return(Return), Sequence(Sequence), @@ -288,6 +296,7 @@ macro_rules! dispatch_on_hir { $crate::hir::Ast::FunctionCall(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Definition(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::If(inner) => $function(inner $(, $($args),* )? ), + $crate::hir::Ast::Else(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Match(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Return(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Sequence(inner) => $function(inner $(, $($args),* )? ), @@ -323,6 +332,7 @@ impl_display!(Lambda); impl_display!(FunctionCall); impl_display!(Definition); impl_display!(If); +impl_display!(Else); impl_display!(Match); impl_display!(Return); impl_display!(Sequence); diff --git a/src/hir/monomorphisation.rs b/src/hir/monomorphisation.rs index 0cebbd4a..90149095 100644 --- a/src/hir/monomorphisation.rs +++ b/src/hir/monomorphisation.rs @@ -112,6 +112,7 @@ impl<'c> Context<'c> { FunctionCall(call) => self.monomorphise_call(call), Definition(definition) => self.monomorphise_definition(definition), If(if_) => self.monomorphise_if(if_), + Else(else_) => self.monomorphise_else(else_), Match(match_) => self.monomorphise_match(match_), TypeDefinition(_) => unit_literal(), TypeAnnotation(annotation) => self.monomorphise(&annotation.lhs), @@ -1499,6 +1500,14 @@ impl<'c> Context<'c> { hir::Ast::If(hir::If { condition, then, otherwise, result_type }) } + fn monomorphise_else(&mut self, else_: &ast::Else<'c>) -> hir::Ast { + let expr = Box::new(self.monomorphise(&else_.expr)); + let otherwise = Box::new(self.monomorphise(&else_.otherwise)); + let result_type = self.convert_type(else_.typ.as_ref().unwrap()); + + hir::Ast::Else(hir::Else { expr, otherwise, result_type }) + } + fn monomorphise_return(&mut self, return_: &ast::Return<'c>) -> hir::Ast { hir::Ast::Return(hir::Return { expression: Box::new(self.monomorphise(&return_.expression)) }) } diff --git a/src/hir/printer.rs b/src/hir/printer.rs index c1b12294..a42421a4 100644 --- a/src/hir/printer.rs +++ b/src/hir/printer.rs @@ -177,6 +177,16 @@ impl FmtAst for If { } } +impl FmtAst for Else { + fn fmt_ast(&self, printer: &mut AstPrinter, f: &mut Formatter) -> fmt::Result { + write!(f, "Maybe a")?; + printer.block(self.expr.as_ref(), f)?; + write!(f, "else ")?; + printer.block(self.otherwise.as_ref(), f)?; + write!(f, " endelse") + } +} + impl FmtAst for Return { fn fmt_ast(&self, printer: &mut AstPrinter, f: &mut Formatter) -> fmt::Result { write!(f, "return ")?; diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index 1260fd08..075eaed2 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -627,6 +627,47 @@ impl<'g> CodeGen<'g> for hir::If { } } +impl<'g> CodeGen<'g> for hir::Else { + fn codegen(&self, generator: &mut Generator<'g>) -> BasicValueEnum<'g> { + let current_function = generator.current_function(); + let expr_block = generator.context.append_basic_block(current_function, "expr"); + let end_block = generator.context.append_basic_block(current_function, "end_else"); + + // Setup conditional jump + let else_block = generator.context.append_basic_block(current_function, "else"); + + generator.builder.position_at_end(expr_block); + let (if_type, then_option) = generator.codegen_branch(&self.expr, end_block); + + generator.builder.position_at_end(else_block); + let (_, else_option) = generator.codegen_branch(&self.otherwise, end_block); + + // Create phi at the end of the if beforehand + generator.builder.position_at_end(end_block); + + // Some of the branches may have terminated early. We need to check each case to + // determine which we should add to the phi or if we should even create a phi at all. + match (then_option, else_option) { + (Some((then_value, then_branch)), Some((else_value, else_branch))) => { + let phi = generator.builder.build_phi(then_value.get_type(), "if_result").expect("Could not build phi"); + + phi.add_incoming(&[(&then_value, then_branch), (&else_value, else_branch)]); + phi.as_basic_value() + }, + (Some((then_value, _)), None) => then_value, + (None, Some((else_value, _))) => else_value, + (None, None) => { + generator.builder.build_unreachable().expect("Could not create 'unreachable' for if"); + + // Block is unreachable but we still need to return an undef value. + // If we return None the compiler would crash while compiling + // `2 + if true return "uh" else return "oh"` + Generator::undef_value(if_type) + }, + } + } +} + impl<'g> CodeGen<'g> for hir::Match { fn codegen(&self, generator: &mut Generator<'g>) -> BasicValueEnum<'g> { generator.codegen_tree(self) diff --git a/src/nameresolution/builtin.rs b/src/nameresolution/builtin.rs index b77ce384..4f2d8675 100644 --- a/src/nameresolution/builtin.rs +++ b/src/nameresolution/builtin.rs @@ -78,7 +78,10 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>) resolver.current_scope().import(exports, cache, Location::builtin(), &HashSet::new()); } } - + // Extract stdlib Types (specifically Maybe a) to keep track of for downstream + // sytantic sugaring + let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); + cache.maybe_type = maybe_id; // Manually insert some builtins as if they were defined in the prelude resolver.current_scope().types.insert(Token::Comma.to_string(), PAIR_TYPE); resolver.current_scope().definitions.insert(Token::Comma.to_string(), PAIR_ID); diff --git a/src/nameresolution/mod.rs b/src/nameresolution/mod.rs index af6a9519..74618f91 100644 --- a/src/nameresolution/mod.rs +++ b/src/nameresolution/mod.rs @@ -1065,6 +1065,18 @@ impl<'c> Resolvable<'c> for ast::If<'c> { } } +impl<'c> Resolvable<'c> for ast::Else<'c> { + fn declare(&mut self, _resolver: &mut NameResolver, _cache: &mut ModuleCache<'c>) {} + + fn define(&mut self, resolver: &mut NameResolver, cache: &mut ModuleCache<'c>) { + self.expr.define(resolver, cache); + + resolver.push_scope(cache); + self.otherwise.define(resolver, cache); + resolver.pop_scope(cache, true, None); + } +} + impl<'c> Resolvable<'c> for ast::Match<'c> { fn declare(&mut self, _resolver: &mut NameResolver, _cache: &mut ModuleCache<'c>) {} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 23b51271..0bfdf4b3 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -172,6 +172,14 @@ pub struct If<'a> { pub location: Location<'a>, pub typ: Option, } +// Maybe a then a else expression +#[derive(Debug, Clone)] +pub struct Else<'a> { + pub expr: Box>, + pub otherwise: Box>, + pub location: Location<'a>, + pub typ: Option, +} /// match expression /// | pattern1 -> branch1 @@ -413,6 +421,7 @@ pub enum Ast<'a> { FunctionCall(FunctionCall<'a>), Definition(Definition<'a>), If(If<'a>), + Else(Else<'a>), Match(Match<'a>), TypeDefinition(TypeDefinition<'a>), TypeAnnotation(TypeAnnotation<'a>), @@ -588,6 +597,10 @@ impl<'a> Ast<'a> { } } + pub fn else_expr(expr: Ast<'a>, otherwise: Ast<'a>, location: Location<'a>) -> Ast<'a> { + Ast::Else(Else { expr: Box::new(expr), otherwise: Box::new(otherwise), location, typ: None }) + } + pub fn definition(pattern: Ast<'a>, expr: Ast<'a>, location: Location<'a>) -> Ast<'a> { Ast::Definition(Definition { pattern: Box::new(pattern), @@ -736,6 +749,7 @@ macro_rules! dispatch_on_expr { $crate::parser::ast::Ast::FunctionCall(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::Definition(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::If(inner) => $function(inner $(, $($args),* )? ), + $crate::parser::ast::Ast::Else(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::Match(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::TypeDefinition(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::TypeAnnotation(inner) => $function(inner $(, $($args),* )? ), @@ -776,6 +790,7 @@ impl_locatable_for!(Lambda); impl_locatable_for!(FunctionCall); impl_locatable_for!(Definition); impl_locatable_for!(If); +impl_locatable_for!(Else); impl_locatable_for!(Match); impl_locatable_for!(TypeDefinition); impl_locatable_for!(TypeAnnotation); diff --git a/src/parser/pretty_printer.rs b/src/parser/pretty_printer.rs index 097f7c54..77775003 100644 --- a/src/parser/pretty_printer.rs +++ b/src/parser/pretty_printer.rs @@ -75,6 +75,12 @@ impl<'a> Display for ast::If<'a> { } } +impl<'a> Display for ast::Else<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "( {} else {})", self.expr, self.otherwise) + } +} + impl<'a> Display for ast::Match<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "(match {}", self.expression)?; diff --git a/src/types/typechecker.rs b/src/types/typechecker.rs index 04e8fa7c..c39147c8 100644 --- a/src/types/typechecker.rs +++ b/src/types/typechecker.rs @@ -1728,6 +1728,28 @@ impl<'a> Inferable<'a> for ast::If<'a> { } } +impl<'a> Inferable<'a> for ast::Else<'a> { + fn infer_impl(&mut self, cache: &mut ModuleCache<'a>) -> TypeResult { + // Create new serogate Variable x + let x = next_type_variable(cache); + //let x = Type::TypeVariable(id); + // Construct a Maybe x Type + //let maybe_typeinfo_id = cache.type_infos.get(cache.maybe_type.0); + let maybe_type = UserDefined(cache.maybe_type); + let maybe_x = TypeApplication(Box::new(maybe_type), vec![x.clone()]); + // Unify Maybe x with expr and raise if Type is mismatched + let mut expr = infer(self.expr.as_mut(), cache); + unify(&maybe_x, &mut expr.typ, self.expr.locate(), cache, TE::ElseBranchMismatch); + + // Unify x with a and raise if Type is mismatched + let mut otherwise = infer(self.otherwise.as_mut(), cache); + expr.combine(&mut otherwise, cache); + + unify(&x, &otherwise.typ, self.location, cache, TE::ArgumentTypeMismatch); + expr.with_type(otherwise.typ) + } +} + impl<'a> Inferable<'a> for ast::Match<'a> { fn infer_impl(&mut self, cache: &mut ModuleCache<'a>) -> TypeResult { let error_count = cache.error_count(); diff --git a/src/types/typed.rs b/src/types/typed.rs index f4cd1b8b..d9c9a65b 100644 --- a/src/types/typed.rs +++ b/src/types/typed.rs @@ -39,6 +39,7 @@ impl_typed_for!(Lambda); impl_typed_for!(FunctionCall); impl_typed_for!(Definition); impl_typed_for!(If); +impl_typed_for!(Else); impl_typed_for!(Match); impl_typed_for!(TypeDefinition); impl_typed_for!(TypeAnnotation); From abcc77218ce987da08e41ef098bc80c611a79f87 Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Fri, 5 Apr 2024 13:29:17 -0400 Subject: [PATCH 02/10] try reordering to avoid stack overflow --- src/nameresolution/builtin.rs | 1 + src/parser/mod.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nameresolution/builtin.rs b/src/nameresolution/builtin.rs index 4f2d8675..8d5f31cd 100644 --- a/src/nameresolution/builtin.rs +++ b/src/nameresolution/builtin.rs @@ -80,6 +80,7 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>) } // Extract stdlib Types (specifically Maybe a) to keep track of for downstream // sytantic sugaring + //println!("{:?}", resolver.current_scope().types); let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); cache.maybe_type = maybe_id; // Manually insert some builtins as if they were defined in the prelude diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3fd28112..69ca5550 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -442,6 +442,7 @@ fn expression<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { fn term<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { match input[0].0 { Token::If => if_expr(input), + Token::Else => else_expr(input), Token::Loop => loop_expr(input), Token::Match => match_expr(input), Token::Handle => handle_expr(input), @@ -634,9 +635,10 @@ parser!(match_branch _loc -> 'b (Ast<'b>, Ast<'b>) = parser!(else_expr _loc = _ <- maybe_newline; + expr <- block_or_statement; _ <- expect(Token::Else); otherwise !<- block_or_statement; - otherwise + Ast::else_expr(expr, otherwise, _loc) ); /// A function_argument is a unary expr or a member_access of From b6bcddcfdeede19b3e7df8c811547097788f0f68 Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Sun, 7 Apr 2024 22:19:38 -0400 Subject: [PATCH 03/10] add changes from comments --- src/cache/mod.rs | 4 ++-- src/cranelift_backend/mod.rs | 8 ++++---- src/hir/closures.rs | 4 ++-- src/hir/mod.rs | 4 ++-- src/hir/monomorphisation.rs | 6 +++--- src/hir/printer.rs | 10 +++++----- src/llvm/mod.rs | 4 ++-- src/nameresolution/builtin.rs | 7 ++++--- src/nameresolution/mod.rs | 4 ++-- src/parser/ast.rs | 8 ++++---- src/parser/mod.rs | 12 ++++++++++-- src/parser/pretty_printer.rs | 2 +- src/types/typechecker.rs | 14 +++++++------- 13 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 6852f75d..9e05f044 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -132,7 +132,7 @@ pub struct ModuleCache<'a> { pub file_cache: FileCache, - pub maybe_type: TypeInfoId, + pub maybe_type: Option, } pub type FileCache = HashMap; @@ -419,7 +419,7 @@ impl<'a> ModuleCache<'a> { global_dependency_graph: DependencyGraph::default(), diagnostics: Vec::new(), error_count: 0, - maybe_type: TypeInfoId(0), // sentinel value + maybe_type: Some(TypeInfoId(0)), // sentinel value file_cache, } } diff --git a/src/cranelift_backend/mod.rs b/src/cranelift_backend/mod.rs index 707c88ca..883802ba 100644 --- a/src/cranelift_backend/mod.rs +++ b/src/cranelift_backend/mod.rs @@ -165,15 +165,15 @@ impl CodeGen for hir::If { impl CodeGen for hir::Else { fn codegen<'a>(&'a self, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> Value { - let expr = builder.create_block(); - let then_values = context.eval_all_in_block(&self.expr, expr, builder); + let lhs = builder.create_block(); + let then_values = context.eval_all_in_block(&self.lhs, lhs, builder); let end = context.new_block_with_arg(&self.result_type, builder); let else_none = builder.create_block(); builder.ins().jump(else_none, &[]); - let else_values = context.eval_all_in_block(&self.otherwise, else_none, builder); + let else_values = context.eval_all_in_block(&self.rhs, else_none, builder); if let Some(else_values) = else_values { builder.ins().jump(end, &else_values); @@ -184,7 +184,7 @@ impl CodeGen for hir::Else { let end_values = builder.block_params(end); let ret = context.array_to_value(end_values, &self.result_type); - builder.seal_block(expr); + builder.seal_block(lhs); builder.seal_block(else_none); ret } diff --git a/src/hir/closures.rs b/src/hir/closures.rs index 42bc81ac..18447475 100644 --- a/src/hir/closures.rs +++ b/src/hir/closures.rs @@ -91,8 +91,8 @@ fn replace_env(expr: Ast, env: &Ast, definition_id: hir::DefinitionId, f: &hir:: Ast::If(if_expr) }, Ast::Else(mut else_expr) => { - else_expr.expr = Box::new(replace_env(*else_expr.expr, env, definition_id, f)); - else_expr.otherwise = Box::new(replace_env(*else_expr.otherwise, env, definition_id, f)); + else_expr.lhs = Box::new(replace_env(*else_expr.lhs, env, definition_id, f)); + else_expr.rhs = Box::new(replace_env(*else_expr.rhs, env, definition_id, f)); Ast::Else(else_expr) }, Ast::Sequence(mut seq) => { diff --git a/src/hir/mod.rs b/src/hir/mod.rs index 2f8c2c27..368cc1a6 100644 --- a/src/hir/mod.rs +++ b/src/hir/mod.rs @@ -110,8 +110,8 @@ pub struct If { #[derive(Debug, Clone)] pub struct Else { - pub expr: Box, - pub otherwise: Box, + pub lhs: Box, + pub rhs: Box, pub result_type: Type, } diff --git a/src/hir/monomorphisation.rs b/src/hir/monomorphisation.rs index 90149095..7c356c18 100644 --- a/src/hir/monomorphisation.rs +++ b/src/hir/monomorphisation.rs @@ -1501,11 +1501,11 @@ impl<'c> Context<'c> { } fn monomorphise_else(&mut self, else_: &ast::Else<'c>) -> hir::Ast { - let expr = Box::new(self.monomorphise(&else_.expr)); - let otherwise = Box::new(self.monomorphise(&else_.otherwise)); + let lhs = Box::new(self.monomorphise(&else_.lhs)); + let rhs = Box::new(self.monomorphise(&else_.rhs)); let result_type = self.convert_type(else_.typ.as_ref().unwrap()); - hir::Ast::Else(hir::Else { expr, otherwise, result_type }) + hir::Ast::Else(hir::Else { lhs, rhs, result_type }) } fn monomorphise_return(&mut self, return_: &ast::Return<'c>) -> hir::Ast { diff --git a/src/hir/printer.rs b/src/hir/printer.rs index a42421a4..a0d3675c 100644 --- a/src/hir/printer.rs +++ b/src/hir/printer.rs @@ -179,11 +179,11 @@ impl FmtAst for If { impl FmtAst for Else { fn fmt_ast(&self, printer: &mut AstPrinter, f: &mut Formatter) -> fmt::Result { - write!(f, "Maybe a")?; - printer.block(self.expr.as_ref(), f)?; - write!(f, "else ")?; - printer.block(self.otherwise.as_ref(), f)?; - write!(f, " endelse") + write!(f, "(")?; + printer.block(self.lhs.as_ref(), f)?; + write!(f, " else ")?; + printer.block(self.rhs.as_ref(), f)?; + write!(f, ") ") } } diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index 075eaed2..96c70bcc 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -637,10 +637,10 @@ impl<'g> CodeGen<'g> for hir::Else { let else_block = generator.context.append_basic_block(current_function, "else"); generator.builder.position_at_end(expr_block); - let (if_type, then_option) = generator.codegen_branch(&self.expr, end_block); + let (if_type, then_option) = generator.codegen_branch(&self.lhs, end_block); generator.builder.position_at_end(else_block); - let (_, else_option) = generator.codegen_branch(&self.otherwise, end_block); + let (_, else_option) = generator.codegen_branch(&self.rhs, end_block); // Create phi at the end of the if beforehand generator.builder.position_at_end(end_block); diff --git a/src/nameresolution/builtin.rs b/src/nameresolution/builtin.rs index 8d5f31cd..c843e754 100644 --- a/src/nameresolution/builtin.rs +++ b/src/nameresolution/builtin.rs @@ -70,6 +70,7 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>) if resolver.filepath == prelude_path() { // If we're in the prelude include the built-in symbol "builtin" to define primitives resolver.current_scope().definitions.insert("builtin".into(), BUILTIN_ID); + //println!("{:?}", &resolver.current_scope().types); } else { // Otherwise, import the prelude itself let prelude_dir = prelude_path(); @@ -79,10 +80,10 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>) } } // Extract stdlib Types (specifically Maybe a) to keep track of for downstream + //println!("{:?}", &resolver.current_scope().types); + //let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); + //cache.maybe_type = Some(maybe_id); // sytantic sugaring - //println!("{:?}", resolver.current_scope().types); - let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); - cache.maybe_type = maybe_id; // Manually insert some builtins as if they were defined in the prelude resolver.current_scope().types.insert(Token::Comma.to_string(), PAIR_TYPE); resolver.current_scope().definitions.insert(Token::Comma.to_string(), PAIR_ID); diff --git a/src/nameresolution/mod.rs b/src/nameresolution/mod.rs index 74618f91..0b343940 100644 --- a/src/nameresolution/mod.rs +++ b/src/nameresolution/mod.rs @@ -1069,10 +1069,10 @@ impl<'c> Resolvable<'c> for ast::Else<'c> { fn declare(&mut self, _resolver: &mut NameResolver, _cache: &mut ModuleCache<'c>) {} fn define(&mut self, resolver: &mut NameResolver, cache: &mut ModuleCache<'c>) { - self.expr.define(resolver, cache); + self.lhs.define(resolver, cache); resolver.push_scope(cache); - self.otherwise.define(resolver, cache); + self.rhs.define(resolver, cache); resolver.pop_scope(cache, true, None); } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 0bfdf4b3..1ab1884d 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -175,8 +175,8 @@ pub struct If<'a> { // Maybe a then a else expression #[derive(Debug, Clone)] pub struct Else<'a> { - pub expr: Box>, - pub otherwise: Box>, + pub lhs: Box>, + pub rhs: Box>, pub location: Location<'a>, pub typ: Option, } @@ -597,8 +597,8 @@ impl<'a> Ast<'a> { } } - pub fn else_expr(expr: Ast<'a>, otherwise: Ast<'a>, location: Location<'a>) -> Ast<'a> { - Ast::Else(Else { expr: Box::new(expr), otherwise: Box::new(otherwise), location, typ: None }) + pub fn else_expr(lhs: Ast<'a>, rhs: Ast<'a>, location: Location<'a>) -> Ast<'a> { + Ast::Else(Else { lhs: Box::new(lhs), rhs: Box::new(rhs), location, typ: None }) } pub fn definition(pattern: Ast<'a>, expr: Ast<'a>, location: Location<'a>) -> Ast<'a> { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 69ca5550..7ba6c6bd 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -442,7 +442,7 @@ fn expression<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { fn term<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { match input[0].0 { Token::If => if_expr(input), - Token::Else => else_expr(input), + //Token::Else => else_expr(input), Token::Loop => loop_expr(input), Token::Match => match_expr(input), Token::Handle => handle_expr(input), @@ -506,7 +506,7 @@ parser!(if_expr loc = _ !<- maybe_newline; _ !<- expect(Token::Then); then !<- block_or_statement; - otherwise !<- maybe(else_expr); + otherwise !<- maybe(without_else_expr); Ast::if_expr(condition, then, otherwise, loc) ); @@ -633,6 +633,14 @@ parser!(match_branch _loc -> 'b (Ast<'b>, Ast<'b>) = (pattern, branch) ); +parser!(without_else_expr _loc = + _ <- maybe_newline; + expr <- block_or_statement; + _ <- expect(Token::Else); + otherwise !<- block_or_statement; + otherwise +); + parser!(else_expr _loc = _ <- maybe_newline; expr <- block_or_statement; diff --git a/src/parser/pretty_printer.rs b/src/parser/pretty_printer.rs index 77775003..41007e82 100644 --- a/src/parser/pretty_printer.rs +++ b/src/parser/pretty_printer.rs @@ -77,7 +77,7 @@ impl<'a> Display for ast::If<'a> { impl<'a> Display for ast::Else<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "( {} else {})", self.expr, self.otherwise) + write!(f, "( {} else {})", self.lhs, self.rhs) } } diff --git a/src/types/typechecker.rs b/src/types/typechecker.rs index c39147c8..d7e321ac 100644 --- a/src/types/typechecker.rs +++ b/src/types/typechecker.rs @@ -1735,18 +1735,18 @@ impl<'a> Inferable<'a> for ast::Else<'a> { //let x = Type::TypeVariable(id); // Construct a Maybe x Type //let maybe_typeinfo_id = cache.type_infos.get(cache.maybe_type.0); - let maybe_type = UserDefined(cache.maybe_type); + let maybe_type = UserDefined(cache.maybe_type.expect("Maybe type should be befined from importing prelude")); let maybe_x = TypeApplication(Box::new(maybe_type), vec![x.clone()]); // Unify Maybe x with expr and raise if Type is mismatched - let mut expr = infer(self.expr.as_mut(), cache); - unify(&maybe_x, &mut expr.typ, self.expr.locate(), cache, TE::ElseBranchMismatch); + let mut lhs = infer(self.lhs.as_mut(), cache); + unify(&maybe_x, &mut lhs.typ, self.lhs.locate(), cache, TE::ElseBranchMismatch); // Unify x with a and raise if Type is mismatched - let mut otherwise = infer(self.otherwise.as_mut(), cache); - expr.combine(&mut otherwise, cache); + let mut rhs = infer(self.rhs.as_mut(), cache); + lhs.combine(&mut rhs, cache); - unify(&x, &otherwise.typ, self.location, cache, TE::ArgumentTypeMismatch); - expr.with_type(otherwise.typ) + unify(&x, &rhs.typ, self.location, cache, TE::ArgumentTypeMismatch); + lhs.with_type(rhs.typ) } } From b2b418713e2122e4330a080dc752b61689a7c0fe Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Sun, 7 Apr 2024 22:39:03 -0400 Subject: [PATCH 04/10] fix grabbing maybe type --- src/nameresolution/builtin.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/nameresolution/builtin.rs b/src/nameresolution/builtin.rs index c843e754..c3c19abc 100644 --- a/src/nameresolution/builtin.rs +++ b/src/nameresolution/builtin.rs @@ -70,20 +70,17 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>) if resolver.filepath == prelude_path() { // If we're in the prelude include the built-in symbol "builtin" to define primitives resolver.current_scope().definitions.insert("builtin".into(), BUILTIN_ID); - //println!("{:?}", &resolver.current_scope().types); } else { // Otherwise, import the prelude itself let prelude_dir = prelude_path(); if let Some(id) = declare_module(&prelude_dir, cache, Location::builtin()) { let exports = define_module(id, cache, Location::builtin()).unwrap(); resolver.current_scope().import(exports, cache, Location::builtin(), &HashSet::new()); + let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); + cache.maybe_type = Some(maybe_id); } } - // Extract stdlib Types (specifically Maybe a) to keep track of for downstream - //println!("{:?}", &resolver.current_scope().types); - //let maybe_id = resolver.current_scope().types.get("Maybe").unwrap().clone(); - //cache.maybe_type = Some(maybe_id); - // sytantic sugaring + // Manually insert some builtins as if they were defined in the prelude resolver.current_scope().types.insert(Token::Comma.to_string(), PAIR_TYPE); resolver.current_scope().definitions.insert(Token::Comma.to_string(), PAIR_ID); From 4117dda84876a7492b126f6d93e977bd3aeb44e9 Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Mon, 8 Apr 2024 00:45:45 -0400 Subject: [PATCH 05/10] try parsing else operators --- src/llvm/mod.rs | 2 -- src/parser/mod.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index 96c70bcc..a70cbefd 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -630,13 +630,11 @@ impl<'g> CodeGen<'g> for hir::If { impl<'g> CodeGen<'g> for hir::Else { fn codegen(&self, generator: &mut Generator<'g>) -> BasicValueEnum<'g> { let current_function = generator.current_function(); - let expr_block = generator.context.append_basic_block(current_function, "expr"); let end_block = generator.context.append_basic_block(current_function, "end_else"); // Setup conditional jump let else_block = generator.context.append_basic_block(current_function, "else"); - generator.builder.position_at_end(expr_block); let (if_type, then_option) = generator.codegen_branch(&self.lhs, end_block); generator.builder.position_at_end(else_block); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 7ba6c6bd..82fd18f7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -442,7 +442,7 @@ fn expression<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { fn term<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { match input[0].0 { Token::If => if_expr(input), - //Token::Else => else_expr(input), + Token::Else => else_expr(input), Token::Loop => loop_expr(input), Token::Match => match_expr(input), Token::Handle => handle_expr(input), From 27c22aa5104796889fef683458f5e100ff6ddf9c Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Mon, 8 Apr 2024 00:48:08 -0400 Subject: [PATCH 06/10] fix --- src/parser/pretty_printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/pretty_printer.rs b/src/parser/pretty_printer.rs index 41007e82..30c6eb65 100644 --- a/src/parser/pretty_printer.rs +++ b/src/parser/pretty_printer.rs @@ -77,7 +77,7 @@ impl<'a> Display for ast::If<'a> { impl<'a> Display for ast::Else<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "( {} else {})", self.lhs, self.rhs) + write!(f, "({} else {})", self.lhs, self.rhs) } } From e0e384e2fd9aabb711c9e0a14b4ff16a76f1ea94 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 20 May 2024 15:50:54 -0500 Subject: [PATCH 07/10] Update src/hir/printer.rs --- src/hir/printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hir/printer.rs b/src/hir/printer.rs index a0d3675c..28804ba7 100644 --- a/src/hir/printer.rs +++ b/src/hir/printer.rs @@ -183,7 +183,7 @@ impl FmtAst for Else { printer.block(self.lhs.as_ref(), f)?; write!(f, " else ")?; printer.block(self.rhs.as_ref(), f)?; - write!(f, ") ") + write!(f, ")") } } From ac6599b0ecf3c07f5e528afdecbc8135a64fcc8f Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 20 May 2024 15:51:49 -0500 Subject: [PATCH 08/10] Update src/cache/mod.rs --- src/cache/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 9e05f044..0292247b 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -419,7 +419,7 @@ impl<'a> ModuleCache<'a> { global_dependency_graph: DependencyGraph::default(), diagnostics: Vec::new(), error_count: 0, - maybe_type: Some(TypeInfoId(0)), // sentinel value + maybe_type: None, file_cache, } } From 01afcd1eda4aab75abc534f8f78a3c20bf6d6898 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 20 May 2024 15:52:05 -0500 Subject: [PATCH 09/10] Update src/types/typechecker.rs --- src/types/typechecker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/typechecker.rs b/src/types/typechecker.rs index d7e321ac..f62936f7 100644 --- a/src/types/typechecker.rs +++ b/src/types/typechecker.rs @@ -1730,7 +1730,6 @@ impl<'a> Inferable<'a> for ast::If<'a> { impl<'a> Inferable<'a> for ast::Else<'a> { fn infer_impl(&mut self, cache: &mut ModuleCache<'a>) -> TypeResult { - // Create new serogate Variable x let x = next_type_variable(cache); //let x = Type::TypeVariable(id); // Construct a Maybe x Type From bdcbf85bc4d06e74d7e08da7d9c648c0155c2b40 Mon Sep 17 00:00:00 2001 From: anoojpatel <1996anoojpatel@gmail.com> Date: Sun, 26 May 2024 14:40:50 -0400 Subject: [PATCH 10/10] implement else operator desguaring into the a match ast at parser level and delete dead code --- examples/parsing/else.an | 3 +++ src/cranelift_backend/mod.rs | 27 ------------------------- src/error/mod.rs | 7 ------- src/hir/closures.rs | 5 ----- src/hir/mod.rs | 10 --------- src/hir/monomorphisation.rs | 9 --------- src/hir/printer.rs | 10 --------- src/llvm/mod.rs | 39 ------------------------------------ src/nameresolution/mod.rs | 12 ----------- src/parser/ast.rs | 15 -------------- src/parser/desugar.rs | 9 +++++++++ src/parser/mod.rs | 19 +++++------------- src/parser/pretty_printer.rs | 6 ------ src/types/typechecker.rs | 21 ------------------- src/types/typed.rs | 1 - 15 files changed, 17 insertions(+), 176 deletions(-) create mode 100644 examples/parsing/else.an diff --git a/examples/parsing/else.an b/examples/parsing/else.an new file mode 100644 index 00000000..29902e88 --- /dev/null +++ b/examples/parsing/else.an @@ -0,0 +1,3 @@ +x = Some 10 + +y = x else 0 diff --git a/src/cranelift_backend/mod.rs b/src/cranelift_backend/mod.rs index 883802ba..a8bbdb57 100644 --- a/src/cranelift_backend/mod.rs +++ b/src/cranelift_backend/mod.rs @@ -163,33 +163,6 @@ impl CodeGen for hir::If { } } -impl CodeGen for hir::Else { - fn codegen<'a>(&'a self, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> Value { - let lhs = builder.create_block(); - let then_values = context.eval_all_in_block(&self.lhs, lhs, builder); - - let end = context.new_block_with_arg(&self.result_type, builder); - - let else_none = builder.create_block(); - builder.ins().jump(else_none, &[]); - - let else_values = context.eval_all_in_block(&self.rhs, else_none, builder); - - if let Some(else_values) = else_values { - builder.ins().jump(end, &else_values); - } - - builder.seal_block(end); - builder.switch_to_block(end); - let end_values = builder.block_params(end); - let ret = context.array_to_value(end_values, &self.result_type); - - builder.seal_block(lhs); - builder.seal_block(else_none); - ret - } -} - impl CodeGen for hir::Match { fn codegen<'a>(&'a self, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> Value { context.codegen_match(self, builder) diff --git a/src/error/mod.rs b/src/error/mod.rs index 206406fd..a1b3efbe 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -104,7 +104,6 @@ pub enum TypeErrorKind { ArgumentTypeMismatch, NonBoolInCondition, IfBranchMismatch, - ElseBranchMismatch, MatchPatternTypeDiffers, MatchReturnTypeDiffers, DoesNotMatchAnnotatedType, @@ -279,12 +278,6 @@ impl Display for DiagnosticKind { "Expected 'then' and 'else' branch types to match, but found {expected} and {actual} respectively" ) }, - DiagnosticKind::TypeError(TypeErrorKind::ElseBranchMismatch, expected, actual) => { - write!( - f, - "Expected 'expr' and 'else' branch types to match, but found {expected} and {actual} respectively" - ) - }, DiagnosticKind::TypeError(TypeErrorKind::MatchPatternTypeDiffers, expected, actual) => { write!(f, "This pattern of type {actual} does not match the type {expected} that is being matched on") }, diff --git a/src/hir/closures.rs b/src/hir/closures.rs index 18447475..01a45eca 100644 --- a/src/hir/closures.rs +++ b/src/hir/closures.rs @@ -90,11 +90,6 @@ fn replace_env(expr: Ast, env: &Ast, definition_id: hir::DefinitionId, f: &hir:: if_expr.otherwise = Box::new(replace_env(*if_expr.otherwise, env, definition_id, f)); Ast::If(if_expr) }, - Ast::Else(mut else_expr) => { - else_expr.lhs = Box::new(replace_env(*else_expr.lhs, env, definition_id, f)); - else_expr.rhs = Box::new(replace_env(*else_expr.rhs, env, definition_id, f)); - Ast::Else(else_expr) - }, Ast::Sequence(mut seq) => { seq.statements = fmap(seq.statements, |stmt| replace_env(stmt, env, definition_id, f)); Ast::Sequence(seq) diff --git a/src/hir/mod.rs b/src/hir/mod.rs index 368cc1a6..eb4d4dd5 100644 --- a/src/hir/mod.rs +++ b/src/hir/mod.rs @@ -108,13 +108,6 @@ pub struct If { pub result_type: Type, } -#[derive(Debug, Clone)] -pub struct Else { - pub lhs: Box, - pub rhs: Box, - pub result_type: Type, -} - #[derive(Debug, Clone)] pub struct Match { // Unlike ast::Match this only contains the parts of the @@ -269,7 +262,6 @@ pub enum Ast { FunctionCall(FunctionCall), Definition(Definition), If(If), - Else(Else), Match(Match), Return(Return), Sequence(Sequence), @@ -296,7 +288,6 @@ macro_rules! dispatch_on_hir { $crate::hir::Ast::FunctionCall(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Definition(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::If(inner) => $function(inner $(, $($args),* )? ), - $crate::hir::Ast::Else(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Match(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Return(inner) => $function(inner $(, $($args),* )? ), $crate::hir::Ast::Sequence(inner) => $function(inner $(, $($args),* )? ), @@ -332,7 +323,6 @@ impl_display!(Lambda); impl_display!(FunctionCall); impl_display!(Definition); impl_display!(If); -impl_display!(Else); impl_display!(Match); impl_display!(Return); impl_display!(Sequence); diff --git a/src/hir/monomorphisation.rs b/src/hir/monomorphisation.rs index 7c356c18..0cebbd4a 100644 --- a/src/hir/monomorphisation.rs +++ b/src/hir/monomorphisation.rs @@ -112,7 +112,6 @@ impl<'c> Context<'c> { FunctionCall(call) => self.monomorphise_call(call), Definition(definition) => self.monomorphise_definition(definition), If(if_) => self.monomorphise_if(if_), - Else(else_) => self.monomorphise_else(else_), Match(match_) => self.monomorphise_match(match_), TypeDefinition(_) => unit_literal(), TypeAnnotation(annotation) => self.monomorphise(&annotation.lhs), @@ -1500,14 +1499,6 @@ impl<'c> Context<'c> { hir::Ast::If(hir::If { condition, then, otherwise, result_type }) } - fn monomorphise_else(&mut self, else_: &ast::Else<'c>) -> hir::Ast { - let lhs = Box::new(self.monomorphise(&else_.lhs)); - let rhs = Box::new(self.monomorphise(&else_.rhs)); - let result_type = self.convert_type(else_.typ.as_ref().unwrap()); - - hir::Ast::Else(hir::Else { lhs, rhs, result_type }) - } - fn monomorphise_return(&mut self, return_: &ast::Return<'c>) -> hir::Ast { hir::Ast::Return(hir::Return { expression: Box::new(self.monomorphise(&return_.expression)) }) } diff --git a/src/hir/printer.rs b/src/hir/printer.rs index 28804ba7..c1b12294 100644 --- a/src/hir/printer.rs +++ b/src/hir/printer.rs @@ -177,16 +177,6 @@ impl FmtAst for If { } } -impl FmtAst for Else { - fn fmt_ast(&self, printer: &mut AstPrinter, f: &mut Formatter) -> fmt::Result { - write!(f, "(")?; - printer.block(self.lhs.as_ref(), f)?; - write!(f, " else ")?; - printer.block(self.rhs.as_ref(), f)?; - write!(f, ")") - } -} - impl FmtAst for Return { fn fmt_ast(&self, printer: &mut AstPrinter, f: &mut Formatter) -> fmt::Result { write!(f, "return ")?; diff --git a/src/llvm/mod.rs b/src/llvm/mod.rs index a70cbefd..1260fd08 100644 --- a/src/llvm/mod.rs +++ b/src/llvm/mod.rs @@ -627,45 +627,6 @@ impl<'g> CodeGen<'g> for hir::If { } } -impl<'g> CodeGen<'g> for hir::Else { - fn codegen(&self, generator: &mut Generator<'g>) -> BasicValueEnum<'g> { - let current_function = generator.current_function(); - let end_block = generator.context.append_basic_block(current_function, "end_else"); - - // Setup conditional jump - let else_block = generator.context.append_basic_block(current_function, "else"); - - let (if_type, then_option) = generator.codegen_branch(&self.lhs, end_block); - - generator.builder.position_at_end(else_block); - let (_, else_option) = generator.codegen_branch(&self.rhs, end_block); - - // Create phi at the end of the if beforehand - generator.builder.position_at_end(end_block); - - // Some of the branches may have terminated early. We need to check each case to - // determine which we should add to the phi or if we should even create a phi at all. - match (then_option, else_option) { - (Some((then_value, then_branch)), Some((else_value, else_branch))) => { - let phi = generator.builder.build_phi(then_value.get_type(), "if_result").expect("Could not build phi"); - - phi.add_incoming(&[(&then_value, then_branch), (&else_value, else_branch)]); - phi.as_basic_value() - }, - (Some((then_value, _)), None) => then_value, - (None, Some((else_value, _))) => else_value, - (None, None) => { - generator.builder.build_unreachable().expect("Could not create 'unreachable' for if"); - - // Block is unreachable but we still need to return an undef value. - // If we return None the compiler would crash while compiling - // `2 + if true return "uh" else return "oh"` - Generator::undef_value(if_type) - }, - } - } -} - impl<'g> CodeGen<'g> for hir::Match { fn codegen(&self, generator: &mut Generator<'g>) -> BasicValueEnum<'g> { generator.codegen_tree(self) diff --git a/src/nameresolution/mod.rs b/src/nameresolution/mod.rs index 0b343940..af6a9519 100644 --- a/src/nameresolution/mod.rs +++ b/src/nameresolution/mod.rs @@ -1065,18 +1065,6 @@ impl<'c> Resolvable<'c> for ast::If<'c> { } } -impl<'c> Resolvable<'c> for ast::Else<'c> { - fn declare(&mut self, _resolver: &mut NameResolver, _cache: &mut ModuleCache<'c>) {} - - fn define(&mut self, resolver: &mut NameResolver, cache: &mut ModuleCache<'c>) { - self.lhs.define(resolver, cache); - - resolver.push_scope(cache); - self.rhs.define(resolver, cache); - resolver.pop_scope(cache, true, None); - } -} - impl<'c> Resolvable<'c> for ast::Match<'c> { fn declare(&mut self, _resolver: &mut NameResolver, _cache: &mut ModuleCache<'c>) {} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 1ab1884d..23b51271 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -172,14 +172,6 @@ pub struct If<'a> { pub location: Location<'a>, pub typ: Option, } -// Maybe a then a else expression -#[derive(Debug, Clone)] -pub struct Else<'a> { - pub lhs: Box>, - pub rhs: Box>, - pub location: Location<'a>, - pub typ: Option, -} /// match expression /// | pattern1 -> branch1 @@ -421,7 +413,6 @@ pub enum Ast<'a> { FunctionCall(FunctionCall<'a>), Definition(Definition<'a>), If(If<'a>), - Else(Else<'a>), Match(Match<'a>), TypeDefinition(TypeDefinition<'a>), TypeAnnotation(TypeAnnotation<'a>), @@ -597,10 +588,6 @@ impl<'a> Ast<'a> { } } - pub fn else_expr(lhs: Ast<'a>, rhs: Ast<'a>, location: Location<'a>) -> Ast<'a> { - Ast::Else(Else { lhs: Box::new(lhs), rhs: Box::new(rhs), location, typ: None }) - } - pub fn definition(pattern: Ast<'a>, expr: Ast<'a>, location: Location<'a>) -> Ast<'a> { Ast::Definition(Definition { pattern: Box::new(pattern), @@ -749,7 +736,6 @@ macro_rules! dispatch_on_expr { $crate::parser::ast::Ast::FunctionCall(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::Definition(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::If(inner) => $function(inner $(, $($args),* )? ), - $crate::parser::ast::Ast::Else(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::Match(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::TypeDefinition(inner) => $function(inner $(, $($args),* )? ), $crate::parser::ast::Ast::TypeAnnotation(inner) => $function(inner $(, $($args),* )? ), @@ -790,7 +776,6 @@ impl_locatable_for!(Lambda); impl_locatable_for!(FunctionCall); impl_locatable_for!(Definition); impl_locatable_for!(If); -impl_locatable_for!(Else); impl_locatable_for!(Match); impl_locatable_for!(TypeDefinition); impl_locatable_for!(TypeAnnotation); diff --git a/src/parser/desugar.rs b/src/parser/desugar.rs index ab8d3de8..5cbc8980 100644 --- a/src/parser/desugar.rs +++ b/src/parser/desugar.rs @@ -60,6 +60,7 @@ pub fn desugar_operators<'a>(operator: Token, lhs: Ast<'a>, rhs: Ast<'a>, locati Some(Token::ApplyRight) => prepend_argument_to_function(rhs, lhs, location), Some(Token::And) => Ast::if_expr(lhs, rhs, Some(Ast::bool_literal(false, location)), location), Some(Token::Or) => Ast::if_expr(lhs, Ast::bool_literal(true, location), Some(rhs), location), + Some(Token::Else) => create_else_match(lhs, rhs, location), Some(operator_token) => { let operator = Ast::operator(operator_token, location); Ast::function_call(operator, vec![lhs, rhs], location) @@ -72,6 +73,14 @@ pub fn desugar_operators<'a>(operator: Token, lhs: Ast<'a>, rhs: Ast<'a>, locati desugar_explicit_currying(operator_symbol, vec![lhs, rhs], call_operator_function, location) } +fn create_else_match<'a>(lhs: Ast<'a>, rhs: Ast<'a>, location: Location<'a>) -> Ast<'a> { + let x = Ast::variable(vec![], "x".to_owned(), location); + let some = Ast::type_constructor(vec!["prelude".to_owned()], "Some".to_owned(), location); + let some_x = Ast::function_call(some, vec![x.clone()], location); + let none = Ast::type_constructor(vec!["prelude".to_owned()], "None".to_owned(), location); + Ast::match_expr(lhs, vec![(some_x, x), (none, rhs)], location) +} + fn prepend_argument_to_function<'a>(f: Ast<'a>, arg: Ast<'a>, location: Location<'a>) -> Ast<'a> { match f { Ast::FunctionCall(mut call) => { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 82fd18f7..1431cd0f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -380,8 +380,9 @@ fn precedence(token: &Token) -> Option<(i8, bool)> { Token::In => Some((8, false)), Token::Append => Some((9, false)), Token::Range => Some((10, false)), - Token::Add | Token::Subtract => Some((11, false)), - Token::Multiply | Token::Divide | Token::Modulus => Some((12, false)), + Token::Else => Some((11, false)), + Token::Add | Token::Subtract => Some((12, false)), + Token::Multiply | Token::Divide | Token::Modulus => Some((13, false)), Token::Index => Some((14, false)), Token::As => Some((15, false)), _ => None, @@ -442,7 +443,6 @@ fn expression<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { fn term<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> { match input[0].0 { Token::If => if_expr(input), - Token::Else => else_expr(input), Token::Loop => loop_expr(input), Token::Match => match_expr(input), Token::Handle => handle_expr(input), @@ -506,7 +506,7 @@ parser!(if_expr loc = _ !<- maybe_newline; _ !<- expect(Token::Then); then !<- block_or_statement; - otherwise !<- maybe(without_else_expr); + otherwise !<- maybe(else_expr); Ast::if_expr(condition, then, otherwise, loc) ); @@ -633,20 +633,11 @@ parser!(match_branch _loc -> 'b (Ast<'b>, Ast<'b>) = (pattern, branch) ); -parser!(without_else_expr _loc = - _ <- maybe_newline; - expr <- block_or_statement; - _ <- expect(Token::Else); - otherwise !<- block_or_statement; - otherwise -); - parser!(else_expr _loc = _ <- maybe_newline; - expr <- block_or_statement; _ <- expect(Token::Else); otherwise !<- block_or_statement; - Ast::else_expr(expr, otherwise, _loc) + otherwise ); /// A function_argument is a unary expr or a member_access of diff --git a/src/parser/pretty_printer.rs b/src/parser/pretty_printer.rs index 30c6eb65..097f7c54 100644 --- a/src/parser/pretty_printer.rs +++ b/src/parser/pretty_printer.rs @@ -75,12 +75,6 @@ impl<'a> Display for ast::If<'a> { } } -impl<'a> Display for ast::Else<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "({} else {})", self.lhs, self.rhs) - } -} - impl<'a> Display for ast::Match<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "(match {}", self.expression)?; diff --git a/src/types/typechecker.rs b/src/types/typechecker.rs index f62936f7..04e8fa7c 100644 --- a/src/types/typechecker.rs +++ b/src/types/typechecker.rs @@ -1728,27 +1728,6 @@ impl<'a> Inferable<'a> for ast::If<'a> { } } -impl<'a> Inferable<'a> for ast::Else<'a> { - fn infer_impl(&mut self, cache: &mut ModuleCache<'a>) -> TypeResult { - let x = next_type_variable(cache); - //let x = Type::TypeVariable(id); - // Construct a Maybe x Type - //let maybe_typeinfo_id = cache.type_infos.get(cache.maybe_type.0); - let maybe_type = UserDefined(cache.maybe_type.expect("Maybe type should be befined from importing prelude")); - let maybe_x = TypeApplication(Box::new(maybe_type), vec![x.clone()]); - // Unify Maybe x with expr and raise if Type is mismatched - let mut lhs = infer(self.lhs.as_mut(), cache); - unify(&maybe_x, &mut lhs.typ, self.lhs.locate(), cache, TE::ElseBranchMismatch); - - // Unify x with a and raise if Type is mismatched - let mut rhs = infer(self.rhs.as_mut(), cache); - lhs.combine(&mut rhs, cache); - - unify(&x, &rhs.typ, self.location, cache, TE::ArgumentTypeMismatch); - lhs.with_type(rhs.typ) - } -} - impl<'a> Inferable<'a> for ast::Match<'a> { fn infer_impl(&mut self, cache: &mut ModuleCache<'a>) -> TypeResult { let error_count = cache.error_count(); diff --git a/src/types/typed.rs b/src/types/typed.rs index d9c9a65b..f4cd1b8b 100644 --- a/src/types/typed.rs +++ b/src/types/typed.rs @@ -39,7 +39,6 @@ impl_typed_for!(Lambda); impl_typed_for!(FunctionCall); impl_typed_for!(Definition); impl_typed_for!(If); -impl_typed_for!(Else); impl_typed_for!(Match); impl_typed_for!(TypeDefinition); impl_typed_for!(TypeAnnotation);