[Impl] Ast Visitor (#1769)

* visitor pattern

* merge upstream, regen grammar readme

* rename reducer to passes

* update comments to properly reflect visitor

* fmt and clippy fixes

* fix comments

Co-authored-by: collin <16715212+collinc97@users.noreply.github.com>
This commit is contained in:
gluax 2022-04-22 16:05:50 -07:00 committed by GitHub
parent a7b2cbd9e2
commit 124e6b2e9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 296 additions and 8 deletions

View File

@ -43,12 +43,12 @@ pub use self::input::*;
pub mod pass;
pub use self::pass::*;
pub mod passes;
pub use self::passes::*;
pub mod program;
pub use self::program::*;
pub mod reducer;
pub use self::reducer::*;
pub mod statements;
pub use self::statements::*;

View File

@ -14,13 +14,19 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! This module contains both a Director to reconstruct the AST
//! which maps over every node of the AST and calls a reducer.
//! The Trait for a reducer are methods that can be overridden
//! to make changes to how AST nodes are rebuilt.
//! This module contains both a Reducer and Visitor design pattern.
//! These both iterate over the AST.
// todo @gluax: Move the files in this module into `leo-passes` in a future PR.
pub mod reconstructing_reducer;
pub use reconstructing_reducer::*;
pub mod reconstructing_director;
pub use reconstructing_director::*;
pub mod visitor;
pub use visitor::*;
pub mod visitor_director;
pub use visitor_director::*;

View File

@ -0,0 +1,112 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! This module contains Visitor traits for the AST.
use crate::*;
pub enum VisitResult {
VisitChildren,
SkipChildren,
}
impl Default for VisitResult {
fn default() -> Self {
VisitResult::VisitChildren
}
}
pub trait ExpressionVisitor {
fn visit_expression(&mut self, _input: &Expression) -> VisitResult {
Default::default()
}
fn visit_identifer(&mut self, _input: &Identifier) -> VisitResult {
Default::default()
}
fn visit_value(&mut self, _input: &ValueExpression) -> VisitResult {
Default::default()
}
fn visit_binary(&mut self, _input: &BinaryExpression) -> VisitResult {
Default::default()
}
fn visit_unary(&mut self, _input: &UnaryExpression) -> VisitResult {
Default::default()
}
fn visit_ternary(&mut self, _input: &TernaryExpression) -> VisitResult {
Default::default()
}
fn visit_call(&mut self, _input: &CallExpression) -> VisitResult {
Default::default()
}
fn visit_err(&mut self, _input: &ErrExpression) -> VisitResult {
Default::default()
}
}
pub trait StatementVisitor {
fn visit_statement(&mut self, _input: &Statement) -> VisitResult {
Default::default()
}
fn visit_return(&mut self, _input: &ReturnStatement) -> VisitResult {
Default::default()
}
fn visit_definition(&mut self, _input: &DefinitionStatement) -> VisitResult {
Default::default()
}
fn visit_assign(&mut self, _input: &AssignStatement) -> VisitResult {
Default::default()
}
fn visit_conditional(&mut self, _input: &ConditionalStatement) -> VisitResult {
Default::default()
}
fn visit_iteration(&mut self, _input: &IterationStatement) -> VisitResult {
Default::default()
}
fn visit_console(&mut self, _input: &ConsoleStatement) -> VisitResult {
Default::default()
}
fn visit_expression_statement(&mut self, _input: &ExpressionStatement) -> VisitResult {
Default::default()
}
fn visit_block(&mut self, _input: &Block) -> VisitResult {
Default::default()
}
}
pub trait ProgramVisitor {
fn visit_program(&mut self, _input: &Program) -> VisitResult {
Default::default()
}
fn visit_function(&mut self, _input: &Function) -> VisitResult {
Default::default()
}
}

View File

@ -0,0 +1,170 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! This module contains Visitor trait implementations for the AST.
//! It implements default methods for each node to be made
//! given the type of node its visiting.
// temporary till we use in another pr.
#![allow(dead_code)]
use crate::*;
pub struct VisitorDirector<V: ExpressionVisitor> {
visitor: V,
}
impl<V: ExpressionVisitor> VisitorDirector<V> {
pub fn new(visitor: V) -> Self {
Self { visitor }
}
pub fn visitor(self) -> V {
self.visitor
}
pub fn visit_expression(&mut self, input: &Expression) {
if let VisitResult::VisitChildren = self.visitor.visit_expression(input) {
match input {
Expression::Identifier(_) => {}
Expression::Value(_) => {}
Expression::Binary(expr) => self.visit_binary(expr),
Expression::Unary(expr) => self.visit_unary(expr),
Expression::Ternary(expr) => self.visit_ternary(expr),
Expression::Call(expr) => self.visit_call(expr),
Expression::Err(_) => {}
}
}
}
pub fn visit_binary(&mut self, input: &BinaryExpression) {
if let VisitResult::VisitChildren = self.visitor.visit_binary(input) {
self.visit_expression(&input.left);
self.visit_expression(&input.right);
}
}
pub fn visit_unary(&mut self, input: &UnaryExpression) {
if let VisitResult::VisitChildren = self.visitor.visit_unary(input) {
self.visit_expression(&input.inner);
}
}
pub fn visit_ternary(&mut self, input: &TernaryExpression) {
if let VisitResult::VisitChildren = self.visitor.visit_ternary(input) {
self.visit_expression(&input.condition);
self.visit_expression(&input.if_true);
self.visit_expression(&input.if_false);
}
}
pub fn visit_call(&mut self, input: &CallExpression) {
if let VisitResult::VisitChildren = self.visitor.visit_call(input) {
self.visit_expression(&input.function);
input.arguments.iter().for_each(|expr| self.visit_expression(expr));
}
}
}
impl<V: ExpressionVisitor + StatementVisitor> VisitorDirector<V> {
fn visit_statement(&mut self, input: &Statement) {
if let VisitResult::VisitChildren = self.visitor.visit_statement(input) {
match input {
Statement::Return(stmt) => self.visit_return(stmt),
Statement::Definition(stmt) => self.visit_definition(stmt),
Statement::Assign(stmt) => self.visit_assign(stmt),
Statement::Conditional(stmt) => self.visit_conditional(stmt),
Statement::Iteration(stmt) => self.visit_iteration(stmt),
Statement::Console(stmt) => self.visit_console(stmt),
Statement::Expression(stmt) => self.visit_expression_statement(stmt),
Statement::Block(stmt) => self.visit_block(stmt),
}
}
}
fn visit_return(&mut self, input: &ReturnStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_return(input) {
self.visit_expression(&input.expression);
}
}
fn visit_definition(&mut self, input: &DefinitionStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_definition(input) {
self.visit_expression(&input.value);
}
}
fn visit_assign(&mut self, input: &AssignStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_assign(input) {
self.visit_expression(&input.value);
}
}
fn visit_conditional(&mut self, input: &ConditionalStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_conditional(input) {
self.visit_expression(&input.condition);
self.visit_block(&input.block);
if let Some(stmt) = input.next.as_ref() {
self.visit_statement(stmt);
}
}
}
fn visit_iteration(&mut self, input: &IterationStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_iteration(input) {
self.visit_expression(&input.start);
self.visit_expression(&input.stop);
self.visit_block(&input.block);
}
}
fn visit_console(&mut self, input: &ConsoleStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_console(input) {
if let ConsoleFunction::Assert(expr) = &input.function {
self.visit_expression(expr);
}
}
}
fn visit_expression_statement(&mut self, input: &ExpressionStatement) {
if let VisitResult::VisitChildren = self.visitor.visit_expression_statement(input) {
self.visit_expression(&input.expression);
}
}
fn visit_block(&mut self, input: &Block) {
if let VisitResult::VisitChildren = self.visitor.visit_block(input) {
input.statements.iter().for_each(|stmt| self.visit_statement(stmt));
}
}
}
impl<V: ExpressionVisitor + ProgramVisitor + StatementVisitor> VisitorDirector<V> {
fn visit_program(&mut self, input: &Program) {
if let VisitResult::VisitChildren = self.visitor.visit_program(input) {
input
.functions
.values()
.for_each(|function| self.visit_function(function));
}
}
fn visit_function(&mut self, input: &Function) {
if let VisitResult::VisitChildren = self.visitor.visit_function(input) {
self.visit_block(&input.block);
}
}
}

View File

@ -46,7 +46,7 @@ fn eat_identifier(input: &mut Peekable<impl Iterator<Item = char>>) -> Option<St
///
fn is_bidi_override(c: char) -> bool {
let i = c as u32;
return (0x202A <= i && i <= 0x202E) || (0x2066 <= i && i <= 0x2069);
(0x202A..=0x202E).contains(&i) || (0x2066..=0x2069).contains(&i)
}
impl Token {

Binary file not shown.