[go: up one dir, main page]

aster 0.1.10

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

use attr::AttrBuilder;
use ident::ToIdent;
use invoke::{Invoke, Identity};
use ty::TyBuilder;

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

pub struct StructDefBuilder<F=Identity> {
    callback: F,
    span: Span,
    fields: Vec<ast::StructField>,
}

impl StructDefBuilder {
    pub fn new() -> Self {
        StructDefBuilder::new_with_callback(Identity)
    }
}

impl<F> StructDefBuilder<F>
    where F: Invoke<P<ast::StructDef>>
{
    pub fn new_with_callback(callback: F) -> Self {
        StructDefBuilder {
            callback: callback,
            span: DUMMY_SP,
            fields: vec![],
        }
    }

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

    pub fn with_field(mut self, field: ast::StructField) -> Self {
        self.fields.push(field);
        self
    }

    pub fn field<T>(self, id: T) -> TyBuilder<StructFieldBuilder<Self>>
        where T: ToIdent,
    {
        let span = self.span;
        let builder = StructFieldBuilder::named_with_callback(id, self).span(span);
        TyBuilder::new_with_callback(builder)
    }

    pub fn build(self) -> F::Result {
        self.callback.invoke(P(ast::StructDef {
            fields: self.fields,
            ctor_id: None,
        }))
    }
}

impl<F> Invoke<ast::StructField> for StructDefBuilder<F>
    where F: Invoke<P<ast::StructDef>>,
{
    type Result = Self;

    fn invoke(self, field: ast::StructField) -> Self {
        self.with_field(field)
    }
}

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

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

impl StructFieldBuilder {
    pub fn named<T>(name: T) -> Self
        where T: ToIdent,
    {
        StructFieldBuilder::named_with_callback(name, Identity)
    }

    pub fn unnamed() -> Self {
        StructFieldBuilder::unnamed_with_callback(Identity)
    }
}

impl<F> StructFieldBuilder<F>
    where F: Invoke<ast::StructField>,
{
    pub fn named_with_callback<T>(id: T, callback: F) -> Self
        where T: ToIdent,
    {
        let id = id.to_ident();
        StructFieldBuilder {
            callback: callback,
            span: DUMMY_SP,
            kind: ast::StructFieldKind::NamedField(id, ast::Inherited),
            attrs: vec![],
        }
    }

    pub fn unnamed_with_callback(callback: F) -> Self {
        StructFieldBuilder {
            callback: callback,
            span: DUMMY_SP,
            kind: ast::StructFieldKind::UnnamedField(ast::Inherited),
            attrs: vec![],
        }
    }

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

    pub fn pub_(mut self) -> Self {
        match self.kind {
            ast::StructFieldKind::NamedField(_, ref mut vis) => { *vis = ast::Public; }
            ast::StructFieldKind::UnnamedField(ref mut vis) => { *vis = ast::Public; }
        }
        self
    }

    pub fn attr(self) -> AttrBuilder<Self> {
        let span = self.span;
        AttrBuilder::new_with_callback(self).span(span)
    }

    pub fn build_ty(self, ty: P<ast::Ty>) -> F::Result {
        let field = ast::StructField_ {
            kind: self.kind,
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: self.attrs,
        };
        self.callback.invoke(respan(self.span, field))
    }

    pub fn ty(self) -> TyBuilder<Self> {
        let span = self.span;
        TyBuilder::new_with_callback(self).span(span)
    }
}

impl<F> Invoke<ast::Attribute> for StructFieldBuilder<F> {
    type Result = Self;

    fn invoke(mut self, attr: ast::Attribute) -> Self {
        self.attrs.push(attr);
        self
    }
}

impl<F> Invoke<P<ast::Ty>> for StructFieldBuilder<F>
    where F: Invoke<ast::StructField>,
{
    type Result = F::Result;

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