From 6ee9bbd72ebfcfddd8e73fd528915a8091522e8b Mon Sep 17 00:00:00 2001 From: John Date: Wed, 29 Jan 2025 04:15:33 -0600 Subject: [PATCH] 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 --- compiler/cl-ast/src/ast.rs | 4 +- compiler/cl-ast/src/ast_impl.rs | 2 + compiler/cl-ast/src/ast_visitor/fold.rs | 3 +- compiler/cl-ast/src/ast_visitor/visit.rs | 3 +- compiler/cl-interpret/src/error.rs | 19 +- .../src/function/collect_upvars.rs | 33 ++- compiler/cl-interpret/src/interpret.rs | 264 ++++++++++++------ compiler/cl-parser/src/error.rs | 8 + compiler/cl-parser/src/parser.rs | 34 ++- compiler/cl-parser/src/parser/prec.rs | 19 +- compiler/cl-repl/examples/yaml.rs | 1 + compiler/cl-token/src/token_type.rs | 3 + compiler/cl-typeck/src/source.rs | 2 +- compiler/cl-typeck/src/stage/populate.rs | 9 +- 14 files changed, 285 insertions(+), 119 deletions(-) diff --git a/compiler/cl-ast/src/ast.rs b/compiler/cl-ast/src/ast.rs index f96af4d..e159831 100644 --- a/compiler/cl-ast/src/ast.rs +++ b/compiler/cl-ast/src/ast.rs @@ -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>, pub init: Option>, } diff --git a/compiler/cl-ast/src/ast_impl.rs b/compiler/cl-ast/src/ast_impl.rs index bbb0444..7ea808a 100644 --- a/compiler/cl-ast/src/ast_impl.rs +++ b/compiler/cl-ast/src/ast_impl.rs @@ -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, diff --git a/compiler/cl-ast/src/ast_visitor/fold.rs b/compiler/cl-ast/src/ast_visitor/fold.rs index 9b31d23..4d28bbd 100644 --- a/compiler/cl-ast/src/ast_visitor/fold.rs +++ b/compiler/cl-ast/src/ast_visitor/fold.rs @@ -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(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)), diff --git a/compiler/cl-ast/src/ast_visitor/visit.rs b/compiler/cl-ast/src/ast_visitor/visit.rs index acbafbd..cc71530 100644 --- a/compiler/cl-ast/src/ast_visitor/visit.rs +++ b/compiler/cl-ast/src/ast_visitor/visit.rs @@ -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), diff --git a/compiler/cl-interpret/src/error.rs b/compiler/cl-interpret/src/error.rs index de3f515..a03a383 100644 --- a/compiler/cl-interpret/src/error.rs +++ b/compiler/cl-interpret/src/error.rs @@ -1,6 +1,6 @@ //! The [Error] type represents any error thrown by the [Environment](super::Environment) -use cl_ast::Sym; +use cl_ast::{Pattern, Sym}; use super::convalue::ConValue; @@ -39,11 +39,11 @@ pub enum Error { /// A value was called, but is not callable NotCallable(ConValue), /// A function was called with the wrong number of arguments - ArgNumber { - want: usize, - got: usize, - }, - Outlined(Sym), + ArgNumber { want: usize, got: usize }, + /// A pattern failed to match + PatFailed(Pattern), + /// Fell through a non-exhaustive match + MatchNonexhaustive, } impl std::error::Error for Error {} @@ -83,8 +83,11 @@ impl std::fmt::Display for Error { if *want == 1 { "" } else { "s" } ) } - Error::Outlined(name) => { - write!(f, "Module {name} specified, but not imported.") + Error::PatFailed(pattern) => { + write!(f, "Failed to match pattern {pattern}") + } + Error::MatchNonexhaustive => { + write!(f, "Fell through a non-exhaustive match expression!") } } } diff --git a/compiler/cl-interpret/src/function/collect_upvars.rs b/compiler/cl-interpret/src/function/collect_upvars.rs index 236a5fc..f2a603f 100644 --- a/compiler/cl-interpret/src/function/collect_upvars.rs +++ b/compiler/cl-interpret/src/function/collect_upvars.rs @@ -1,6 +1,6 @@ //! Collects the "Upvars" of a function at the point of its creation, allowing variable capture use crate::{convalue::ConValue, env::Environment}; -use cl_ast::{ast_visitor::visit::*, Function, Let, Param, Path, PathPart, Sym}; +use cl_ast::{ast_visitor::visit::*, Function, Let, Param, Path, PathPart, Pattern, Sym}; use std::collections::{HashMap, HashSet}; pub fn collect_upvars(f: &Function, env: &Environment) -> super::Upvars { @@ -61,7 +61,7 @@ impl<'a> Visit<'a> for CollectUpvars<'_> { self.visit_expr(init) } // a bound name can never be an upvar - self.bind_name(name); + self.visit_pattern(name); } fn visit_function(&mut self, f: &'a cl_ast::Function) { @@ -102,4 +102,33 @@ impl<'a> Visit<'a> for CollectUpvars<'_> { self.add_upvar(name); // fielder without init grabs from env } } + + fn visit_pattern(&mut self, p: &'a cl_ast::Pattern) { + match p { + Pattern::Path(path) => { + if let [PathPart::Ident(name)] = path.parts.as_slice() { + self.bind_name(name) + } + } + Pattern::Literal(literal) => self.visit_literal(literal), + Pattern::Ref(mutability, pattern) => { + self.visit_mutability(mutability); + self.visit_pattern(pattern); + } + Pattern::Tuple(patterns) => { + patterns.iter().for_each(|p| self.visit_pattern(p)); + } + Pattern::Array(patterns) => { + patterns.iter().for_each(|p| self.visit_pattern(p)); + } + Pattern::Struct(path, items) => { + self.visit_path(path); + items.iter().for_each(|(_name, bind)| { + bind.as_ref().inspect(|bind| { + self.visit_pattern(bind); + }); + }); + } + } + } } diff --git a/compiler/cl-interpret/src/interpret.rs b/compiler/cl-interpret/src/interpret.rs index a24146e..275ebf5 100644 --- a/compiler/cl-interpret/src/interpret.rs +++ b/compiler/cl-interpret/src/interpret.rs @@ -75,11 +75,11 @@ impl Interpret for Module { let out = match kind { ModuleKind::Inline(file) => file.interpret(env), ModuleKind::Outline => { - eprintln!("{}", Error::Outlined(*name)); + eprintln!("Module {name} specified, but not imported."); Ok(ConValue::Empty) } }; - + let frame = env .pop_frame() .expect("Environment frames must be balanced"); @@ -128,14 +128,7 @@ impl Interpret for Stmt { }) } } -impl Interpret for Let { - fn interpret(&self, env: &mut Environment) -> IResult { - let Let { mutable: _, name, ty: _, init } = self; - let init = init.as_ref().map(|i| i.interpret(env)).transpose()?; - env.insert(*name, init); - Ok(ConValue::Empty) - } -} + impl Interpret for Expr { #[inline] fn interpret(&self, env: &mut Environment) -> IResult { @@ -143,12 +136,14 @@ impl Interpret for Expr { kind.interpret(env) } } + impl Interpret for ExprKind { fn interpret(&self, env: &mut Environment) -> IResult { match self { ExprKind::Empty => Ok(ConValue::Empty), ExprKind::Quote(q) => q.interpret(env), ExprKind::Let(v) => v.interpret(env), + ExprKind::Match(v) => v.interpret(env), ExprKind::Assign(v) => v.interpret(env), ExprKind::Modify(v) => v.interpret(env), ExprKind::Binary(v) => v.interpret(env), @@ -182,38 +177,190 @@ impl Interpret for Quote { } } +impl Interpret for Let { + fn interpret(&self, env: &mut Environment) -> IResult { + let Let { mutable: _, name, ty: _, init } = self; + match init.as_ref().map(|i| i.interpret(env)).transpose()? { + Some(value) => { + for (path, value) in assignment::pattern_substitution(name, value)? { + match path.parts.as_slice() { + [PathPart::Ident(name)] => env.insert(*name, Some(value)), + _ => eprintln!("Bad assignment: {path} = {value}"), + } + } + } + None => { + for path in assignment::pattern_variables(name) { + match path.parts.as_slice() { + [PathPart::Ident(name)] => env.insert(*name, None), + _ => eprintln!("Bad assignment: {path}"), + } + } + } + } + Ok(ConValue::Empty) + } +} + +impl Interpret for Match { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { scrutinee, arms } = self; + let scrutinee = scrutinee.interpret(env)?; + 'arm: for MatchArm(pat, expr) in arms { + if let Ok(substitution) = assignment::pattern_substitution(pat, scrutinee.clone()) { + let mut env = env.frame("match"); + for (path, value) in substitution { + let [PathPart::Ident(name)] = path.parts.as_slice() else { + continue 'arm; + }; + env.insert(*name, Some(value)); + } + return expr.interpret(&mut env); + } + } + Err(Error::MatchNonexhaustive) + } +} + mod assignment { /// Pattern matching engine for assignment use super::*; use std::collections::HashMap; type Namespace = HashMap>; - pub(super) fn assign(env: &mut Environment, pat: &ExprKind, value: ConValue) -> IResult<()> { - match (pat, value) { - (ExprKind::Empty, ConValue::Empty) => Ok(()), - (ExprKind::Path(path), value) => assign_path(env, path, value), - (ExprKind::Group(Group { expr }), value) => assign(env, expr, value), - (ExprKind::Tuple(tuple), value) => assign_destructure_tuple(env, tuple, value), - (ExprKind::Array(array), value) => assign_destructure_array(env, array, value), - (ExprKind::Index(index), value) => assign_index(env, index, value), - (ExprKind::Member(member), value) => assign_member(env, member, value), - (ExprKind::Structor(structor), value) => { - assign_destructure_struct(env, structor, value) + /// Gets the path variables in the given Pattern + pub fn pattern_variables(pat: &Pattern) -> Vec<&Path> { + fn patvars<'p>(set: &mut Vec<&'p Path>, pat: &'p Pattern) { + match pat { + Pattern::Path(path) if path.is_sinkhole() => {} + Pattern::Path(path) => set.push(path), + Pattern::Literal(_) => {} + Pattern::Ref(_, pattern) => patvars(set, pattern), + Pattern::Tuple(patterns) | Pattern::Array(patterns) => { + patterns.iter().for_each(|pat| patvars(set, pat)) + } + Pattern::Struct(_path, items) => { + items.iter().for_each(|(name, pat)| match pat { + Some(pat) => patvars(set, pat), + None => set.push(name), + }); + } } - _ => { - eprintln!("{pat} is not a valid pattern expression"); - Err(Error::NotAssignable) + } + let mut set = Vec::new(); + patvars(&mut set, pat); + set + } + + /// Appends a substitution to the provided table + pub fn append_sub<'pat>( + env: &mut HashMap<&'pat Path, ConValue>, + pat: &'pat Pattern, + value: ConValue, + ) -> IResult<()> { + match pat { + Pattern::Path(path) if path.is_sinkhole() => Ok(()), + Pattern::Path(path) => { + env.insert(path, value); + Ok(()) + } + + Pattern::Literal(literal) => match (literal, value) { + (Literal::Bool(a), ConValue::Bool(b)) => *a == b, + (Literal::Char(a), ConValue::Char(b)) => *a == b, + (Literal::Int(a), ConValue::Int(b)) => *a as isize == b, + (Literal::Float(a), ConValue::Float(b)) => f64::from_bits(*a) == b, + (Literal::String(a), ConValue::String(b)) => *a == *b, + _ => false, + } + .then_some(()) + .ok_or(Error::NotAssignable), + + Pattern::Ref(_, pattern) => match value { + ConValue::Ref(value) => append_sub(env, pattern, Rc::unwrap_or_clone(value)), + _ => Err(Error::NotAssignable), + }, + + Pattern::Tuple(patterns) => match value { + ConValue::Tuple(values) => { + if patterns.len() != values.len() { + return Err(Error::OobIndex(patterns.len(), values.len())); + }; + for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) { + append_sub(env, pat, value)?; + } + Ok(()) + } + _ => Err(Error::NotAssignable), + }, + + Pattern::Array(patterns) => match value { + ConValue::Array(values) => { + if patterns.len() != values.len() { + return Err(Error::OobIndex(patterns.len(), values.len())); + }; + for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) { + append_sub(env, pat, value)?; + } + Ok(()) + } + _ => Err(Error::NotAssignable), + }, + + Pattern::Struct(_path, patterns) => { + let ConValue::Struct(parts) = value else { + return Err(Error::TypeError); + }; + let (_, mut values) = *parts; + if values.len() != patterns.len() { + return Err(Error::TypeError); + } + for (name, pat) in patterns { + let [.., PathPart::Ident(index)] = name.parts.as_slice() else { + Err(Error::TypeError)? + }; + let value = values.remove(index).ok_or(Error::TypeError)?; + match pat { + Some(pat) => append_sub(env, pat, value)?, + None => { + env.insert(name, value); + } + } + } + + Ok(()) } } } - fn assign_member(env: &mut Environment, member: &Member, value: ConValue) -> IResult<()> { - *addrof_member(env, member)? = value; + /// Constructs a substitution from a pattern and a value + pub fn pattern_substitution( + pat: &Pattern, + value: ConValue, + ) -> IResult> { + let mut substitution = HashMap::new(); + append_sub(&mut substitution, pat, value)?; + Ok(substitution) + } + + pub(super) fn pat_assign(env: &mut Environment, pat: &Pattern, value: ConValue) -> IResult<()> { + let mut substitution = HashMap::new(); + append_sub(&mut substitution, pat, value).map_err(|_| Error::PatFailed(pat.clone()))?; + for (path, value) in substitution { + assign_path(env, path, value)?; + } Ok(()) } - fn assign_index(env: &mut Environment, index: &Index, value: ConValue) -> IResult<()> { - *addrof_index(env, index)? = value; + pub(super) fn assign(env: &mut Environment, pat: &ExprKind, value: ConValue) -> IResult<()> { + if let Ok(pat) = Pattern::try_from(pat.clone()) { + return pat_assign(env, &pat, value); + } + match pat { + ExprKind::Member(member) => *addrof_member(env, member)? = value, + ExprKind::Index(index) => *addrof_index(env, index)? = value, + _ => Err(Error::NotAssignable)?, + } Ok(()) } @@ -226,66 +373,6 @@ mod assignment { Ok(()) } - fn assign_destructure_array( - env: &mut Environment, - array: &Array, - value: ConValue, - ) -> IResult<()> { - let Array { values } = array; - let ConValue::Array(inits) = &value else { - eprintln!("{value} does not match pattern {array}"); - return Err(Error::TypeError); - }; - if values.len() != inits.len() { - return Err(Error::TypeError); - } - - for (init, expr) in inits.iter().zip(values) { - assign(env, &expr.kind, init.clone())?; - } - Ok(()) - } - - fn assign_destructure_tuple( - env: &mut Environment, - tuple: &Tuple, - value: ConValue, - ) -> IResult<()> { - let Tuple { exprs } = tuple; - let ConValue::Tuple(inits) = &value else { - eprintln!("{value} does not match pattern {tuple}"); - return Err(Error::TypeError); - }; - if exprs.len() != inits.len() { - return Err(Error::TypeError); - } - - for (init, expr) in inits.iter().zip(exprs) { - assign(env, &expr.kind, init.clone())?; - } - Ok(()) - } - - fn assign_destructure_struct( - env: &mut Environment, - pat: &Structor, - value: ConValue, - ) -> IResult<()> { - let Structor { to: _, init: pat } = pat; - let ConValue::Struct(parts) = value else { - return Err(Error::TypeError); - }; - let (_, members) = *parts; - for Fielder { name, init: pat } in pat { - let value = members.get(name).ok_or(Error::NotDefined(*name))?; - match pat { - Some(pat) => assign(env, &pat.kind, value.clone())?, - None => *env.get_mut(*name)? = Some(value.clone()), - } - } - Ok(()) - } - pub(super) fn addrof<'e>( env: &'e mut Environment, pat: &ExprKind, @@ -297,6 +384,7 @@ mod assignment { ExprKind::Member(member) => addrof_member(env, member), ExprKind::Index(index) => addrof_index(env, index), ExprKind::Group(Group { expr }) => addrof(env, expr), + ExprKind::AddrOf(AddrOf { mutable: Mutability::Mut, expr }) => addrof(env, expr), _ => Err(Error::TypeError), } } diff --git a/compiler/cl-parser/src/error.rs b/compiler/cl-parser/src/error.rs index bd46c12..bb714dc 100644 --- a/compiler/cl-parser/src/error.rs +++ b/compiler/cl-parser/src/error.rs @@ -119,6 +119,10 @@ pub enum Parsing { Break, Return, Continue, + + Pattern, + Match, + MatchArm, } impl Display for Error { @@ -225,6 +229,10 @@ impl Display for Parsing { Parsing::Break => "a break expression", Parsing::Return => "a return expression", Parsing::Continue => "a continue expression", + + Parsing::Pattern => "a pattern", + Parsing::Match => "a match expression", + Parsing::MatchArm => "a match arm", } .fmt(f) } diff --git a/compiler/cl-parser/src/parser.rs b/compiler/cl-parser/src/parser.rs index ee49f86..f1c7785 100644 --- a/compiler/cl-parser/src/parser.rs +++ b/compiler/cl-parser/src/parser.rs @@ -917,7 +917,7 @@ impl Parse<'_> for Let { p.consume_peeked(); Ok(Let { mutable: Mutability::parse(p)?, - name: Sym::parse(p)?, + name: Pattern::parse(p)?, ty: if p.match_type(TokenKind::Colon, Parsing::Let).is_ok() { Some(Ty::parse(p)?.into()) } else { @@ -1075,6 +1075,38 @@ impl Parse<'_> for Return { } } +impl Parse<'_> for Pattern { + fn parse(p: &mut Parser<'_>) -> PResult { + let value = prec::exprkind(p, prec::Precedence::Highest.level())?; + Pattern::try_from(value) + .map_err(|_| p.error(ExpectedParsing { want: Parsing::Pattern }, Parsing::Pattern)) + } +} + +impl Parse<'_> for Match { + /// [Match] = `match` [Expr] `{` [MatchArm],* `}` + fn parse(p: &mut Parser<'_>) -> PResult { + p.match_type(TokenKind::Match, Parsing::Match)?; + let scrutinee = Expr::parse(p)?.into(); + let arms = delim( + sep(MatchArm::parse, TokenKind::Comma, CURLIES.1, Parsing::Match), + CURLIES, + Parsing::Match, + )(p)?; + Ok(Match { scrutinee, arms }) + } +} + +impl Parse<'_> for MatchArm { + /// [MatchArm] = [Pattern] `=>` [Expr] + fn parse(p: &mut Parser<'_>) -> PResult { + let pat = Pattern::parse(p)?; + p.match_type(TokenKind::FatArrow, Parsing::MatchArm)?; + let expr = Expr::parse(p)?; + Ok(MatchArm(pat, expr)) + } +} + /// ret_body = (*unconsumed* `;` | [Expr]) fn ret_body(p: &mut Parser, while_parsing: Parsing) -> PResult>> { Ok(match p.peek_kind(while_parsing)? { diff --git a/compiler/cl-parser/src/parser/prec.rs b/compiler/cl-parser/src/parser/prec.rs index 8147364..19a966b 100644 --- a/compiler/cl-parser/src/parser/prec.rs +++ b/compiler/cl-parser/src/parser/prec.rs @@ -21,6 +21,7 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult { TokenKind::LBrack => exprkind_arraylike(p)?, TokenKind::LParen => exprkind_tuplelike(p)?, TokenKind::Let => Let::parse(p)?.into(), + TokenKind::Match => Match::parse(p)?.into(), TokenKind::While => ExprKind::While(While::parse(p)?), TokenKind::If => ExprKind::If(If::parse(p)?), TokenKind::For => ExprKind::For(For::parse(p)?), @@ -32,8 +33,7 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult { } op => { - let (kind, prec) = - from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?; + let (kind, prec) = from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?; let ((), after) = prec.prefix().expect("should have a precedence"); p.consume_peeked(); Unary { kind, tail: exprkind(p, after)?.into() }.into() @@ -65,14 +65,10 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult { ExprKind::Index(Index { head: head.into(), indices }) } TokenKind::LParen => { - let exprs = - sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?; + let exprs = sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?; p.match_type(TokenKind::RParen, parsing)?; - Binary { - kind: BinaryKind::Call, - parts: (head, Tuple { exprs }.into()).into(), - } - .into() + Binary { kind: BinaryKind::Call, parts: (head, Tuple { exprs }.into()).into() } + .into() } TokenKind::Dot => { let kind = MemberKind::parse(p)?; @@ -260,6 +256,7 @@ pub enum Precedence { Cast, Member, // left-associative Call, + Highest, } impl Precedence { @@ -310,9 +307,7 @@ impl From for Precedence { Op::BitAnd | Op::BitOr | Op::BitXor => Precedence::Bitwise, Op::LogAnd | Op::LogOr | Op::LogXor => Precedence::Logic, Op::RangeExc | Op::RangeInc => Precedence::Range, - Op::Lt | Op::LtEq | Op::Equal | Op::NotEq | Op::GtEq | Op::Gt => { - Precedence::Compare - } + Op::Lt | Op::LtEq | Op::Equal | Op::NotEq | Op::GtEq | Op::Gt => Precedence::Compare, } } } diff --git a/compiler/cl-repl/examples/yaml.rs b/compiler/cl-repl/examples/yaml.rs index 86fa1c9..912861a 100644 --- a/compiler/cl-repl/examples/yaml.rs +++ b/compiler/cl-repl/examples/yaml.rs @@ -380,6 +380,7 @@ pub mod yamlify { match self { ExprKind::Quote(k) => k.yaml(y), ExprKind::Let(k) => k.yaml(y), + ExprKind::Match(k) => k.yaml(y), ExprKind::Assign(k) => k.yaml(y), ExprKind::Modify(k) => k.yaml(y), ExprKind::Binary(k) => k.yaml(y), diff --git a/compiler/cl-token/src/token_type.rs b/compiler/cl-token/src/token_type.rs index d33dcdf..c874e86 100644 --- a/compiler/cl-token/src/token_type.rs +++ b/compiler/cl-token/src/token_type.rs @@ -28,6 +28,7 @@ pub enum TokenKind { In, // "in" Let, // "let" Loop, // "loop" + Match, // "match" Mod, // "mod" Mut, // "mut" Pub, // "pub" @@ -121,6 +122,7 @@ impl Display for TokenKind { TokenKind::In => "in".fmt(f), TokenKind::Let => "let".fmt(f), TokenKind::Loop => "loop".fmt(f), + TokenKind::Match => "match".fmt(f), TokenKind::Mod => "mod".fmt(f), TokenKind::Mut => "mut".fmt(f), TokenKind::Pub => "pub".fmt(f), @@ -213,6 +215,7 @@ impl FromStr for TokenKind { "in" => Self::In, "let" => Self::Let, "loop" => Self::Loop, + "match" => Self::Match, "mod" => Self::Mod, "mut" => Self::Mut, "pub" => Self::Pub, diff --git a/compiler/cl-typeck/src/source.rs b/compiler/cl-typeck/src/source.rs index fbe175b..2f1e285 100644 --- a/compiler/cl-typeck/src/source.rs +++ b/compiler/cl-typeck/src/source.rs @@ -32,7 +32,7 @@ impl Source<'_> { Source::Const(v) => Some(v.name), Source::Static(v) => Some(v.name), Source::Function(v) => Some(v.name), - Source::Local(l) => Some(l.name), + Source::Local(_) => None, Source::Impl(_) | Source::Use(_) | Source::Ty(_) => None, } } diff --git a/compiler/cl-typeck/src/stage/populate.rs b/compiler/cl-typeck/src/stage/populate.rs index 0947d18..4a280d3 100644 --- a/compiler/cl-typeck/src/stage/populate.rs +++ b/compiler/cl-typeck/src/stage/populate.rs @@ -146,11 +146,11 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { } fn visit_let(&mut self, l: &'a cl_ast::Let) { - let cl_ast::Let { mutable, name, ty, init } = l; + let cl_ast::Let { mutable, name: _, ty, init } = l; let mut entry = self.new_entry(NodeKind::Local); entry.inner.set_source(Source::Local(l)); - entry.set_name(*name); + // entry.set_name(*name); entry.visit_mutability(mutable); if let Some(ty) = ty { @@ -160,7 +160,8 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { entry.visit_expr(init) } - let child = entry.inner.id(); - self.inner.add_child(*name, child); + // let child = entry.inner.id(); + // self.inner.add_child(*name, child); + todo!("Pattern destructuring in cl-typeck") } }