From 193734f45385b179f40dc0145034204dad3cae8f Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 3 Mar 2021 22:33:00 +0100 Subject: [PATCH] =?UTF-8?q?Callee=20expressions=20=F0=9F=8D=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parse/mod.rs | 153 +++++++++++++++++++++------------------- src/pretty.rs | 1 + tests/ref/expr/call.png | Bin 5260 -> 6143 bytes tests/typ/expr/call.typ | 47 +++++++++--- tests/typ/spacing.typ | 4 +- 5 files changed, 124 insertions(+), 81 deletions(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index afd851930..f23f19785 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -75,7 +75,7 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option { let group = if stmt { Group::Stmt } else { Group::Expr }; p.start_group(group, TokenMode::Code); - let expr = primary(p); + let expr = expr_with(p, true, 0); if stmt && expr.is_some() && !p.eof() { p.expected_at("semicolon or line break", p.end()); } @@ -166,8 +166,73 @@ fn unicode_escape(p: &mut Parser, token: TokenUnicodeEscape) -> String { text } +/// Parse an expression. +fn expr(p: &mut Parser) -> Option { + expr_with(p, false, 0) +} + +/// Parse an expression with operators having at least the minimum precedence. +/// +/// If `atomic` is true, this does not parse binary operations and arrow +/// functions, which is exactly what we want in a shorthand expression directly +/// in markup. +/// +/// Stops parsing at operations with lower precedence than `min_prec`, +fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> Option { + let start = p.start(); + let mut lhs = match p.eat_map(UnOp::from_token) { + Some(op) => { + let prec = op.precedence(); + let expr = Box::new(expr_with(p, atomic, prec)?); + Expr::Unary(ExprUnary { span: p.span(start), op, expr }) + } + None => primary(p, atomic)?, + }; + + loop { + // Parenthesis or bracket means this is a function call. + if matches!( + p.peek_direct(), + Some(Token::LeftParen) | Some(Token::LeftBracket), + ) { + lhs = call(p, lhs); + continue; + } + + if atomic { + break; + } + + let op = match p.peek().and_then(BinOp::from_token) { + Some(binop) => binop, + None => break, + }; + + let mut prec = op.precedence(); + if prec < min_prec { + break; + } + + p.eat(); + match op.associativity() { + Associativity::Left => prec += 1, + Associativity::Right => {} + } + + let rhs = match expr_with(p, atomic, prec) { + Some(rhs) => Box::new(rhs), + None => break, + }; + + let span = lhs.span().join(rhs.span()); + lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs }); + } + + Some(lhs) +} + /// Parse a primary expression. -fn primary(p: &mut Parser) -> Option { +fn primary(p: &mut Parser, atomic: bool) -> Option { if let Some(expr) = literal(p) { return Some(expr); } @@ -175,31 +240,23 @@ fn primary(p: &mut Parser) -> Option { match p.peek() { // Things that start with an identifier. Some(Token::Ident(string)) => { - let ident = Ident { + let id = Ident { span: p.eat_span(), string: string.into(), }; - // Parenthesis or bracket means this is a function call. - if matches!( - p.peek_direct(), - Some(Token::LeftParen) | Some(Token::LeftBracket), - ) { - return Some(call(p, ident)); - } - - // Arrow means this is closure's lone parameter. - if p.eat_if(Token::Arrow) { + // Arrow means this is a closure's lone parameter. + Some(if !atomic && p.eat_if(Token::Arrow) { let body = expr(p)?; - return Some(Expr::Closure(ExprClosure { - span: ident.span.join(body.span()), + Expr::Closure(ExprClosure { + span: id.span.join(body.span()), name: None, - params: Rc::new(vec![ident]), + params: Rc::new(vec![id]), body: Rc::new(body), - })); - } - - Some(Expr::Ident(ident)) + }) + } else { + Expr::Ident(id) + }) } // Structures. @@ -260,7 +317,7 @@ pub fn parenthesized(p: &mut Parser) -> Option { return Some(dict(p, items, span)); } - // Arrow means this is closure's parameter list. + // Arrow means this is a closure's parameter list. if p.eat_if(Token::Arrow) { let params = params(p, items); let body = expr(p)?; @@ -400,54 +457,8 @@ fn block(p: &mut Parser, scoping: bool) -> Expr { Expr::Block(ExprBlock { span, exprs, scoping }) } -/// Parse an expression. -fn expr(p: &mut Parser) -> Option { - expr_with(p, 0) -} - -/// Parse an expression with operators having at least the minimum precedence. -fn expr_with(p: &mut Parser, min_prec: usize) -> Option { - let start = p.start(); - let mut lhs = match p.eat_map(UnOp::from_token) { - Some(op) => { - let prec = op.precedence(); - let expr = Box::new(expr_with(p, prec)?); - Expr::Unary(ExprUnary { span: p.span(start), op, expr }) - } - None => primary(p)?, - }; - - loop { - let op = match p.peek().and_then(BinOp::from_token) { - Some(binop) => binop, - None => break, - }; - - let mut prec = op.precedence(); - if prec < min_prec { - break; - } - - p.eat(); - match op.associativity() { - Associativity::Left => prec += 1, - Associativity::Right => {} - } - - let rhs = match expr_with(p, prec) { - Some(rhs) => Box::new(rhs), - None => break, - }; - - let span = lhs.span().join(rhs.span()); - lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs }); - } - - Some(lhs) -} - /// Parse a function call. -fn call(p: &mut Parser, name: Ident) -> Expr { +fn call(p: &mut Parser, callee: Expr) -> Expr { let mut args = match p.peek_direct() { Some(Token::LeftParen) => { p.start_group(Group::Paren, TokenMode::Code); @@ -456,7 +467,7 @@ fn call(p: &mut Parser, name: Ident) -> Expr { args } _ => ExprArgs { - span: Span::at(name.span.end), + span: Span::at(callee.span().end), items: vec![], }, }; @@ -467,8 +478,8 @@ fn call(p: &mut Parser, name: Ident) -> Expr { } Expr::Call(ExprCall { - span: p.span(name.span.start), - callee: Box::new(Expr::Ident(name)), + span: p.span(callee.span().start), + callee: Box::new(callee), args, }) } diff --git a/src/pretty.rs b/src/pretty.rs index 3f4205486..963157c02 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -726,6 +726,7 @@ mod tests { // Function calls. roundtrip("{v()}"); + roundtrip("{v()()}"); roundtrip("{v(1)}"); roundtrip("{v(a: 1, b)}"); roundtrip("#v()"); diff --git a/tests/ref/expr/call.png b/tests/ref/expr/call.png index b8086900310b02cda984c75f63498236f803dc67..39941778b039885f6ed342a6760c97d312cfce7a 100644 GIT binary patch literal 6143 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 literal 5260 zcmai2c{J4R+yBmt=iGl>*ZsM#&*!?rt{CZYu=2A40KlPt zQTr+Yz!(n47I=67;5EoX=un#SN3sy7s-(j}v!yXgtVc z2|twJ!wmSX^BB#C zEbQ?LalL%fVT%L=Tb8p$Y8tvQX-OUr-5A>a?@QrY+iTEiU2rj=T)@-&Tp|Xj7*Q1i zF1T0SvwoDuKic@6J7&(&=b|=EL>^8He(I;Ik>)J{Civ;1i7feOHs5$IKGrD-&{jcM zEAzhJ^=cJ(kQR{44j3!+L^F@SPpW?RCmdp1wFp&P;D9Bo0yi16`FD*UvOro0;57M`Yk|stbxO!$Gpu8kZ$p#oF=CHu*>M0}!>8_rTU-C&oSXLuW7PH_? zjEqBH(`=D~W2arKygd0lncVy2`0oPjV&flXiycPX@2Mf)s#>a%j&GrCHPQ)R~iT>2!!jOwCYiGZ#gH4y^7u8#0Rr=H%m&?e323#TDji9!di zTc??weTwOniHb$rJ5q4u@a;uUzO@vNoPZl2PA|Cox@Q?888rX1J>-W$AO8@*mH(b7 zwh$Y?q?3aSHPlPAeFnVBp4eMbJrJ{4&i}xgF2VWda5w_1(K_%l73GEunY@>d=>!2m z>aGZqJ(PO_zNF{YSMy^K<|*_Qzy9g~pXCJ(odXd&kJ(ZfbPRh7>)AI=zdWMlKBA zi?t0O|M46Hc;)zdK8iPvxquHi&8Mc2haC;nc9`-F=`<_4f!VF@Y+LZ5o>(CNLo$lX390_TG!^4rnw zbvPdb@ny1>GS4klUXYE2idUhoE4DF&v;)R%DI{m^uI_v?Cf$?iG_1(&lGu z73zq>q859pXfr`4or;GE&Fgv1m#l@u?4}BAX8I^x$@9vbzKnZ0yNNP7X-MVYu1|?P z4UgqhqD=B!Knd*q=F(ALmSj7fl>ljUH`PMaK23b30oRS}A)uXhT{iQ!-5DY;wI~?Z zMnns|5Crm=n3o^S$2Ggk6oh*h5MyEy$0-LBXyaP?Qu#6!$I=n$F&LX z*Vr}t)5`)C^D&lPj7}+`KC_`&1d&~#-P~Z@fqcW;a6&Ptka&_I`ho$Rv8ShjG?8C5 zwo_mkx|W3$REptQ>CSg@WBqkA<&MoUKzYZVq<5o5m`J{vI0~th{`$a#WbI0Nh=2G! zIr2^)o0O(38>+zpAN)F)OW&5daSk=tc!~6w+3n;IkL0A*5kA{EL^0E+(XmW5O+J8h zW5@MbaHA7T*PMbue}0ww;H~_HYw!C;V1{iCiF6Ud!>T&m`~4A*a)RHDS3A~O`4C7j%fvYEX3U0m1bWsIW%p1BeC72)H3S#V%Klvgist#U7SaMC(L z_T%LrtD#IUUk7;j4%GLZYUbPH%2?PQyTq6fZ2s>k`3oqin$iEuGmAgP%RB!+j`@p( z>K-9^jaWuEhlR&*AFxK$x;q{MsJ5`bvtFo2L;gbN8*n)(RN~1(u^yxeO4~_z|flCEWi~rNw`J`IZ{^gZqpd|F=e7nhA9L3 z`PN68Y<@ua?b%n}lL5s(GOHc&ZY-zUIfdHC$OLe}Wo}&vQ`owP z$2(@JJ<|w`M0SO)abG3XC5f&y>5J4nUZhLL3iOkYYCf1hLMoEw5Wu9) z>D&_4ZB~-mS@*<#8fjL8C(V9p=a7}-POp1%B?|;-p54;6Dh{fP+)5qXU#v)*GNZF` zJEYUMkHfY^_jayZ2phSsFe+vJyncive>udA?3Kz_YRJ%Xw6PL~5bDa(io*cfzg<8g z1=}>1h`Rni>Qrk zvuhp=7^*x^a_Dy?Z~QzqEF8!NOk7UNTwR`~7$E&H$p!YCRMfZSt^iotVqaLADX9Z< z_PM!u!yuhARVQuDTMEa8?ii%>&k3Op^LU|mYYJTWvrt+DR1WoxkmHmTCc$<0E`IMsSkb#HM5 zr9_V0bpta;=l+PsgMNlKh*ZqNJ7d|ib=K>Gh6SdiLg_I@uFwn+>OQF(kFywn79*K~ zGI=daSh}0S5UD=iY={UP50Y*dhU&1)6>slk6_Hc#=KQ29*yIGxgIsNf|IrK=DLSJ?Xc!^q3=hVzxtrP7p^$-j{$v@dx(VbNeH3 zKr3i3uQKQBm!=o1`oqZ)ddq+(rIenzGhjw31P84`?J1=n2CbGUr5*tWH_u?+IBLiS zU6@<35HqN+WPbHcxA12jF8li3ywT5aS`ew8rDjTeDPbS{)QhnG~d>o4*+U`(g%?R&yunp;av>Oias2Lf~ zl9wIhmJyH_T`?w zW%J>i#82M@g{G9VIQz@*Ag;s?>YTQ8`0<7{WeRA^b3cRUV>A2mLOh~9n=wvE?I9wV zMfSXqI9NF~sdQr+ILjD|!S5~y^8*|le_gj%gp#F^~p z;6^?0j!W#P66{-jlv06Irspd4D#M|wDg6@1Rgqm^srf@cW!dd`!mok*_4q9o1^m7# z!@k5XhmdIA-ibXQp;hsDQuQ}COaV1jeGr_UCd&J`qweUa?SoXWKg|-+47DPYo{ms^ zpd!^eRdx`4fjbJ>jJ+Q!8S-}gL1;@md_W_sXjw|4d_7X`^L89rHep&t927N`&gW@q zI^9BWQITx(f3uImnZWClGQor{I{#a~w)&ZYz}_4?P2g23P41Sm4?YfEf5R-LeKoCn zU^bf{aK~S@Y*MwyevIW;#Z~mYpU0-4NeC25NU$ePndlP#IKyXIM(62A(t#7h+uw}N zKrzIS)u4TUKqkpACP6g-_PbO$amfKa3p(qe<(28fBuiM-johWO?kVv z5Ia?7n|+@LZcM{%{-~0UWN=hc6&PUM8sr&7mlT$HE4jF$jm0Z3GUpBcyz(W_R_+=5gnGF}@iXrFDq8|dH|Bc-KA<9f30uh}|KVahWm z;S~Vtn1L37VQjbuw{~`B$Tj!LH=Cocw?_ny$5uW?zQI{C2y+w+IGI&v8Wx)fJ3Ln@uH9FJde;hj7s)TRg&6&%2vkG{bm~BO1lpjB7 z+s5TELcScUt5%b)VnnUl2;l6i`^a|jcj`>`LVC81U;Uf;)^3O~IvrM{v^`a~{?_Z2 ztNgcfn~x@_F~Q>0>OFQfuAM7-E>+WGBkuF(ROWKhP^4VdjZos))W*kA&o@r3xyXdF z>jLpt_jy0nQ7?mGD*uNl|JhcvYX04>GfXb&eo6aRZvE%Vzb+c=L@&nuQ x + dx + test(adder(2)(5), 7) +} + +#let f(x, body) = (y) => { + [{x}] + body + [{y}] +} + +// Call return value of function with body. +#f(1)[2](3) + +// Don't allow this to be a closure. +// Should output `x => "hi"`. +#let x = "x" +#x => "hi" + --- // Different forms of template arguments. // Ref: true @@ -30,11 +69,3 @@ // Should output ` (Okay.)`. #args (Okay.) - ---- -// Call function assigned to variable. -#let alias = type -#test(alias(alias), "function") - -// Library function `font` returns template. -#test(type(font(12pt)), "template") diff --git a/tests/typ/spacing.typ b/tests/typ/spacing.typ index 77dac53cc..ccaf084a2 100644 --- a/tests/typ/spacing.typ +++ b/tests/typ/spacing.typ @@ -12,8 +12,8 @@ A#let x = 3; B #test(x, 3) \ --- // Spacing around if-else. -A#if true[B]C \ -A#if true[B] C \ +A#if true [B]C \ +A#if true [B] C \ A #if true{"B"}C \ A #if true{"B"} C \ A#if false [] #else [B]C \