10358: internal: Remove inherent methods from ast nodes that do non-syntactic complex tasks  r=Veykril a=Veykril



Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-09-26 14:49:25 +00:00 committed by GitHub
commit c51a3c78cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 392 additions and 365 deletions

View file

@ -1,6 +1,6 @@
//! Various extension methods to ast Expr Nodes, which are hard to code-generate.
use rowan::WalkEvent;
//!
//! These methods should only do simple, shallow tasks related to the syntax of the node itself.
use crate::{
ast::{
@ -28,139 +28,6 @@ impl ast::Expr {
| ast::Expr::EffectExpr(_)
)
}
pub fn name_ref(&self) -> Option<ast::NameRef> {
if let ast::Expr::PathExpr(expr) = self {
let path = expr.path()?;
let segment = path.segment()?;
let name_ref = segment.name_ref()?;
if path.qualifier().is_none() {
return Some(name_ref);
}
}
None
}
/// Preorder walk all the expression's child expressions.
pub fn walk(&self, cb: &mut dyn FnMut(ast::Expr)) {
self.preorder(&mut |ev| {
if let WalkEvent::Enter(expr) = ev {
cb(expr);
}
false
})
}
/// Preorder walk all the expression's child expressions preserving events.
/// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped.
/// Note that the subtree may already be skipped due to the context analysis this function does.
pub fn preorder(&self, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
let mut preorder = self.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
WalkEvent::Leave(node) => {
if let Some(expr) = ast::Expr::cast(node) {
cb(WalkEvent::Leave(expr));
}
continue;
}
};
match ast::Stmt::cast(node.clone()) {
// recursively walk the initializer, skipping potential const pat expressions
// let statements aren't usually nested too deeply so this is fine to recurse on
Some(ast::Stmt::LetStmt(l)) => {
if let Some(expr) = l.initializer() {
expr.preorder(cb);
}
preorder.skip_subtree();
}
// Don't skip subtree since we want to process the expression child next
Some(ast::Stmt::ExprStmt(_)) => (),
// This might be an expression
Some(ast::Stmt::Item(ast::Item::MacroCall(mcall))) => {
cb(WalkEvent::Enter(ast::Expr::MacroCall(mcall)));
preorder.skip_subtree();
}
// skip inner items which might have their own expressions
Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
None => {
// skip const args, those expressions are a different context
if ast::GenericArg::can_cast(node.kind()) {
preorder.skip_subtree();
} else if let Some(expr) = ast::Expr::cast(node) {
let is_different_context = match &expr {
ast::Expr::EffectExpr(effect) => {
matches!(
effect.effect(),
ast::Effect::Async(_)
| ast::Effect::Try(_)
| ast::Effect::Const(_)
)
}
ast::Expr::ClosureExpr(_) => true,
_ => false,
};
let skip = cb(WalkEvent::Enter(expr));
if skip || is_different_context {
preorder.skip_subtree();
}
}
}
}
}
}
/// Preorder walk all the expression's child patterns.
pub fn walk_patterns(&self, cb: &mut dyn FnMut(ast::Pat)) {
let mut preorder = self.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
WalkEvent::Leave(_) => continue,
};
match ast::Stmt::cast(node.clone()) {
Some(ast::Stmt::LetStmt(l)) => {
if let Some(pat) = l.pat() {
pat.walk(cb);
}
if let Some(expr) = l.initializer() {
expr.walk_patterns(cb);
}
preorder.skip_subtree();
}
// Don't skip subtree since we want to process the expression child next
Some(ast::Stmt::ExprStmt(_)) => (),
// skip inner items which might have their own patterns
Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
None => {
// skip const args, those are a different context
if ast::GenericArg::can_cast(node.kind()) {
preorder.skip_subtree();
} else if let Some(expr) = ast::Expr::cast(node.clone()) {
let is_different_context = match &expr {
ast::Expr::EffectExpr(effect) => {
matches!(
effect.effect(),
ast::Effect::Async(_)
| ast::Effect::Try(_)
| ast::Effect::Const(_)
)
}
ast::Expr::ClosureExpr(_) => true,
_ => false,
};
if is_different_context {
preorder.skip_subtree();
}
} else if let Some(pat) = ast::Pat::cast(node) {
preorder.skip_subtree();
pat.walk(cb);
}
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -374,6 +241,7 @@ impl ast::Literal {
.and_then(|e| e.into_token())
.unwrap()
}
pub fn kind(&self) -> LiteralKind {
let token = self.token();

View file

@ -1,11 +1,13 @@
//! Various extension methods to ast Nodes, which are hard to code-generate.
//! Extensions for various expressions live in a sibling `expr_extensions` module.
//!
//! These methods should only do simple, shallow tasks related to the syntax of the node itself.
use std::{borrow::Cow, fmt, iter::successors};
use itertools::Itertools;
use parser::SyntaxKind;
use rowan::{GreenNodeData, GreenTokenData, WalkEvent};
use rowan::{GreenNodeData, GreenTokenData};
use crate::{
ast::{
@ -56,66 +58,6 @@ impl ast::BlockExpr {
pub fn is_empty(&self) -> bool {
self.statements().next().is_none() && self.tail_expr().is_none()
}
pub fn as_lone_tail(&self) -> Option<ast::Expr> {
self.statements().next().is_none().then(|| self.tail_expr()).flatten()
}
}
impl ast::Pat {
/// Preorder walk all the pattern's sub patterns.
pub fn walk(&self, cb: &mut dyn FnMut(ast::Pat)) {
let mut preorder = self.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
WalkEvent::Leave(_) => continue,
};
let kind = node.kind();
match ast::Pat::cast(node) {
Some(pat @ ast::Pat::ConstBlockPat(_)) => {
preorder.skip_subtree();
cb(pat);
}
Some(pat) => {
cb(pat);
}
// skip const args
None if ast::GenericArg::can_cast(kind) => {
preorder.skip_subtree();
}
None => (),
}
}
}
}
impl ast::Type {
/// Preorder walk all the type's sub types.
pub fn walk(&self, cb: &mut dyn FnMut(ast::Type)) {
let mut preorder = self.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
WalkEvent::Leave(_) => continue,
};
let kind = node.kind();
match ast::Type::cast(node) {
Some(ty @ ast::Type::MacroType(_)) => {
preorder.skip_subtree();
cb(ty)
}
Some(ty) => {
cb(ty);
}
// skip const args
None if ast::ConstArg::can_cast(kind) => {
preorder.skip_subtree();
}
None => (),
}
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@ -443,7 +385,15 @@ impl ast::RecordExprField {
if let Some(name_ref) = self.name_ref() {
return Some(name_ref);
}
self.expr()?.name_ref()
if let ast::Expr::PathExpr(expr) = self.expr()? {
let path = expr.path()?;
let segment = path.segment()?;
let name_ref = segment.name_ref()?;
if path.qualifier().is_none() {
return Some(name_ref);
}
}
None
}
}
@ -721,29 +671,6 @@ impl ast::Visibility {
None => VisibilityKind::Pub,
}
}
pub fn is_eq_to(&self, other: &Self) -> bool {
match (self.kind(), other.kind()) {
(VisibilityKind::In(this), VisibilityKind::In(other)) => {
stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
(PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
| (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
| (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
(PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
lhs.text() == rhs.text()
}
_ => false,
})
})
}
(VisibilityKind::PubSelf, VisibilityKind::PubSelf)
| (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
| (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
| (VisibilityKind::Pub, VisibilityKind::Pub) => true,
_ => false,
}
}
}
impl ast::LifetimeParam {