conlang: PATTERN MATCHING AND DESTRUCTURED BINDINGS WOOOOO

- Integrate the Match and Pattern nodes into the AST
  - TODO: `let x: T` is ambiguous with `let x: {}`. Currently the latter takes precedence in the parser.

- Implement pattern matching through unification in the interpreter.
  - It's not fast, but it works!

- Refactor destructuring assignments to use the new pattern functionality
This commit is contained in:
2025-01-29 04:15:33 -06:00
parent 6e94b702c9
commit 6ee9bbd72e
14 changed files with 285 additions and 119 deletions

View File

@@ -351,6 +351,8 @@ pub enum ExprKind {
Quote(Quote),
/// A local bind instruction, `let` [`Sym`] `=` [`Expr`]
Let(Let),
/// A [Match] expression, `match` [Expr] `{` ([MatchArm] `,`)* [MatchArm]? `}`
Match(Match),
/// An [Assign]ment expression: [`Expr`] (`=` [`Expr`])\+
Assign(Assign),
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
@@ -408,7 +410,7 @@ pub struct Quote {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Let {
pub mutable: Mutability,
pub name: Sym,
pub name: Pattern,
pub ty: Option<Box<Ty>>,
pub init: Option<Box<Expr>>,
}

View File

@@ -417,6 +417,7 @@ mod display {
ExprKind::Empty => "()".fmt(f),
ExprKind::Quote(v) => v.fmt(f),
ExprKind::Let(v) => v.fmt(f),
ExprKind::Match(v) => v.fmt(f),
ExprKind::Assign(v) => v.fmt(f),
ExprKind::Modify(v) => v.fmt(f),
ExprKind::Binary(v) => v.fmt(f),
@@ -814,6 +815,7 @@ mod convert {
impl From for ExprKind {
Let => ExprKind::Let,
Quote => ExprKind::Quote,
Match => ExprKind::Match,
Assign => ExprKind::Assign,
Modify => ExprKind::Modify,
Binary => ExprKind::Binary,

View File

@@ -240,7 +240,7 @@ pub trait Fold {
let Let { mutable, name, ty, init } = l;
Let {
mutable: self.fold_mutability(mutable),
name: self.fold_sym(name),
name: self.fold_pattern(name),
ty: ty.map(|t| Box::new(self.fold_ty(*t))),
init: init.map(|e| Box::new(self.fold_expr(*e))),
}
@@ -572,6 +572,7 @@ pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> Ex
ExprKind::Empty => ExprKind::Empty,
ExprKind::Quote(q) => ExprKind::Quote(q), // quoted expressions are left unmodified
ExprKind::Let(l) => ExprKind::Let(folder.fold_let(l)),
ExprKind::Match(m) => ExprKind::Match(folder.fold_match(m)),
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
ExprKind::Modify(m) => ExprKind::Modify(folder.fold_modify(m)),
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),

View File

@@ -203,7 +203,7 @@ pub trait Visit<'a>: Sized {
fn visit_let(&mut self, l: &'a Let) {
let Let { mutable, name, ty, init } = l;
self.visit_mutability(mutable);
self.visit_sym(name);
self.visit_pattern(name);
if let Some(ty) = ty {
self.visit_ty(ty);
}
@@ -492,6 +492,7 @@ pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
ExprKind::Empty => {}
ExprKind::Quote(_q) => {} // Quoted expressions are left unvisited
ExprKind::Let(l) => visitor.visit_let(l),
ExprKind::Match(m) => visitor.visit_match(m),
ExprKind::Assign(a) => visitor.visit_assign(a),
ExprKind::Modify(m) => visitor.visit_modify(m),
ExprKind::Binary(b) => visitor.visit_binary(b),