Skip to content

Commit

Permalink
implement else operator desguaring into the a match ast at parser lev…
Browse files Browse the repository at this point in the history
…el and delete dead code
  • Loading branch information
anoojpatel committed May 26, 2024
1 parent 01afcd1 commit bdcbf85
Show file tree
Hide file tree
Showing 15 changed files with 17 additions and 176 deletions.
3 changes: 3 additions & 0 deletions examples/parsing/else.an
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
x = Some 10

y = x else 0
27 changes: 0 additions & 27 deletions src/cranelift_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 0 additions & 7 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ pub enum TypeErrorKind {
ArgumentTypeMismatch,
NonBoolInCondition,
IfBranchMismatch,
ElseBranchMismatch,
MatchPatternTypeDiffers,
MatchReturnTypeDiffers,
DoesNotMatchAnnotatedType,
Expand Down Expand Up @@ -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")
},
Expand Down
5 changes: 0 additions & 5 deletions src/hir/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 0 additions & 10 deletions src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,6 @@ pub struct If {
pub result_type: Type,
}

#[derive(Debug, Clone)]
pub struct Else {
pub lhs: Box<Ast>,
pub rhs: Box<Ast>,
pub result_type: Type,
}

#[derive(Debug, Clone)]
pub struct Match {
// Unlike ast::Match this only contains the parts of the
Expand Down Expand Up @@ -269,7 +262,6 @@ pub enum Ast {
FunctionCall(FunctionCall),
Definition(Definition),
If(If),
Else(Else),
Match(Match),
Return(Return),
Sequence(Sequence),
Expand All @@ -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),* )? ),
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 0 additions & 9 deletions src/hir/monomorphisation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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)) })
}
Expand Down
10 changes: 0 additions & 10 deletions src/hir/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")?;
Expand Down
39 changes: 0 additions & 39 deletions src/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 0 additions & 12 deletions src/nameresolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>) {}

Expand Down
15 changes: 0 additions & 15 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,6 @@ pub struct If<'a> {
pub location: Location<'a>,
pub typ: Option<types::Type>,
}
// Maybe a then a else expression
#[derive(Debug, Clone)]
pub struct Else<'a> {
pub lhs: Box<Ast<'a>>,
pub rhs: Box<Ast<'a>>,
pub location: Location<'a>,
pub typ: Option<types::Type>,
}

/// match expression
/// | pattern1 -> branch1
Expand Down Expand Up @@ -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>),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),* )? ),
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/parser/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) => {
Expand Down
19 changes: 5 additions & 14 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)
);

Expand Down Expand Up @@ -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
Expand Down
6 changes: 0 additions & 6 deletions src/parser/pretty_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
21 changes: 0 additions & 21 deletions src/types/typechecker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 0 additions & 1 deletion src/types/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit bdcbf85

Please sign in to comment.