Skip to content

Commit

Permalink
Merge pull request #22 from ditto-lang/add-match-expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Mackie committed Apr 19, 2022
2 parents 2bcc9bd + 499cae9 commit c06983b
Show file tree
Hide file tree
Showing 36 changed files with 1,173 additions and 44 deletions.
51 changes: 51 additions & 0 deletions crates/ditto-ast/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ pub enum Expression {
/// The expression to evaluate otherwise.
false_clause: Box<Self>,
},
/// A pattern match.
///
/// ```ditto
/// match some_expr with
/// | Pattern -> another_expr
/// ```
Match {
/// The source span for this expression.
span: Span,

/// The type of the expressions in the `arms`.
match_type: Type,

/// Expression to be matched.
expression: Box<Self>,

/// Patterns to be matched against and their corresponding expressions.
arms: NonEmpty<(Pattern, Self)>,
},
/// A value constructor local to the current module, e.g. `Just` and `Ok`.
LocalConstructor {
/// The source span for this expression.
Expand Down Expand Up @@ -193,6 +212,7 @@ impl Expression {
}
}
Self::If { output_type, .. } => output_type.clone(),
Self::Match { match_type, .. } => match_type.clone(),
Self::LocalConstructor {
constructor_type, ..
} => constructor_type.clone(),
Expand Down Expand Up @@ -220,6 +240,7 @@ impl Expression {
Self::Function { span, .. } => *span,
Self::Call { span, .. } => *span,
Self::If { span, .. } => *span,
Self::Match { span, .. } => *span,
Self::LocalConstructor { span, .. } => *span,
Self::ImportedConstructor { span, .. } => *span,
Self::LocalVariable { span, .. } => *span,
Expand Down Expand Up @@ -296,3 +317,33 @@ impl FunctionBinder {
}
}
}

/// A pattern to be matched.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Pattern {
/// A local constructor pattern.
LocalConstructor {
/// The source span for this pattern.
span: Span,
/// `Just`
constructor: ProperName,
/// Pattern arguments to the constructor.
arguments: Vec<Self>,
},
/// An importedf constructor pattern.
ImportedConstructor {
/// The source span for this pattern.
span: Span,
/// `Maybe.Just`
constructor: FullyQualifiedProperName,
/// Pattern arguments to the constructor.
arguments: Vec<Self>,
},
/// A variable binding pattern.
Variable {
/// The source span for this pattern.
span: Span,
/// Name to bind.
name: Name,
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Test exports (..);

type Foo = Foo;
type Bar = Bar;

nah =
match Foo with
| Bar -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

× types don't unify
╭─[golden:5:1]
5 │
6 │ nah =
7 │ match Foo with
8 │ | Bar -> unit;
· ─┬─
· ╰── here
╰────
help: expected Foo
got Bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module Test exports (..);

type Maybe(a) = Just(a) | Nothing;
type Foo = Foo;
type Bar = Bar;

nah = (maybe_foo : Maybe(Foo)) ->
match maybe_foo with
| Just(Bar) -> unit
| Nothing -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

× types don't unify
╭─[golden:6:1]
6 │
7 │ nah = (maybe_foo : Maybe(Foo)) ->
8 │ match maybe_foo with
9 │ | Just(Bar) -> unit
· ─┬─
· ╰── here
10 │ | Nothing -> unit;
╰────
help: expected Foo
got Bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Test exports (..);

type Maybe(a) = Just(a) | Nothing;

nah = (maybe_foo : Maybe(Int)) ->
match maybe_foo with
| Just(a, b) -> unit
| Nothing -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

× wrong number of arguments
╭─[golden:4:1]
4 │
5 │ nah = (maybe_foo : Maybe(Int)) ->
6 │ match maybe_foo with
7 │ | Just(a, b) -> unit
· ─────┬────
· ╰── this expects 1 argument
8 │ | Nothing -> unit;
╰────
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Test exports (..);

type Maybe(a) = Just(a) | Nothing;

nah = (maybe_foo : Maybe(Int)) ->
match maybe_foo with
| Just -> unit
| Nothing -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

× wrong number of arguments
╭─[golden:4:1]
4 │
5 │ nah = (maybe_foo : Maybe(Int)) ->
6 │ match maybe_foo with
7 │ | Just -> unit
· ──┬─
· ╰── this expects 1 argument
8 │ | Nothing -> unit;
╰────
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Test exports (..);

type Maybe(a) = Just(a) | Nothing;

nah = (maybe_foo : Maybe(Int)) ->
match maybe_foo with
| Just(n) -> unit
| Nothing(a) -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

× wrong number of arguments
╭─[golden:5:1]
5 │ nah = (maybe_foo : Maybe(Int)) ->
6 │ match maybe_foo with
7 │ | Just(n) -> unit
8 │ | Nothing(a) -> unit;
· ─────┬────
· ╰── this expects no arguments
╰────
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Test exports (..);

type Maybe(a) = Just(a) | Nothing;

nah = (maybe_foo : Maybe(Int)): Int ->
match maybe_foo with
| Just(n) -> unit
| Nothing -> unit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

× types don't unify
╭─[golden:4:1]
4 │
5 │ nah = (maybe_foo : Maybe(Int)): Int ->
6 │ match maybe_foo with
7 │ | Just(n) -> unit
· ──┬─
· ╰── here
8 │ | Nothing -> unit;
╰────
help: expected Int
got Unit
12 changes: 12 additions & 0 deletions crates/ditto-checker/src/module/value_declarations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ fn toposort_value_declarations(
get_connected_nodes_rec(true_clause, nodes, accum);
get_connected_nodes_rec(false_clause, nodes, accum);
}
Expression::Match {
expression,
head_arm,
tail_arms,
..
} => {
get_connected_nodes_rec(expression, nodes, accum);
get_connected_nodes_rec(&head_arm.expression, nodes, accum);
for tail_arm in tail_arms.iter() {
get_connected_nodes_rec(&tail_arm.expression, nodes, accum);
}
}
Expression::Array(elements) => {
if let Some(ref elements) = elements.value {
elements.iter().for_each(|element| {
Expand Down
26 changes: 23 additions & 3 deletions crates/ditto-checker/src/typechecker/env.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use super::{common::type_variables, Scheme};
use crate::supply::Supply;
use ditto_ast::{
Expression, FullyQualifiedName, FullyQualifiedProperName, Name, ProperName, QualifiedName,
QualifiedProperName, Span, Type,
Expression, FullyQualifiedName, FullyQualifiedProperName, Name, Pattern, ProperName,
QualifiedName, QualifiedProperName, Span, Type,
};
use std::{
collections::{HashMap, HashSet},
default::Default,
};

#[derive(Default)]
#[derive(Default, Clone)]
pub struct Env {
pub constructors: EnvConstructors,
pub values: EnvValues,
Expand Down Expand Up @@ -157,6 +157,26 @@ impl EnvConstructor {
}
}

// REVIEW should this be `into_pattern`?
pub fn to_pattern(&self, span: Span, arguments: Vec<Pattern>) -> Pattern {
match self {
Self::ModuleConstructor { constructor, .. } => Pattern::LocalConstructor {
span,
constructor: constructor.clone(),
arguments,
},
Self::ImportedConstructor { constructor, .. } => Pattern::ImportedConstructor {
span,
constructor: constructor.clone(),
arguments,
},
}
}

pub fn get_type(&self, supply: &mut Supply) -> Type {
self.get_scheme().instantiate(supply)
}

fn get_scheme(&self) -> Scheme {
match self {
Self::ModuleConstructor {
Expand Down
Loading

0 comments on commit c06983b

Please sign in to comment.