Improve clarity of ast.rs for newcomers to the codebase (#5784)

Co-authored-by: PgBiel <9021226+PgBiel@users.noreply.github.com>
Co-authored-by: T0mstone <39707032+T0mstone@users.noreply.github.com>
This commit is contained in:
Ian Wrzesinski 2025-02-26 15:10:36 -05:00 committed by GitHub
parent 52f1f53973
commit cfb3b1a270
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 415 additions and 311 deletions

View File

@ -466,7 +466,7 @@ impl<'a> CapturesVisitor<'a> {
} }
// Code and content blocks create a scope. // Code and content blocks create a scope.
Some(ast::Expr::Code(_) | ast::Expr::Content(_)) => { Some(ast::Expr::CodeBlock(_) | ast::Expr::ContentBlock(_)) => {
self.internal.enter(); self.internal.enter();
for child in node.children() { for child in node.children() {
self.visit(child); self.visit(child);
@ -516,7 +516,7 @@ impl<'a> CapturesVisitor<'a> {
// A let expression contains a binding, but that binding is only // A let expression contains a binding, but that binding is only
// active after the body is evaluated. // active after the body is evaluated.
Some(ast::Expr::Let(expr)) => { Some(ast::Expr::LetBinding(expr)) => {
if let Some(init) = expr.init() { if let Some(init) = expr.init() {
self.visit(init.to_untyped()); self.visit(init.to_untyped());
} }
@ -529,7 +529,7 @@ impl<'a> CapturesVisitor<'a> {
// 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.
Some(ast::Expr::For(expr)) => { Some(ast::Expr::ForLoop(expr)) => {
self.visit(expr.iterable().to_untyped()); self.visit(expr.iterable().to_untyped());
self.internal.enter(); self.internal.enter();
@ -544,7 +544,7 @@ impl<'a> CapturesVisitor<'a> {
// An import contains items, but these are active only after the // An import contains items, but these are active only after the
// path is evaluated. // path is evaluated.
Some(ast::Expr::Import(expr)) => { Some(ast::Expr::ModuleImport(expr)) => {
self.visit(expr.source().to_untyped()); self.visit(expr.source().to_untyped());
if let Some(ast::Imports::Items(items)) = expr.imports() { if let Some(ast::Imports::Items(items)) = expr.imports() {
for item in items.iter() { for item in items.iter() {

View File

@ -30,7 +30,7 @@ fn eval_code<'a>(
while let Some(expr) = exprs.next() { while let Some(expr) = exprs.next() {
let span = expr.span(); let span = expr.span();
let value = match expr { let value = match expr {
ast::Expr::Set(set) => { ast::Expr::SetRule(set) => {
let styles = set.eval(vm)?; let styles = set.eval(vm)?;
if vm.flow.is_some() { if vm.flow.is_some() {
break; break;
@ -39,7 +39,7 @@ fn eval_code<'a>(
let tail = eval_code(vm, exprs)?.display(); let tail = eval_code(vm, exprs)?.display();
Value::Content(tail.styled_with_map(styles)) Value::Content(tail.styled_with_map(styles))
} }
ast::Expr::Show(show) => { ast::Expr::ShowRule(show) => {
let recipe = show.eval(vm)?; let recipe = show.eval(vm)?;
if vm.flow.is_some() { if vm.flow.is_some() {
break; break;
@ -94,9 +94,9 @@ impl Eval for ast::Expr<'_> {
Self::Label(v) => v.eval(vm), Self::Label(v) => v.eval(vm),
Self::Ref(v) => v.eval(vm).map(Value::Content), Self::Ref(v) => v.eval(vm).map(Value::Content),
Self::Heading(v) => v.eval(vm).map(Value::Content), Self::Heading(v) => v.eval(vm).map(Value::Content),
Self::List(v) => v.eval(vm).map(Value::Content), Self::ListItem(v) => v.eval(vm).map(Value::Content),
Self::Enum(v) => v.eval(vm).map(Value::Content), Self::EnumItem(v) => v.eval(vm).map(Value::Content),
Self::Term(v) => v.eval(vm).map(Value::Content), Self::TermItem(v) => v.eval(vm).map(Value::Content),
Self::Equation(v) => v.eval(vm).map(Value::Content), Self::Equation(v) => v.eval(vm).map(Value::Content),
Self::Math(v) => v.eval(vm).map(Value::Content), Self::Math(v) => v.eval(vm).map(Value::Content),
Self::MathText(v) => v.eval(vm).map(Value::Content), Self::MathText(v) => v.eval(vm).map(Value::Content),
@ -116,8 +116,8 @@ impl Eval for ast::Expr<'_> {
Self::Float(v) => v.eval(vm), Self::Float(v) => v.eval(vm),
Self::Numeric(v) => v.eval(vm), Self::Numeric(v) => v.eval(vm),
Self::Str(v) => v.eval(vm), Self::Str(v) => v.eval(vm),
Self::Code(v) => v.eval(vm), Self::CodeBlock(v) => v.eval(vm),
Self::Content(v) => v.eval(vm).map(Value::Content), Self::ContentBlock(v) => v.eval(vm).map(Value::Content),
Self::Array(v) => v.eval(vm).map(Value::Array), Self::Array(v) => v.eval(vm).map(Value::Array),
Self::Dict(v) => v.eval(vm).map(Value::Dict), Self::Dict(v) => v.eval(vm).map(Value::Dict),
Self::Parenthesized(v) => v.eval(vm), Self::Parenthesized(v) => v.eval(vm),
@ -126,19 +126,19 @@ impl Eval for ast::Expr<'_> {
Self::Closure(v) => v.eval(vm), Self::Closure(v) => v.eval(vm),
Self::Unary(v) => v.eval(vm), Self::Unary(v) => v.eval(vm),
Self::Binary(v) => v.eval(vm), Self::Binary(v) => v.eval(vm),
Self::Let(v) => v.eval(vm), Self::LetBinding(v) => v.eval(vm),
Self::DestructAssign(v) => v.eval(vm), Self::DestructAssignment(v) => v.eval(vm),
Self::Set(_) => bail!(forbidden("set")), Self::SetRule(_) => bail!(forbidden("set")),
Self::Show(_) => bail!(forbidden("show")), Self::ShowRule(_) => bail!(forbidden("show")),
Self::Contextual(v) => v.eval(vm).map(Value::Content), Self::Contextual(v) => v.eval(vm).map(Value::Content),
Self::Conditional(v) => v.eval(vm), Self::Conditional(v) => v.eval(vm),
Self::While(v) => v.eval(vm), Self::WhileLoop(v) => v.eval(vm),
Self::For(v) => v.eval(vm), Self::ForLoop(v) => v.eval(vm),
Self::Import(v) => v.eval(vm), Self::ModuleImport(v) => v.eval(vm),
Self::Include(v) => v.eval(vm).map(Value::Content), Self::ModuleInclude(v) => v.eval(vm).map(Value::Content),
Self::Break(v) => v.eval(vm), Self::LoopBreak(v) => v.eval(vm),
Self::Continue(v) => v.eval(vm), Self::LoopContinue(v) => v.eval(vm),
Self::Return(v) => v.eval(vm), Self::FuncReturn(v) => v.eval(vm),
}? }?
.spanned(span); .spanned(span);

View File

@ -33,7 +33,7 @@ fn eval_markup<'a>(
while let Some(expr) = exprs.next() { while let Some(expr) = exprs.next() {
match expr { match expr {
ast::Expr::Set(set) => { ast::Expr::SetRule(set) => {
let styles = set.eval(vm)?; let styles = set.eval(vm)?;
if vm.flow.is_some() { if vm.flow.is_some() {
break; break;
@ -41,7 +41,7 @@ fn eval_markup<'a>(
seq.push(eval_markup(vm, exprs)?.styled_with_map(styles)) seq.push(eval_markup(vm, exprs)?.styled_with_map(styles))
} }
ast::Expr::Show(show) => { ast::Expr::ShowRule(show) => {
let recipe = show.eval(vm)?; let recipe = show.eval(vm)?;
if vm.flow.is_some() { if vm.flow.is_some() {
break; break;

View File

@ -45,7 +45,7 @@ impl Eval for ast::ShowRule<'_> {
let transform = self.transform(); let transform = self.transform();
let transform = match transform { let transform = match transform {
ast::Expr::Set(set) => Transformation::Style(set.eval(vm)?), ast::Expr::SetRule(set) => Transformation::Style(set.eval(vm)?),
expr => expr.eval(vm)?.cast::<Transformation>().at(transform.span())?, expr => expr.eval(vm)?.cast::<Transformation>().at(transform.span())?,
}; };

View File

@ -517,7 +517,7 @@ fn complete_imports(ctx: &mut CompletionContext) -> bool {
// "#import "path.typ": a, b, |". // "#import "path.typ": a, b, |".
if_chain! { if_chain! {
if let Some(prev) = ctx.leaf.prev_sibling(); if let Some(prev) = ctx.leaf.prev_sibling();
if let Some(ast::Expr::Import(import)) = prev.get().cast(); if let Some(ast::Expr::ModuleImport(import)) = prev.get().cast();
if let Some(ast::Imports::Items(items)) = import.imports(); if let Some(ast::Imports::Items(items)) = import.imports();
if let Some(source) = prev.children().find(|child| child.is::<ast::Expr>()); if let Some(source) = prev.children().find(|child| child.is::<ast::Expr>());
then { then {
@ -536,7 +536,7 @@ fn complete_imports(ctx: &mut CompletionContext) -> bool {
if let Some(grand) = parent.parent(); if let Some(grand) = parent.parent();
if grand.kind() == SyntaxKind::ImportItems; if grand.kind() == SyntaxKind::ImportItems;
if let Some(great) = grand.parent(); if let Some(great) = grand.parent();
if let Some(ast::Expr::Import(import)) = great.get().cast(); if let Some(ast::Expr::ModuleImport(import)) = great.get().cast();
if let Some(ast::Imports::Items(items)) = import.imports(); if let Some(ast::Imports::Items(items)) = import.imports();
if let Some(source) = great.children().find(|child| child.is::<ast::Expr>()); if let Some(source) = great.children().find(|child| child.is::<ast::Expr>());
then { then {
@ -677,10 +677,10 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
if let Some(args) = parent.get().cast::<ast::Args>(); if let Some(args) = parent.get().cast::<ast::Args>();
if let Some(grand) = parent.parent(); if let Some(grand) = parent.parent();
if let Some(expr) = grand.get().cast::<ast::Expr>(); if let Some(expr) = grand.get().cast::<ast::Expr>();
let set = matches!(expr, ast::Expr::Set(_)); let set = matches!(expr, ast::Expr::SetRule(_));
if let Some(callee) = match expr { if let Some(callee) = match expr {
ast::Expr::FuncCall(call) => Some(call.callee()), ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::Set(set) => Some(set.target()), ast::Expr::SetRule(set) => Some(set.target()),
_ => None, _ => None,
}; };
then { then {

View File

@ -232,7 +232,9 @@ pub fn deref_target(node: LinkedNode) -> Option<DerefTarget<'_>> {
ast::Expr::FuncCall(call) => { ast::Expr::FuncCall(call) => {
DerefTarget::Callee(expr_node.find(call.callee().span())?) DerefTarget::Callee(expr_node.find(call.callee().span())?)
} }
ast::Expr::Set(set) => DerefTarget::Callee(expr_node.find(set.target().span())?), ast::Expr::SetRule(set) => {
DerefTarget::Callee(expr_node.find(set.target().span())?)
}
ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::FieldAccess(_) => { ast::Expr::Ident(_) | ast::Expr::MathIdent(_) | ast::Expr::FieldAccess(_) => {
DerefTarget::VarAccess(expr_node) DerefTarget::VarAccess(expr_node)
} }

View File

@ -201,7 +201,7 @@ fn named_param_tooltip(world: &dyn IdeWorld, leaf: &LinkedNode) -> Option<Toolti
if let Some(expr) = grand_grand.cast::<ast::Expr>(); if let Some(expr) = grand_grand.cast::<ast::Expr>();
if let Some(ast::Expr::Ident(callee)) = match expr { if let Some(ast::Expr::Ident(callee)) = match expr {
ast::Expr::FuncCall(call) => Some(call.callee()), ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::Set(set) => Some(set.target()), ast::Expr::SetRule(set) => Some(set.target()),
_ => None, _ => None,
}; };

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,6 @@ use std::sync::Arc;
use ecow::{eco_format, eco_vec, EcoString, EcoVec}; use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use crate::ast::AstNode;
use crate::{FileId, Span, SyntaxKind}; use crate::{FileId, Span, SyntaxKind};
/// A node in the untyped syntax tree. /// A node in the untyped syntax tree.
@ -119,26 +118,6 @@ impl SyntaxNode {
} }
} }
/// Whether the node can be cast to the given AST node.
pub fn is<'a, T: AstNode<'a>>(&'a self) -> bool {
self.cast::<T>().is_some()
}
/// Try to convert the node to a typed AST node.
pub fn cast<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
T::from_untyped(self)
}
/// Cast the first child that can cast to the AST type `T`.
pub fn cast_first_match<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
self.children().find_map(Self::cast)
}
/// Cast the last child that can cast to the AST type `T`.
pub fn cast_last_match<'a, T: AstNode<'a>>(&'a self) -> Option<T> {
self.children().rev().find_map(Self::cast)
}
/// Whether the node or its children contain an error. /// Whether the node or its children contain an error.
pub fn erroneous(&self) -> bool { pub fn erroneous(&self) -> bool {
match &self.0 { match &self.0 {