diff --git a/mk/crates.mk b/mk/crates.mk index aeb336f844fac..37ef4b5bc4380 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -53,7 +53,7 @@ TARGET_CRATES := libc std flate arena term \ serialize getopts collections test rand \ log graphviz core rbml alloc \ rustc_unicode rustc_bitflags \ - alloc_system + alloc_system aster RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics @@ -104,6 +104,7 @@ DEPS_rand := core DEPS_log := std DEPS_fmt_macros = std DEPS_alloc_system := core libc +DEPS_aster := std syntax TOOL_DEPS_compiletest := test getopts TOOL_DEPS_rustdoc := rustdoc diff --git a/src/libaster/attr.rs b/src/libaster/attr.rs new file mode 100644 index 0000000000000..170b80e20aea5 --- /dev/null +++ b/src/libaster/attr.rs @@ -0,0 +1,299 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::attr; +use syntax::codemap::{DUMMY_SP, Span, respan}; +use syntax::parse::token; +use syntax::ptr::P; + +use invoke::{Invoke, Identity}; +use lit::LitBuilder; +use str::ToInternedString; + +////////////////////////////////////////////////////////////////////////////// + +pub struct AttrBuilder { + callback: F, + span: Span, + style: ast::AttrStyle, + is_sugared_doc: bool, +} + +impl AttrBuilder { + pub fn new() -> Self { + AttrBuilder::new_with_callback(Identity) + } +} + +impl AttrBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self { + AttrBuilder { + callback: callback, + span: DUMMY_SP, + style: ast::AttrOuter, + is_sugared_doc: false, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn inner(mut self) -> Self { + self.style = ast::AttrInner; + self + } + + pub fn build_meta_item(self, item: P) -> F::Result { + let attr = respan(self.span, ast::Attribute_ { + id: attr::mk_attr_id(), + style: self.style, + value: item, + is_sugared_doc: self.is_sugared_doc, + }); + self.callback.invoke(attr) + } + + pub fn build_meta_item_(self, item: ast::MetaItem_) -> F::Result { + let item = P(respan(self.span, item)); + self.build_meta_item(item) + } + + pub fn word(self, word: T) -> F::Result + where T: ToInternedString + { + self.build_meta_item_(ast::MetaWord(word.to_interned_string())) + } + + pub fn list(self, word: T) -> AttrListBuilder + where T: ToInternedString + { + AttrListBuilder::new_with_callback(word, self) + } + + pub fn name_value(self, name: T) -> LitBuilder> + where T: ToInternedString, + { + LitBuilder::new_with_callback(AttrNameValueBuilder { + callback: self, + name: name.to_interned_string(), + }) + } + + pub fn automatically_derived(self) -> F::Result { + self.word("automatically_derived") + } + + pub fn inline(self) -> F::Result { + self.word("inline") + } + + pub fn test(self) -> F::Result { + self.word("test") + } + + pub fn allow(self, iter: I) -> F::Result + where I: IntoIterator, + T: ToInternedString, + { + self.list("allow").words(iter).build() + } + + pub fn warn(self, iter: I) -> F::Result + where I: IntoIterator, + T: ToInternedString, + { + self.list("warn").words(iter).build() + } + + pub fn deny(self, iter: I) -> F::Result + where I: IntoIterator, + T: ToInternedString, + { + self.list("deny").words(iter).build() + } + + pub fn features(self, iter: I) -> F::Result + where I: IntoIterator, + T: ToInternedString, + { + self.list("feature").words(iter).build() + } + + pub fn plugins(self, iter: I) -> F::Result + where I: IntoIterator, + T: ToInternedString, + { + self.list("plugin").words(iter).build() + } + + /** + * Create a #[doc = "..."] node. Note that callers of this must make sure to prefix their + * comments with either "///" or "/\*\*" if an outer comment, or "//!" or "/\*!" if an inner + * comment. + */ + pub fn doc(mut self, doc: T) -> F::Result + where T: ToInternedString, + { + self.is_sugared_doc = true; + self.name_value("doc").str(doc) + } +} + +impl Invoke> for AttrBuilder + where F: Invoke, +{ + type Result = F::Result; + + fn invoke(self, item: P) -> F::Result { + self.build_meta_item(item) + } +} + +impl Invoke for AttrBuilder + where F: Invoke, +{ + type Result = F::Result; + + fn invoke(self, item: ast::MetaItem_) -> F::Result { + self.build_meta_item_(item) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct AttrListBuilder { + callback: F, + span: Span, + name: token::InternedString, + items: Vec>, +} + +impl AttrListBuilder + where F: Invoke>, +{ + pub fn new_with_callback(name: T, callback: F) -> Self + where T: ToInternedString, + { + AttrListBuilder { + callback: callback, + span: DUMMY_SP, + name: name.to_interned_string(), + items: vec![], + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_meta_items(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.items.extend(iter); + self + } + + pub fn with_meta_items_(self, iter: I) -> Self + where I: IntoIterator, + { + let iter = iter.into_iter(); + let span = self.span; + self.with_meta_items(iter.map(|item| P(respan(span, item)))) + } + + pub fn with_meta_item(mut self, item: P) -> Self { + self.items.push(item); + self + } + + pub fn with_meta_item_(self, item: ast::MetaItem_) -> Self { + let span = self.span; + self.with_meta_item(P(respan(span, item))) + } + + pub fn words(self, iter: I) -> Self + where I: IntoIterator, + T: ToInternedString, + { + let iter = iter.into_iter(); + self.with_meta_items_(iter.map(|word| ast::MetaWord(word.to_interned_string()))) + } + + pub fn word(self, word: T) -> Self + where T: ToInternedString, + { + self.with_meta_item_(ast::MetaWord(word.to_interned_string())) + } + + pub fn list(self, name: T) -> AttrListBuilder + where T: ToInternedString, + { + AttrListBuilder::new_with_callback(name, self) + } + + pub fn name_value(self, name: T) -> LitBuilder> + where T: ToInternedString, + { + LitBuilder::new_with_callback(AttrNameValueBuilder { + callback: self, + name: name.to_interned_string(), + }) + } + + pub fn build(self) -> F::Result { + let item = respan(self.span, ast::MetaList(self.name, self.items)); + self.callback.invoke(P(item)) + } +} + +impl Invoke> for AttrListBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, item: P) -> Self { + self.with_meta_item(item) + } +} + +impl Invoke for AttrListBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, item: ast::MetaItem_) -> Self { + self.with_meta_item_(item) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct AttrNameValueBuilder { + callback: F, + name: token::InternedString, +} + +impl> Invoke> for AttrNameValueBuilder { + type Result = F::Result; + + fn invoke(self, value: P) -> F::Result { + let item = ast::MetaNameValue(self.name, (*value).clone()); + self.callback.invoke(item) + } +} + diff --git a/src/libaster/block.rs b/src/libaster/block.rs new file mode 100644 index 0000000000000..68918a23b100a --- /dev/null +++ b/src/libaster/block.rs @@ -0,0 +1,116 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ptr::P; + +use expr::ExprBuilder; +use invoke::{Invoke, Identity}; +use stmt::StmtBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct BlockBuilder { + callback: F, + span: Span, + stmts: Vec>, + block_check_mode: ast::BlockCheckMode, +} + +impl BlockBuilder { + pub fn new() -> Self { + BlockBuilder::new_with_callback(Identity) + } +} + +impl BlockBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + BlockBuilder { + callback: callback, + span: DUMMY_SP, + stmts: Vec::new(), + block_check_mode: ast::BlockCheckMode::DefaultBlock, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn unsafe_(mut self) -> Self { + let source = ast::UnsafeSource::CompilerGenerated; + self.block_check_mode = ast::BlockCheckMode::UnsafeBlock(source); + self + } + + pub fn with_stmts(mut self, iter: I) -> Self + where I: IntoIterator> + { + self.stmts.extend(iter); + self + } + + pub fn with_stmt(mut self, stmt: P) -> Self { + self.stmts.push(stmt); + self + } + + pub fn stmt(self) -> StmtBuilder { + StmtBuilder::new_with_callback(self) + } + + pub fn build_expr(self, expr: P) -> F::Result { + self.build_(Some(expr)) + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.build_(None) + } + + fn build_(self, expr: Option>) -> F::Result { + self.callback.invoke(P(ast::Block { + stmts: self.stmts, + expr: expr, + id: ast::DUMMY_NODE_ID, + rules: self.block_check_mode, + span: self.span, + })) + } +} + +impl Invoke> for BlockBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, stmt: P) -> Self { + self.with_stmt(stmt) + } +} + +impl Invoke> for BlockBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.build_expr(expr) + } +} diff --git a/src/libaster/constant.rs b/src/libaster/constant.rs new file mode 100644 index 0000000000000..6bc007681120a --- /dev/null +++ b/src/libaster/constant.rs @@ -0,0 +1,97 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ptr::P; + +use expr::ExprBuilder; +use invoke::{Invoke, Identity}; +use ty::TyBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct Const { + pub ty: P, + pub expr: Option>, +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ConstBuilder { + callback: F, + span: Span, + expr: Option>, +} + +impl ConstBuilder { + pub fn new() -> Self { + ConstBuilder::new_with_callback(Identity) + } +} + +impl ConstBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self + where F: Invoke, + { + ConstBuilder { + callback: callback, + span: DUMMY_SP, + expr: None, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_expr(mut self, expr: P) -> Self { + self.expr = Some(expr); + self + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build(self, ty: P) -> F::Result { + self.callback.invoke(Const { + ty: ty, + expr: self.expr, + }) + } +} + +impl Invoke> for ConstBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, expr: P) -> Self { + self.with_expr(expr) + } +} + +impl Invoke> for ConstBuilder + where F: Invoke, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build(ty) + } +} diff --git a/src/libaster/ctx.rs b/src/libaster/ctx.rs new file mode 100644 index 0000000000000..2ce0c2214cc39 --- /dev/null +++ b/src/libaster/ctx.rs @@ -0,0 +1,27 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::parse::token; + +////////////////////////////////////////////////////////////////////////////// + +#[derive(Copy)] +pub struct Ctx; + +impl Ctx { + pub fn new() -> Ctx { + Ctx + } + + pub fn intern(&self, name: &str) -> ast::Name { + token::intern(name) + } +} diff --git a/src/libaster/expr.rs b/src/libaster/expr.rs new file mode 100644 index 0000000000000..6df1e8cf4475b --- /dev/null +++ b/src/libaster/expr.rs @@ -0,0 +1,1093 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span, Spanned, respan}; +use syntax::ptr::P; + +use block::BlockBuilder; +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use lit::LitBuilder; +use path::{IntoPath, PathBuilder}; +use qpath::QPathBuilder; +use str::ToInternedString; +use ty::TyBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprBuilder { + callback: F, + span: Span, +} + +impl ExprBuilder { + pub fn new() -> Self { + ExprBuilder::new_with_callback(Identity) + } +} + +impl ExprBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + ExprBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn build(self, expr: P) -> F::Result { + self.callback.invoke(expr) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build_expr_(self, expr: ast::Expr_) -> F::Result { + let expr = P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: expr, + span: self.span, + }); + self.build(expr) + } + + pub fn build_path(self, path: ast::Path) -> F::Result { + self.build_expr_(ast::Expr_::ExprPath(None, path)) + } + + pub fn build_qpath(self, qself: ast::QSelf, path: ast::Path) -> F::Result { + self.build_expr_(ast::Expr_::ExprPath(Some(qself), path)) + } + + pub fn path(self) -> PathBuilder { + PathBuilder::new_with_callback(self) + } + + pub fn qpath(self) -> QPathBuilder { + QPathBuilder::new_with_callback(self) + } + + pub fn id(self, id: I) -> F::Result + where I: ToIdent + { + self.path().id(id).build() + } + + pub fn build_lit(self, lit: P) -> F::Result { + self.build_expr_(ast::Expr_::ExprLit(lit)) + } + + pub fn lit(self) -> LitBuilder { + LitBuilder::new_with_callback(self) + } + + pub fn bool(self, value: bool) -> F::Result { + self.lit().bool(value) + } + + pub fn int(self, value: i64) -> F::Result { + self.lit().int(value) + } + + pub fn isize(self, value: isize) -> F::Result { + self.lit().isize(value) + } + + pub fn i8(self, value: i8) -> F::Result { + self.lit().i8(value) + } + + pub fn i16(self, value: i16) -> F::Result { + self.lit().i16(value) + } + + pub fn i32(self, value: i32) -> F::Result { + self.lit().i32(value) + } + + pub fn i64(self, value: i64) -> F::Result { + self.lit().i64(value) + } + + pub fn usize(self, value: usize) -> F::Result { + self.lit().usize(value) + } + + pub fn u8(self, value: u8) -> F::Result { + self.lit().u8(value) + } + + pub fn u16(self, value: u16) -> F::Result { + self.lit().u16(value) + } + + pub fn u32(self, value: u32) -> F::Result { + self.lit().u32(value) + } + + pub fn u64(self, value: u64) -> F::Result { + self.lit().u64(value) + } + + pub fn f32(self, value: S) -> F::Result + where S: ToInternedString, + { + self.lit().f32(value) + } + + pub fn f64(self, value: S) -> F::Result + where S: ToInternedString, + { + self.lit().f64(value) + } + + pub fn str(self, value: S) -> F::Result + where S: ToInternedString, + { + self.lit().str(value) + } + + pub fn build_unary(self, unop: ast::UnOp, expr: P) -> F::Result { + self.build_expr_(ast::ExprUnary(unop, expr)) + } + + pub fn build_box(self, expr: P) -> F::Result { + self.build_unary(ast::UnUniq, expr) + } + + pub fn build_deref(self, expr: P) -> F::Result { + self.build_unary(ast::UnDeref, expr) + } + + pub fn build_not(self, expr: P) -> F::Result { + self.build_unary(ast::UnNot, expr) + } + + pub fn build_neg(self, expr: P) -> F::Result { + self.build_unary(ast::UnNeg, expr) + } + + pub fn unary(self, unop: ast::UnOp) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprUnaryBuilder { + builder: self, + unop: unop, + }) + } + + // FIXME: Disabled for now until the `box` keyword is stablized. + /* + pub fn box_(self) -> ExprBuilder> { + self.unary(ast::UnUniq) + } + */ + + pub fn deref(self) -> ExprBuilder> { + self.unary(ast::UnDeref) + } + + pub fn not(self) -> ExprBuilder> { + self.unary(ast::UnNot) + } + + pub fn neg(self) -> ExprBuilder> { + self.unary(ast::UnNeg) + } + + pub fn build_binary( + self, + binop: ast::BinOp_, + lhs: P, + rhs: P, + ) -> F::Result { + let binop = respan(self.span, binop); + self.build_expr_(ast::Expr_::ExprBinary(binop, lhs, rhs)) + } + + pub fn build_add(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiAdd, lhs, rhs) + } + + pub fn build_sub(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiSub, lhs, rhs) + } + + pub fn build_mul(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiMul, lhs, rhs) + } + + pub fn build_div(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiDiv, lhs, rhs) + } + + pub fn build_rem(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiRem, lhs, rhs) + } + + pub fn build_and(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiAnd, lhs, rhs) + } + + pub fn build_or(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiOr, lhs, rhs) + } + + pub fn build_bit_xor(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiBitXor, lhs, rhs) + } + + pub fn build_bit_and(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiBitAnd, lhs, rhs) + } + + pub fn build_bit_or(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiBitOr, lhs, rhs) + } + + pub fn build_shl(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiShl, lhs, rhs) + } + + pub fn build_shr(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiShr, lhs, rhs) + } + + pub fn build_eq(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiEq, lhs, rhs) + } + + pub fn build_lt(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiLt, lhs, rhs) + } + + pub fn build_le(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiLe, lhs, rhs) + } + + pub fn build_ne(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiNe, lhs, rhs) + } + + pub fn build_ge(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiGe, lhs, rhs) + } + + pub fn build_gt(self, lhs: P, rhs: P) -> F::Result { + self.build_binary(ast::BinOp_::BiGt, lhs, rhs) + } + + pub fn binary(self, binop: ast::BinOp_) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprBinaryLhsBuilder { + builder: self, + binop: binop, + }) + } + + pub fn add(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiAdd) + } + + pub fn sub(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiSub) + } + + pub fn mul(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiMul) + } + + pub fn div(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiDiv) + } + + pub fn rem(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiRem) + } + + pub fn and(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiAnd) + } + + pub fn or(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiOr) + } + + pub fn bit_xor(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiBitXor) + } + + pub fn bit_and(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiBitAnd) + } + + pub fn bit_or(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiBitOr) + } + + pub fn shl(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiShl) + } + + pub fn shr(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiShr) + } + + pub fn eq(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiEq) + } + + pub fn lt(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiLt) + } + + pub fn le(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiLe) + } + + pub fn ne(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiNe) + } + + pub fn ge(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiGe) + } + + pub fn gt(self) -> ExprBuilder> { + self.binary(ast::BinOp_::BiGt) + } + + pub fn addr_of(self) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprAddrOfBuilder { + builder: self, + mutability: ast::Mutability::MutImmutable, + }) + } + + pub fn mut_addr_of(self) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprAddrOfBuilder { + builder: self, + mutability: ast::Mutability::MutMutable, + }) + } + + pub fn unit(self) -> F::Result { + self.tuple().build() + } + + pub fn tuple(self) -> ExprTupleBuilder { + ExprTupleBuilder { + builder: self, + exprs: Vec::new(), + } + } + + pub fn struct_path

