From 44d8028b49d6aa954519ce5f9e84eb5816bda2e9 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 30 Jun 2021 22:49:11 +0200 Subject: [PATCH] Allow wide calls only directly in templates --- src/parse/mod.rs | 65 +++++++++++------------------------ tests/ref/code/call-wide.png | Bin 1864 -> 2686 bytes tests/typ/code/call-wide.typ | 23 +++++-------- 3 files changed, 29 insertions(+), 59 deletions(-) diff --git a/src/parse/mod.rs b/src/parse/mod.rs index a56e451d9..793c4139c 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -15,7 +15,6 @@ pub use tokens::*; use std::rc::Rc; use crate::diag::Pass; -use crate::syntax::visit::{mutable::visit_expr, VisitMut}; use crate::syntax::*; /// Parse a string of source code. @@ -50,55 +49,25 @@ fn tree_while(p: &mut Parser, mut at_start: bool, f: &mut F) -> SyntaxTree where F: FnMut(&mut Parser) -> bool, { - /// Visitor that adds a recursively parsed rest template to the first wide - /// call's argument list and diagnoses all following wide calls. - struct WideVisitor<'a, 's, F> { - p: &'a mut Parser<'s>, - f: &'a mut F, - found: bool, - } - - impl<'ast, 'a, 's, F> VisitMut<'ast> for WideVisitor<'a, 's, F> - where - F: FnMut(&mut Parser) -> bool, - { - fn visit_expr(&mut self, node: &'ast mut Expr) { - visit_expr(self, node); - - if let Expr::Call(call) = node { - if call.wide { - let start = self.p.next_start(); - let tree = if !self.found { - tree_while(self.p, true, self.f) - } else { - self.p.diag(error!(call.callee.span(), "duplicate wide call")); - SyntaxTree::default() - }; - - call.args.items.push(CallArg::Pos(Expr::Template(TemplateExpr { - span: self.p.span(start), - tree: Rc::new(tree), - }))); - - self.found = true; - } - } - } - - // Don't recurse into templates. - fn visit_template(&mut self, _: &'ast mut TemplateExpr) {} - } - // We use `at_start` to keep track of whether we are at the start of a line // or template to know whether things like headings are allowed. let mut tree = vec![]; while !p.eof() && f(p) { if let Some(mut node) = node(p, &mut at_start) { at_start &= matches!(node, Node::Space | Node::Parbreak(_)); - if let Node::Expr(expr) = &mut node { - let mut visitor = WideVisitor { p, f, found: false }; - visitor.visit_expr(expr); + + // Look for wide call. + if let Node::Expr(Expr::Call(call)) = &mut node { + if call.wide { + let start = p.next_start(); + let tree = tree_while(p, true, f); + call.args.items.push(CallArg::Pos(Expr::Template(TemplateExpr { + span: p.span(start), + tree: Rc::new(tree), + }))); + } } + tree.push(node); } } @@ -557,7 +526,15 @@ fn block(p: &mut Parser, scoping: bool) -> Expr { /// Parse a function call. fn call(p: &mut Parser, callee: Expr) -> Option { - let wide = p.eat_if(Token::Excl); + let mut wide = p.eat_if(Token::Excl); + if wide && p.outer_mode() == TokenMode::Code { + let span = p.span(callee.span().start); + p.diag(error!( + span, + "wide calls are only allowed directly in templates", + )); + wide = false; + } let mut args = match p.peek_direct() { Some(Token::LeftParen) => { diff --git a/tests/ref/code/call-wide.png b/tests/ref/code/call-wide.png index 028d7aa4e33423b2b48276d486e8b0b6b49750fc..2d5b4ffe762facd42b31d6fc36c7fff5bf8cc01b 100644 GIT binary patch delta 2331 zcmZ{mc`y_X8^?FIjSaEuY#qsxGur%I`8n3M>&(^Rh_YKbDz~4r*tIrytZ0-Yyn45C zEnyMDk{n5F<;bz5kTc6#*70iQJ^y%TJ~Q7xo@eHHo|*4_=jjsO6Q@Xu0Hq;^002O% zzzFj|erBA^Iz*vRG8&vc^Z9c|0e~a+Rv5EO5u;1v(IKOqlC4wnWoHr%oi6wbpf@{} zHIokMB;8_@sxFbLB4D#TLOw5H7+!ql2zc>IU|2ldwY7)mv$<$(d1dBfW?~^E`M#?@M zIbuQE9}4TLiyPY5{&h_OYzBQ+>|q>nmA0=>EN+Q2Bz%fv+42^w_Il5#_~q%ho4NOl$yQFZLN z?9hS*@0u9rq#7wR2q;ZJ)1k?<51b=KT#M%+8+vsk%7XcU1<+(?3Ds-P`eR;N>zjvx zbM7E+zO8<@uZQ~LWuGv$-XM%BGW>|JkHEDHW`wgaJkI)1}|5k)@E;vqH>$V=n#ze8MUA!{LTf#LSNDBjMKXmw_J`>Z}Cp z!@8GV5lU3QH8}D^q+X)*y@068fb{k`vrcf##qgr#VM~rf~K6>@2^! zpxthIK1R`3OTj&6SRbrj5F7@*7kwGrqtot;s(9S^rU&@8vYza4RD-AIs})a}>1u9% zZ+5aN>id3>`Lf|6ch57HInyk_N_dVsSq93UDqXun>s!tA7?uJjOAY0xJhROUt2nKJ zs@U3k?FvZl``}tF#PyD0XIV1?oD^omwQ?K!VU%^8Zv_q|6ff zGHD<#s^k>0<%Z>xCx~ zgM9*|j@eqaTgE^MlCDNlQEatz8jbT#QPN&o62Pk-C8}yHDVQDmE3@j`lHGMu(%*ld zQ0IC}L{ItDw2Lnti-QUI_Mq=pLU2Dyx4Ud%o!YBL{cLG=Y7Ku1t`yxw&;&&wQnqz^ zEDw4(EHgTmSd_X~fJd07IlNDi+`98)T;xDYU4^VHNYj{Pz*v7@eT(paoU3-oKc8HTKs zzc;PoObt)a&1@^tIu?Bu9N5fTQ#GEiA}urkI@wJtdhWZwu>VXnKEiQ{w(`%M1;!6s zm_ZACgBLfl{m4en~5|UdTB;N^@8<&d7 z$e}{LzlHPFW#5PP8XOGpS+^L#_4D;bUHI2xU^spVl8_^A2Kx^OK_{oD@jFMP2#gBY z`GECL)_^SP#0>?2*G{1r>QPklwE*UyDa1jHiHRi0%cw4#_~^~jHWlCc;BVdi<0Qke zpVYnwP`<%R@IqhgC6MZP8BYW>5e?b=PANea`z=q7gWGETVz*vwD3ZzQYR-3T$h=@m zfQ^t>49@^!Bl3|815u^=-R23wPjZ@*-hX=N%vhkp0Ci5*w3@Sk@yM}8o>BUjey96K zVbhHw4qPB<{w@1W6;pj!&B7mZ^CwBA-NoMxaU-!KKe^+ z!F_3f%()&nWmML{gsHpw_@p*+jQH>@kA@t*BZgC+UNaplc@GW zc#~-F?4p1cDQsAFx+)u1{m4lZi)vCV)eY%(p^W>2e|&duV||C5f}ULI)4DZ`Cx?~6K;NS`H7H8 zC$Yvg>#y=v->#V~c(*)W`K4A+jVy_q9uQ^RJL6{Cv3nLu=+E9{tb3nhP}_evE>dB{ z`I2bVtvR51r~lGdz`K zl9+d+^Q&?$Ro0xCSE)Dy*wULa6>5 cMmTdHn4=vU>R8Zy<>2`NSYhoj6=)pkABN3Jm;e9( delta 1516 zcmVPvsl^Ax`Tn10UqH^O9O;o2cTJf43JDtT z@661dBo}1WhlrpEil7LJpa_bf2#TNxPeNeDhLg_%7n4v51b_d90C=TUMF1~0=1UyM zC&tS+#PcE{HVuIH9-HRlsv-o&1E|#SF1A(zq4N7i>2ZX4gPf$uQxTwHjQL!ehX9q? zS;K)>G=#s5F=p#Age{KB-UAo#;T<%=?(I}nQXn(|bAI--g$U`tZ6#-&njMj~^Z!+=8`ccmi;55pAJHqV1aR3}^2{VMO7YwH*bOym56%B!K(kj{x z^=#Sbf6a1dqG6*42%XcSA<+8jWKD3t>jHHmy8}3`)9*TfYuyJ3ZQCkZ+w9s84$fi6 zftKy=gdcWs`Zfu}PL=h^u@(^8b)aS2K*#RX-$wRpSS<wC_|Hf1{oR@K@paXu&P556hRRbK@k)| z5fniYo{FGtvy;yP7k`2xybwaUyy^(xk1lgDxin4F?d>#8f23);y-bAi-y@N6E)aTm z(+ORRh>X9NmxaK-h=?@v5$Hn^k^3?n-;2mid07aTA|f)#2g1IH$TdJuMC5o`2;w03#{Gv53f7UJzuwx4m~IGMrb&7De!72$Ur+`QT?$5*ek- zLb#NDfa|>E!vtY)Ht8L&mQoYSV@cCAO|SBj4_Qr^*0FK)K{oP`4;ccK@8_+N ziz3{}!1sOM-+#Z)Nj_u~E~S>RzGgHv!7N@BcD!_2G+?&jJ^d-~t7I{HF-b?d@W1Y+e+By&uC~Z*VvIzN!eY zc6B?s!+!bNpF+MA0yM|B+1&5^RYkbTc4a^>C;PjXjli+w<4X=NiZFcbPvZXzgs~K> z5d13yQ3SZl$41_lMYxo!RYw3nCmY*e6oEk&3eekMRRk_&dd+ZLu$Wlr0_yDU=2Mvy zW}1g>oG*m{?DvM(gMu~9dQ(M{e+C&V6k*v2t2z`x5fniY6hRRbK@k+;m*XGrUQp+( SuMIZ<0000)") +#f!(x) +{ x = 2 } --- // Test multiple wide calls in one expression. // Ref: false -#let id(x) = x -#let add(x, y) = x + y +#let f() = [] +#let g(x, y) = [] -// Error: 11-13 duplicate wide call -[{id!() + id!()}] +// Error: 2-4 wide calls are only allowed directly in templates +{f!()} // Test nested wide calls. -// Error: 2-6 duplicate wide call -[#add!(id!())] +// Error: 5-7 wide calls are only allowed directly in templates +#g!(f!()) --- // Test missing parentheses.