-
-
Notifications
You must be signed in to change notification settings - Fork 411
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c72e4c2
commit ad14efe
Showing
7 changed files
with
241 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//! Javascript Abstract Syntax Tree visitors. | ||
//! | ||
//! This module contains visitors which can be used to inspect or modify AST nodes. This allows for | ||
//! fine-grained manipulation of ASTs for analysis, rewriting, or instrumentation. | ||
#[cfg(doc)] | ||
use super::statement_list::StatementListVisitor; | ||
|
||
/// `Try`-like conditional unwrapping of `ControlFlow`. | ||
#[macro_export] | ||
macro_rules! try_break { | ||
($expr:expr) => { | ||
match $expr { | ||
core::ops::ControlFlow::Continue(c) => c, | ||
core::ops::ControlFlow::Break(b) => return core::ops::ControlFlow::Break(b), | ||
} | ||
}; | ||
} | ||
|
||
use crate::syntax::ast::{Declaration, Statement, StatementList, StatementListItem}; | ||
|
||
macro_rules! define_visit { | ||
($fn_name:ident, $type_name:ident) => { | ||
fn $fn_name(&mut self, node: &'ast $type_name) -> core::ops::ControlFlow<Self::BreakTy> { | ||
node.visit_with(self) | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! define_visit_mut { | ||
($fn_name:ident, $type_name:ident) => { | ||
fn $fn_name( | ||
&mut self, | ||
node: &'ast mut $type_name, | ||
) -> core::ops::ControlFlow<Self::BreakTy> { | ||
node.visit_with_mut(self) | ||
} | ||
}; | ||
} | ||
|
||
/// Represents an AST visitor. | ||
/// | ||
/// This implementation is based largely on [chalk](https://github.com/rust-lang/chalk/blob/23d39c90ceb9242fbd4c43e9368e813e7c2179f7/chalk-ir/src/visit.rs)'s | ||
/// visitor pattern. | ||
#[allow(unused_variables)] | ||
#[allow(missing_docs)] | ||
pub trait Visitor<'ast>: Sized { | ||
/// Type which will be propagated from the visitor if completing early. | ||
type BreakTy; | ||
|
||
define_visit!(visit_statement_list, StatementList); | ||
define_visit!(visit_statement_list_item, StatementListItem); | ||
define_visit!(visit_statement, Statement); | ||
define_visit!(visit_declaration, Declaration); | ||
} | ||
|
||
/// Represents an AST visitor which can modify AST content. | ||
/// | ||
/// This implementation is based largely on [chalk](https://github.com/rust-lang/chalk/blob/23d39c90ceb9242fbd4c43e9368e813e7c2179f7/chalk-ir/src/visit.rs)'s | ||
/// visitor pattern. | ||
#[allow(unused_variables)] | ||
#[allow(missing_docs)] | ||
pub trait VisitorMut<'ast>: Sized { | ||
/// Type which will be propagated from the visitor if completing early. | ||
type BreakTy; | ||
|
||
define_visit_mut!(visit_statement_list_mut, StatementList); | ||
define_visit_mut!(visit_statement_list_item_mut, StatementListItem); | ||
define_visit_mut!(visit_statement_mut, Statement); | ||
define_visit_mut!(visit_declaration_mut, Declaration); | ||
} | ||
|
||
/// Denotes that a type may be visited, providing a method which allows a visitor to traverse its | ||
/// private fields. | ||
pub trait VisitWith<V> { | ||
/// Visit this node with the provided visitor. | ||
fn visit_with<'a>(&'a self, visitor: &mut V) -> core::ops::ControlFlow<V::BreakTy> | ||
where | ||
V: Visitor<'a>; | ||
|
||
/// Visit this node with the provided visitor mutably, allowing the visitor to modify private | ||
/// fields. | ||
fn visit_with_mut<'a>(&'a mut self, visitor: &mut V) -> core::ops::ControlFlow<V::BreakTy> | ||
where | ||
V: VisitorMut<'a>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
use boa_engine::syntax::ast::visitor::{VisitWith, Visitor}; | ||
use boa_engine::syntax::ast::{Declaration, Statement, StatementList, StatementListItem}; | ||
use boa_engine::syntax::Parser; | ||
use boa_engine::Context; | ||
use std::convert::Infallible; | ||
use std::fs::File; | ||
use std::io::BufReader; | ||
use core::ops::ControlFlow; | ||
|
||
#[derive(Debug, Clone, Default)] | ||
struct PrinterVisitor { | ||
indent: String, | ||
} | ||
|
||
impl<'ast> Visitor<'ast> for PrinterVisitor { | ||
type BreakTy = Infallible; | ||
|
||
fn visit_statement_list(&mut self, node: &'ast StatementList) -> ControlFlow<Self::BreakTy> { | ||
println!( | ||
"{}StatementList (strict: {}) {{", | ||
self.indent, | ||
node.strict() | ||
); | ||
self.indent.push(' '); | ||
let res = node.visit_with(self); | ||
self.indent.pop(); | ||
println!("{}}}", self.indent); | ||
res | ||
} | ||
|
||
fn visit_statement_list_item( | ||
&mut self, | ||
node: &'ast StatementListItem, | ||
) -> ControlFlow<Self::BreakTy> { | ||
print!("{}StatementListItem: ", self.indent); | ||
self.indent.push(' '); | ||
let res = node.visit_with(self); | ||
self.indent.pop(); | ||
res | ||
} | ||
|
||
fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> { | ||
println!("Statement: {:?}", node); | ||
ControlFlow::Continue(()) | ||
} | ||
|
||
fn visit_declaration(&mut self, node: &'ast Declaration) -> ControlFlow<Self::BreakTy> { | ||
println!("Declaration: {:?}", node); | ||
ControlFlow::Continue(()) | ||
} | ||
} | ||
|
||
fn main() { | ||
let mut parser = Parser::new(BufReader::new( | ||
File::open("boa_examples/scripts/calctest.js").unwrap(), | ||
)); | ||
let mut ctx = Context::default(); | ||
|
||
let statements = parser.parse_all(&mut ctx).unwrap(); | ||
|
||
let mut visitor = PrinterVisitor::default(); | ||
|
||
visitor.visit_statement_list(&statements); | ||
} |