luaparse 0.2.0

A Lua 5.3 parser
Documentation
//! The visitor trait.
//!
//! Defines the `VisitorMut` trait for traversing the syntax tree.
//!
//! ```rust
//! # use luaparse::{parse, AstDescend, VisitorMut};
//! # use luaparse::ast::*;
//! struct ExprCounter {
//!     count: usize,
//! }
//!
//! impl ExprCounter {
//!     fn new() -> Self {
//!         Self {
//!             count: 0,
//!         }
//!     }
//!
//!     fn count(&self) -> usize {
//!         self.count
//!     }
//! }
//!
//! impl<'a> VisitorMut<'a> for ExprCounter {
//!     fn visit_expr(&mut self, expr: &mut Expr<'a>) {
//!         self.count += 1;
//!         expr.descend_mut(self);
//!     }
//! }
//!
//! let buf = "local a = {1, 2, 3, [4] = 1}";
//! let mut chunk = parse(buf).unwrap();
//! let mut counter = ExprCounter::new();
//! counter.visit_block(&mut chunk);
//! assert_eq!(counter.count(), 6);
//! ```

use crate::ast::*;

/// The trait implemented by non-terminal syntax tree nodes to walk through the children of the
/// node.
pub trait AstDescend<'a> {
    fn descend_mut<T: VisitorMut<'a>>(&mut self, visitor: &mut T);
}

macro_rules! visitor {
    (Descend: { $( $name1:ident ( $arg1:ident: $ty1:ty ) , )+ };
     Terminal: { $( $name2:ident ( $arg2:ident: $ty2:ty ) , )+ };) => {
        /// The trait intended to be implemented by visitors.
        pub trait VisitorMut<'a>
        where
            Self: Sized,
        {
            $(
                /// Visit a syntax node.
                ///
                /// This node is non-terminal and implements `AstDescend`. If you're overring this
                /// function, call `descend_mut(self)` manually.
                ///
                /// The default behavior: call `descend_mut(self)`.
                fn $name1(&mut self, $arg1: $ty1) {
                    $arg1.descend_mut(self);
                }
            )+
            $(
                /// Visit a syntax node.
                ///
                /// This not is terminal and does not implement `AstDescend`.
                ///
                /// The default behavior: do nothing.
                #[allow(unused_variables)]
                fn $name2(&mut self, $arg2: $ty2) {}
            )+
        }
    };
}

visitor! {
    Descend: {
        visit_expr(expr: &mut Expr<'a>),
        visit_prefix_expr(prefix_expr: &mut PrefixExpr<'a>),
        visit_var_field(var_field: &mut VarField<'a>),
        visit_table_constructor(table_constructor: &mut TableConstructor<'a>),
        visit_callee(callee: &mut FunctionCallee<'a>),
        visit_args(args: &mut FunctionArgs<'a>),
        visit_var(var: &mut Var<'a>),
        visit_function_call(function_call: &mut FunctionCall<'a>),
        visit_un_op(un_op: &mut UnOpExpr<'a>),
        visit_bin_op(bin_op: &mut BinOpExpr<'a>),
        visit_function_expr(function_expr: &mut FunctionExpr<'a>),
        visit_table_field(table_field: &mut TableField<'a>),
        visit_table_key(table_key: &mut TableKey<'a>),
        visit_stmt(stmt: &mut Statement<'a>),
        visit_block(block: &mut Block<'a>),
        visit_return_stmt(stmt: &mut ReturnStat<'a>),
        visit_assignment_stmt(stmt: &mut AssignmentStat<'a>),
        visit_while_stmt(stmt: &mut WhileStat<'a>),
        visit_for_stmt(stmt: &mut ForStat<'a>),
        visit_repeat_stmt(stmt: &mut RepeatStat<'a>),
        visit_local_decl(stmt: &mut LocalDeclarationStat<'a>),
        visit_function_decl(stmt: &mut FunctionDeclarationStat<'a>),
        visit_label_stmt(stmt: &mut LabelStat<'a>),
        visit_goto_stmt(stmt: &mut GotoStat<'a>),
        visit_if_stmt(stmt: &mut IfStat<'a>),
        visit_generic_for(stmt: &mut GenericFor<'a>),
        visit_numerical_for(stmt: &mut NumericalFor<'a>),
        visit_function_body(body: &mut FunctionBody<'a>),
    };

    Terminal: {
        visit_name(name: &mut Name<'a>),
        visit_string_lit(string_lit: &mut StringLit<'a>),
        visit_nil_lit(nil_lit: &mut NilLit<'a>),
        visit_boolean_lit(boolean_lit: &mut BooleanLit<'a>),
        visit_number_lit(number_lit: &mut NumberLit<'a>),
        visit_vararg(vararg: &mut Vararg<'a>),
        visit_empty_stmt(stmt: &mut EmptyStat<'a>),
        visit_break_stmt(stmt: &mut BreakStat<'a>),
    };
}