diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-06-30 22:49:11 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-06-30 22:49:11 +0200 |
| commit | 44d8028b49d6aa954519ce5f9e84eb5816bda2e9 (patch) | |
| tree | 7117715178d4cd3e765235db09b321826a4df8dc | |
| parent | 17e89468847735df10381c47c46c7d82d33cc463 (diff) | |
Allow wide calls only directly in templates
| -rw-r--r-- | src/parse/mod.rs | 63 | ||||
| -rw-r--r-- | tests/ref/code/call-wide.png | bin | 1864 -> 2686 bytes | |||
| -rw-r--r-- | tests/typ/code/call-wide.typ | 23 |
3 files changed, 28 insertions, 58 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index a56e451d..793c4139 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<F>(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); + // 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 Expr::Call(call) = node { + // Look for wide call. + if let Node::Expr(Expr::Call(call)) = &mut 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() - }; - + let start = p.next_start(); + let tree = tree_while(p, true, f); call.args.items.push(CallArg::Pos(Expr::Template(TemplateExpr { - span: self.p.span(start), + span: 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); - } 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<Expr> { - 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 Binary files differindex 028d7aa4..2d5b4ffe 100644 --- a/tests/ref/code/call-wide.png +++ b/tests/ref/code/call-wide.png diff --git a/tests/typ/code/call-wide.typ b/tests/typ/code/call-wide.typ index 2bb6d82e..54da540b 100644 --- a/tests/typ/code/call-wide.typ +++ b/tests/typ/code/call-wide.typ @@ -12,32 +12,25 @@ C --- // Test evaluation semantics. -// Ref: false -#let r #let x = 1 #let f(x, body) = (x, body) - -[ - { r = f!(x) } - { x = 2 } -] - -#test(repr(r), "(1, <template>)") +#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. |
