php_parser/ast/
locator.rs1use crate::ast::visitor::{Visitor, walk_class_member, walk_expr, walk_stmt};
2use crate::ast::*;
3use crate::span::Span;
4
5#[derive(Debug, Clone, Copy)]
6pub enum AstNode<'ast> {
7 Stmt(StmtId<'ast>),
8 Expr(ExprId<'ast>),
9 ClassMember(&'ast ClassMember<'ast>),
10}
11
12impl<'ast> AstNode<'ast> {
13 pub fn span(&self) -> Span {
14 match self {
15 AstNode::Stmt(s) => s.span(),
16 AstNode::Expr(e) => e.span(),
17 AstNode::ClassMember(m) => match m {
18 ClassMember::Property { span, .. } => *span,
19 ClassMember::PropertyHook { span, .. } => *span,
20 ClassMember::Method { span, .. } => *span,
21 ClassMember::Const { span, .. } => *span,
22 ClassMember::TraitUse { span, .. } => *span,
23 ClassMember::Case { span, .. } => *span,
24 },
25 }
26 }
27}
28
29pub struct Locator<'ast> {
30 target: usize,
31 pub path: Vec<AstNode<'ast>>,
32}
33
34impl<'ast> Locator<'ast> {
35 pub fn new(target: usize) -> Self {
36 Self {
37 target,
38 path: Vec::new(),
39 }
40 }
41
42 pub fn find(program: &'ast Program<'ast>, target: usize) -> Vec<AstNode<'ast>> {
43 let mut locator = Self::new(target);
44 locator.visit_program(program);
45 locator.path
46 }
47}
48
49impl<'ast> Visitor<'ast> for Locator<'ast> {
50 fn visit_stmt(&mut self, stmt: StmtId<'ast>) {
51 let span = stmt.span();
52 if span.start <= self.target && self.target <= span.end {
53 self.path.push(AstNode::Stmt(stmt));
54 walk_stmt(self, stmt);
55 }
56 }
57
58 fn visit_expr(&mut self, expr: ExprId<'ast>) {
59 let span = expr.span();
60 if span.start <= self.target && self.target <= span.end {
61 self.path.push(AstNode::Expr(expr));
62 walk_expr(self, expr);
63 }
64 }
65
66 fn visit_class_member(&mut self, member: &'ast ClassMember<'ast>) {
67 let span = match member {
68 ClassMember::Property { span, .. } => *span,
69 ClassMember::PropertyHook { span, .. } => *span,
70 ClassMember::Method { span, .. } => *span,
71 ClassMember::Const { span, .. } => *span,
72 ClassMember::TraitUse { span, .. } => *span,
73 ClassMember::Case { span, .. } => *span,
74 };
75
76 if span.start <= self.target && self.target <= span.end {
77 self.path.push(AstNode::ClassMember(member));
78 walk_class_member(self, member);
79 }
80 }
81}