summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-06-30 22:49:11 +0200
committerLaurenz <laurmaedje@gmail.com>2021-06-30 22:49:11 +0200
commit44d8028b49d6aa954519ce5f9e84eb5816bda2e9 (patch)
tree7117715178d4cd3e765235db09b321826a4df8dc
parent17e89468847735df10381c47c46c7d82d33cc463 (diff)
Allow wide calls only directly in templates
-rw-r--r--src/parse/mod.rs63
-rw-r--r--tests/ref/code/call-wide.pngbin1864 -> 2686 bytes
-rw-r--r--tests/typ/code/call-wide.typ23
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
index 028d7aa4..2d5b4ffe 100644
--- a/tests/ref/code/call-wide.png
+++ b/tests/ref/code/call-wide.png
Binary files differ
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.