Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Add Else Operator #198

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub struct ModuleCache<'a> {

pub file_cache: FileCache,

pub maybe_type: TypeInfoId,
pub maybe_type: Option<TypeInfoId>,
}

pub type FileCache = HashMap<PathBuf, String>;
Expand Down Expand Up @@ -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
jfecher marked this conversation as resolved.
Show resolved Hide resolved
file_cache,
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/cranelift_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
jfecher marked this conversation as resolved.
Show resolved Hide resolved

if let Some(else_values) = else_values {
builder.ins().jump(end, &else_values);
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions src/hir/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
4 changes: 2 additions & 2 deletions src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ pub struct If {

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

Expand Down
6 changes: 3 additions & 3 deletions src/hir/monomorphisation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions src/hir/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, ") ")
jfecher marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,17 +630,15 @@ 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);
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);
Expand Down
8 changes: 3 additions & 5 deletions src/nameresolution/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,11 @@ pub fn import_prelude(resolver: &mut NameResolver, cache: &mut ModuleCache<'_>)
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
// 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);
Expand Down
4 changes: 2 additions & 2 deletions src/nameresolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ pub struct If<'a> {
// Maybe a then a else expression
#[derive(Debug, Clone)]
pub struct Else<'a> {
pub expr: Box<Ast<'a>>,
pub otherwise: Box<Ast<'a>>,
pub lhs: Box<Ast<'a>>,
pub rhs: Box<Ast<'a>>,
pub location: Location<'a>,
pub typ: Option<types::Type>,
}
Expand Down Expand Up @@ -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> {
Expand Down
10 changes: 9 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);

Expand Down Expand Up @@ -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
);
jfecher marked this conversation as resolved.
Show resolved Hide resolved

parser!(else_expr _loc =
_ <- maybe_newline;
expr <- block_or_statement;
Expand Down
2 changes: 1 addition & 1 deletion src/parser/pretty_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/types/typechecker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Loading