From bf5efeed5d3ea3e27eb5c9600b1f92d8f4c8c225 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 26 Aug 2015 13:57:35 -0700 Subject: [PATCH] Initial import of the Aster syntax::ast builder library This imports the [aster](https://github.com/serde-rs/serde) library into the Rust repository as an unstable library. Aster is a `syntax::ast` builder, that simplifies the generation of rust AST. It abstracts away many of the default options, and shields the user from fields being added, removed, or restructured in many circumstances. This allows a library like [Serde](https://github.com/serde-rs/serde) to be much more reliably compiled on nightly, which has not been broken by aster in the past couple months. This is specifically being done for the Servo project, which has started to use Serde and has gotten broken a few times because of the lag between libsyntax changes and the requisite changes needed to be made in Aster. --- mk/crates.mk | 3 +- src/libaster/attr.rs | 299 +++++++ src/libaster/block.rs | 116 +++ src/libaster/constant.rs | 97 +++ src/libaster/ctx.rs | 27 + src/libaster/expr.rs | 1093 +++++++++++++++++++++++++ src/libaster/fn_decl.rs | 187 +++++ src/libaster/generics.rs | 248 ++++++ src/libaster/ident.rs | 55 ++ src/libaster/invoke.rs | 26 + src/libaster/item.rs | 1037 +++++++++++++++++++++++ src/libaster/lib.rs | 195 +++++ src/libaster/lifetime.rs | 126 +++ src/libaster/lit.rs | 136 +++ src/libaster/mac.rs | 123 +++ src/libaster/method.rs | 273 ++++++ src/libaster/name.rs | 42 + src/libaster/pat.rs | 350 ++++++++ src/libaster/path.rs | 295 +++++++ src/libaster/qpath.rs | 164 ++++ src/libaster/stmt.rs | 266 ++++++ src/libaster/str.rs | 53 ++ src/libaster/struct_def.rs | 183 +++++ src/libaster/tests/mod.rs | 21 + src/libaster/tests/test_attr.rs | 38 + src/libaster/tests/test_expr.rs | 239 ++++++ src/libaster/tests/test_fn_decl.rs | 89 ++ src/libaster/tests/test_generics.rs | 59 ++ src/libaster/tests/test_item.rs | 645 +++++++++++++++ src/libaster/tests/test_lit.rs | 85 ++ src/libaster/tests/test_path.rs | 159 ++++ src/libaster/tests/test_stmt.rs | 140 ++++ src/libaster/tests/test_struct_def.rs | 154 ++++ src/libaster/tests/test_ty.rs | 200 +++++ src/libaster/tests/test_variant.rs | 98 +++ src/libaster/ty.rs | 391 +++++++++ src/libaster/ty_param.rs | 186 +++++ src/libaster/variant.rs | 193 +++++ 38 files changed, 8090 insertions(+), 1 deletion(-) create mode 100644 src/libaster/attr.rs create mode 100644 src/libaster/block.rs create mode 100644 src/libaster/constant.rs create mode 100644 src/libaster/ctx.rs create mode 100644 src/libaster/expr.rs create mode 100644 src/libaster/fn_decl.rs create mode 100644 src/libaster/generics.rs create mode 100644 src/libaster/ident.rs create mode 100644 src/libaster/invoke.rs create mode 100644 src/libaster/item.rs create mode 100644 src/libaster/lib.rs create mode 100644 src/libaster/lifetime.rs create mode 100644 src/libaster/lit.rs create mode 100644 src/libaster/mac.rs create mode 100644 src/libaster/method.rs create mode 100644 src/libaster/name.rs create mode 100644 src/libaster/pat.rs create mode 100644 src/libaster/path.rs create mode 100644 src/libaster/qpath.rs create mode 100644 src/libaster/stmt.rs create mode 100644 src/libaster/str.rs create mode 100644 src/libaster/struct_def.rs create mode 100644 src/libaster/tests/mod.rs create mode 100644 src/libaster/tests/test_attr.rs create mode 100644 src/libaster/tests/test_expr.rs create mode 100644 src/libaster/tests/test_fn_decl.rs create mode 100644 src/libaster/tests/test_generics.rs create mode 100644 src/libaster/tests/test_item.rs create mode 100644 src/libaster/tests/test_lit.rs create mode 100644 src/libaster/tests/test_path.rs create mode 100644 src/libaster/tests/test_stmt.rs create mode 100644 src/libaster/tests/test_struct_def.rs create mode 100644 src/libaster/tests/test_ty.rs create mode 100644 src/libaster/tests/test_variant.rs create mode 100644 src/libaster/ty.rs create mode 100644 src/libaster/ty_param.rs create mode 100644 src/libaster/variant.rs 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) + } +}