Skip to content

Commit

Permalink
Initial import of the Aster syntax::ast builder library
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
erickt committed Aug 26, 2015
1 parent a48c29d commit bf5efee
Show file tree
Hide file tree
Showing 38 changed files with 8,090 additions and 1 deletion.
3 changes: 2 additions & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
299 changes: 299 additions & 0 deletions src/libaster/attr.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<F=Identity> {
callback: F,
span: Span,
style: ast::AttrStyle,
is_sugared_doc: bool,
}

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

impl<F> AttrBuilder<F>
where F: Invoke<ast::Attribute>,
{
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<ast::MetaItem>) -> 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<T>(self, word: T) -> F::Result
where T: ToInternedString
{
self.build_meta_item_(ast::MetaWord(word.to_interned_string()))
}

pub fn list<T>(self, word: T) -> AttrListBuilder<Self>
where T: ToInternedString
{
AttrListBuilder::new_with_callback(word, self)
}

pub fn name_value<T>(self, name: T) -> LitBuilder<AttrNameValueBuilder<Self>>
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<I, T>(self, iter: I) -> F::Result
where I: IntoIterator<Item=T>,
T: ToInternedString,
{
self.list("allow").words(iter).build()
}

pub fn warn<I, T>(self, iter: I) -> F::Result
where I: IntoIterator<Item=T>,
T: ToInternedString,
{
self.list("warn").words(iter).build()
}

pub fn deny<I, T>(self, iter: I) -> F::Result
where I: IntoIterator<Item=T>,
T: ToInternedString,
{
self.list("deny").words(iter).build()
}

pub fn features<I, T>(self, iter: I) -> F::Result
where I: IntoIterator<Item=T>,
T: ToInternedString,
{
self.list("feature").words(iter).build()
}

pub fn plugins<I, T>(self, iter: I) -> F::Result
where I: IntoIterator<Item=T>,
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<T>(mut self, doc: T) -> F::Result
where T: ToInternedString,
{
self.is_sugared_doc = true;
self.name_value("doc").str(doc)
}
}

impl<F> Invoke<P<ast::MetaItem>> for AttrBuilder<F>
where F: Invoke<ast::Attribute>,
{
type Result = F::Result;

fn invoke(self, item: P<ast::MetaItem>) -> F::Result {
self.build_meta_item(item)
}
}

impl<F> Invoke<ast::MetaItem_> for AttrBuilder<F>
where F: Invoke<ast::Attribute>,
{
type Result = F::Result;

fn invoke(self, item: ast::MetaItem_) -> F::Result {
self.build_meta_item_(item)
}
}

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

pub struct AttrListBuilder<F> {
callback: F,
span: Span,
name: token::InternedString,
items: Vec<P<ast::MetaItem>>,
}

impl<F> AttrListBuilder<F>
where F: Invoke<P<ast::MetaItem>>,
{
pub fn new_with_callback<T>(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<I>(mut self, iter: I) -> Self
where I: IntoIterator<Item=P<ast::MetaItem>>,
{
self.items.extend(iter);
self
}

pub fn with_meta_items_<I>(self, iter: I) -> Self
where I: IntoIterator<Item=ast::MetaItem_>,
{
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<ast::MetaItem>) -> 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<I, T>(self, iter: I) -> Self
where I: IntoIterator<Item=T>,
T: ToInternedString,
{
let iter = iter.into_iter();
self.with_meta_items_(iter.map(|word| ast::MetaWord(word.to_interned_string())))
}

pub fn word<T>(self, word: T) -> Self
where T: ToInternedString,
{
self.with_meta_item_(ast::MetaWord(word.to_interned_string()))
}

pub fn list<T>(self, name: T) -> AttrListBuilder<Self>
where T: ToInternedString,
{
AttrListBuilder::new_with_callback(name, self)
}

pub fn name_value<T>(self, name: T) -> LitBuilder<AttrNameValueBuilder<Self>>
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<F> Invoke<P<ast::MetaItem>> for AttrListBuilder<F>
where F: Invoke<P<ast::MetaItem>>,
{
type Result = Self;

fn invoke(self, item: P<ast::MetaItem>) -> Self {
self.with_meta_item(item)
}
}

impl<F> Invoke<ast::MetaItem_> for AttrListBuilder<F>
where F: Invoke<P<ast::MetaItem>>,
{
type Result = Self;

fn invoke(self, item: ast::MetaItem_) -> Self {
self.with_meta_item_(item)
}
}

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

pub struct AttrNameValueBuilder<F> {
callback: F,
name: token::InternedString,
}

impl<F: Invoke<ast::MetaItem_>> Invoke<P<ast::Lit>> for AttrNameValueBuilder<F> {
type Result = F::Result;

fn invoke(self, value: P<ast::Lit>) -> F::Result {
let item = ast::MetaNameValue(self.name, (*value).clone());
self.callback.invoke(item)
}
}

Loading

0 comments on commit bf5efee

Please sign in to comment.