ripex 0.2.0

Multi-language structural parsing and fact extraction.
Documentation
use crate::rust::ast::*;

pub trait Fold {
    fn fold_expr(&mut self, expr: Expr) -> Expr;
    fn fold_stmt(&mut self, stmt: Stmt) -> Stmt;
    fn fold_item(&mut self, item: Item) -> Item;
    fn fold_pattern(&mut self, pat: Pattern) -> Pattern;
}

fn fold_block(folder: &mut dyn Fold, block: Block) -> Block {
    Block {
        stmts: block
            .stmts
            .into_iter()
            .map(|s| folder.fold_stmt(s))
            .collect(),
        span: block.span,
    }
}

pub fn fold_expr(folder: &mut dyn Fold, expr: Expr) -> Expr {
    match expr {
        Expr::Binary(left, op, right, span) => Expr::Binary(
            Box::new(folder.fold_expr(*left)),
            op,
            Box::new(folder.fold_expr(*right)),
            span,
        ),
        Expr::Unary(op, operand, span) => {
            Expr::Unary(op, Box::new(folder.fold_expr(*operand)), span)
        }
        Expr::Call(callee, args, span) => Expr::Call(
            Box::new(folder.fold_expr(*callee)),
            args.into_iter().map(|a| folder.fold_expr(a)).collect(),
            span,
        ),
        Expr::MethodCall(obj, name, args, span) => Expr::MethodCall(
            Box::new(folder.fold_expr(*obj)),
            name,
            args.into_iter().map(|a| folder.fold_expr(a)).collect(),
            span,
        ),
        Expr::Index(arr, idx, span) => Expr::Index(
            Box::new(folder.fold_expr(*arr)),
            Box::new(folder.fold_expr(*idx)),
            span,
        ),
        Expr::Field(obj, name, span) => Expr::Field(Box::new(folder.fold_expr(*obj)), name, span),
        Expr::Tuple(elems, span) => Expr::Tuple(
            elems.into_iter().map(|e| folder.fold_expr(e)).collect(),
            span,
        ),
        Expr::Array(elems, span) => Expr::Array(
            elems.into_iter().map(|e| folder.fold_expr(e)).collect(),
            span,
        ),
        Expr::Struct(name, fields, base, span) => Expr::Struct(
            name,
            fields,
            base.map(|b| Box::new(folder.fold_expr(*b))),
            span,
        ),
        Expr::Closure(params, body, span) => {
            Expr::Closure(params, Box::new(folder.fold_expr(*body)), span)
        }
        Expr::Block(b, span) => Expr::Block(Box::new(fold_block(folder, *b)), span),
        Expr::If(cond, body, alt, span) => Expr::If(
            Box::new(folder.fold_expr(*cond)),
            Box::new(fold_block(folder, *body)),
            alt.map(|a| Box::new(folder.fold_expr(*a))),
            span,
        ),
        Expr::Match(expr_, arms, span) => {
            Expr::Match(Box::new(folder.fold_expr(*expr_)), arms, span)
        }
        Expr::While(cond, body, span) => Expr::While(
            Box::new(folder.fold_expr(*cond)),
            Box::new(fold_block(folder, *body)),
            span,
        ),
        Expr::Loop(body, span) => Expr::Loop(Box::new(fold_block(folder, *body)), span),
        Expr::For(pat, iter, body, span) => Expr::For(
            Box::new(folder.fold_pattern(*pat)),
            Box::new(folder.fold_expr(*iter)),
            Box::new(fold_block(folder, *body)),
            span,
        ),
        Expr::Return(e, span) => Expr::Return(e.map(|e| Box::new(folder.fold_expr(*e))), span),
        Expr::Break(e, span) => Expr::Break(e.map(|e| Box::new(folder.fold_expr(*e))), span),
        Expr::Paren(e, span) => Expr::Paren(Box::new(folder.fold_expr(*e)), span),
        Expr::Async(e, span) => Expr::Async(Box::new(folder.fold_expr(*e)), span),
        Expr::Await(e, span) => Expr::Await(Box::new(folder.fold_expr(*e)), span),
        Expr::Ref(e, mut_, span) => Expr::Ref(Box::new(folder.fold_expr(*e)), mut_, span),
        Expr::Deref(e, span) => Expr::Deref(Box::new(folder.fold_expr(*e)), span),
        Expr::Cast(e, t, span) => Expr::Cast(Box::new(folder.fold_expr(*e)), t, span),
        other => other,
    }
}

pub fn fold_stmt(folder: &mut dyn Fold, stmt: Stmt) -> Stmt {
    match stmt {
        Stmt::Expr(e, span) => Stmt::Expr(folder.fold_expr(e), span),
        Stmt::Item(item, span) => Stmt::Item(folder.fold_item(item), span),
        Stmt::Let(l, span) => Stmt::Let(
            LetDecl {
                pattern: folder.fold_pattern(l.pattern),
                mutable: l.mutable,
                type_ann: l.type_ann,
                init: l.init.map(|i| Box::new(folder.fold_expr(*i))),
                span,
            },
            span,
        ),
        Stmt::Empty(_) => stmt,
    }
}

pub fn fold_item(folder: &mut dyn Fold, item: Item) -> Item {
    match item {
        Item::Fn(f, span) => Item::Fn(
            FnDecl {
                name: f.name,
                generics: f.generics,
                params: f.params,
                return_type: f.return_type,
                body: f.body.map(|b| fold_block(folder, b)),
                visibility: f.visibility,
                is_async: f.is_async,
                is_unsafe: f.is_unsafe,
                is_extern: f.is_extern,
                span,
            },
            span,
        ),
        Item::Mod(m, span) => Item::Mod(
            ModDecl {
                name: m.name,
                items: m.items.into_iter().map(|i| folder.fold_item(i)).collect(),
                visibility: m.visibility,
                span,
            },
            span,
        ),
        Item::Impl(imp, span) => Item::Impl(
            ImplBlock {
                trait_name: imp.trait_name,
                type_name: imp.type_name,
                methods: imp
                    .methods
                    .into_iter()
                    .map(|m| FnDecl {
                        name: m.name,
                        generics: m.generics,
                        params: m.params,
                        return_type: m.return_type,
                        body: m.body.map(|b| fold_block(folder, b)),
                        visibility: m.visibility,
                        is_async: m.is_async,
                        is_unsafe: m.is_unsafe,
                        is_extern: m.is_extern,
                        span: m.span,
                    })
                    .collect(),
                span,
            },
            span,
        ),
        other => other,
    }
}

pub fn fold_pattern(folder: &mut dyn Fold, pat: Pattern) -> Pattern {
    match pat {
        Pattern::Tuple(pats, span) => Pattern::Tuple(
            pats.into_iter().map(|p| folder.fold_pattern(p)).collect(),
            span,
        ),
        Pattern::Struct(name, fields, span) => Pattern::Struct(name, fields, span),
        Pattern::Range(low, high, span) => Pattern::Range(
            Box::new(folder.fold_pattern(*low)),
            Box::new(folder.fold_pattern(*high)),
            span,
        ),
        Pattern::Or(pats, span) => Pattern::Or(
            pats.into_iter().map(|p| folder.fold_pattern(p)).collect(),
            span,
        ),
        Pattern::Ref(pat, mut_, span) => {
            Pattern::Ref(Box::new(folder.fold_pattern(*pat)), mut_, span)
        }
        Pattern::Slice(pats, span) => Pattern::Slice(
            pats.into_iter().map(|p| folder.fold_pattern(p)).collect(),
            span,
        ),
        other => other,
    }
}