diff --git a/compiler/cl-ast/src/ast.rs b/compiler/cl-ast/src/ast.rs index 1e01033..663fcd0 100644 --- a/compiler/cl-ast/src/ast.rs +++ b/compiler/cl-ast/src/ast.rs @@ -323,7 +323,6 @@ pub struct Stmt { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum StmtKind { Empty, - Local(Let), Item(Box), Expr(Box), } @@ -342,6 +341,7 @@ pub struct Let { pub name: Sym, pub ty: Option>, pub init: Option>, + pub tail: Option>, } /// An expression, the beating heart of the language @@ -357,6 +357,8 @@ pub enum ExprKind { /// An empty expression: `(` `)` #[default] Empty, + /// A local bind instruction, `let` [`Sym`] `=` [`Expr`] + Let(Let), /// An [Assign]ment expression: [`Expr`] (`=` [`Expr`])\+ Assign(Assign), /// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+ diff --git a/compiler/cl-ast/src/ast_impl.rs b/compiler/cl-ast/src/ast_impl.rs index 1e25497..e3693e3 100644 --- a/compiler/cl-ast/src/ast_impl.rs +++ b/compiler/cl-ast/src/ast_impl.rs @@ -389,7 +389,6 @@ mod display { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { StmtKind::Empty => Ok(()), - StmtKind::Local(v) => v.fmt(f), StmtKind::Item(v) => v.fmt(f), StmtKind::Expr(v) => v.fmt(f), } @@ -407,7 +406,7 @@ mod display { impl Display for Let { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { mutable, name, ty, init } = self; + let Self { mutable, name, ty, init, tail } = self; write!(f, "let {mutable}{name}")?; if let Some(value) = ty { write!(f, ": {value}")?; @@ -415,6 +414,9 @@ mod display { if let Some(value) = init { write!(f, " = {value}")?; } + if let Some(value) = tail { + write!(f, ";\n{value}")?; + } Ok(()) } } @@ -429,6 +431,7 @@ mod display { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ExprKind::Empty => "()".fmt(f), + ExprKind::Let(v) => v.fmt(f), ExprKind::Assign(v) => v.fmt(f), ExprKind::Modify(v) => v.fmt(f), ExprKind::Binary(v) => v.fmt(f), @@ -763,11 +766,11 @@ mod convert { TyFn => TyKind::Fn, } impl From for StmtKind { - Let => StmtKind::Local, Item => StmtKind::Item, Expr => StmtKind::Expr, } impl From for ExprKind { + Let => ExprKind::Let, 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 b8a6159..7f9c4ad 100644 --- a/compiler/cl-ast/src/ast_visitor/fold.rs +++ b/compiler/cl-ast/src/ast_visitor/fold.rs @@ -227,12 +227,13 @@ pub trait Fold { s } fn fold_let(&mut self, l: Let) -> Let { - let Let { mutable, name, ty, init } = l; + let Let { mutable, name, ty, init, tail } = l; Let { mutable: self.fold_mutability(mutable), name: self.fold_sym(name), ty: ty.map(|t| Box::new(self.fold_ty(*t))), init: init.map(|e| Box::new(self.fold_expr(*e))), + tail: tail.map(|e| Box::new(self.fold_expr(*e))), } } fn fold_expr(&mut self, e: Expr) -> Expr { @@ -525,7 +526,6 @@ pub fn or_fold_ty_kind(folder: &mut F, kind: TyKind) -> TyKind pub fn or_fold_stmt_kind(folder: &mut F, kind: StmtKind) -> StmtKind { match kind { StmtKind::Empty => StmtKind::Empty, - StmtKind::Local(l) => StmtKind::Local(folder.fold_let(l)), StmtKind::Item(i) => StmtKind::Item(Box::new(folder.fold_item(*i))), StmtKind::Expr(e) => StmtKind::Expr(Box::new(folder.fold_expr(*e))), } @@ -535,6 +535,7 @@ pub fn or_fold_stmt_kind(folder: &mut F, kind: StmtKind) -> St pub fn or_fold_expr_kind(folder: &mut F, kind: ExprKind) -> ExprKind { match kind { ExprKind::Empty => ExprKind::Empty, + ExprKind::Let(l) => ExprKind::Let(folder.fold_let(l)), 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 cfbd410..5c99353 100644 --- a/compiler/cl-ast/src/ast_visitor/visit.rs +++ b/compiler/cl-ast/src/ast_visitor/visit.rs @@ -192,7 +192,7 @@ pub trait Visit<'a>: Sized { } fn visit_semi(&mut self, _s: &'a Semi) {} fn visit_let(&mut self, l: &'a Let) { - let Let { mutable, name, ty, init } = l; + let Let { mutable, name, ty, init, tail } = l; self.visit_mutability(mutable); self.visit_sym(name); if let Some(ty) = ty { @@ -201,6 +201,9 @@ pub trait Visit<'a>: Sized { if let Some(init) = init { self.visit_expr(init) } + if let Some(tail) = tail { + self.visit_expr(tail) + } } fn visit_expr(&mut self, e: &'a Expr) { let Expr { extents, kind } = e; @@ -448,7 +451,6 @@ pub fn or_visit_ty_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a TyKind) { pub fn or_visit_stmt_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StmtKind) { match kind { StmtKind::Empty => {} - StmtKind::Local(l) => visitor.visit_let(l), StmtKind::Item(i) => visitor.visit_item(i), StmtKind::Expr(e) => visitor.visit_expr(e), } @@ -457,6 +459,7 @@ pub fn or_visit_stmt_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StmtKind) pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) { match e { ExprKind::Empty => {} + ExprKind::Let(l) => visitor.visit_let(l), 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/interpret.rs b/compiler/cl-interpret/src/interpret.rs index 1293c2c..49ccf6a 100644 --- a/compiler/cl-interpret/src/interpret.rs +++ b/compiler/cl-interpret/src/interpret.rs @@ -105,7 +105,6 @@ impl Interpret for Stmt { let Self { extents: _, kind, semi } = self; let out = match kind { StmtKind::Empty => ConValue::Empty, - StmtKind::Local(stmt) => stmt.interpret(env)?, StmtKind::Item(stmt) => stmt.interpret(env)?, StmtKind::Expr(stmt) => stmt.interpret(env)?, }; @@ -117,9 +116,10 @@ impl Interpret for Stmt { } impl Interpret for Let { fn interpret(&self, env: &mut Environment) -> IResult { - let Let { mutable: _, name, ty: _, init } = self; + let Let { mutable: _, name, ty: _, init, tail } = self; let init = init.as_ref().map(|i| i.interpret(env)).transpose()?; env.insert(*name, init); + tail.as_ref().map(|e| e.interpret(env)).transpose()?; Ok(ConValue::Empty) } } @@ -134,6 +134,7 @@ impl Interpret for ExprKind { fn interpret(&self, env: &mut Environment) -> IResult { match self { ExprKind::Empty => Ok(ConValue::Empty), + ExprKind::Let(v) => v.interpret(env), ExprKind::Assign(v) => v.interpret(env), ExprKind::Modify(v) => v.interpret(env), ExprKind::Binary(v) => v.interpret(env), diff --git a/compiler/cl-parser/src/parser.rs b/compiler/cl-parser/src/parser.rs index 687ff58..32fdbd6 100644 --- a/compiler/cl-parser/src/parser.rs +++ b/compiler/cl-parser/src/parser.rs @@ -815,31 +815,10 @@ impl<'t> Parser<'t> { pub fn stmtkind(&mut self) -> PResult { Ok(match self.peek_kind(Parsing::StmtKind)? { TokenKind::Semi => StmtKind::Empty, - TokenKind::Let => self.parse_let()?.into(), item_like!() => self.item()?.into(), _ => self.expr()?.into(), }) } - - pub fn parse_let(&mut self) -> PResult { - self.consume_peeked(); - Ok(Let { - mutable: self.mutability(), - name: self.identifier()?, - ty: if Ok(TokenKind::Colon) == self.peek_kind(Parsing::Let) { - self.consume_peeked(); - Some(self.ty()?.into()) - } else { - None - }, - init: if Ok(TokenKind::Eq) == self.peek_kind(Parsing::Let) { - self.consume_peeked(); - Some(self.expr()?.into()) - } else { - None - }, - }) - } } /// # Expression parsing @@ -863,6 +842,7 @@ impl<'t> Parser<'t> { TokenKind::LCurly => self.block()?.into(), TokenKind::LBrack => self.exprkind_arraylike()?, TokenKind::LParen => self.exprkind_tuplelike()?, + TokenKind::Let => self.parse_let()?.into(), TokenKind::Loop => { self.consume_peeked(); Loop { body: self.expr()?.into() }.into() @@ -1157,6 +1137,29 @@ impl<'t> Parser<'t> { const A_BLOCK: Parsing = Parsing::Block; Ok(Block { stmts: delim(rep(Self::stmt, CURLIES.1, A_BLOCK), CURLIES, A_BLOCK)(self)? }) } + + pub fn parse_let(&mut self) -> PResult { + self.consume_peeked(); + Ok(Let { + mutable: self.mutability(), + name: self.identifier()?, + ty: if self.match_type(TokenKind::Colon, Parsing::Let).is_ok() { + Some(self.ty()?.into()) + } else { + None + }, + init: if self.match_type(TokenKind::Eq, Parsing::Let).is_ok() { + Some(self.expr()?.into()) + } else { + None + }, + tail: if self.match_type(TokenKind::Semi, Parsing::Let).is_ok() { + Some(self.expr()?.into()) + } else { + None + }, + }) + } } /// ## Control flow subexpressions impl<'t> Parser<'t> { diff --git a/compiler/cl-repl/examples/yaml.rs b/compiler/cl-repl/examples/yaml.rs index c03d29d..16655d0 100644 --- a/compiler/cl-repl/examples/yaml.rs +++ b/compiler/cl-repl/examples/yaml.rs @@ -363,7 +363,6 @@ pub mod yamlify { fn yaml(&self, y: &mut Yamler) { match self { StmtKind::Empty => y, - StmtKind::Local(s) => y.yaml(s), StmtKind::Item(s) => y.yaml(s), StmtKind::Expr(s) => y.yaml(s), }; @@ -371,12 +370,13 @@ pub mod yamlify { } impl Yamlify for Let { fn yaml(&self, y: &mut Yamler) { - let Self { mutable, name, ty, init } = self; + let Self { mutable, name, ty, init, tail } = self; y.key("Let") .pair("name", name) .yaml(mutable) .pair("ty", ty) - .pair("init", init); + .pair("init", init) + .pair("tail", tail); } } impl Yamlify for Expr { @@ -388,6 +388,7 @@ pub mod yamlify { impl Yamlify for ExprKind { fn yaml(&self, y: &mut Yamler) { match self { + ExprKind::Let(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-typeck/src/stage/populate.rs b/compiler/cl-typeck/src/stage/populate.rs index c8a0d3e..c1f6827 100644 --- a/compiler/cl-typeck/src/stage/populate.rs +++ b/compiler/cl-typeck/src/stage/populate.rs @@ -145,35 +145,25 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { self.visit_use_tree(tree); } - fn visit_stmt(&mut self, s: &'a cl_ast::Stmt) { - let cl_ast::Stmt { extents, kind, semi } = s; - let cl_ast::StmtKind::Local(local) = kind else { - self.visit_span(extents); - self.visit_stmt_kind(kind); - self.visit_semi(semi); - return; - }; - - let mut entry = self.new_entry(NodeKind::Local); - entry.inner.set_span(*extents); - entry.visit_let(local); - - if let (Some(name), child) = (entry.name, entry.inner.id()) { - self.inner.add_child(name, child); - } - } - fn visit_let(&mut self, l: &'a cl_ast::Let) { - let cl_ast::Let { mutable, name, ty, init } = l; - self.inner.set_source(Source::Local(l)); - self.set_name(*name); + let cl_ast::Let { mutable, name, ty, init, tail } = l; + let mut entry = self.new_entry(NodeKind::Local); - self.visit_mutability(mutable); + entry.inner.set_source(Source::Local(l)); + entry.set_name(*name); + + entry.visit_mutability(mutable); if let Some(ty) = ty { - self.visit_ty(ty); + entry.visit_ty(ty); } if let Some(init) = init { - self.visit_expr(init) + entry.visit_expr(init) } + if let Some(tail) = tail { + entry.visit_expr(tail) + } + + let child = entry.inner.id(); + self.inner.add_child(*name, child); } }