[go: up one dir, main page]

aster 0.14.0

A libsyntax ast builder
use syntax::ast;
use syntax::attr::AttributesExt;
use syntax::codemap::{DUMMY_SP, Span, respan};
use syntax::ptr::P;

use invoke::{Invoke, Identity};

use expr::ExprBuilder;
use ident::ToIdent;
use item::ItemBuilder;
use pat::PatBuilder;
use ty::TyBuilder;

//////////////////////////////////////////////////////////////////////////////

pub struct StmtBuilder<F=Identity> {
    callback: F,
    span: Span,
    attrs: Vec<ast::Attribute>,
}

impl StmtBuilder {
    pub fn new() -> StmtBuilder {
        StmtBuilder::with_callback(Identity)
    }
}

impl<F> StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn with_callback(callback: F) -> Self {
        StmtBuilder {
            callback: callback,
            span: DUMMY_SP,
            attrs: vec![],
        }
    }

    pub fn build(self, stmt: ast::Stmt) -> F::Result {
        self.callback.invoke(stmt)
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build_stmt_kind(self, stmt_: ast::StmtKind) -> F::Result {
        let stmt = respan(self.span, stmt_);
        self.build(stmt)
    }

    pub fn build_let(self,
                     pat: P<ast::Pat>,
                     ty: Option<P<ast::Ty>>,
                     init: Option<P<ast::Expr>>) -> F::Result {
        let local = ast::Local {
            pat: pat,
            ty: ty,
            init: init,
            id: ast::DUMMY_NODE_ID,
            span: self.span,
            attrs: self.attrs.clone().into_thin_attrs(),
        };

        let decl = respan(self.span, ast::DeclKind::Local(P(local)));

        self.build_stmt_kind(ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn let_(self) -> PatBuilder<Self> {
        PatBuilder::with_callback(self)
    }

    pub fn let_id<I>(self, id: I) -> ExprBuilder<StmtLetIdBuilder<F>>
        where I: ToIdent,
    {
        let span = self.span;
        ExprBuilder::with_callback(StmtLetIdBuilder(self, id.to_ident())).span(span)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.build_stmt_kind(ast::StmtKind::Expr(expr, ast::DUMMY_NODE_ID))
    }

    pub fn expr(self) -> ExprBuilder<StmtExprBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtExprBuilder(self)).span(span)
    }

    pub fn semi(self) -> ExprBuilder<StmtSemiBuilder<F>> {
        let span = self.span;
        ExprBuilder::with_callback(StmtSemiBuilder(self)).span(span)
    }

    pub fn build_item(self, item: P<ast::Item>) -> F::Result {
        let decl = respan(self.span, ast::DeclKind::Item(item));
        self.build_stmt_kind(ast::StmtKind::Decl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn item(self) -> ItemBuilder<StmtItemBuilder<F>> {
        let span = self.span;
        ItemBuilder::with_callback(StmtItemBuilder(self)).span(span)
    }
}

impl<F> Invoke<P<ast::Pat>> for StmtBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetBuilder<F>;

    fn invoke(self, pat: P<ast::Pat>) -> StmtLetBuilder<F> {
        StmtLetBuilder {
            builder: self,
            pat: pat,
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetIdBuilder<F>(StmtBuilder<F>, ast::Ident);

impl<F> Invoke<P<ast::Expr>> for StmtLetIdBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.let_().id(self.1).build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtExprBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtExprBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtSemiBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtSemiBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_stmt_kind(ast::StmtKind::Semi(expr, ast::DUMMY_NODE_ID))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
}

impl<F> StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    fn build_ty(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        StmtLetTyBuilder {
            builder: self.builder,
            pat: self.pat,
            ty: ty,
        }
    }

    pub fn ty(self) -> TyBuilder<Self> {
        TyBuilder::with_callback(self)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, None, Some(expr))
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, None, None)
    }
}

impl<F> Invoke<P<ast::Ty>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = StmtLetTyBuilder<F>;

    fn invoke(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        self.build_ty(ty)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetTyBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
    ty: P<ast::Ty>,
}

impl<F> StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), None)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetTyBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), Some(expr))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtItemBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Item>> for StmtItemBuilder<F>
    where F: Invoke<ast::Stmt>,
{
    type Result = F::Result;

    fn invoke(self, item: P<ast::Item>) -> F::Result {
        self.0.build_item(item)
    }
}