Add support for destructuring def

This commit introduces the `DefDestructure` bound kind and modifies the
binder, analyzer, type checker, and VM to support destructuring in `def`
statements. This allows for pattern matching on the right-hand side of a
`def` to bind multiple variables.

The parser has been updated to accept patterns in `def` statements. The
binder now handles `UntypedKind::Def` with a `target` pattern, rather
than a simple `name`. This enables destructuring.

The `Gemini.md` documentation has been updated to include a new rule for
incremental development.
This commit is contained in:
Michael Schimmel
2026-02-24 08:40:45 +01:00
parent eeb6621280
commit 252b725677
13 changed files with 290 additions and 117 deletions
+41 -41
View File
@@ -185,17 +185,12 @@ impl<'a> Parser<'a> {
}
fn parse_def(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
let name_node = self.parse_expression()?;
let name = match name_node.kind {
UntypedKind::Identifier(sym) => sym,
_ => return Err("Expected identifier for def name".to_string()),
};
let target = Box::new(self.parse_pattern()?);
let value = Box::new(self.parse_expression()?);
Ok(Node {
identity,
kind: UntypedKind::Def { name, value },
kind: UntypedKind::Def { target, value },
ty: (),
})
}
@@ -264,44 +259,49 @@ impl<'a> Parser<'a> {
self.peek()
));
}
let token = self.advance()?;
let identity = Rc::new(NodeIdentity {
location: token.location,
});
self.parse_pattern()
}
let mut elements = Vec::new();
while *self.peek() != TokenKind::RightBracket {
let next_peek = self.peek();
match next_peek {
TokenKind::Identifier(name) => {
let name = name.clone();
let token = self.advance()?;
let p_identity = Rc::new(NodeIdentity {
fn parse_pattern(&mut self) -> Result<Node<UntypedKind>, String> {
let next = self.peek();
match next {
TokenKind::Identifier(_) => {
let token = self.advance()?;
let sym: Symbol = match token.kind {
TokenKind::Identifier(s) => s.into(),
_ => unreachable!(),
};
Ok(Node {
identity: Rc::new(NodeIdentity {
location: token.location,
});
elements.push(Node {
identity: p_identity,
kind: UntypedKind::Parameter(name.into()),
ty: (),
});
}
TokenKind::LeftBracket => {
elements.push(self.parse_param_vector()?);
}
_ => {
return Err(format!(
"Expected identifier or nested parameter vector, found {:?}",
next_peek
));
}
}),
kind: UntypedKind::Parameter(sym),
ty: (),
})
}
TokenKind::LeftBracket => {
let token = self.advance()?;
let identity = Rc::new(NodeIdentity {
location: token.location,
});
let mut elements = Vec::new();
while *self.peek() != TokenKind::RightBracket {
elements.push(self.parse_pattern()?);
}
self.expect(TokenKind::RightBracket)?;
Ok(Node {
identity,
kind: UntypedKind::Tuple { elements },
ty: (),
})
}
_ => Err(format!(
"Expected identifier or pattern vector [...] for definition, found {:?}",
next
)),
}
self.expect(TokenKind::RightBracket)?;
Ok(Node {
identity,
kind: UntypedKind::Tuple { elements },
ty: (),
})
}
fn parse_call(