mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
parent
961d70dade
commit
b7430f6da0
@ -42,7 +42,7 @@ macro_rules! node {
|
|||||||
impl<'a> AstNode<'a> for $name<'a> {
|
impl<'a> AstNode<'a> for $name<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
|
fn from_untyped(node: &'a SyntaxNode) -> Option<Self> {
|
||||||
if matches!(node.kind(), SyntaxKind::$name) {
|
if node.kind() == SyntaxKind::$name {
|
||||||
Some(Self(node))
|
Some(Self(node))
|
||||||
} else {
|
} else {
|
||||||
Option::None
|
Option::None
|
||||||
@ -1440,6 +1440,18 @@ impl BinOp {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this is an assignment operator.
|
||||||
|
pub fn is_assignment(self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::Assign
|
||||||
|
| Self::AddAssign
|
||||||
|
| Self::SubAssign
|
||||||
|
| Self::MulAssign
|
||||||
|
| Self::DivAssign
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// The precedence of this operator.
|
/// The precedence of this operator.
|
||||||
pub fn precedence(self) -> usize {
|
pub fn precedence(self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
|
@ -638,6 +638,11 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
self.internal.exit();
|
self.internal.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't capture the field of a field access.
|
||||||
|
Some(ast::Expr::FieldAccess(access)) => {
|
||||||
|
self.visit(access.target().to_untyped());
|
||||||
|
}
|
||||||
|
|
||||||
// A closure contains parameter bindings, which are bound before the
|
// A closure contains parameter bindings, which are bound before the
|
||||||
// body is evaluated. Care must be taken so that the default values
|
// body is evaluated. Care must be taken so that the default values
|
||||||
// of named parameters cannot access previous parameter bindings.
|
// of named parameters cannot access previous parameter bindings.
|
||||||
@ -683,6 +688,16 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't capture left-hand side of an assignment.
|
||||||
|
Some(ast::Expr::Binary(binary)) if binary.op().is_assignment() => {
|
||||||
|
self.visit(binary.rhs().to_untyped());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't capture the left-hand side of a destructuring assignment.
|
||||||
|
Some(ast::Expr::DestructAssign(assignment)) => {
|
||||||
|
self.visit(assignment.value().to_untyped());
|
||||||
|
}
|
||||||
|
|
||||||
// A for loop contains one or two bindings in its pattern. These are
|
// A for loop contains one or two bindings in its pattern. These are
|
||||||
// active after the iterable is evaluated but before the body is
|
// active after the iterable is evaluated but before the body is
|
||||||
// evaluated.
|
// evaluated.
|
||||||
@ -710,8 +725,14 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything else is traversed from left to right.
|
|
||||||
_ => {
|
_ => {
|
||||||
|
// Never capture the name part of a named pair.
|
||||||
|
if let Some(named) = node.cast::<ast::Named>() {
|
||||||
|
self.visit(named.expr().to_untyped());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else is traversed from left to right.
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
self.visit(child);
|
self.visit(child);
|
||||||
}
|
}
|
||||||
@ -800,5 +821,12 @@ mod tests {
|
|||||||
// Blocks.
|
// Blocks.
|
||||||
test("#{ let x = 1; { let y = 2; y }; x + y }", &["y"]);
|
test("#{ let x = 1; { let y = 2; y }; x + y }", &["y"]);
|
||||||
test("#[#let x = 1]#x", &["x"]);
|
test("#[#let x = 1]#x", &["x"]);
|
||||||
|
|
||||||
|
// Field access.
|
||||||
|
test("#foo(body: 1)", &[]);
|
||||||
|
test("#(body: 1)", &[]);
|
||||||
|
test("#(body = 1)", &[]);
|
||||||
|
test("#(body += y)", &["y"]);
|
||||||
|
test("#{ (body, a) = (y, 1) }", &["y"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user