diff --git a/src/eval/mod.rs b/src/eval/mod.rs index f30ee7a7c..176201619 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -401,7 +401,8 @@ impl Eval for ExprClosure { visitor.finish() }; - Value::Func(ValueFunc::new(None, move |ctx, args| { + let name = self.name.as_ref().map(|id| id.to_string()); + Value::Func(ValueFunc::new(name, move |ctx, args| { // Don't leak the scopes from the call site. Instead, we use the // scope of captured variables we collected earlier. let prev = std::mem::take(&mut ctx.scopes); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 298015277..afd851930 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -190,13 +190,13 @@ fn primary(p: &mut Parser) -> Option { // Arrow means this is closure's lone parameter. if p.eat_if(Token::Arrow) { - return expr(p).map(|body| { - Expr::Closure(ExprClosure { - span: ident.span.join(body.span()), - params: Rc::new(vec![ident]), - body: Rc::new(body), - }) - }); + let body = expr(p)?; + return Some(Expr::Closure(ExprClosure { + span: ident.span.join(body.span()), + name: None, + params: Rc::new(vec![ident]), + body: Rc::new(body), + })); } Some(Expr::Ident(ident)) @@ -263,13 +263,13 @@ pub fn parenthesized(p: &mut Parser) -> Option { // Arrow means this is closure's parameter list. if p.eat_if(Token::Arrow) { let params = params(p, items); - return expr(p).map(|body| { - Expr::Closure(ExprClosure { - span: span.join(body.span()), - params: Rc::new(params), - body: Rc::new(body), - }) - }); + let body = expr(p)?; + return Some(Expr::Closure(ExprClosure { + span: span.join(body.span()), + name: None, + params: Rc::new(params), + body: Rc::new(body), + })); } // Find out which kind of collection this is. @@ -509,6 +509,7 @@ fn expr_let(p: &mut Parser) -> Option { let body = init?; init = Some(Expr::Closure(ExprClosure { span: binding.span.join(body.span()), + name: Some(binding.clone()), params: Rc::new(params), body: Rc::new(body), })); diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index d76ada69e..5d10349b4 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -27,7 +27,7 @@ pub enum Expr { Binary(ExprBinary), /// An invocation of a function: `f(x, y)`. Call(ExprCall), - /// A closure expression: `(x, y) => { z }`. + /// A closure expression: `(x, y) => z`. Closure(ExprClosure), /// A let expression: `let x = 1`. Let(ExprLet), @@ -414,11 +414,15 @@ impl ExprArg { } } -/// A closure expression: `(x, y) => { z }`. +/// A closure expression: `(x, y) => z`. #[derive(Debug, Clone, PartialEq)] pub struct ExprClosure { /// The source code location. pub span: Span, + /// The name of the closure. + /// + /// This only exists if you use the function syntax sugar: `let f(x) = y`. + pub name: Option, /// The parameter bindings. pub params: Rc>, /// The body of the closure. diff --git a/tests/ref/repr.png b/tests/ref/repr.png index 2e7755d38..54a1d2409 100644 Binary files a/tests/ref/repr.png and b/tests/ref/repr.png differ diff --git a/tests/typ/repr.typ b/tests/typ/repr.typ index 666db4285..6eead75e0 100644 --- a/tests/typ/repr.typ +++ b/tests/typ/repr.typ @@ -48,3 +48,11 @@ --- // Templates. {[*{"H" + "i"} there*]} + +--- +// Functions +#let f(x) = x + +{box} \ +{f} \ +{() => none} \