(self, path: P) -> ExprStructPathBuilder + where P: IntoPath, + { + let span = self.span; + let path = path.into_path(); + ExprStructPathBuilder { + builder: self, + span: span, + path: path, + fields: vec![], + } + } + + pub fn struct_(self) -> PathBuilder> { + PathBuilder::new_with_callback(ExprStructBuilder { + builder: self, + }) + } + + pub fn self_(self) -> F::Result { + self.id("self") + } + + pub fn none(self) -> F::Result { + self.path() + .global() + .id("std").id("option").id("Option").id("None") + .build() + } + + pub fn some(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("option").id("Option").id("Some") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn ok(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("result").id("Result").id("Ok") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn err(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("result").id("Result").id("Err") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn phantom_data(self) -> F::Result { + self.path() + .global() + .ids(&["std", "marker", "PhantomData"]) + .build() + } + + pub fn call(self) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprCallBuilder { + builder: self, + }) + } + + pub fn method_call(self, id: I) -> ExprBuilder> + where I: ToIdent, + { + let id = respan(self.span, id.to_ident()); + ExprBuilder::new_with_callback(ExprMethodCallBuilder { + builder: self, + id: id, + }) + } + + pub fn block(self) -> BlockBuilder { + BlockBuilder::new_with_callback(self) + } + + pub fn paren(self) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprParenBuilder { + builder: self, + }) + } + + pub fn field(self, id: I) -> ExprBuilder> + where I: ToIdent, + { + let id = respan(self.span, id.to_ident()); + ExprBuilder::new_with_callback(ExprFieldBuilder { + builder: self, + id: id, + }) + } + + pub fn tup_field(self, index: usize) -> ExprBuilder> { + let index = respan(self.span, index); + ExprBuilder::new_with_callback(ExprTupFieldBuilder { + builder: self, + index: index, + }) + } + + pub fn box_(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("boxed").id("Box").id("new") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn rc(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("rc").id("Rc").id("new") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn arc(self) -> ExprBuilder> { + let path = PathBuilder::new() + .global() + .id("std").id("arc").id("Arc").id("new") + .build(); + + ExprBuilder::new_with_callback(ExprPathBuilder { + builder: self, + path: path, + }) + } + + pub fn slice(self) -> ExprSliceBuilder { + ExprSliceBuilder { + builder: self, + exprs: Vec::new(), + } + } + + pub fn vec(self) -> ExprSliceBuilder> { + ExprBuilder::new_with_callback(ExprVecBuilder { + builder: self, + }).slice() + } +} + +impl Invoke> for ExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, lit: P) -> F::Result { + self.build_lit(lit) + } +} + +impl Invoke for ExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, path: ast::Path) -> F::Result { + self.build_path(path) + } +} + +impl Invoke<(ast::QSelf, ast::Path)> for ExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, (qself, path): (ast::QSelf, ast::Path)) -> F::Result { + self.build_qpath(qself, path) + } +} + +impl Invoke> for ExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, block: P) -> F::Result { + self.build_expr_(ast::ExprBlock(block)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprUnaryBuilder { + builder: ExprBuilder, + unop: ast::UnOp, +} + +impl Invoke> for ExprUnaryBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_unary(self.unop, expr) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprBinaryLhsBuilder { + builder: ExprBuilder, + binop: ast::BinOp_, +} + +impl Invoke> for ExprBinaryLhsBuilder + where F: Invoke>, +{ + type Result = ExprBuilder>; + + fn invoke(self, lhs: P) -> ExprBuilder> { + ExprBuilder::new_with_callback(ExprBinaryRhsBuilder { + builder: self.builder, + binop: self.binop, + lhs: lhs, + }) + } +} + +pub struct ExprBinaryRhsBuilder { + builder: ExprBuilder, + binop: ast::BinOp_, + lhs: P, +} + +impl Invoke> for ExprBinaryRhsBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, rhs: P) -> F::Result { + self.builder.build_binary(self.binop, self.lhs, rhs) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprTupleBuilder { + builder: ExprBuilder, + exprs: Vec>, +} + +impl>> ExprTupleBuilder + where F: Invoke> +{ + pub fn with_exprs(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.exprs.extend(iter); + self + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_expr_(ast::ExprTup(self.exprs)) + } +} + +impl Invoke> for ExprTupleBuilder + where F: Invoke> +{ + type Result = ExprTupleBuilder; + + fn invoke(mut self, expr: P) -> Self { + self.exprs.push(expr); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprStructBuilder { + builder: ExprBuilder, +} + +impl Invoke for ExprStructBuilder + where F: Invoke> +{ + type Result = ExprStructPathBuilder; + + fn invoke(self, path: ast::Path) -> ExprStructPathBuilder { + self.builder.struct_path(path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprStructPathBuilder { + builder: ExprBuilder, + span: Span, + path: ast::Path, + fields: Vec, +} + +impl ExprStructPathBuilder + where F: Invoke> +{ + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_fields(mut self, iter: I) -> Self + where I: IntoIterator, + { + self.fields.extend(iter); + self + } + + pub fn with_id_exprs(mut self, iter: I) -> Self + where I: IntoIterator)>, + { + for (id, expr) in iter { + self = self.field(id).build(expr); + } + + self + } + + pub fn field(self, id: I) -> ExprBuilder> + where I: ToIdent, + { + ExprBuilder::new_with_callback(ExprStructFieldBuilder { + builder: self, + id: id, + }) + } + + pub fn build_with(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + let expr_ = ast::ExprStruct(self.path, self.fields, None); + self.builder.build_expr_(expr_) + } +} + +impl Invoke> for ExprStructPathBuilder + where F: Invoke> +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + let expr_ = ast::ExprStruct(self.path, self.fields, Some(expr)); + self.builder.build_expr_(expr_) + } +} + +pub struct ExprStructFieldBuilder { + builder: ExprStructPathBuilder, + id: I, +} + +impl Invoke> for ExprStructFieldBuilder + where I: ToIdent, + F: Invoke>, +{ + type Result = ExprStructPathBuilder; + + fn invoke(mut self, expr: P) -> ExprStructPathBuilder { + let field = ast::Field { + ident: respan(self.builder.span, self.id.to_ident()), + expr: expr, + span: self.builder.span, + }; + self.builder.fields.push(field); + self.builder + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprCallBuilder { + builder: ExprBuilder, +} + +impl Invoke> for ExprCallBuilder + where F: Invoke>, +{ + type Result = ExprCallArgsBuilder; + + fn invoke(self, expr: P) -> ExprCallArgsBuilder { + ExprCallArgsBuilder { + builder: self.builder, + fn_: expr, + args: vec![], + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprCallArgsBuilder { + builder: ExprBuilder, + fn_: P, + args: Vec>, +} + +impl ExprCallArgsBuilder + where F: Invoke>, +{ + pub fn with_args(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.args.extend(iter); + self + } + + pub fn with_arg(mut self, arg: P) -> Self { + self.args.push(arg); + self + } + + pub fn arg(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_expr_(ast::ExprCall(self.fn_, self.args)) + } +} + +impl Invoke> for ExprCallArgsBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, arg: P) -> Self { + self.with_arg(arg) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprMethodCallBuilder { + builder: ExprBuilder, + id: ast::SpannedIdent, +} + +impl Invoke> for ExprMethodCallBuilder + where F: Invoke>, +{ + type Result = ExprMethodCallArgsBuilder; + + fn invoke(self, expr: P) -> ExprMethodCallArgsBuilder { + ExprMethodCallArgsBuilder { + builder: self.builder, + id: self.id, + tys: vec![], + args: vec![expr], + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprMethodCallArgsBuilder { + builder: ExprBuilder, + id: ast::SpannedIdent, + tys: Vec>, + args: Vec>, +} + +impl ExprMethodCallArgsBuilder + where F: Invoke>, +{ + pub fn with_tys(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.tys.extend(iter); + self + } + + pub fn with_ty(mut self, ty: P) -> Self { + self.tys.push(ty); + self + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn with_args(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.args.extend(iter); + self + } + + pub fn with_arg(mut self, arg: P) -> Self { + self.args.push(arg); + self + } + + pub fn arg(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_expr_(ast::ExprMethodCall(self.id, self.tys, self.args)) + } +} + +impl Invoke> for ExprMethodCallArgsBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, ty: P) -> Self { + self.with_ty(ty) + } +} + +impl Invoke> for ExprMethodCallArgsBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, arg: P) -> Self { + self.with_arg(arg) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprAddrOfBuilder { + builder: ExprBuilder, + mutability: ast::Mutability, +} + +impl Invoke> for ExprAddrOfBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_expr_(ast::ExprAddrOf(self.mutability, expr)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprPathBuilder { + builder: ExprBuilder, + path: ast::Path, +} + +impl Invoke> for ExprPathBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, arg: P) -> F::Result { + self.builder.call() + .build_path(self.path) + .with_arg(arg) + .build() + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprParenBuilder { + builder: ExprBuilder, +} + +impl Invoke> for ExprParenBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_expr_(ast::ExprParen(expr)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprFieldBuilder { + builder: ExprBuilder, + id: ast::SpannedIdent, +} + +impl Invoke> for ExprFieldBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_expr_(ast::ExprField(expr, self.id)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprTupFieldBuilder { + builder: ExprBuilder, + index: Spanned, +} + +impl Invoke> for ExprTupFieldBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_expr_(ast::ExprTupField(expr, self.index)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprSliceBuilder { + builder: ExprBuilder, + exprs: Vec>, +} + +impl>> ExprSliceBuilder + where F: Invoke> +{ + pub fn with_exprs(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.exprs.extend(iter); + self + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_expr_(ast::ExprVec(self.exprs)) + } +} + +impl Invoke> for ExprSliceBuilder + where F: Invoke> +{ + type Result = ExprSliceBuilder; + + fn invoke(mut self, expr: P) -> Self { + self.exprs.push(expr); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprVecBuilder { + builder: ExprBuilder, +} + +impl Invoke> for ExprVecBuilder + where F: Invoke> +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + let qpath = ExprBuilder::new().qpath() + .ty().slice().infer() + .id("into_vec"); + + self.builder.call() + .build(qpath) + .arg().box_().build(expr) + .build() + } +} diff --git a/src/libaster/fn_decl.rs b/src/libaster/fn_decl.rs new file mode 100644 index 0000000000000..e77a9f75ae435 --- /dev/null +++ b/src/libaster/fn_decl.rs @@ -0,0 +1,187 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span, respan}; +use syntax::ptr::P; + +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use ty::TyBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct FnDeclBuilder { + callback: F, + span: Span, + args: Vec, + variadic: bool, +} + +impl FnDeclBuilder { + pub fn new() -> FnDeclBuilder { + FnDeclBuilder::new_with_callback(Identity) + } +} + +impl FnDeclBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + FnDeclBuilder { + callback: callback, + span: DUMMY_SP, + args: Vec::new(), + variadic: false, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn variadic(mut self) -> Self { + self.variadic = true; + self + } + + pub fn with_arg(mut self, arg: ast::Arg) -> Self { + self.args.push(arg); + self + } + + pub fn with_args(mut self, iter: I) -> Self + where I: IntoIterator + { + self.args.extend(iter); + self + } + + pub fn arg(self, id: I) -> ArgBuilder + where I: ToIdent, + { + ArgBuilder::new_with_callback(id, self) + } + + pub fn no_return(self) -> F::Result { + let ret_ty = ast::FunctionRetTy::NoReturn(self.span); + self.build(ret_ty) + } + + pub fn default_return(self) -> F::Result { + let ret_ty = ast::FunctionRetTy::DefaultReturn(self.span); + self.build(ret_ty) + } + + pub fn build_return(self, ty: P) -> F::Result { + self.build(ast::FunctionRetTy::Return(ty)) + } + + pub fn return_(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build(self, output: ast::FunctionRetTy) -> F::Result { + self.callback.invoke(P(ast::FnDecl { + inputs: self.args, + output: output, + variadic: self.variadic, + })) + } +} + +impl Invoke for FnDeclBuilder + where F: Invoke> +{ + type Result = Self; + + fn invoke(self, arg: ast::Arg) -> Self { + self.with_arg(arg) + } +} + +impl Invoke> for FnDeclBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_return(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ArgBuilder { + callback: F, + span: Span, + id: ast::Ident, +} + +impl ArgBuilder { + pub fn new(id: I) -> Self where I: ToIdent { + ArgBuilder::new_with_callback(id, Identity) + } +} + +impl ArgBuilder + where F: Invoke, +{ + pub fn new_with_callback(id: I, callback: F) -> ArgBuilder + where I: ToIdent, + { + ArgBuilder { + callback: callback, + span: DUMMY_SP, + id: id.to_ident(), + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build_ty(self, ty: P) -> F::Result { + let path = respan(self.span, self.id); + + self.callback.invoke(ast::Arg { + id: ast::DUMMY_NODE_ID, + ty: ty, + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatIdent( + ast::BindByValue(ast::Mutability::MutImmutable), + path, + None, + ), + span: self.span, + }), + }) + } + + pub fn ty(self) -> TyBuilder> { + TyBuilder::new_with_callback(ArgTyBuilder(self)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ArgTyBuilder(ArgBuilder); + +impl> Invoke> for ArgTyBuilder +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.0.build_ty(ty) + } +} diff --git a/src/libaster/generics.rs b/src/libaster/generics.rs new file mode 100644 index 0000000000000..d1342741127e0 --- /dev/null +++ b/src/libaster/generics.rs @@ -0,0 +1,248 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::owned_slice::OwnedSlice; + +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder}; +use name::ToName; +use path::IntoPath; +use ty_param::TyParamBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct GenericsBuilder { + callback: F, + span: Span, + lifetimes: Vec, + ty_params: Vec, + predicates: Vec, +} + +impl GenericsBuilder { + pub fn new() -> Self { + GenericsBuilder::new_with_callback(Identity) + } + + pub fn from_generics(generics: ast::Generics) -> Self { + GenericsBuilder::from_generics_with_callback(generics, Identity) + } +} + +impl GenericsBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self { + GenericsBuilder { + callback: callback, + span: DUMMY_SP, + lifetimes: Vec::new(), + ty_params: Vec::new(), + predicates: Vec::new(), + } + } + + pub fn from_generics_with_callback(generics: ast::Generics, callback: F) -> Self { + GenericsBuilder { + callback: callback, + span: DUMMY_SP, + lifetimes: generics.lifetimes, + ty_params: generics.ty_params.into_vec(), + predicates: generics.where_clause.predicates, + } + } + + pub fn with(self, generics: ast::Generics) -> Self { + self.with_lifetimes(generics.lifetimes.into_iter()) + .with_ty_params(generics.ty_params.move_iter()) + .with_predicates(generics.where_clause.predicates.into_iter()) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_lifetimes(mut self, iter: I) -> Self + where I: IntoIterator, + L: IntoLifetimeDef, + { + let iter = iter.into_iter().map(|lifetime_def| lifetime_def.into_lifetime_def()); + self.lifetimes.extend(iter); + self + } + + pub fn with_lifetime_names(mut self, iter: I) -> Self + where I: IntoIterator, + N: ToName, + { + for name in iter { + self = self.lifetime_name(name); + } + self + } + + pub fn with_lifetime(mut self, lifetime: ast::LifetimeDef) -> Self { + self.lifetimes.push(lifetime); + self + } + + pub fn lifetime_name(self, name: N) -> Self + where N: ToName, + { + self.lifetime(name).build() + } + + pub fn lifetime(self, name: N) -> LifetimeDefBuilder + where N: ToName, + { + LifetimeDefBuilder::new_with_callback(name, self) + } + + pub fn with_ty_params(mut self, iter: I) -> Self + where I: IntoIterator, + { + self.ty_params.extend(iter); + self + } + + pub fn with_ty_param_ids(mut self, iter: I) -> Self + where I: IntoIterator, + T: ToIdent, + { + for id in iter { + self = self.ty_param_id(id); + } + self + } + + pub fn with_ty_param(mut self, ty_param: ast::TyParam) -> Self { + self.ty_params.push(ty_param); + self + } + + pub fn ty_param_id(self, id: I) -> Self + where I: ToIdent, + { + self.ty_param(id).build() + } + + pub fn ty_param(self, id: I) -> TyParamBuilder + where I: ToIdent, + { + let span = self.span; + TyParamBuilder::new_with_callback(id, self).span(span) + } + + pub fn with_predicates(mut self, iter: I) -> Self + where I: IntoIterator, + { + self.predicates.extend(iter); + self + } + + pub fn with_predicate(mut self, predicate: ast::WherePredicate) -> Self { + self.predicates.push(predicate); + self + } + + pub fn add_lifetime_bound(mut self, lifetime: L) -> Self + where L: IntoLifetime, + { + let lifetime = lifetime.into_lifetime(); + + for lifetime_def in self.lifetimes.iter_mut() { + lifetime_def.bounds.push(lifetime.clone()); + } + + for ty_param in self.ty_params.iter_mut() { + *ty_param = TyParamBuilder::from_ty_param(ty_param.clone()) + .lifetime_bound(lifetime.clone()) + .build(); + } + + self + } + + pub fn add_ty_param_bound

(mut self, path: P) -> Self + where P: IntoPath, + { + let path = path.into_path(); + + for ty_param in self.ty_params.iter_mut() { + *ty_param = TyParamBuilder::from_ty_param(ty_param.clone()) + .trait_bound(path.clone()).build() + .build(); + } + + self + } + + pub fn strip_bounds(self) -> Self { + self.strip_lifetimes() + .strip_ty_params() + .strip_predicates() + } + + pub fn strip_lifetimes(mut self) -> Self { + for lifetime in self.lifetimes.iter_mut() { + lifetime.bounds = vec![]; + } + self + } + + pub fn strip_ty_params(mut self) -> Self { + for ty_param in self.ty_params.iter_mut() { + ty_param.bounds = OwnedSlice::empty(); + } + self + } + + pub fn strip_predicates(mut self) -> Self { + self.predicates = vec![]; + self + } + + pub fn build(self) -> F::Result { + self.callback.invoke(ast::Generics { + lifetimes: self.lifetimes, + ty_params: OwnedSlice::from_vec(self.ty_params), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: self.predicates, + }, + }) + } +} + +impl Invoke for GenericsBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, lifetime: ast::LifetimeDef) -> Self { + self.with_lifetime(lifetime) + } +} + +impl Invoke for GenericsBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, ty_param: ast::TyParam) -> Self { + self.with_ty_param(ty_param) + } +} diff --git a/src/libaster/ident.rs b/src/libaster/ident.rs new file mode 100644 index 0000000000000..dec5b31de4085 --- /dev/null +++ b/src/libaster/ident.rs @@ -0,0 +1,55 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; + +use name::ToName; + +////////////////////////////////////////////////////////////////////////////// + +pub trait ToIdent { + fn to_ident(&self) -> ast::Ident; +} + +impl ToIdent for ast::Ident { + fn to_ident(&self) -> ast::Ident { + *self + } +} + +impl ToIdent for ast::Name { + fn to_ident(&self) -> ast::Ident { + ast::Ident::new(*self) + } +} + +impl<'a> ToIdent for &'a str { + fn to_ident(&self) -> ast::Ident { + self.to_name().to_ident() + } +} + +impl ToIdent for String { + fn to_ident(&self) -> ast::Ident { + (&**self).to_ident() + } +} + +impl<'a, T> ToIdent for &'a T where T: ToIdent { + fn to_ident(&self) -> ast::Ident { + (**self).to_ident() + } +} + +impl<'a, T> ToIdent for &'a mut T where T: ToIdent { + fn to_ident(&self) -> ast::Ident { + (**self).to_ident() + } +} diff --git a/src/libaster/invoke.rs b/src/libaster/invoke.rs new file mode 100644 index 0000000000000..1516b8808a55c --- /dev/null +++ b/src/libaster/invoke.rs @@ -0,0 +1,26 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Invoke { + type Result; + + fn invoke(self, arg: A) -> Self::Result; +} + +////////////////////////////////////////////////////////////////////////////// + +#[derive(Copy, Clone)] +pub struct Identity; + +impl Invoke for Identity { + type Result = A; + + fn invoke(self, arg: A) -> A { arg } +} diff --git a/src/libaster/item.rs b/src/libaster/item.rs new file mode 100644 index 0000000000000..8d2536185e930 --- /dev/null +++ b/src/libaster/item.rs @@ -0,0 +1,1037 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span, respan}; +use syntax::parse::token; +use syntax::ptr::P; + +use attr::AttrBuilder; +use block::BlockBuilder; +use constant::{Const, ConstBuilder}; +use fn_decl::FnDeclBuilder; +use generics::GenericsBuilder; +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use mac::MacBuilder; +use method::{Method, MethodBuilder}; +use path::PathBuilder; +use struct_def::{StructDefBuilder, StructFieldBuilder}; +use ty::TyBuilder; +use variant::{VariantBuilder, VariantTupleBuilder, VariantStructBuilder}; + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemBuilder { + callback: F, + span: Span, + attrs: Vec, + vis: ast::Visibility, +} + +impl ItemBuilder { + pub fn new() -> Self { + ItemBuilder::new_with_callback(Identity) + } +} + +impl ItemBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + ItemBuilder { + callback: callback, + span: DUMMY_SP, + attrs: vec![], + vis: ast::Visibility::Inherited, + } + } + + pub fn build(self, item: P) -> F::Result { + self.callback.invoke(item) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_attr(mut self, attr: ast::Attribute) -> Self { + self.attrs.push(attr); + self + } + + pub fn attr(self) -> AttrBuilder { + AttrBuilder::new_with_callback(self) + } + + pub fn pub_(mut self) -> Self { + self.vis = ast::Visibility::Public; + self + } + + pub fn build_item_(self, id: T, item_: ast::Item_) -> F::Result + where T: ToIdent, + { + let item = ast::Item { + ident: id.to_ident(), + attrs: self.attrs, + id: ast::DUMMY_NODE_ID, + node: item_, + vis: self.vis, + span: self.span, + }; + self.callback.invoke(P(item)) + } + + pub fn fn_(self, id: T) -> FnDeclBuilder> + where T: ToIdent, + { + let id = id.to_ident(); + FnDeclBuilder::new_with_callback(ItemFnDeclBuilder { + builder: self, + id: id, + }) + } + + pub fn build_use(self, view_path: ast::ViewPath_) -> F::Result { + let item = ast::ItemUse(P(respan(self.span, view_path))); + self.build_item_(token::special_idents::invalid, item) + } + + pub fn use_(self) -> PathBuilder> { + PathBuilder::new_with_callback(ItemUseBuilder { + builder: self, + }) + } + + pub fn struct_(self, id: T) -> ItemStructBuilder + where T: ToIdent, + { + let id = id.to_ident(); + let generics = GenericsBuilder::new().build(); + + ItemStructBuilder { + builder: self, + id: id, + generics: generics, + } + } + + pub fn tuple_struct(self, id: T) -> ItemTupleStructBuilder + where T: ToIdent, + { + let id = id.to_ident(); + let generics = GenericsBuilder::new().build(); + + ItemTupleStructBuilder { + builder: self, + id: id, + generics: generics, + fields: vec![], + } + } + + pub fn enum_(self, id: T) -> ItemEnumBuilder + where T: ToIdent, + { + let id = id.to_ident(); + let generics = GenericsBuilder::new().build(); + + ItemEnumBuilder { + builder: self, + id: id, + generics: generics, + variants: vec![], + } + + } + + pub fn extern_crate(self, id: T) -> ItemExternCrateBuilder + where T: ToIdent, + { + let id = id.to_ident(); + + ItemExternCrateBuilder { + builder: self, + id: id, + } + } + + pub fn mac(self) -> ItemMacBuilder { + ItemMacBuilder { + builder: self, + } + } + + pub fn type_(self, id: T) -> ItemTyBuilder + where T: ToIdent, + { + let id = id.to_ident(); + let generics = GenericsBuilder::new().build(); + + ItemTyBuilder { + builder: self, + id: id, + generics: generics, + } + } + + pub fn impl_(self) -> ItemImplBuilder { + let generics = GenericsBuilder::new().build(); + + ItemImplBuilder { + builder: self, + unsafety: ast::Unsafety::Normal, + polarity: ast::ImplPolarity::Positive, + generics: generics, + trait_ref: None, + items: vec![], + } + } + + pub fn const_(self, id: T) -> ConstBuilder> + where T: ToIdent, + { + ConstBuilder::new_with_callback(ItemConstBuilder { + builder: self, + id: id.to_ident(), + }) + } +} + +impl Invoke for ItemBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, attr: ast::Attribute) -> Self { + self.with_attr(attr) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemFnDeclBuilder { + builder: ItemBuilder, + id: ast::Ident, +} + +impl Invoke> for ItemFnDeclBuilder + where F: Invoke>, +{ + type Result = ItemFnBuilder; + + fn invoke(self, fn_decl: P) -> ItemFnBuilder { + let generics = GenericsBuilder::new().build(); + + ItemFnBuilder { + builder: self.builder, + id: self.id, + fn_decl: fn_decl, + unsafety: ast::Unsafety::Normal, + constness: ast::Constness::NotConst, + abi: Abi::Rust, + generics: generics, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemFnBuilder { + builder: ItemBuilder, + id: ast::Ident, + fn_decl: P, + unsafety: ast::Unsafety, + constness: ast::Constness, + abi: Abi, + generics: ast::Generics, +} + +impl ItemFnBuilder + where F: Invoke>, +{ + pub fn unsafe_(mut self) -> Self { + self.unsafety = ast::Unsafety::Unsafe; + self + } + + pub fn const_(mut self) -> Self { + self.constness = ast::Constness::Const; + self + } + + pub fn abi(mut self, abi: Abi) -> Self { + self.abi = abi; + self + } + + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn build(self, block: P) -> F::Result { + self.builder.build_item_(self.id, ast::Item_::ItemFn( + self.fn_decl, + self.unsafety, + self.constness, + self.abi, + self.generics, + block, + )) + } + + pub fn block(self) -> BlockBuilder { + BlockBuilder::new_with_callback(self) + } +} + +impl Invoke for ItemFnBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } +} + +impl Invoke> for ItemFnBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, block: P) -> F::Result { + self.build(block) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemUseBuilder { + builder: ItemBuilder, +} + +impl Invoke for ItemUseBuilder + where F: Invoke>, +{ + type Result = ItemUsePathBuilder; + + fn invoke(self, path: ast::Path) -> ItemUsePathBuilder { + ItemUsePathBuilder { + builder: self.builder, + path: path, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemUsePathBuilder { + builder: ItemBuilder, + path: ast::Path, +} + +impl ItemUsePathBuilder + where F: Invoke>, +{ + pub fn as_(self, id: T) -> F::Result + where T: ToIdent, + { + self.builder.build_use(ast::ViewPathSimple(id.to_ident(), self.path)) + } + + pub fn build(self) -> F::Result { + let id = { + let segment = self.path.segments.last().expect("path with no segments!"); + segment.identifier + }; + self.as_(id) + } + + pub fn glob(self) -> F::Result { + self.builder.build_use(ast::ViewPathGlob(self.path)) + } + + pub fn list(self) -> ItemUsePathListBuilder { + let span = self.builder.span; + ItemUsePathListBuilder { + builder: self.builder, + span: span, + path: self.path, + idents: Vec::new(), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemUsePathListBuilder { + builder: ItemBuilder, + span: Span, + path: ast::Path, + idents: Vec, +} + +impl ItemUsePathListBuilder + where F: Invoke>, +{ + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn self_(mut self) -> Self { + self.idents.push(respan(self.span, ast::PathListMod { + id: ast::DUMMY_NODE_ID, + rename: None, + })); + self + } + + pub fn id(mut self, id: T) -> Self + where T: ToIdent, + { + self.idents.push(respan(self.span, ast::PathListIdent { + name: id.to_ident(), + rename: None, + id: ast::DUMMY_NODE_ID, + })); + self + } + + pub fn build(self) -> F::Result { + self.builder.build_use(ast::ViewPathList(self.path, self.idents)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemStructBuilder { + builder: ItemBuilder, + id: ast::Ident, + generics: ast::Generics, +} + +impl ItemStructBuilder + where F: Invoke>, +{ + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn with_fields(self, iter: I) -> StructDefBuilder + where I: IntoIterator, + { + let span = self.builder.span; + StructDefBuilder::new_with_callback(self).span(span).with_fields(iter) + } + + pub fn with_field(self, field: ast::StructField) -> StructDefBuilder { + let span = self.builder.span; + StructDefBuilder::new_with_callback(self).span(span).with_field(field) + } + + pub fn field(self, id: T) -> StructFieldBuilder> + where T: ToIdent, + { + let span = self.builder.span; + StructDefBuilder::new_with_callback(self).span(span).field(id) + } + + pub fn build(self) -> F::Result { + StructDefBuilder::new_with_callback(self).build() + } +} + +impl Invoke for ItemStructBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } +} + +impl Invoke> for ItemStructBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, struct_def: P) -> F::Result { + let struct_ = ast::ItemStruct(struct_def, self.generics); + self.builder.build_item_(self.id, struct_) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemTupleStructBuilder { + builder: ItemBuilder, + id: ast::Ident, + generics: ast::Generics, + fields: Vec, +} + +impl ItemTupleStructBuilder + where F: Invoke>, +{ + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn with_tys(mut self, iter: I) -> Self + where I: IntoIterator>, + { + for ty in iter { + self = self.ty().build(ty); + } + self + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn field(self) -> StructFieldBuilder { + let span = self.builder.span; + StructFieldBuilder::unnamed_with_callback(self).span(span) + } + + pub fn build(self) -> F::Result { + let struct_def = ast::StructDef { + fields: self.fields, + ctor_id: Some(ast::DUMMY_NODE_ID), + }; + let struct_ = ast::ItemStruct(P(struct_def), self.generics); + self.builder.build_item_(self.id, struct_) + } +} + +impl Invoke for ItemTupleStructBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } +} + +impl Invoke> for ItemTupleStructBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, ty: P) -> Self { + self.field().build_ty(ty) + } +} + +impl Invoke for ItemTupleStructBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, field: ast::StructField) -> Self { + self.fields.push(field); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemEnumBuilder { + builder: ItemBuilder, + id: ast::Ident, + generics: ast::Generics, + variants: Vec>, +} + +impl ItemEnumBuilder + where F: Invoke>, +{ + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn with_variants(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.variants.extend(iter); + self + } + + pub fn with_variant(mut self, variant: P) -> Self { + self.variants.push(variant); + self + } + + pub fn with_variant_(self, variant: ast::Variant_) -> Self { + let variant = P(respan(self.builder.span, variant)); + self.with_variant(variant) + } + + pub fn ids(mut self, ids: I) -> Self + where I: IntoIterator, + T: ToIdent, + { + for id in ids.into_iter() { + self = self.id(id); + } + self + } + + pub fn id(self, id: T) -> Self + where T: ToIdent, + { + self.variant(id).tuple().build() + } + + pub fn tuple(self, id: T) -> VariantTupleBuilder + where T: ToIdent, + { + self.variant(id).tuple() + } + + pub fn struct_(self, id: T) -> StructDefBuilder> + where T: ToIdent, + { + self.variant(id).struct_() + } + + pub fn variant(self, id: T) -> VariantBuilder + where T: ToIdent, + { + VariantBuilder::new_with_callback(id, self) + } + + pub fn build(self) -> F::Result { + let enum_def = ast::EnumDef { + variants: self.variants, + }; + let enum_ = ast::ItemEnum(enum_def, self.generics); + self.builder.build_item_(self.id, enum_) + } +} + +impl Invoke for ItemEnumBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } +} + +impl Invoke> for ItemEnumBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, variant: P) -> Self { + self.with_variant(variant) + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// A builder for extern crate items +pub struct ItemExternCrateBuilder { + builder: ItemBuilder, + id: ast::Ident, +} + +impl ItemExternCrateBuilder + where F: Invoke>, +{ + pub fn with_name(self, name: ast::Name) -> F::Result { + let extern_ = ast::ItemExternCrate(Some(name)); + self.builder.build_item_(self.id, extern_) + } + + pub fn build(self) -> F::Result { + let extern_ = ast::ItemExternCrate(None); + self.builder.build_item_(self.id, extern_) + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// A builder for macro invocation items. +/// +/// Specifying the macro path returns a `MacBuilder`, which is used to +/// add expressions to the macro invocation. +pub struct ItemMacBuilder { + builder: ItemBuilder, +} + +impl ItemMacBuilder + where F: Invoke>, +{ + pub fn path(self) -> PathBuilder { + PathBuilder::new_with_callback(self) + } + + pub fn build(self, mac: ast::Mac) -> F::Result { + let item_mac = ast::ItemMac(mac); + self.builder.build_item_(ast::Ident::new(ast::Name(0)), item_mac) + } +} + +impl Invoke for ItemMacBuilder + where F: Invoke>, +{ + type Result = MacBuilder>; + + fn invoke(self, path: ast::Path) -> MacBuilder { + MacBuilder::new_with_callback(self).path(path) + } +} + +impl Invoke for ItemMacBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, mac: ast::Mac) -> F::Result { + self.build(mac) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemTyBuilder { + builder: ItemBuilder, + id: ast::Ident, + generics: ast::Generics, +} + +impl ItemTyBuilder + where F: Invoke>, +{ + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build_ty(self, ty: P) -> F::Result { + let ty_ = ast::ItemTy(ty, self.generics); + self.builder.build_item_(self.id, ty_) + } +} + +impl Invoke for ItemTyBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } +} + +impl Invoke> for ItemTyBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_ty(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemImplBuilder { + builder: ItemBuilder, + unsafety: ast::Unsafety, + polarity: ast::ImplPolarity, + generics: ast::Generics, + trait_ref: Option, + items: Vec>, +} + +impl ItemImplBuilder + where F: Invoke>, +{ + pub fn unsafe_(mut self) -> Self { + self.unsafety = ast::Unsafety::Unsafe; + self + } + + pub fn negative(mut self) -> Self { + self.polarity = ast::ImplPolarity::Negative; + self + } + + pub fn with_generics(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } + + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn with_trait(mut self, trait_ref: ast::TraitRef) -> Self { + self.trait_ref = Some(trait_ref); + self + } + + pub fn trait_(self) -> PathBuilder { + PathBuilder::new_with_callback(self) + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build_ty(self, ty: P) -> F::Result { + let ty_ = ast::ItemImpl( + self.unsafety, + self.polarity, + self.generics, + self.trait_ref, + ty, + self.items); + self.builder.build_item_(token::special_idents::invalid, ty_) + } + + pub fn with_items(mut self, items: I) -> Self + where I: IntoIterator>, + { + self.items.extend(items); + self + } + + pub fn with_item(mut self, item: P) -> Self { + self.items.push(item); + self + } + + pub fn item(self, id: T) -> ItemImplItemBuilder + where T: ToIdent, + { + ItemImplItemBuilder::new_with_callback(id, self) + } +} + +impl Invoke for ItemImplBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, generics: ast::Generics) -> Self { + self.with_generics(generics) + } +} + +impl Invoke for ItemImplBuilder + where F: Invoke> +{ + type Result = Self; + + fn invoke(self, path: ast::Path) -> Self { + self.with_trait(ast::TraitRef { + path: path, + ref_id: 0 + }) + } +} + +impl Invoke> for ItemImplBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, item: P) -> Self { + self.with_item(item) + } +} + +impl Invoke> for ItemImplBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_ty(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemImplItemBuilder { + callback: F, + id: ast::Ident, + vis: ast::Visibility, + attrs: Vec, + span: Span, +} + +impl ItemImplItemBuilder + where F: Invoke>, +{ + pub fn new_with_callback(id: T, callback: F) -> Self + where F: Invoke>, + T: ToIdent, + { + ItemImplItemBuilder { + callback: callback, + id: id.to_ident(), + vis: ast::Visibility::Inherited, + attrs: vec![], + span: DUMMY_SP, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_attr(mut self, attr: ast::Attribute) -> Self { + self.attrs.push(attr); + self + } + + pub fn attr(self) -> AttrBuilder { + AttrBuilder::new_with_callback(self) + } + + pub fn pub_(mut self) -> Self { + self.vis = ast::Visibility::Public; + self + } + + pub fn const_(self) -> ConstBuilder { + ConstBuilder::new_with_callback(self) + } + + pub fn method(self) -> MethodBuilder { + MethodBuilder::new_with_callback(self) + } + + pub fn type_(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn mac(self) -> MacBuilder { + MacBuilder::new_with_callback(self) + } + + pub fn build_item(self, node: ast::ImplItem_) -> F::Result { + let item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: self.id, + vis: self.vis, + attrs: self.attrs, + node: node, + span: self.span, + }; + self.callback.invoke(P(item)) + } +} + +impl Invoke for ItemImplItemBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, attr: ast::Attribute) -> Self { + self.with_attr(attr) + } +} + +impl Invoke for ItemImplItemBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, const_: Const) -> F::Result { + let node = ast::ConstImplItem( + const_.ty, + const_.expr.expect("an expr is required for a const impl item")); + + self.build_item(node) + } +} + +impl Invoke for ItemImplItemBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, method: Method) -> F::Result { + let node = ast::MethodImplItem( + method.sig, + method.block.expect("a block is required for a method impl item")); + + self.build_item(node) + } +} + +impl Invoke> for ItemImplItemBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + let node = ast::TypeImplItem(ty); + self.build_item(node) + } +} + +impl Invoke for ItemImplItemBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, mac: ast::Mac) -> F::Result { + let node = ast::MacImplItem(mac); + self.build_item(node) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ItemConstBuilder { + builder: ItemBuilder, + id: ast::Ident, +} + +impl Invoke for ItemConstBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, const_: Const) -> F::Result { + let ty = ast::ItemConst( + const_.ty, + const_.expr.expect("an expr is required for a const item")); + + self.builder.build_item_(self.id, ty) + } +} diff --git a/src/libaster/lib.rs b/src/libaster/lib.rs new file mode 100644 index 0000000000000..19bfaed6718e7 --- /dev/null +++ b/src/libaster/lib.rs @@ -0,0 +1,195 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Aster is a syntax ast builder. + +#![crate_name = "aster"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![staged_api] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/")] + +#![feature(rustc_private)] +#![feature(staged_api)] + +extern crate syntax; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::parse::token; + +pub mod attr; +pub mod block; +pub mod constant; +pub mod expr; +pub mod fn_decl; +pub mod generics; +pub mod ident; +pub mod invoke; +pub mod item; +pub mod lifetime; +pub mod lit; +pub mod mac; +pub mod method; +pub mod name; +pub mod pat; +pub mod path; +pub mod qpath; +pub mod stmt; +pub mod str; +pub mod struct_def; +pub mod ty; +pub mod ty_param; +pub mod variant; + +#[cfg(test)] +mod tests; + +////////////////////////////////////////////////////////////////////////////// + +#[derive(Copy, Clone)] +pub struct AstBuilder { + span: Span, +} + +impl AstBuilder { + pub fn new() -> AstBuilder { + AstBuilder { + span: DUMMY_SP, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn interned_string(&self, s: S) -> token::InternedString + where S: str::ToInternedString + { + s.to_interned_string() + } + + pub fn id(&self, id: I) -> ast::Ident + where I: ident::ToIdent + { + id.to_ident() + } + + pub fn name(&self, name: N) -> ast::Name + where N: name::ToName + { + name.to_name() + } + + pub fn lifetime(&self, lifetime: L) -> ast::Lifetime + where L: lifetime::IntoLifetime + { + lifetime.into_lifetime() + } + + pub fn attr(&self) -> attr::AttrBuilder { + attr::AttrBuilder::new() + } + + pub fn path(&self) -> path::PathBuilder { + path::PathBuilder::new() + } + + pub fn ty(&self) -> ty::TyBuilder { + ty::TyBuilder::new().span(self.span) + } + + pub fn lifetime_def(&self, name: N) -> lifetime::LifetimeDefBuilder + where N: name::ToName, + { + lifetime::LifetimeDefBuilder::new(name) + } + + pub fn ty_param(&self, id: I) -> ty_param::TyParamBuilder + where I: ident::ToIdent, + { + ty_param::TyParamBuilder::new(id).span(self.span) + } + + pub fn from_ty_param(&self, ty_param: ast::TyParam) -> ty_param::TyParamBuilder { + ty_param::TyParamBuilder::from_ty_param(ty_param) + } + + pub fn generics(&self) -> generics::GenericsBuilder { + generics::GenericsBuilder::new().span(self.span) + } + + pub fn from_generics(&self, generics: ast::Generics) -> generics::GenericsBuilder { + generics::GenericsBuilder::from_generics(generics).span(self.span) + } + + pub fn lit(&self) -> lit::LitBuilder { + lit::LitBuilder::new().span(self.span) + } + + pub fn expr(&self) -> expr::ExprBuilder { + expr::ExprBuilder::new().span(self.span) + } + + pub fn stmt(&self) -> stmt::StmtBuilder { + stmt::StmtBuilder::new().span(self.span) + } + + pub fn block(&self) -> block::BlockBuilder { + block::BlockBuilder::new().span(self.span) + } + + pub fn pat(&self) -> pat::PatBuilder { + pat::PatBuilder::new().span(self.span) + } + + pub fn fn_decl(&self) -> fn_decl::FnDeclBuilder { + fn_decl::FnDeclBuilder::new().span(self.span) + } + + pub fn method(&self) -> method::MethodBuilder { + method::MethodBuilder::new().span(self.span) + } + + pub fn arg(&self, id: I) -> fn_decl::ArgBuilder + where I: ident::ToIdent, + { + fn_decl::ArgBuilder::new(id).span(self.span) + } + + pub fn struct_def(&self) -> struct_def::StructDefBuilder { + struct_def::StructDefBuilder::new().span(self.span) + } + + pub fn variant(&self, id: T) -> variant::VariantBuilder + where T: ident::ToIdent, + { + variant::VariantBuilder::new(id).span(self.span) + } + + pub fn field(&self, id: T) -> struct_def::StructFieldBuilder + where T: ident::ToIdent, + { + struct_def::StructFieldBuilder::named(id).span(self.span) + } + + pub fn item(&self) -> item::ItemBuilder { + item::ItemBuilder::new().span(self.span) + } + + pub fn const_(&self) -> constant::ConstBuilder { + constant::ConstBuilder::new().span(self.span) + } +} diff --git a/src/libaster/lifetime.rs b/src/libaster/lifetime.rs new file mode 100644 index 0000000000000..9a02d12c372b3 --- /dev/null +++ b/src/libaster/lifetime.rs @@ -0,0 +1,126 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP}; + +use invoke::{Invoke, Identity}; +use name::ToName; + +////////////////////////////////////////////////////////////////////////////// + +pub trait IntoLifetime { + fn into_lifetime(self) -> ast::Lifetime; +} + +impl IntoLifetime for ast::Lifetime { + fn into_lifetime(self) -> ast::Lifetime { + self + } +} + +impl<'a> IntoLifetime for &'a str { + fn into_lifetime(self) -> ast::Lifetime { + ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + name: self.to_name(), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub trait IntoLifetimeDef { + fn into_lifetime_def(self) -> ast::LifetimeDef; +} + +impl IntoLifetimeDef for ast::LifetimeDef { + fn into_lifetime_def(self) -> ast::LifetimeDef { + self + } +} + +impl IntoLifetimeDef for ast::Lifetime { + fn into_lifetime_def(self) -> ast::LifetimeDef { + ast::LifetimeDef { + lifetime: self, + bounds: vec![], + } + } +} + +impl<'a> IntoLifetimeDef for &'a str { + fn into_lifetime_def(self) -> ast::LifetimeDef { + self.into_lifetime().into_lifetime_def() + } +} + +impl IntoLifetimeDef for String { + fn into_lifetime_def(self) -> ast::LifetimeDef { + (*self).into_lifetime().into_lifetime_def() + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct LifetimeDefBuilder { + callback: F, + lifetime: ast::Lifetime, + bounds: Vec, +} + +impl LifetimeDefBuilder { + pub fn new(name: N) -> Self + where N: ToName, + { + LifetimeDefBuilder::new_with_callback(name, Identity) + } +} + +impl LifetimeDefBuilder + where F: Invoke, +{ + pub fn new_with_callback(name: N, callback: F) -> Self + where N: ToName, + { + let lifetime = ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + name: name.to_name(), + }; + + LifetimeDefBuilder { + callback: callback, + lifetime: lifetime, + bounds: Vec::new(), + } + } + + pub fn bound(mut self, name: N) -> Self + where N: ToName, + { + let lifetime = ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + name: name.to_name(), + }; + + self.bounds.push(lifetime); + self + } + + pub fn build(self) -> F::Result { + self.callback.invoke(ast::LifetimeDef { + lifetime: self.lifetime, + bounds: self.bounds, + }) + } +} diff --git a/src/libaster/lit.rs b/src/libaster/lit.rs new file mode 100644 index 0000000000000..f34896c5ae8d1 --- /dev/null +++ b/src/libaster/lit.rs @@ -0,0 +1,136 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ptr::P; + +use invoke::{Invoke, Identity}; + +use str::ToInternedString; + +////////////////////////////////////////////////////////////////////////////// + +pub struct LitBuilder { + callback: F, + span: Span, +} + +impl LitBuilder { + pub fn new() -> LitBuilder { + LitBuilder::new_with_callback(Identity) + } +} + +impl LitBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + LitBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn span(mut self, span: Span) -> LitBuilder { + self.span = span; + self + } + + pub fn build_lit(self, lit: ast::Lit_) -> F::Result { + self.callback.invoke(P(ast::Lit { + span: self.span, + node: lit, + })) + } + + pub fn bool(self, value: bool) -> F::Result { + self.build_lit(ast::LitBool(value)) + } + + pub fn int(self, value: i64) -> F::Result { + let sign = ast::Sign::new(value); + self.build_lit(ast::LitInt(value as u64, ast::UnsuffixedIntLit(sign))) + } + + fn build_int(self, value: i64, ty: ast::IntTy) -> F::Result { + let sign = ast::Sign::new(value); + self.build_lit(ast::LitInt(value as u64, ast::LitIntType::SignedIntLit(ty, sign))) + } + + pub fn isize(self, value: isize) -> F::Result { + self.build_int(value as i64, ast::IntTy::TyIs) + } + + pub fn i8(self, value: i8) -> F::Result { + self.build_int(value as i64, ast::IntTy::TyI8) + } + + pub fn i16(self, value: i16) -> F::Result { + self.build_int(value as i64, ast::IntTy::TyI16) + } + + pub fn i32(self, value: i32) -> F::Result { + self.build_int(value as i64, ast::IntTy::TyI32) + } + + pub fn i64(self, value: i64) -> F::Result { + self.build_int(value, ast::IntTy::TyI64) + } + + fn build_uint(self, value: u64, ty: ast::UintTy) -> F::Result { + self.build_lit(ast::LitInt(value, ast::LitIntType::UnsignedIntLit(ty))) + } + + pub fn usize(self, value: usize) -> F::Result { + self.build_uint(value as u64, ast::UintTy::TyUs) + } + + pub fn u8(self, value: u8) -> F::Result { + self.build_uint(value as u64, ast::UintTy::TyU8) + } + + pub fn u16(self, value: u16) -> F::Result { + self.build_uint(value as u64, ast::UintTy::TyU16) + } + + pub fn u32(self, value: u32) -> F::Result { + self.build_uint(value as u64, ast::UintTy::TyU32) + } + + pub fn u64(self, value: u64) -> F::Result { + self.build_uint(value, ast::UintTy::TyU64) + } + + fn build_float(self, value: S, ty: ast::FloatTy) -> F::Result + where S: ToInternedString, + { + self.build_lit(ast::LitFloat(value.to_interned_string(), ty)) + } + + pub fn f32(self, value: S) -> F::Result + where S: ToInternedString, + { + self.build_float(value, ast::FloatTy::TyF32) + } + + pub fn f64(self, value: S) -> F::Result + where S: ToInternedString, + { + self.build_float(value, ast::FloatTy::TyF64) + } + + pub fn str(self, value: S) -> F::Result + where S: ToInternedString, + { + let value = value.to_interned_string(); + self.build_lit(ast::LitStr(value, ast::CookedStr)) + } +} diff --git a/src/libaster/mac.rs b/src/libaster/mac.rs new file mode 100644 index 0000000000000..5d2c5d738c9df --- /dev/null +++ b/src/libaster/mac.rs @@ -0,0 +1,123 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{self, DUMMY_SP, Span, respan}; +use syntax::ext::base::ExtCtxt; +use syntax::ext::expand; +use syntax::ext::quote::rt::ToTokens; +use syntax::feature_gate::GatedCfg; +use syntax::parse::ParseSess; +use syntax::ptr::P; + +use expr::ExprBuilder; +use invoke::{Invoke, Identity}; + +/// A Builder for macro invocations. +/// +/// Note that there are no commas added between args, as otherwise +/// that macro invocations that could be expressed would be limited. +/// You will need to add all required symbols with `with_arg` or +/// `with_argss`. +pub struct MacBuilder { + callback: F, + span: Span, + tokens: Vec, + path: Option, +} + +impl MacBuilder { + pub fn new() -> Self { + MacBuilder::new_with_callback(Identity) + } +} + +impl MacBuilder + where F: Invoke +{ + pub fn new_with_callback(callback: F) -> Self { + MacBuilder { + callback: callback, + span: DUMMY_SP, + tokens: vec![], + path: None, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn path(mut self, path: ast::Path) -> Self { + self.path = Some(path); + self + } + + pub fn build(self) -> F::Result { + let mac = ast::Mac_::MacInvocTT( + self.path.expect("No path set for macro"), self.tokens, 0); + self.callback.invoke(respan(self.span, mac)) + } + + pub fn with_args(self, iter: I) -> Self + where I: IntoIterator, T: ToTokens + { + iter.into_iter().fold(self, |self_, expr| self_.with_arg(expr)) + } + + pub fn with_arg(mut self, expr: T) -> Self + where T: ToTokens + { + let parse_sess = ParseSess::new(); + let mut feature_gated_cfgs = Vec::new(); + let cx = make_ext_ctxt(&parse_sess, &mut feature_gated_cfgs); + let tokens = expr.to_tokens(&cx); + assert!(tokens.len() == 1); + self.tokens.push(tokens[0].clone()); + self + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + +} + +impl Invoke> for MacBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, expr: P) -> Self { + self.with_arg(expr) + } +} + +fn make_ext_ctxt<'a>(sess: &'a ParseSess, + feature_gated_cfgs: &'a mut Vec) -> ExtCtxt<'a> { + let info = codemap::ExpnInfo { + call_site: codemap::DUMMY_SP, + callee: codemap::NameAndSpan { + name: "test".to_string(), + format: codemap::MacroAttribute, + allow_internal_unstable: false, + span: None + } + }; + + let cfg = vec![]; + let ecfg = expand::ExpansionConfig::default(String::new()); + + let mut cx = ExtCtxt::new(&sess, cfg, ecfg, feature_gated_cfgs); + cx.bt_push(info); + + cx +} diff --git a/src/libaster/method.rs b/src/libaster/method.rs new file mode 100644 index 0000000000000..ae78e3e473c1f --- /dev/null +++ b/src/libaster/method.rs @@ -0,0 +1,273 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span, respan}; +use syntax::ptr::P; + +use block::BlockBuilder; +use fn_decl::FnDeclBuilder; +use generics::GenericsBuilder; +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use lifetime::IntoLifetime; + +////////////////////////////////////////////////////////////////////////////// + +pub struct Method { + pub sig: ast::MethodSig, + pub block: Option>, +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct MethodBuilder { + callback: F, + span: Span, + abi: Abi, + generics: ast::Generics, + unsafety: ast::Unsafety, + constness: ast::Constness, + explicit_self: ast::ExplicitSelf, + fn_decl: P, + block: Option>, +} + +impl MethodBuilder { + pub fn new() -> Self { + MethodBuilder::new_with_callback(Identity) + } +} + +impl MethodBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self { + MethodBuilder { + callback: callback, + span: DUMMY_SP, + abi: Abi::Rust, + generics: GenericsBuilder::new().build(), + unsafety: ast::Unsafety::Normal, + constness: ast::Constness::NotConst, + explicit_self: respan(DUMMY_SP, ast::ExplicitSelf_::SelfStatic), + fn_decl: P(ast::FnDecl { + inputs: vec![], + output: ast::FunctionRetTy::NoReturn(DUMMY_SP), + variadic: false + }), + block: None, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn unsafe_(mut self) -> Self { + self.unsafety = ast::Unsafety::Normal; + self + } + + pub fn const_(mut self) -> Self { + self.constness = ast::Constness::Const; + self + } + + pub fn abi(mut self, abi: Abi) -> Self { + self.abi = abi; + self + } + + pub fn with_generics(mut self, generics: ast::Generics) -> Self { + self.generics = generics; + self + } + + pub fn generics(self) -> GenericsBuilder { + GenericsBuilder::new_with_callback(self) + } + + pub fn with_self(mut self, explicit_self: ast::ExplicitSelf) -> Self { + self.explicit_self = explicit_self; + self + } + + pub fn self_(self) -> SelfBuilder { + SelfBuilder::new_with_callback(self) + } + + pub fn with_fn_decl(mut self, fn_decl: P) -> Self { + self.fn_decl = fn_decl; + self + } + + pub fn fn_decl(self) -> FnDeclBuilder { + FnDeclBuilder::new_with_callback(self) + } + + pub fn with_block(mut self, block: P) -> Self { + self.block = Some(block); + self + } + + pub fn block(self) -> BlockBuilder { + BlockBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + let method_sig = ast::MethodSig { + unsafety: self.unsafety, + constness: self.constness, + abi: self.abi, + decl: self.fn_decl, + generics: self.generics, + explicit_self: self.explicit_self, + }; + self.callback.invoke(Method { + sig: method_sig, + block: self.block, + }) + } +} + +impl Invoke for MethodBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, generics: ast::Generics) -> Self { + self.with_generics(generics) + } +} + +impl Invoke for MethodBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, explicit_self: ast::ExplicitSelf) -> Self { + self.with_self(explicit_self) + } +} + +impl Invoke> for MethodBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, fn_decl: P) -> Self { + self.with_fn_decl(fn_decl) + } +} + +impl Invoke> for MethodBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, block: P) -> Self { + self.with_block(block) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct SelfBuilder { + callback: F, + span: Span, +} + +impl SelfBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self { + SelfBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn build(self, self_: ast::ExplicitSelf) -> F::Result { + self.callback.invoke(self_) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build_self_(self, self_: ast::ExplicitSelf_) -> F::Result { + let self_ = respan(self.span, self_); + self.build(self_) + } + + pub fn static_(self) -> F::Result { + self.build_self_(ast::ExplicitSelf_::SelfStatic) + } + + pub fn value(self) -> F::Result { + self.build_self_(ast::ExplicitSelf_::SelfValue("self".to_ident())) + } + + pub fn ref_(self) -> F::Result { + self.build_self_(ast::ExplicitSelf_::SelfRegion( + None, + ast::Mutability::MutImmutable, + "self".to_ident(), + )) + } + + pub fn ref_lifetime(self, lifetime: L) -> F::Result + where L: IntoLifetime, + { + self.build_self_(ast::ExplicitSelf_::SelfRegion( + Some(lifetime.into_lifetime()), + ast::Mutability::MutImmutable, + "self".to_ident(), + )) + } + + pub fn ref_mut(self) -> F::Result { + self.build_self_(ast::ExplicitSelf_::SelfRegion( + None, + ast::Mutability::MutMutable, + "self".to_ident(), + )) + } + + pub fn ref_mut_lifetime(self, lifetime: L) -> F::Result + where L: IntoLifetime, + { + self.build_self_(ast::ExplicitSelf_::SelfRegion( + Some(lifetime.into_lifetime()), + ast::Mutability::MutMutable, + "self".to_ident(), + )) + } + + /* + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + */ +} + +impl Invoke> for SelfBuilder + where F: Invoke, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_self_(ast::ExplicitSelf_::SelfExplicit(ty, "self".to_ident())) + } +} diff --git a/src/libaster/name.rs b/src/libaster/name.rs new file mode 100644 index 0000000000000..ad8e02be5c09f --- /dev/null +++ b/src/libaster/name.rs @@ -0,0 +1,42 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::parse::token; + +////////////////////////////////////////////////////////////////////////////// + +pub trait ToName { + fn to_name(&self) -> ast::Name; +} + +impl ToName for ast::Name { + fn to_name(&self) -> ast::Name { + *self + } +} + +impl<'a> ToName for &'a str { + fn to_name(&self) -> ast::Name { + token::intern(*self) + } +} + +impl<'a, T> ToName for &'a T where T: ToName { + fn to_name(&self) -> ast::Name { + (**self).to_name() + } +} + +impl<'a, T> ToName for &'a mut T where T: ToName { + fn to_name(&self) -> ast::Name { + (**self).to_name() + } +} diff --git a/src/libaster/pat.rs b/src/libaster/pat.rs new file mode 100644 index 0000000000000..18928624b55be --- /dev/null +++ b/src/libaster/pat.rs @@ -0,0 +1,350 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span, Spanned, respan}; +use syntax::ptr::P; + +use invoke::{Invoke, Identity}; + +use expr::ExprBuilder; +use ident::ToIdent; +use path::PathBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatBuilder { + callback: F, + span: Span, +} + +impl PatBuilder { + pub fn new() -> Self { + PatBuilder::new_with_callback(Identity) + } +} + + +impl PatBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + PatBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build(self, pat: P) -> F::Result { + self.callback.invoke(pat) + } + + pub fn build_pat_(self, pat_: ast::Pat_) -> F::Result { + let span = self.span; + self.build(P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: pat_, + span: span, + })) + } + + pub fn wild(self) -> F::Result { + self.build_pat_(ast::Pat_::PatWild(ast::PatWildKind::PatWildSingle)) + } + + pub fn wild_multi(self) -> F::Result { + self.build_pat_(ast::Pat_::PatWild(ast::PatWildKind::PatWildMulti)) + } + + pub fn build_id(self, mode: ast::BindingMode, id: I, sub: Option>) -> F::Result + where I: ToIdent, + { + let id = respan(self.span, id.to_ident()); + + self.build_pat_(ast::Pat_::PatIdent(mode, id, sub)) + } + + pub fn id(self, id: I) -> F::Result + where I: ToIdent + { + let mode = ast::BindingMode::BindByValue(ast::Mutability::MutImmutable); + self.build_id(mode, id, None) + } + + pub fn mut_id(self, id: I) -> F::Result + where I: ToIdent + { + let mode = ast::BindingMode::BindByValue(ast::Mutability::MutMutable); + self.build_id(mode, id, None) + } + + pub fn ref_id(self, id: I) -> F::Result + where I: ToIdent + { + let mode = ast::BindingMode::BindByRef(ast::Mutability::MutImmutable); + self.build_id(mode, id, None) + } + + pub fn ref_mut_id(self, id: I) -> F::Result + where I: ToIdent + { + let mode = ast::BindingMode::BindByRef(ast::Mutability::MutMutable); + self.build_id(mode, id, None) + } + + pub fn enum_(self) -> PathBuilder> { + PathBuilder::new_with_callback(PatEnumBuilder(self)) + } + + pub fn struct_(self) -> PathBuilder> { + PathBuilder::new_with_callback(PatStructBuilder(self)) + } + + pub fn expr(self) -> ExprBuilder> { + ExprBuilder::new_with_callback(PatExprBuilder(self)) + } + + pub fn tuple(self) -> PatTupleBuilder { + PatTupleBuilder { + builder: self, + pats: Vec::new(), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatEnumBuilder(PatBuilder); + +impl Invoke for PatEnumBuilder { + type Result = PatEnumPathBuilder; + + fn invoke(self, path: ast::Path) -> PatEnumPathBuilder { + PatEnumPathBuilder { + builder: self.0, + path: path, + pats: Vec::new(), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatEnumPathBuilder { + builder: PatBuilder, + path: ast::Path, + pats: Vec>, +} + +impl PatEnumPathBuilder + where F: Invoke>, +{ + pub fn with_pats(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.pats.extend(iter); + self + } + + pub fn pat(self) -> PatBuilder { + PatBuilder::new_with_callback(self) + } + + pub fn with_ids(mut self, iter: I) -> Self + where I: IntoIterator, + T: ToIdent, + { + for id in iter { + self = self.id(id); + } + self + } + + pub fn id(self, id: I) -> Self + where I: ToIdent + { + self.pat().id(id) + } + + pub fn build(self) -> F::Result { + self.builder.build_pat_(ast::Pat_::PatEnum(self.path, Some(self.pats))) + } +} + +impl Invoke> for PatEnumPathBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, pat: P) -> Self { + self.pats.push(pat); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatStructBuilder(PatBuilder); + +impl Invoke for PatStructBuilder { + type Result = PatStructPathBuilder; + + fn invoke(self, path: ast::Path) -> PatStructPathBuilder { + PatStructPathBuilder { + builder: self.0, + path: path, + pats: Vec::new(), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatStructPathBuilder { + builder: PatBuilder, + path: ast::Path, + pats: Vec>, +} + +impl PatStructPathBuilder + where F: Invoke>, +{ + pub fn with_field_pat(mut self, pat: ast::FieldPat) -> Self { + self.pats.push(respan(self.builder.span, pat)); + self + } + + pub fn with_pats(mut self, iter: I) -> Self + where I: IntoIterator)>, + T: ToIdent, + { + for (id, pat) in iter { + self = self.pat(id).build(pat); + } + self + } + + pub fn pat(self, id: I) -> PatBuilder> + where I: ToIdent, + { + PatBuilder::new_with_callback(PatStructFieldBuilder { + builder: self, + id: id.to_ident(), + }) + } + + pub fn with_ids(mut self, iter: I) -> Self + where I: IntoIterator, + T: ToIdent, + { + for id in iter { + self = self.id(id); + } + self + } + + pub fn id(self, id: I) -> Self + where I: ToIdent, + { + let id = id.to_ident(); + let span = self.builder.span; + let pat = PatBuilder::new().span(span).id(id); + + self.with_field_pat(ast::FieldPat { + ident: id, + pat: pat, + is_shorthand: true, + }) + } + + pub fn etc(self) -> F::Result { + self.builder.build_pat_(ast::Pat_::PatStruct(self.path, self.pats, true)) + } + + pub fn build(self) -> F::Result { + self.builder.build_pat_(ast::Pat_::PatStruct(self.path, self.pats, false)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatStructFieldBuilder { + builder: PatStructPathBuilder, + id: ast::Ident, +} + +impl Invoke> for PatStructFieldBuilder + where F: Invoke>, +{ + type Result = PatStructPathBuilder; + + fn invoke(self, pat: P) -> PatStructPathBuilder { + self.builder.with_field_pat(ast::FieldPat { + ident: self.id, + pat: pat, + is_shorthand: false, + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatExprBuilder(PatBuilder); + +impl Invoke> for PatExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.0.build_pat_(ast::Pat_::PatLit(expr)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatTupleBuilder { + builder: PatBuilder, + pats: Vec>, +} + +impl>> PatTupleBuilder + where F: Invoke> +{ + pub fn with_pat(mut self, pat: P) -> PatTupleBuilder { + self.pats.push(pat); + self + } + + pub fn pat(self) -> PatBuilder> { + PatBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_pat_(ast::PatTup(self.pats)) + } +} + +impl Invoke> for PatTupleBuilder + where F: Invoke> +{ + type Result = PatTupleBuilder; + + fn invoke(self, pat: P) -> Self { + self.with_pat(pat) + } +} diff --git a/src/libaster/path.rs b/src/libaster/path.rs new file mode 100644 index 0000000000000..f6f2b63aba775 --- /dev/null +++ b/src/libaster/path.rs @@ -0,0 +1,295 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::owned_slice::OwnedSlice; +use syntax::ptr::P; + +use invoke::{Invoke, Identity}; + +use ident::ToIdent; +use name::ToName; +use ty::TyBuilder; + +use lifetime::IntoLifetime; + +////////////////////////////////////////////////////////////////////////////// + +pub trait IntoPath { + fn into_path(self) -> ast::Path; +} + +impl IntoPath for ast::Path { + fn into_path(self) -> ast::Path { + self + } +} + +impl IntoPath for ast::Ident { + fn into_path(self) -> ast::Path { + PathBuilder::new().id(self).build() + } +} + +impl<'a> IntoPath for &'a str { + fn into_path(self) -> ast::Path { + PathBuilder::new().id(self).build() + } +} + +impl IntoPath for String { + fn into_path(self) -> ast::Path { + (&*self).into_path() + } +} + +impl<'a, T> IntoPath for &'a [T] where T: ToIdent { + fn into_path(self) -> ast::Path { + PathBuilder::new().ids(self).build() + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PathBuilder { + callback: F, + span: Span, + global: bool, +} + +impl PathBuilder { + pub fn new() -> Self { + PathBuilder::new_with_callback(Identity) + } +} + +impl PathBuilder + where F: Invoke, +{ + pub fn new_with_callback(callback: F) -> Self { + PathBuilder { + callback: callback, + span: DUMMY_SP, + global: false, + } + } + + pub fn build(self, path: ast::Path) -> F::Result { + self.callback.invoke(path) + } + + /// Update the span to start from this location. + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn global(mut self) -> Self { + self.global = true; + self + } + + pub fn ids(self, ids: I) -> PathSegmentsBuilder + where I: IntoIterator, + T: ToIdent, + { + let mut ids = ids.into_iter(); + let id = ids.next().expect("passed path with no id"); + + self.id(id).ids(ids) + } + + pub fn id(self, id: I) -> PathSegmentsBuilder + where I: ToIdent, + { + self.segment(id).build() + } + + pub fn segment(self, id: I) + -> PathSegmentBuilder> + where I: ToIdent, + { + PathSegmentBuilder::new_with_callback(id, PathSegmentsBuilder { + callback: self.callback, + span: self.span, + global: self.global, + segments: Vec::new(), + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PathSegmentsBuilder { + callback: F, + span: Span, + global: bool, + segments: Vec, +} + +impl PathSegmentsBuilder + where F: Invoke, +{ + pub fn ids(mut self, ids: I) -> PathSegmentsBuilder + where I: IntoIterator, + T: ToIdent, + { + for id in ids { + self = self.id(id); + } + + self + } + + pub fn id(self, id: T) -> PathSegmentsBuilder + where T: ToIdent, + { + self.segment(id).build() + } + + pub fn segment(self, id: T) -> PathSegmentBuilder + where T: ToIdent, + { + PathSegmentBuilder::new_with_callback(id, self) + } + + pub fn build(self) -> F::Result { + self.callback.invoke(ast::Path { + span: self.span, + global: self.global, + segments: self.segments, + }) + } +} + +impl Invoke for PathSegmentsBuilder { + type Result = Self; + + fn invoke(mut self, segment: ast::PathSegment) -> Self { + self.segments.push(segment); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PathSegmentBuilder { + callback: F, + span: Span, + id: ast::Ident, + lifetimes: Vec, + tys: Vec>, + bindings: Vec>, +} + +impl PathSegmentBuilder + where F: Invoke, +{ + pub fn new_with_callback(id: I, callback: F) -> Self + where I: ToIdent, + { + PathSegmentBuilder { + callback: callback, + span: DUMMY_SP, + id: id.to_ident(), + lifetimes: Vec::new(), + tys: Vec::new(), + bindings: Vec::new(), + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_generics(self, generics: ast::Generics) -> Self { + // Strip off the bounds. + let lifetimes = generics.lifetimes.iter() + .map(|lifetime_def| lifetime_def.lifetime); + + let tys = generics.ty_params.iter() + .map(|ty_param| TyBuilder::new().id(ty_param.ident)); + + self.with_lifetimes(lifetimes) + .with_tys(tys) + } + + pub fn with_lifetimes(mut self, iter: I) -> Self + where I: IntoIterator, + L: IntoLifetime, + { + let iter = iter.into_iter().map(|lifetime| lifetime.into_lifetime()); + self.lifetimes.extend(iter); + self + } + + pub fn with_lifetime(mut self, lifetime: L) -> Self + where L: IntoLifetime, + { + self.lifetimes.push(lifetime.into_lifetime()); + self + } + + pub fn lifetime(self, name: N) -> Self + where N: ToName, + { + let lifetime = ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: self.span, + name: name.to_name(), + }; + self.with_lifetime(lifetime) + } + + pub fn with_tys(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.tys.extend(iter); + self + } + + pub fn with_ty(mut self, ty: P) -> Self { + self.tys.push(ty); + self + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + let data = ast::AngleBracketedParameterData { + lifetimes: self.lifetimes, + types: OwnedSlice::from_vec(self.tys), + bindings: OwnedSlice::from_vec(self.bindings), + }; + + let parameters = ast::PathParameters::AngleBracketedParameters(data); + + self.callback.invoke(ast::PathSegment { + identifier: self.id, + parameters: parameters, + }) + } +} + +impl Invoke> for PathSegmentBuilder + where F: Invoke +{ + type Result = Self; + + fn invoke(self, ty: P) -> Self { + self.with_ty(ty) + } +} diff --git a/src/libaster/qpath.rs b/src/libaster/qpath.rs new file mode 100644 index 0000000000000..ea9e0241f70b5 --- /dev/null +++ b/src/libaster/qpath.rs @@ -0,0 +1,164 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ptr::P; + +use invoke::{Invoke, Identity}; + +use ident::ToIdent; +use path::{PathBuilder, PathSegmentBuilder}; +use ty::TyBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct QPathBuilder { + callback: F, + span: Span, +} + +impl QPathBuilder { + pub fn new() -> Self { + QPathBuilder::new_with_callback(Identity) + } +} + +impl QPathBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + /// Construct a `QPathBuilder` that will call the `callback` with a constructed `ast::QSelf` + /// and `ast::Path`. + pub fn new_with_callback(callback: F) -> Self { + QPathBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + /// Update the span to start from this location. + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + /// Build a qualified path first by starting with a type builder. + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + /// Build a qualified path with a concrete type and path. + pub fn build(self, qself: ast::QSelf, path: ast::Path) -> F::Result { + self.callback.invoke((qself, path)) + } +} + +impl Invoke> for QPathBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + type Result = QPathTyBuilder; + + fn invoke(self, ty: P) -> QPathTyBuilder { + QPathTyBuilder { + builder: self, + ty: ty, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct QPathTyBuilder { + builder: QPathBuilder, + ty: P, +} + +impl QPathTyBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + /// Build a qualified path with a path builder. + pub fn as_(self) -> PathBuilder { + PathBuilder::new_with_callback(self) + } + + pub fn id(self, id: T) -> F::Result + where T: ToIdent, + { + let path = ast::Path { + span: self.builder.span, + global: false, + segments: vec![], + }; + self.as_().build(path).id(id) + } + + pub fn segment(self, id: T) -> PathSegmentBuilder> + where T: ToIdent, + { + let path = ast::Path { + span: self.builder.span, + global: false, + segments: vec![], + }; + self.as_().build(path).segment(id) + } +} + +impl Invoke for QPathTyBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + type Result = QPathQSelfBuilder; + + fn invoke(self, path: ast::Path) -> QPathQSelfBuilder { + QPathQSelfBuilder { + builder: self.builder, + qself: ast::QSelf { + ty: self.ty, + position: path.segments.len(), + }, + path: path, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct QPathQSelfBuilder { + builder: QPathBuilder, + qself: ast::QSelf, + path: ast::Path, +} + +impl QPathQSelfBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + pub fn id(self, id: T) -> F::Result + where T: ToIdent, + { + self.segment(id).build() + } + + pub fn segment(self, id: T) -> PathSegmentBuilder> + where T: ToIdent, + { + PathSegmentBuilder::new_with_callback(id, self) + } +} + +impl Invoke for QPathQSelfBuilder + where F: Invoke<(ast::QSelf, ast::Path)>, +{ + type Result = F::Result; + + fn invoke(mut self, segment: ast::PathSegment) -> F::Result { + self.path.segments.push(segment); + self.builder.build(self.qself, self.path) + } +} diff --git a/src/libaster/stmt.rs b/src/libaster/stmt.rs new file mode 100644 index 0000000000000..98ed1ad2dcd7b --- /dev/null +++ b/src/libaster/stmt.rs @@ -0,0 +1,266 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +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 { + callback: F, + span: Span, +} + +impl StmtBuilder { + pub fn new() -> StmtBuilder { + StmtBuilder::new_with_callback(Identity) + } +} + +impl StmtBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + StmtBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn build(self, stmt: P) -> F::Result { + self.callback.invoke(stmt) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build_stmt_(self, stmt_: ast::Stmt_) -> F::Result { + let stmt = P(respan(self.span, stmt_)); + self.build(stmt) + } + + pub fn build_let(self, + pat: P, + ty: Option>, + init: Option>) -> F::Result { + let local = ast::Local { + pat: pat, + ty: ty, + init: init, + id: ast::DUMMY_NODE_ID, + span: self.span, + }; + + let decl = respan(self.span, ast::Decl_::DeclLocal(P(local))); + + self.build_stmt_(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)) + } + + pub fn let_(self) -> PatBuilder { + PatBuilder::new_with_callback(self) + } + + pub fn let_id(self, id: I) -> ExprBuilder> + where I: ToIdent, + { + let span = self.span; + ExprBuilder::new_with_callback(StmtLetIdBuilder(self, id.to_ident())).span(span) + } + + pub fn build_expr(self, expr: P) -> F::Result { + self.build_stmt_(ast::Stmt_::StmtExpr(expr, ast::DUMMY_NODE_ID)) + } + + pub fn expr(self) -> ExprBuilder> { + let span = self.span; + ExprBuilder::new_with_callback(StmtExprBuilder(self)).span(span) + } + + pub fn semi(self) -> ExprBuilder> { + let span = self.span; + ExprBuilder::new_with_callback(StmtSemiBuilder(self)).span(span) + } + + pub fn build_item(self, item: P) -> F::Result { + let decl = respan(self.span, ast::Decl_::DeclItem(item)); + self.build_stmt_(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)) + } + + pub fn item(self) -> ItemBuilder> { + let span = self.span; + ItemBuilder::new_with_callback(StmtItemBuilder(self)).span(span) + } +} + +impl Invoke> for StmtBuilder + where F: Invoke>, +{ + type Result = StmtLetBuilder; + + fn invoke(self, pat: P) -> StmtLetBuilder { + StmtLetBuilder { + builder: self, + pat: pat, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtLetIdBuilder(StmtBuilder, ast::Ident); + +impl Invoke> for StmtLetIdBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.0.let_().id(self.1).build_expr(expr) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtExprBuilder(StmtBuilder); + +impl Invoke> for StmtExprBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.0.build_expr(expr) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtSemiBuilder(StmtBuilder); + +impl Invoke> for StmtSemiBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.0.build_stmt_(ast::Stmt_::StmtSemi(expr, ast::DUMMY_NODE_ID)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtLetBuilder { + builder: StmtBuilder, + pat: P, +} + +impl StmtLetBuilder + where F: Invoke>, +{ + fn build_ty(self, ty: P) -> StmtLetTyBuilder { + StmtLetTyBuilder { + builder: self.builder, + pat: self.pat, + ty: ty, + } + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build_expr(self, expr: P) -> F::Result { + self.builder.build_let(self.pat, None, Some(expr)) + } + + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_let(self.pat, None, None) + } +} + +impl Invoke> for StmtLetBuilder + where F: Invoke>, +{ + type Result = StmtLetTyBuilder; + + fn invoke(self, ty: P) -> StmtLetTyBuilder { + self.build_ty(ty) + } +} + +impl Invoke> for StmtLetBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.build_expr(expr) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtLetTyBuilder { + builder: StmtBuilder, + pat: P, + ty: P, +} + +impl StmtLetTyBuilder + where F: Invoke>, +{ + pub fn expr(self) -> ExprBuilder { + ExprBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_let(self.pat, Some(self.ty), None) + } +} + +impl Invoke> for StmtLetTyBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, expr: P) -> F::Result { + self.builder.build_let(self.pat, Some(self.ty), Some(expr)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StmtItemBuilder(StmtBuilder); + +impl Invoke> for StmtItemBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, item: P) -> F::Result { + self.0.build_item(item) + } +} + diff --git a/src/libaster/str.rs b/src/libaster/str.rs new file mode 100644 index 0000000000000..8e6f5fbedbcd2 --- /dev/null +++ b/src/libaster/str.rs @@ -0,0 +1,53 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::parse::token; + +pub use expr::ExprBuilder; +pub use ident::ToIdent; +pub use name::ToName; +pub use path::PathBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub trait ToInternedString { + fn to_interned_string(&self) -> token::InternedString; +} + +impl ToInternedString for token::InternedString { + fn to_interned_string(&self) -> token::InternedString { + self.clone() + } +} + +impl<'a> ToInternedString for &'a str { + fn to_interned_string(&self) -> token::InternedString { + token::intern_and_get_ident(self) + } +} + +impl ToInternedString for ast::Ident { + fn to_interned_string(&self) -> token::InternedString { + self.name.as_str() + } +} + +impl ToInternedString for ast::Name { + fn to_interned_string(&self) -> token::InternedString { + self.as_str() + } +} + +impl<'a, T> ToInternedString for &'a T where T: ToInternedString { + fn to_interned_string(&self) -> token::InternedString { + (**self).to_interned_string() + } +} diff --git a/src/libaster/struct_def.rs b/src/libaster/struct_def.rs new file mode 100644 index 0000000000000..62fde73220d32 --- /dev/null +++ b/src/libaster/struct_def.rs @@ -0,0 +1,183 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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 { + callback: F, + span: Span, + fields: Vec, +} + +impl StructDefBuilder { + pub fn new() -> Self { + StructDefBuilder::new_with_callback(Identity) + } +} + +impl StructDefBuilder + where F: Invoke> +{ + 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_fields(mut self, iter: I) -> Self + where I: IntoIterator, + { + self.fields.extend(iter); + self + } + + pub fn with_field(mut self, field: ast::StructField) -> Self { + self.fields.push(field); + self + } + + pub fn field(self, id: T) -> StructFieldBuilder + where T: ToIdent, + { + let span = self.span; + StructFieldBuilder::named_with_callback(id, self).span(span) + } + + pub fn build(self) -> F::Result { + self.callback.invoke(P(ast::StructDef { + fields: self.fields, + ctor_id: None, + })) + } +} + +impl Invoke for StructDefBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, field: ast::StructField) -> Self { + self.with_field(field) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct StructFieldBuilder { + callback: F, + span: Span, + kind: ast::StructFieldKind, + attrs: Vec, +} + +impl StructFieldBuilder { + pub fn named(name: T) -> Self + where T: ToIdent, + { + StructFieldBuilder::named_with_callback(name, Identity) + } + + pub fn unnamed() -> Self { + StructFieldBuilder::unnamed_with_callback(Identity) + } +} + +impl StructFieldBuilder + where F: Invoke, +{ + pub fn named_with_callback(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 { + let span = self.span; + AttrBuilder::new_with_callback(self).span(span) + } + + pub fn build_ty(self, ty: P) -> 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 { + let span = self.span; + TyBuilder::new_with_callback(self).span(span) + } +} + +impl Invoke for StructFieldBuilder { + type Result = Self; + + fn invoke(mut self, attr: ast::Attribute) -> Self { + self.attrs.push(attr); + self + } +} + +impl Invoke> for StructFieldBuilder + where F: Invoke, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_ty(ty) + } +} diff --git a/src/libaster/tests/mod.rs b/src/libaster/tests/mod.rs new file mode 100644 index 0000000000000..3c8cd0e6a7ff6 --- /dev/null +++ b/src/libaster/tests/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod test_attr; +mod test_expr; +mod test_fn_decl; +mod test_generics; +mod test_item; +mod test_lit; +mod test_path; +mod test_stmt; +mod test_struct_def; +mod test_ty; +mod test_variant; diff --git a/src/libaster/tests/test_attr.rs b/src/libaster/tests/test_attr.rs new file mode 100644 index 0000000000000..d2ddb0acb8df2 --- /dev/null +++ b/src/libaster/tests/test_attr.rs @@ -0,0 +1,38 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, respan}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_doc() { + let builder = AstBuilder::new(); + assert_eq!( + builder.attr().doc("/// doc string"), + respan( + DUMMY_SP, + ast::Attribute_ { + id: ast::AttrId(0), + style: ast::AttrOuter, + value: P(respan( + DUMMY_SP, + ast::MetaNameValue( + builder.interned_string("doc"), + (*builder.lit().str("/// doc string")).clone(), + ), + )), + is_sugared_doc: true, + } + ) + ); +} diff --git a/src/libaster/tests/test_expr.rs b/src/libaster/tests/test_expr.rs new file mode 100644 index 0000000000000..1b0dcf9c4f995 --- /dev/null +++ b/src/libaster/tests/test_expr.rs @@ -0,0 +1,239 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Spanned}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_lit() { + let builder = AstBuilder::new(); + + fn check(expr: P, lit: P) { + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprLit(lit), + span: DUMMY_SP, + }) + ); + } + + check(builder.expr().int(5), builder.lit().int(5)); + + check(builder.expr().i8(5), builder.lit().i8(5)); + check(builder.expr().i16(5), builder.lit().i16(5)); + check(builder.expr().i32(5), builder.lit().i32(5)); + check(builder.expr().i64(5), builder.lit().i64(5)); + check(builder.expr().isize(5), builder.lit().isize(5)); + + check(builder.expr().u8(5), builder.lit().u8(5)); + check(builder.expr().u16(5), builder.lit().u16(5)); + check(builder.expr().u32(5), builder.lit().u32(5)); + check(builder.expr().u64(5), builder.lit().u64(5)); + check(builder.expr().usize(5), builder.lit().usize(5)); + + check(builder.expr().str("string"), builder.lit().str("string")); +} + +#[test] +fn test_path() { + let builder = AstBuilder::new(); + + let expr = builder.expr().path() + .id("x") + .build(); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + None, + builder.path().id("x").build(), + ), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_qpath() { + let builder = AstBuilder::new(); + + let expr = builder.expr().qpath() + .ty().slice().infer() + .id("into_vec"); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + Some(ast::QSelf { + ty: builder.ty().slice().infer(), + position: 0, + }), + builder.path().id("into_vec").build(), + ), + span: DUMMY_SP, + }) + ); + + let expr: P = builder.expr().qpath() + .ty().slice().infer() + .as_().id("Slice").build() + .id("into_vec"); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + Some(ast::QSelf { + ty: builder.ty().slice().infer(), + position: 1, + }), + builder.path() + .id("Slice") + .id("into_vec") + .build(), + ), + span: DUMMY_SP, + }) + ); +} + + +#[test] +fn test_bin() { + let builder = AstBuilder::new(); + + assert_eq!( + builder.expr().add().i8(1).i8(2), + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprBinary( + Spanned { + span: DUMMY_SP, + node: ast::BiAdd, + }, + builder.expr().i8(1), + builder.expr().i8(2), + ), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_unit() { + let builder = AstBuilder::new(); + + assert_eq!( + builder.expr().unit(), + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprTup(vec![]), + span: DUMMY_SP, + }) + ); + + assert_eq!( + builder.expr().tuple().build(), + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprTup(vec![]), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_tuple() { + let builder = AstBuilder::new(); + + let expr = builder.expr().tuple() + .expr().i8(1) + .expr().tuple() + .expr().unit() + .expr().isize(2) + .build() + .build(); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprTup(vec![ + builder.expr().i8(1), + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprTup(vec![ + builder.expr().unit(), + builder.expr().isize(2), + ]), + span: DUMMY_SP, + }) + ]), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_slice() { + let builder = AstBuilder::new(); + + let expr = builder.expr().slice() + .expr().i8(1) + .expr().i8(2) + .expr().i8(3) + .build(); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprVec(vec![ + builder.expr().i8(1), + builder.expr().i8(2), + builder.expr().i8(3), + ]), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_vec() { + let builder = AstBuilder::new(); + + let expr = builder.expr().vec() + .expr().i8(1) + .expr().i8(2) + .expr().i8(3) + .build(); + + assert_eq!( + expr, + builder.expr().call() + .qpath().ty().slice().infer().id("into_vec") + .arg().box_().slice() + .expr().i8(1) + .expr().i8(2) + .expr().i8(3) + .build() + .build() + ); +} diff --git a/src/libaster/tests/test_fn_decl.rs b/src/libaster/tests/test_fn_decl.rs new file mode 100644 index 0000000000000..22a600a75bf72 --- /dev/null +++ b/src/libaster/tests/test_fn_decl.rs @@ -0,0 +1,89 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_no_args_return_isize() { + let builder = AstBuilder::new(); + let fn_decl = builder.fn_decl().return_().isize(); + + assert_eq!( + fn_decl, + P(ast::FnDecl { + inputs: vec![], + output: ast::Return(builder.ty().isize()), + variadic: false, + }) + ); +} + +#[test] +fn test_args_return_isize() { + let builder = AstBuilder::new(); + let fn_decl = builder.fn_decl() + .arg("x").ty().isize() + .arg("y").ty().isize() + .return_().isize(); + + assert_eq!( + fn_decl, + P(ast::FnDecl { + inputs: vec![ + ast::Arg { + ty: builder.ty().isize(), + pat: builder.pat().id("x"), + id: ast::DUMMY_NODE_ID, + }, + ast::Arg { + ty: builder.ty().isize(), + pat: builder.pat().id("y"), + id: ast::DUMMY_NODE_ID, + }, + ], + output: ast::Return(builder.ty().isize()), + variadic: false, + }) + ); +} + +#[test] +fn test_no_return() { + let builder = AstBuilder::new(); + let fn_decl = builder.fn_decl().no_return(); + + assert_eq!( + fn_decl, + P(ast::FnDecl { + inputs: vec![], + output: ast::NoReturn(DUMMY_SP), + variadic: false, + }) + ); +} + +#[test] +fn test_default_return() { + let builder = AstBuilder::new(); + let fn_decl = builder.fn_decl().default_return(); + + assert_eq!( + fn_decl, + P(ast::FnDecl { + inputs: vec![], + output: ast::DefaultReturn(DUMMY_SP), + variadic: false, + }) + ); +} diff --git a/src/libaster/tests/test_generics.rs b/src/libaster/tests/test_generics.rs new file mode 100644 index 0000000000000..89ea1ecbe36f8 --- /dev/null +++ b/src/libaster/tests/test_generics.rs @@ -0,0 +1,59 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::owned_slice::OwnedSlice; + +use super::super::AstBuilder; + +#[test] +fn test_empty() { + let builder = AstBuilder::new(); + let generics = builder.generics().build(); + + assert_eq!( + generics, + ast::Generics { + lifetimes: vec![], + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: vec![], + }, + } + ); +} + +#[test] +fn test_with_ty_params_and_lifetimes() { + let builder = AstBuilder::new(); + let generics = builder.generics() + .lifetime("'a").build() + .lifetime("'b").bound("'a").build() + .ty_param("T").lifetime_bound("'a").build() + .build(); + + assert_eq!( + generics, + ast::Generics { + lifetimes: vec![ + builder.lifetime_def("'a").build(), + builder.lifetime_def("'b").bound("'a").build(), + ], + ty_params: OwnedSlice::from_vec(vec![ + builder.ty_param("T").lifetime_bound("'a").build(), + ]), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: vec![], + }, + } + ); +} diff --git a/src/libaster/tests/test_item.rs b/src/libaster/tests/test_item.rs new file mode 100644 index 0000000000000..686716e2ba32d --- /dev/null +++ b/src/libaster/tests/test_item.rs @@ -0,0 +1,645 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Spanned, respan}; +use syntax::parse::token; +use syntax::print::pprust; +use syntax::ptr::P; + +use super::super::AstBuilder; +use super::super::ident::ToIdent; +use super::super::name::ToName; + +#[test] +fn test_fn() { + let builder = AstBuilder::new(); + + let block = builder.block() + .stmt().let_id("x").isize(1) + .stmt().let_id("y").isize(2) + .expr().add().id("x").id("y"); + + let fn_ = builder.item().fn_("foo") + .return_().isize() + .build(block.clone()); + + assert_eq!( + fn_, + P(ast::Item { + ident: builder.id("foo"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemFn( + builder.fn_decl().return_().isize(), + ast::Unsafety::Normal, + ast::Constness::NotConst, + Abi::Rust, + builder.generics().build(), + block + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_generic_fn() { + let builder = AstBuilder::new(); + + let block = builder.block() + .stmt().let_id("x").isize(1) + .stmt().let_id("y").isize(2) + .expr().add().id("x").id("y"); + + let fn_ = builder.item().fn_("foo") + .return_().isize() + .generics() + .lifetime("'a").build() + .lifetime("'b").bound("'a").build() + .ty_param("T").build() + .build() + .build(block.clone()); + + assert_eq!( + fn_, + P(ast::Item { + ident: builder.id("foo"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemFn( + builder.fn_decl().return_().isize(), + ast::Unsafety::Normal, + ast::Constness::NotConst, + Abi::Rust, + builder.generics() + .lifetime("'a").build() + .lifetime("'b").bound("'a").build() + .ty_param("T").build() + .build(), + block + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_empty_struct() { + let builder = AstBuilder::new(); + let struct_ = builder.item().struct_("Struct").build(); + + assert_eq!( + struct_, + P(ast::Item { + ident: builder.id("Struct"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemStruct( + builder.struct_def().build(), + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_struct() { + let builder = AstBuilder::new(); + let struct_ = builder.item().struct_("Struct") + .field("x").ty().isize() + .field("y").ty().isize() + .build(); + + assert_eq!( + struct_, + P(ast::Item { + ident: builder.id("Struct"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemStruct( + builder.struct_def() + .field("x").ty().isize() + .field("y").ty().isize() + .build(), + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_struct_with_fields() { + let builder = AstBuilder::new(); + let struct_ = builder.item().struct_("Struct") + .field("x").ty().isize() + .field("y").ty().isize() + .build(); + + let struct_2 = builder.item().struct_("Struct") + .with_fields( + vec!["x","y"].iter() + .map(|f| builder.field(f).ty().isize()) + ) + .build(); + + assert_eq!( + struct_, + struct_2 + ); +} + +#[test] +fn test_tuple_struct() { + let builder = AstBuilder::new(); + let struct_ = builder.item().tuple_struct("Struct") + .ty().isize() + .ty().isize() + .build(); + + assert_eq!( + struct_, + P(ast::Item { + ident: builder.id("Struct"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemStruct( + P(ast::StructDef { + fields: vec![ + Spanned { + span: DUMMY_SP, + node: ast::StructField_ { + kind: ast::UnnamedField( + ast::Inherited, + ), + id: ast::DUMMY_NODE_ID, + ty: builder.ty().isize(), + attrs: vec![], + }, + }, + Spanned { + span: DUMMY_SP, + node: ast::StructField_ { + kind: ast::UnnamedField( + ast::Inherited, + ), + id: ast::DUMMY_NODE_ID, + ty: builder.ty().isize(), + attrs: vec![], + }, + }, + ], + ctor_id: Some(ast::DUMMY_NODE_ID), + }), + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_empty_enum() { + let builder = AstBuilder::new(); + let enum_= builder.item().enum_("Enum").build(); + + assert_eq!( + enum_, + P(ast::Item { + ident: builder.id("Enum"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemEnum( + ast::EnumDef { + variants: vec![], + }, + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_enum() { + let builder = AstBuilder::new(); + let enum_= builder.item().enum_("Enum") + .id("A") + .tuple("B").build() + .tuple("C") + .ty().isize() + .build() + .tuple("D") + .ty().isize() + .ty().isize() + .build() + .struct_("E") + .field("a").ty().isize() + .build() + .struct_("F") + .field("a").ty().isize() + .field("b").ty().isize() + .build() + .build(); + + assert_eq!( + enum_, + P(ast::Item { + ident: builder.id("Enum"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemEnum( + ast::EnumDef { + variants: vec![ + builder.variant("A").tuple().build(), + builder.variant("B").tuple().build(), + builder.variant("C").tuple() + .ty().isize() + .build(), + builder.variant("D").tuple() + .ty().isize() + .ty().isize() + .build(), + builder.variant("E").struct_() + .field("a").ty().isize() + .build(), + builder.variant("F").struct_() + .field("a").ty().isize() + .field("b").ty().isize() + .build(), + ], + }, + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_use() { + fn check(item: P, view_path: ast::ViewPath_) { + assert_eq!( + item, + P(ast::Item { + ident: token::special_idents::invalid, + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemUse( + P(respan(DUMMY_SP, view_path)) + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); + } + + let builder = AstBuilder::new(); + + let item = builder.item().use_() + .ids(&["std", "vec", "Vec"]).build() + .build(); + + check( + item, + ast::ViewPathSimple( + "Vec".to_ident(), + builder.path().ids(&["std", "vec", "Vec"]).build() + ) + ); + + let item = builder.item().use_() + .ids(&["std", "vec", "Vec"]).build() + .as_("MyVec"); + + check( + item, + ast::ViewPathSimple( + "MyVec".to_ident(), + builder.path().ids(&["std", "vec", "Vec"]).build() + ) + ); + + let item = builder.item().use_() + .ids(&["std", "vec"]).build() + .glob(); + + check( + item, + ast::ViewPathGlob( + builder.path().ids(&["std", "vec"]).build() + ) + ); + + let item = builder.item().use_() + .ids(&["std", "vec"]).build() + .list() + .build(); + + check( + item, + ast::ViewPathList( + builder.path().ids(&["std", "vec"]).build(), + vec![], + ) + ); + + let item = builder.item().use_() + .ids(&["std", "vec"]).build() + .list() + .self_() + .id("Vec") + .id("IntoIter") + .build(); + + check( + item, + ast::ViewPathList( + builder.path().ids(&["std", "vec"]).build(), + vec![ + respan(DUMMY_SP, ast::PathListMod { + id: ast::DUMMY_NODE_ID, + rename: None + }), + respan(DUMMY_SP, ast::PathListIdent { + name: "Vec".to_ident(), + id: ast::DUMMY_NODE_ID, + rename: None + }), + respan(DUMMY_SP, ast::PathListIdent { + name: "IntoIter".to_ident(), + id: ast::DUMMY_NODE_ID, + rename: None + }), + ], + ) + ); +} + +#[test] +fn test_attr() { + let builder = AstBuilder::new(); + let struct_ = builder.item() + .attr().doc("/// doc string") + .struct_("Struct") + .field("x").ty().isize() + .field("y").ty().isize() + .build(); + + assert_eq!( + struct_, + P(ast::Item { + ident: builder.id("Struct"), + attrs: vec![ + respan( + DUMMY_SP, + ast::Attribute_ { + id: ast::AttrId(0), + style: ast::AttrOuter, + value: P(respan( + DUMMY_SP, + ast::MetaNameValue( + builder.interned_string("doc"), + (*builder.lit().str("/// doc string")).clone(), + ), + )), + is_sugared_doc: true, + } + ), + ], + id: ast::DUMMY_NODE_ID, + node: ast::ItemStruct( + builder.struct_def() + .field("x").ty().isize() + .field("y").ty().isize() + .build(), + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_extern_crate() { + let builder = AstBuilder::new(); + let item = builder.item() + .extern_crate("aster") + .build(); + + assert_eq!( + item, + P(ast::Item { + ident: builder.id("aster"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemExternCrate(None), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); + + let item = builder.item() + .extern_crate("aster") + .with_name("aster1".to_name()); + + assert_eq!( + item, + P(ast::Item { + ident: builder.id("aster"), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemExternCrate(Some("aster1".to_name())), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_mac() { + let builder = AstBuilder::new(); + let mac = builder.item().mac() + .path().id("my_macro").build() + .expr().str("abc") + .expr().id(",") + .expr().build_add(builder.expr().u32(0), builder.expr().u32(1)) + .build(); + + assert_eq!( + &pprust::item_to_string(&mac)[..], + "my_macro! (\"abc\" , 0u32 + 1u32);" + ); + + let mac = builder.item().mac() + .path().id("my_macro").build() + .with_args( + vec![ + builder.expr().str("abc"), + builder.expr().id(","), + builder.expr().build_add(builder.expr().u32(0), builder.expr().u32(1)) + ] + ) + .build(); + + assert_eq!( + &pprust::item_to_string(&mac)[..], + "my_macro! (\"abc\" , 0u32 + 1u32);" + ); +} + +#[test] +fn test_type() { + let builder = AstBuilder::new(); + let enum_= builder.item().type_("MyT") + .ty().isize(); + + assert_eq!( + enum_, + P(ast::Item { + ident: builder.id("MyT"), + id: ast::DUMMY_NODE_ID, + attrs: vec![], + node: ast::ItemTy( + builder.ty().isize(), + builder.generics().build(), + ), + vis: ast::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_impl() { + let builder = AstBuilder::new(); + let impl_ = builder.item().impl_() + .trait_().id("ser").id("Serialize").build() + + // Type + .item("MyFloat").type_().f64() + + // Const + .item("PI").const_() + .expr().f64("3.14159265358979323846264338327950288") + .ty().f64() + + // Method + .item("serialize").method() + .fn_decl() + .arg("serializer").ty().ref_().mut_().ty().path().id("ser").id("Serialize").build() + .default_return() + .block().build() // empty method block + .build() + + .ty().id("MySerializer"); + + assert_eq!( + impl_, + P(ast::Item { + ident: builder.id(""), + id: ast::DUMMY_NODE_ID, + attrs: vec![], + node: ast::ItemImpl( + ast::Unsafety::Normal, + ast::ImplPolarity::Positive, + builder.generics().build(), + Some(ast::TraitRef { + path: builder.path().id("ser").id("Serialize").build(), + ref_id: 0 + }), + builder.ty().id("MySerializer"), + vec![ + P(ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: builder.id("MyFloat"), + vis: ast::Visibility::Inherited, + attrs: vec![], + node: ast::TypeImplItem(builder.ty().f64()), + span: DUMMY_SP, + }), + + P(ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: builder.id("PI"), + vis: ast::Visibility::Inherited, + attrs: vec![], + node: ast::ConstImplItem( + builder.ty().f64(), + builder.expr().f64("3.14159265358979323846264338327950288"), + ), + span: DUMMY_SP, + }), + + P(ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: builder.id("serialize"), + vis: ast::Visibility::Inherited, + attrs: vec![], + node: ast::MethodImplItem( + ast::MethodSig { + unsafety: ast::Unsafety::Normal, + constness: ast::Constness::NotConst, + abi: Abi::Rust, + decl: builder.fn_decl() + .arg("serializer").ty() + .ref_() + .mut_() + .ty() + .path().id("ser").id("Serialize").build() + .default_return(), + generics: builder.generics().build(), + explicit_self: respan(DUMMY_SP, ast::ExplicitSelf_::SelfStatic), + }, + builder.block().build() + ), + span: DUMMY_SP, + }) + ] + ), + vis: ast::Visibility::Inherited, + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_const() { + let builder = AstBuilder::new(); + let const_ = builder.item().const_("PI") + .expr().f64("3.14159265358979323846264338327950288") + .ty().f64(); + + assert_eq!( + const_, + P(ast::Item { + ident: builder.id("PI"), + id: ast::DUMMY_NODE_ID, + attrs: vec![], + node: ast::ItemConst( + builder.ty().f64(), + builder.expr().f64("3.14159265358979323846264338327950288") + ), + vis: ast::Visibility::Inherited, + span: DUMMY_SP, + }) + ); +} diff --git a/src/libaster/tests/test_lit.rs b/src/libaster/tests/test_lit.rs new file mode 100644 index 0000000000000..7c208c119d14a --- /dev/null +++ b/src/libaster/tests/test_lit.rs @@ -0,0 +1,85 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Spanned}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_int() { + let builder = AstBuilder::new(); + + fn check(lit: P, value: u64, lit_int_ty: ast::LitIntType) { + assert_eq!( + lit, + P(Spanned { + span: DUMMY_SP, + node: ast::LitInt(value, lit_int_ty), + }) + ); + } + + check(builder.lit().i8(1), 1, ast::SignedIntLit(ast::TyI8, ast::Plus)); + check(builder.lit().i16(1), 1, ast::SignedIntLit(ast::TyI16, ast::Plus)); + check(builder.lit().i32(1), 1, ast::SignedIntLit(ast::TyI32, ast::Plus)); + check(builder.lit().i64(1), 1, ast::SignedIntLit(ast::TyI64, ast::Plus)); + check(builder.lit().isize(1), 1, ast::SignedIntLit(ast::TyIs, ast::Plus)); + + check(builder.lit().i8(-1), !0, ast::SignedIntLit(ast::TyI8, ast::Minus)); + check(builder.lit().i16(-1), !0, ast::SignedIntLit(ast::TyI16, ast::Minus)); + check(builder.lit().i32(-1), !0, ast::SignedIntLit(ast::TyI32, ast::Minus)); + check(builder.lit().i64(-1), !0, ast::SignedIntLit(ast::TyI64, ast::Minus)); + check(builder.lit().isize(-1), !0, ast::SignedIntLit(ast::TyIs, ast::Minus)); + + check(builder.lit().u8(1), 1, ast::UnsignedIntLit(ast::TyU8)); + check(builder.lit().u16(1), 1, ast::UnsignedIntLit(ast::TyU16)); + check(builder.lit().u32(1), 1, ast::UnsignedIntLit(ast::TyU32)); + check(builder.lit().u64(1), 1, ast::UnsignedIntLit(ast::TyU64)); + check(builder.lit().usize(1), 1, ast::UnsignedIntLit(ast::TyUs)); + + check(builder.lit().int(1), 1, ast::UnsuffixedIntLit(ast::Plus)); + check(builder.lit().int(-1), !0, ast::UnsuffixedIntLit(ast::Minus)); +} + +#[test] +fn test_bool() { + let builder = AstBuilder::new(); + + assert_eq!(builder.lit().bool(true), + P(Spanned { + span: DUMMY_SP, + node: ast::LitBool(true) + }) + ); + + assert_eq!(builder.lit().bool(false), + P(Spanned { + span: DUMMY_SP, + node: ast::LitBool(false) + }) + ); +} + +#[test] +fn test_str() { + let builder = AstBuilder::new(); + + assert_eq!(builder.lit().str("string"), + P(Spanned { + span: DUMMY_SP, + node: ast::LitStr( + builder.interned_string("string"), + ast::CookedStr, + ), + }) + ); +} diff --git a/src/libaster/tests/test_path.rs b/src/libaster/tests/test_path.rs new file mode 100644 index 0000000000000..84f5527de01c0 --- /dev/null +++ b/src/libaster/tests/test_path.rs @@ -0,0 +1,159 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use syntax::owned_slice::OwnedSlice; + +use super::super::AstBuilder; + +#[test] +fn test_id() { + let builder = AstBuilder::new(); + let path = builder.path().id("isize").build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ + ast::PathSegment { + identifier: builder.id("isize"), + parameters: ast::PathParameters::none(), + }, + ] + } + ); +} + +#[test] +fn test_single_segment() { + let builder = AstBuilder::new(); + let path = builder.path() + .segment("isize").build() + .build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ + ast::PathSegment { + identifier: builder.id("isize"), + parameters: ast::PathParameters::none(), + }, + ] + } + ); +} + +#[test] +fn test_multiple_segments() { + let builder = AstBuilder::new(); + let path = builder.path().global() + .id("std") + .id("thread") + .id("Thread") + .build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: true, + segments: vec![ + ast::PathSegment { + identifier: builder.id("std"), + parameters: ast::PathParameters::none(), + }, + ast::PathSegment { + identifier: builder.id("thread"), + parameters: ast::PathParameters::none(), + }, + ast::PathSegment { + identifier: builder.id("Thread"), + parameters: ast::PathParameters::none(), + }, + ] + } + ); +} + +#[test] +fn test_option() { + let builder = AstBuilder::new(); + let path = builder.path().global() + .id("std") + .id("option") + .segment("Option") + .with_ty(builder.ty().id("isize")) + .build() + .build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: true, + segments: vec![ + ast::PathSegment { + identifier: builder.id("std"), + parameters: ast::PathParameters::none(), + }, + ast::PathSegment { + identifier: builder.id("option"), + parameters: ast::PathParameters::none(), + }, + ast::PathSegment { + identifier: builder.id("Option"), + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: vec![], + types: OwnedSlice::from_vec(vec![ + builder.ty().isize(), + ]), + bindings: OwnedSlice::empty(), + }), + }, + ] + } + ); +} + +#[test] +fn test_lifetimes() { + let builder = AstBuilder::new(); + let path = builder.path() + .segment("Foo") + .lifetime("'a") + .build() + .build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ + ast::PathSegment { + identifier: builder.id("Foo"), + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: vec![ + builder.lifetime("'a"), + ], + types: OwnedSlice::empty(), + bindings: OwnedSlice::empty(), + }), + }, + ] + } + ); +} diff --git a/src/libaster/tests/test_stmt.rs b/src/libaster/tests/test_stmt.rs new file mode 100644 index 0000000000000..e0237cbb21d03 --- /dev/null +++ b/src/libaster/tests/test_stmt.rs @@ -0,0 +1,140 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, respan}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_let() { + let builder = AstBuilder::new(); + + assert_eq!( + builder.stmt() + .let_().id("x").build(), + P(respan( + DUMMY_SP, + ast::StmtDecl( + P(respan( + DUMMY_SP, + ast::DeclLocal(P(ast::Local { + pat: builder.pat().id("x"), + ty: None, + init: None, + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })), + )), + ast::DUMMY_NODE_ID, + ), + )) + ); + + assert_eq!( + builder.stmt() + .let_().id("x").ty().i8().build(), + P(respan( + DUMMY_SP, + ast::StmtDecl( + P(respan( + DUMMY_SP, + ast::DeclLocal(P(ast::Local { + pat: builder.pat().id("x"), + ty: Some(builder.ty().i8()), + init: None, + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })), + )), + ast::DUMMY_NODE_ID, + ), + )) + ); + + assert_eq!( + builder.stmt() + .let_().id("x").expr().i8(5), + P(respan( + DUMMY_SP, + ast::StmtDecl( + P(respan( + DUMMY_SP, + ast::DeclLocal(P(ast::Local { + pat: builder.pat().id("x"), + ty: None, + init: Some(builder.expr().i8(5)), + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })), + )), + ast::DUMMY_NODE_ID, + ), + )) + ); + + assert_eq!( + builder.stmt() + .let_().id("x").ty().i8().expr().i8(5), + P(respan( + DUMMY_SP, + ast::StmtDecl( + P(respan( + DUMMY_SP, + ast::DeclLocal(P(ast::Local { + pat: builder.pat().id("x"), + ty: Some(builder.ty().i8()), + init: Some(builder.expr().i8(5)), + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })), + )), + ast::DUMMY_NODE_ID, + ), + )) + ); + + assert_eq!( + builder.stmt().let_() + .tuple() + .pat().id("x") + .pat().id("y") + .build() + .expr().tuple() + .expr().u8(0) + .expr().u16(1) + .build(), + P(respan( + DUMMY_SP, + ast::StmtDecl( + P(respan( + DUMMY_SP, + ast::DeclLocal(P(ast::Local { + pat: builder.pat().tuple() + .pat().id("x") + .pat().id("y") + .build(), + ty: None, + init: Some( + builder.expr().tuple() + .expr().u8(0) + .expr().u16(1) + .build() + ), + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + })), + )), + ast::DUMMY_NODE_ID, + ), + )) + ); +} diff --git a/src/libaster/tests/test_struct_def.rs b/src/libaster/tests/test_struct_def.rs new file mode 100644 index 0000000000000..acdd875a3c6aa --- /dev/null +++ b/src/libaster/tests/test_struct_def.rs @@ -0,0 +1,154 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Spanned, respan}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_empty() { + let builder = AstBuilder::new(); + let struct_def = builder.struct_def().build(); + + assert_eq!( + struct_def, + P(ast::StructDef { + fields: vec![], + ctor_id: None, + }) + ); +} + +#[test] +fn test_fields() { + let builder = AstBuilder::new(); + let struct_def = builder.struct_def() + .field("x").ty().isize() + .field("y").ty().isize() + .build(); + + assert_eq!( + struct_def, + P(ast::StructDef { + fields: vec![ + Spanned { + span: DUMMY_SP, + node: ast::StructField_ { + kind: ast::NamedField( + builder.id("x"), + ast::Inherited, + ), + id: ast::DUMMY_NODE_ID, + ty: builder.ty().isize(), + attrs: vec![], + }, + }, + Spanned { + span: DUMMY_SP, + node: ast::StructField_ { + kind: ast::NamedField( + builder.id("y"), + ast::Inherited, + ), + id: ast::DUMMY_NODE_ID, + ty: builder.ty().isize(), + attrs: vec![], + }, + }, + ], + ctor_id: None, + }) + ); +} + +#[test] +fn test_attrs() { + let builder = AstBuilder::new(); + let struct_def = builder.struct_def() + .field("x") + .attr().doc("/// doc string") + .attr().automatically_derived() + .ty().isize() + .build(); + + assert_eq!( + struct_def, + P(ast::StructDef { + fields: vec![ + Spanned { + span: DUMMY_SP, + node: ast::StructField_ { + kind: ast::NamedField( + builder.id("x"), + ast::Inherited, + ), + id: ast::DUMMY_NODE_ID, + ty: builder.ty().isize(), + attrs: vec![ + respan( + DUMMY_SP, + ast::Attribute_ { + id: ast::AttrId(0), + style: ast::AttrOuter, + value: P(respan( + DUMMY_SP, + ast::MetaNameValue( + builder.interned_string("doc"), + (*builder.lit().str("/// doc string")).clone(), + ), + )), + is_sugared_doc: true, + } + ), + respan( + DUMMY_SP, + ast::Attribute_ { + id: ast::AttrId(1), + style: ast::AttrOuter, + value: P(respan( + DUMMY_SP, + ast::MetaWord( + builder.interned_string("automatically_derived")), + )), + is_sugared_doc: false, + } + ), + ], + }, + }, + ], + ctor_id: None, + }) + ); +} + + +#[test] +fn test_with_fields() { + let builder = AstBuilder::new(); + let struct_def = builder.struct_def() + .field("x").ty().isize() + .field("y").ty().isize() + .build(); + + let struct_def2 = builder.struct_def() + .with_fields( + vec!["x","y"].iter() + .map(|f| builder.field(f).ty().isize()) + ) + .build(); + + assert_eq!( + struct_def, + struct_def2 + ); +} diff --git a/src/libaster/tests/test_ty.rs b/src/libaster/tests/test_ty.rs new file mode 100644 index 0000000000000..ee37f4164b24c --- /dev/null +++ b/src/libaster/tests/test_ty.rs @@ -0,0 +1,200 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_path() { + let builder = AstBuilder::new(); + let ty = builder.ty().isize(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyPath(None, builder.path().id("isize").build()), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_qpath() { + let builder = AstBuilder::new(); + + let expr = builder.expr().qpath() + .ty().slice().infer() + .id("into_vec"); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + Some(ast::QSelf { + ty: builder.ty().slice().infer(), + position: 0, + }), + builder.path().id("into_vec").build(), + ), + span: DUMMY_SP, + }) + ); + + let expr: P = builder.expr().qpath() + .ty().slice().infer() + .as_().id("Slice").build() + .id("into_vec"); + + assert_eq!( + expr, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprPath( + Some(ast::QSelf { + ty: builder.ty().slice().infer(), + position: 1, + }), + builder.path() + .id("Slice") + .id("into_vec") + .build(), + ), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_option() { + let builder = AstBuilder::new(); + let ty = builder.ty().option().isize(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyPath( + None, + builder.path().global() + .id("std") + .id("option") + .segment("Option") + .with_ty(builder.ty().id("isize")) + .build() + .build() + ), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_result() { + let builder = AstBuilder::new(); + let ty = builder.ty().result().isize().isize(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyPath( + None, + builder.path().global() + .id("std") + .id("result") + .segment("Result") + .with_ty(builder.ty().id("isize")) + .with_ty(builder.ty().id("isize")) + .build() + .build() + ), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_unit() { + let builder = AstBuilder::new(); + let ty = builder.ty().unit(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyTup(vec![]), + span: DUMMY_SP, + }) + ); + + let ty = builder.ty().tuple().build(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyTup(vec![]), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_tuple() { + let builder = AstBuilder::new(); + let ty = builder.ty() + .tuple() + .ty().isize() + .ty().tuple() + .ty().unit() + .ty().isize() + .build() + .build(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyTup(vec![ + builder.ty().isize(), + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyTup(vec![ + builder.ty().unit(), + builder.ty().isize(), + ]), + span: DUMMY_SP, + }), + ]), + span: DUMMY_SP, + }) + ); +} + +#[test] +fn test_slice() { + let builder = AstBuilder::new(); + let ty = builder.ty() + .slice().isize(); + + assert_eq!( + ty, + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyVec(builder.ty().isize()), + span: DUMMY_SP, + }) + ); +} diff --git a/src/libaster/tests/test_variant.rs b/src/libaster/tests/test_variant.rs new file mode 100644 index 0000000000000..45166ee2d51a8 --- /dev/null +++ b/src/libaster/tests/test_variant.rs @@ -0,0 +1,98 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Spanned}; +use syntax::ptr::P; + +use super::super::AstBuilder; + +#[test] +fn test_empty_tuple_variant() { + let builder = AstBuilder::new(); + let variant = builder.variant("A").tuple().build(); + + assert_eq!( + variant, + P(Spanned { + span: DUMMY_SP, + node: ast::Variant_ { + name: builder.id("A"), + attrs: vec![], + kind: ast::TupleVariantKind(vec![]), + id: ast::DUMMY_NODE_ID, + disr_expr: None, + vis: ast::Inherited, + }, + }) + ) +} + +#[test] +fn test_tuple_variant() { + let builder = AstBuilder::new(); + let variant = builder.variant("A").tuple() + .ty().isize() + .ty().isize() + .build(); + + assert_eq!( + variant, + P(Spanned { + span: DUMMY_SP, + node: ast::Variant_ { + name: builder.id("A"), + attrs: vec![], + kind: ast::TupleVariantKind(vec![ + ast::VariantArg { + ty: builder.ty().isize(), + id: ast::DUMMY_NODE_ID, + }, + ast::VariantArg { + ty: builder.ty().isize(), + id: ast::DUMMY_NODE_ID, + }, + ]), + id: ast::DUMMY_NODE_ID, + disr_expr: None, + vis: ast::Inherited, + }, + }) + ) +} + +#[test] +fn test_struct_variant() { + let builder = AstBuilder::new(); + let variant = builder.variant("A").struct_() + .field("a").ty().isize() + .field("b").ty().isize() + .build(); + + assert_eq!( + variant, + P(Spanned { + span: DUMMY_SP, + node: ast::Variant_ { + name: builder.id("A"), + attrs: vec![], + kind: ast::StructVariantKind( + builder.struct_def() + .field("a").ty().isize() + .field("b").ty().isize() + .build() + ), + id: ast::DUMMY_NODE_ID, + disr_expr: None, + vis: ast::Inherited, + }, + }) + ) +} diff --git a/src/libaster/ty.rs b/src/libaster/ty.rs new file mode 100644 index 0000000000000..0439807e00b2c --- /dev/null +++ b/src/libaster/ty.rs @@ -0,0 +1,391 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ptr::P; + +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use name::ToName; +use path::PathBuilder; +use qpath::QPathBuilder; + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyBuilder { + callback: F, + span: Span, +} + +impl TyBuilder { + pub fn new() -> Self { + TyBuilder::new_with_callback(Identity) + } +} + +impl TyBuilder + where F: Invoke>, +{ + pub fn new_with_callback(callback: F) -> Self { + TyBuilder { + callback: callback, + span: DUMMY_SP, + } + } + + pub fn build(self, ty: P) -> F::Result { + self.callback.invoke(ty) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn build_ty_(self, ty_: ast::Ty_) -> F::Result { + let span = self.span; + self.build(P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ty_, + span: span, + })) + } + + pub fn id(self, id: I) -> F::Result + where I: ToIdent, + { + self.path().id(id).build() + } + + pub fn build_path(self, path: ast::Path) -> F::Result { + self.build_ty_(ast::Ty_::TyPath(None, path)) + } + + pub fn build_qpath(self, qself: ast::QSelf, path: ast::Path) -> F::Result { + self.build_ty_(ast::Ty_::TyPath(Some(qself), path)) + } + + pub fn path(self) -> PathBuilder> { + PathBuilder::new_with_callback(TyPathBuilder(self)) + } + + pub fn qpath(self) -> QPathBuilder> { + QPathBuilder::new_with_callback(TyQPathBuilder(self)) + } + + pub fn isize(self) -> F::Result { + self.id("isize") + } + + pub fn i8(self) -> F::Result { + self.id("i8") + } + + pub fn i16(self) -> F::Result { + self.id("i16") + } + + pub fn i32(self) -> F::Result { + self.id("i32") + } + + pub fn i64(self) -> F::Result { + self.id("i64") + } + + pub fn usize(self) -> F::Result { + self.id("usize") + } + + pub fn u8(self) -> F::Result { + self.id("u8") + } + + pub fn u16(self) -> F::Result { + self.id("u16") + } + + pub fn u32(self) -> F::Result { + self.id("u32") + } + + pub fn u64(self) -> F::Result { + self.id("u64") + } + + pub fn f32(self) -> F::Result { + self.id("f32") + } + + pub fn f64(self) -> F::Result { + self.id("f64") + } + + pub fn unit(self) -> F::Result { + self.tuple().build() + } + + pub fn tuple(self) -> TyTupleBuilder { + TyTupleBuilder { + builder: self, + tys: vec![], + } + } + + pub fn build_slice(self, ty: P) -> F::Result { + self.build_ty_(ast::Ty_::TyVec(ty)) + } + + pub fn slice(self) -> TyBuilder> { + TyBuilder::new_with_callback(TySliceBuilder(self)) + } + + pub fn ref_(self) -> TyRefBuilder { + TyRefBuilder { + builder: self, + lifetime: None, + mutability: ast::MutImmutable, + } + } + + pub fn infer(self) -> F::Result { + self.build_ty_(ast::TyInfer) + } + + pub fn option(self) -> TyBuilder> { + TyBuilder::new_with_callback(TyOptionBuilder(self)) + } + + pub fn result(self) -> TyBuilder> { + TyBuilder::new_with_callback(TyResultOkBuilder(self)) + } + + pub fn phantom_data(self) -> TyBuilder> { + TyBuilder::new_with_callback(TyPhantomDataBuilder(self)) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyPathBuilder(TyBuilder); + +impl Invoke for TyPathBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, path: ast::Path) -> F::Result { + self.0.build_path(path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyQPathBuilder(TyBuilder); + +impl Invoke<(ast::QSelf, ast::Path)> for TyQPathBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, (qself, path): (ast::QSelf, ast::Path)) -> F::Result { + self.0.build_qpath(qself, path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TySliceBuilder(TyBuilder); + +impl Invoke> for TySliceBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.0.build_slice(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyRefBuilder { + builder: TyBuilder, + lifetime: Option, + mutability: ast::Mutability, +} + +impl TyRefBuilder + where F: Invoke>, +{ + pub fn mut_(mut self) -> Self { + self.mutability = ast::MutMutable; + self + } + + pub fn lifetime(mut self, name: N) -> Self + where N: ToName, + { + self.lifetime = Some(ast::Lifetime { + id: ast::DUMMY_NODE_ID, + span: self.builder.span, + name: name.to_name(), + }); + self + } + + pub fn build_ty(self, ty: P) -> F::Result { + let ty = ast::MutTy { + ty: ty, + mutbl: self.mutability, + }; + self.builder.build_ty_(ast::TyRptr(self.lifetime, ty)) + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } +} + +impl Invoke> for TyRefBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.build_ty(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyOptionBuilder(TyBuilder); + +impl Invoke> for TyOptionBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + let path = PathBuilder::new() + .global() + .id("std") + .id("option") + .segment("Option") + .with_ty(ty) + .build() + .build(); + + self.0.build_path(path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyResultOkBuilder(TyBuilder); + +impl Invoke> for TyResultOkBuilder + where F: Invoke>, +{ + type Result = TyBuilder>; + + fn invoke(self, ty: P) -> TyBuilder> { + TyBuilder::new_with_callback(TyResultErrBuilder(self.0, ty)) + } +} + +pub struct TyResultErrBuilder(TyBuilder, P); + +impl Invoke> for TyResultErrBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + let path = PathBuilder::new() + .global() + .id("std") + .id("result") + .segment("Result") + .with_ty(self.1) + .with_ty(ty) + .build() + .build(); + + self.0.build_path(path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyPhantomDataBuilder(TyBuilder); + +impl Invoke> for TyPhantomDataBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + let path = PathBuilder::new() + .global() + .id("std") + .id("marker") + .segment("PhantomData") + .with_ty(ty) + .build() + .build(); + + self.0.build_path(path) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyTupleBuilder { + builder: TyBuilder, + tys: Vec>, +} + +impl TyTupleBuilder + where F: Invoke>, +{ + pub fn with_tys(mut self, iter: I) -> Self + where I: IntoIterator>, + { + self.tys.extend(iter); + self + } + + pub fn with_ty(mut self, ty: P) -> Self { + self.tys.push(ty); + self + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + self.builder.build_ty_(ast::TyTup(self.tys)) + } +} + +impl Invoke> for TyTupleBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, ty: P) -> Self { + self.with_ty(ty) + } +} diff --git a/src/libaster/ty_param.rs b/src/libaster/ty_param.rs new file mode 100644 index 0000000000000..9e01d4a01c999 --- /dev/null +++ b/src/libaster/ty_param.rs @@ -0,0 +1,186 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::owned_slice::OwnedSlice; +use syntax::ptr::P; + +use ident::ToIdent; +use invoke::{Invoke, Identity}; +use lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder}; +use name::ToName; +use path::IntoPath; + +////////////////////////////////////////////////////////////////////////////// + +pub struct TyParamBuilder { + callback: F, + span: Span, + id: ast::Ident, + bounds: Vec, + default: Option>, +} + +impl TyParamBuilder { + pub fn new(id: I) -> Self + where I: ToIdent, + { + TyParamBuilder::new_with_callback(id, Identity) + } + + pub fn from_ty_param(ty_param: ast::TyParam) -> Self { + TyParamBuilder::from_ty_param_with_callback(Identity, ty_param) + } +} + +impl TyParamBuilder + where F: Invoke, +{ + pub fn new_with_callback(id: I, callback: F) -> Self + where I: ToIdent + { + TyParamBuilder { + callback: callback, + span: DUMMY_SP, + id: id.to_ident(), + bounds: Vec::new(), + default: None, + } + } + + pub fn from_ty_param_with_callback(callback: F, ty_param: ast::TyParam) -> Self { + TyParamBuilder { + callback: callback, + span: ty_param.span, + id: ty_param.ident, + bounds: ty_param.bounds.into_vec(), + default: ty_param.default, + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_default(mut self, ty: P) -> Self { + self.default = Some(ty); + self + } + + pub fn with_trait_bound(mut self, trait_ref: ast::PolyTraitRef) -> Self { + self.bounds.push(ast::TyParamBound::TraitTyParamBound( + trait_ref, + ast::TraitBoundModifier::None, + )); + self + } + + pub fn trait_bound

(self, path: P) -> PolyTraitRefBuilder + where P: IntoPath, + { + PolyTraitRefBuilder::new_with_callback(path, self) + } + + pub fn lifetime_bound(mut self, lifetime: L) -> Self + where L: IntoLifetime, + { + let lifetime = lifetime.into_lifetime(); + + self.bounds.push(ast::TyParamBound::RegionTyParamBound(lifetime)); + self + } + + pub fn build(self) -> F::Result { + self.callback.invoke(ast::TyParam { + ident: self.id, + id: ast::DUMMY_NODE_ID, + bounds: OwnedSlice::from_vec(self.bounds), + default: self.default, + span: self.span, + }) + } +} + +impl Invoke for TyParamBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, trait_ref: ast::PolyTraitRef) -> Self { + self.with_trait_bound(trait_ref) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct PolyTraitRefBuilder { + callback: F, + span: Span, + trait_ref: ast::TraitRef, + lifetimes: Vec, +} + +impl PolyTraitRefBuilder + where F: Invoke, +{ + pub fn new_with_callback

(path: P, callback: F) -> Self + where P: IntoPath, + { + let trait_ref = ast::TraitRef { + path: path.into_path(), + ref_id: ast::DUMMY_NODE_ID, + }; + + PolyTraitRefBuilder { + callback: callback, + span: DUMMY_SP, + trait_ref: trait_ref, + lifetimes: Vec::new(), + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn with_lifetime(mut self, lifetime: L) -> Self + where L: IntoLifetimeDef, + { + self.lifetimes.push(lifetime.into_lifetime_def()); + self + } + + pub fn lifetime(self, name: N) -> LifetimeDefBuilder + where N: ToName, + { + LifetimeDefBuilder::new_with_callback(name, self) + } + + pub fn build(self) -> F::Result { + self.callback.invoke(ast::PolyTraitRef { + bound_lifetimes: self.lifetimes, + trait_ref: self.trait_ref, + span: self.span, + }) + } +} + +impl Invoke for PolyTraitRefBuilder + where F: Invoke, +{ + type Result = Self; + + fn invoke(self, lifetime: ast::LifetimeDef) -> Self { + self.with_lifetime(lifetime) + } +} diff --git a/src/libaster/variant.rs b/src/libaster/variant.rs new file mode 100644 index 0000000000000..01adc89a7cdef --- /dev/null +++ b/src/libaster/variant.rs @@ -0,0 +1,193 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::IntoIterator; + +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; +use struct_def::{StructDefBuilder, StructFieldBuilder}; + +////////////////////////////////////////////////////////////////////////////// + +pub struct VariantBuilder { + callback: F, + span: Span, + attrs: Vec, + id: ast::Ident, +} + +impl VariantBuilder { + pub fn new(id: T) -> Self + where T: ToIdent, + { + VariantBuilder::new_with_callback(id, Identity) + } +} + +impl VariantBuilder + where F: Invoke>, +{ + pub fn new_with_callback(id: T, callback: F) -> Self + where T: ToIdent, + { + VariantBuilder { + callback: callback, + span: DUMMY_SP, + attrs: vec![], + id: id.to_ident(), + } + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn attr(self) -> AttrBuilder { + let span = self.span; + AttrBuilder::new_with_callback(self).span(span) + } + + pub fn tuple(self) -> VariantTupleBuilder { + VariantTupleBuilder { + builder: self, + args: vec![], + } + } + + pub fn struct_(self) -> StructDefBuilder> { + StructDefBuilder::new_with_callback(VariantStructBuilder { + builder: self, + }) + } + + pub fn build_variant_kind(self, kind: ast::VariantKind) -> F::Result { + let variant_ = ast::Variant_ { + name: self.id, + attrs: self.attrs, + kind: kind, + id: ast::DUMMY_NODE_ID, + disr_expr: None, + vis: ast::Visibility::Inherited, + }; + let variant = P(respan(self.span, variant_)); + self.callback.invoke(variant) + } + + pub fn build_variant_(self, variant: ast::Variant_) -> F::Result { + let variant = P(respan(self.span, variant)); + self.build(variant) + } + + pub fn build(self, variant: P) -> F::Result { + self.callback.invoke(variant) + } +} + +impl Invoke for VariantBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(mut self, attr: ast::Attribute) -> Self { + self.attrs.push(attr); + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct VariantTupleBuilder { + builder: VariantBuilder, + args: Vec, +} + +impl VariantTupleBuilder + where F: Invoke>, +{ + pub fn with_tys(mut self, iter: I) -> Self + where I: IntoIterator>, + { + for ty in iter { + self = self.with_ty(ty); + } + self + } + + pub fn with_ty(mut self, ty: P) -> Self { + self.args.push(ast::VariantArg { + ty: ty, + id: ast::DUMMY_NODE_ID, + }); + self + } + + pub fn ty(self) -> TyBuilder { + TyBuilder::new_with_callback(self) + } + + pub fn build(self) -> F::Result { + let kind = ast::TupleVariantKind(self.args); + self.builder.build_variant_kind(kind) + } +} + +impl Invoke> for VariantTupleBuilder + where F: Invoke>, +{ + type Result = Self; + + fn invoke(self, ty: P) -> Self { + self.with_ty(ty) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct VariantStructBuilder { + builder: VariantBuilder, +} + +impl VariantStructBuilder + where F: Invoke>, +{ + pub fn with_field(self, field: ast::StructField) -> StructDefBuilder { + let span = self.builder.span; + StructDefBuilder::new_with_callback(self).span(span).with_field(field) + } + + pub fn field(self, id: T) -> StructFieldBuilder> + where T: ToIdent, + { + let span = self.builder.span; + StructDefBuilder::new_with_callback(self).span(span).field(id) + } + + pub fn build(self) -> F::Result { + StructDefBuilder::new_with_callback(self).build() + } +} + +impl Invoke> for VariantStructBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, struct_def: P) -> F::Result { + let kind = ast::StructVariantKind(struct_def); + self.builder.build_variant_kind(kind) + } +}