<commit_before>use std::ops::{Deref, DerefMut};

use result::Result;

use url::Url;

#[derive(Debug, Clone)]
pub struct Link(String);

impl From<String> for Link {

    fn from(s: String) -> Link {
        Link(s)
    }

}

impl Deref for Link {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }

}

impl DerefMut for Link {

    fn deref_mut(&mut self) -> &mut String {
        &mut self.0
    }

}

pub trait IntoUrl {
    fn into_url(self) -> Result<Url>;
}

impl IntoUrl for Link {

    fn into_url(self) -> Result<Url> {
        use error::BookmarkErrorKind as BEK;
        use error::MapErrInto;

        Url::parse(&self[..]).map_err_into(BEK::LinkParsingError)
    }

}

<commit_msg>impl From<&'a str> for Link<commit_after>use std::ops::{Deref, DerefMut};

use result::Result;

use url::Url;

#[derive(Debug, Clone)]
pub struct Link(String);

impl From<String> for Link {

    fn from(s: String) -> Link {
        Link(s)
    }

}

impl<'a> From<&'a str> for Link {

    fn from(s: &'a str) -> Link {
        Link(String::from(s))
    }

}

impl Deref for Link {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }

}

impl DerefMut for Link {

    fn deref_mut(&mut self) -> &mut String {
        &mut self.0
    }

}

pub trait IntoUrl {
    fn into_url(self) -> Result<Url>;
}

impl IntoUrl for Link {

    fn into_url(self) -> Result<Url> {
        use error::BookmarkErrorKind as BEK;
        use error::MapErrInto;

        Url::parse(&self[..]).map_err_into(BEK::LinkParsingError)
    }

}

<|endoftext|>


<commit_before>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::convert::Into;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use toml::Table;
use url::Url;
use sodiumoxide::crypto::hash;
use sodiumoxide::crypto::hash::sha512::Digest;

/// "Link" Type, just an abstraction over FileLockEntry to have some convenience internally.
struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| {
                if let Some(_) = Link::get_link_uri_from_filelockentry(&fle) {
                    Some(Link {
                        link: fle
                    })
                } else {
                    None
                }
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a FileLockEntry, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.deref()
            .get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .deref()
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(|s| Some(s))
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
fn is_link_store_id(id: &StoreId) -> bool {
    id.starts_with("/link/external/")
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement ExternalLinker for Entry, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                vect.into_iter()
                    .filter(is_link_store_id)
                    .map(|id| {
                        match store.retrieve(id) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => Err(LE::new(LEK::StoreReadError, Some(Box::new(e)))),
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        /// Convert a hash::sha512::Digest from sodiumoxide into a StoreId
        fn hash_to_storeid(d: Digest) -> StoreId {
            let hash = &d[..];
            let v = Vec::from(hash);
            let s = String::from_utf8(v).unwrap(); // TODO: Uncaught unwrap()
            ModuleEntryPath::new(format!("external/{}", s)).into_storeid()
        }

        for link in links { // for all links
            let hash     = hash::hash(link.serialize().as_bytes());
            let file_id  = hash_to_storeid(hash);

            let mut file = {
                if let Ok(mut file) = store.retrieve(file_id.clone()) { // retrieve the file from the store
                    file
                } else { // or
                    let res = store.create(file_id) // create it
                        .and_then(|mut file| {
                            {
                                let mut hdr = file.deref_mut().get_header_mut();

                                // Write the URI into the header
                                match hdr.set("imag.content", Value::Table(BTreeMap::new())) {
                                    Ok(_) => {
                                        let v = Value::String(link.serialize());
                                        hdr.set("imag.content.uri", v);
                                        Ok(())
                                    },
                                    Err(e) => Err(e),
                                }
                            }.map(|_| file)
                        })
                        .map_err(|e| LE::new(LEK::StoreWriteError, Some(Box::new(e))));

                    // And if that fails we can error
                    if let Err(e) = res {
                        return Err(e);
                    }
                    res.unwrap()
                }
            };

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        self.get_external_links(store)
            .and_then(|mut links| {
                links.push(link);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        unimplemented!()
    }

}

<commit_msg>Implement remove_external_link()<commit_after>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::convert::Into;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use toml::Table;
use url::Url;
use sodiumoxide::crypto::hash;
use sodiumoxide::crypto::hash::sha512::Digest;

/// "Link" Type, just an abstraction over FileLockEntry to have some convenience internally.
struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| {
                if let Some(_) = Link::get_link_uri_from_filelockentry(&fle) {
                    Some(Link {
                        link: fle
                    })
                } else {
                    None
                }
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a FileLockEntry, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.deref()
            .get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .deref()
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(|s| Some(s))
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
fn is_link_store_id(id: &StoreId) -> bool {
    id.starts_with("/link/external/")
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement ExternalLinker for Entry, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                vect.into_iter()
                    .filter(is_link_store_id)
                    .map(|id| {
                        match store.retrieve(id) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => Err(LE::new(LEK::StoreReadError, Some(Box::new(e)))),
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        /// Convert a hash::sha512::Digest from sodiumoxide into a StoreId
        fn hash_to_storeid(d: Digest) -> StoreId {
            let hash = &d[..];
            let v = Vec::from(hash);
            let s = String::from_utf8(v).unwrap(); // TODO: Uncaught unwrap()
            ModuleEntryPath::new(format!("external/{}", s)).into_storeid()
        }

        for link in links { // for all links
            let hash     = hash::hash(link.serialize().as_bytes());
            let file_id  = hash_to_storeid(hash);

            let mut file = {
                if let Ok(mut file) = store.retrieve(file_id.clone()) { // retrieve the file from the store
                    file
                } else { // or
                    let res = store.create(file_id) // create it
                        .and_then(|mut file| {
                            {
                                let mut hdr = file.deref_mut().get_header_mut();

                                // Write the URI into the header
                                match hdr.set("imag.content", Value::Table(BTreeMap::new())) {
                                    Ok(_) => {
                                        let v = Value::String(link.serialize());
                                        hdr.set("imag.content.uri", v);
                                        Ok(())
                                    },
                                    Err(e) => Err(e),
                                }
                            }.map(|_| file)
                        })
                        .map_err(|e| LE::new(LEK::StoreWriteError, Some(Box::new(e))));

                    // And if that fails we can error
                    if let Err(e) = res {
                        return Err(e);
                    }
                    res.unwrap()
                }
            };

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        self.get_external_links(store)
            .and_then(|mut links| {
                links.push(link);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        self.get_external_links(store)
            .and_then(|mut links| {
                let links = links.into_iter()
                    .filter(|l| l.serialize() != link.serialize())
                    .collect();
                self.set_external_links(store, links)
            })
    }

}

<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::rc::Rc;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::DUMMY_SP;
use syntex_syntax::ext::base::{
    ExtCtxt,
    IdentMacroExpander,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    Resolver,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse;
use syntex_syntax::print::pprust;
use syntex_syntax::symbol::Symbol;

use super::resolver;
use super::error::Error;

pub type Pass = fn(ast::Crate) -> ast::Crate;

pub struct Registry {
    syntax_exts: Vec<NamedSyntaxExtension>,
    pre_expansion_passes: Vec<Box<Pass>>,
    post_expansion_passes: Vec<Box<Pass>>,
    cfg: Vec<ast::MetaItem>,
    attrs: Vec<ast::Attribute>,
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            syntax_exts: Vec::new(),
            pre_expansion_passes: Vec::new(),
            post_expansion_passes: Vec::new(),
            cfg: Vec::new(),
            attrs: Vec::new(),
        }
    }

    pub fn add_cfg(&mut self, cfg: &str) {
        let parse_sess = parse::ParseSess::new();
        let meta_item = parse::parse_meta_from_source_str(
            "cfgspec".to_string(),
            cfg.to_string(),
            &parse_sess).unwrap();

        self.cfg.push(meta_item);
    }

    pub fn add_attr(&mut self, attr: &str) {
        let parse_sess = parse::ParseSess::new();
        let meta_item = parse::parse_meta_from_source_str(
            "attrspec".to_string(),
            attr.to_string(),
            &parse_sess).unwrap();

        self.attrs.push(ast::Attribute {
            id: attr::mk_attr_id(),
            style: ast::AttrStyle::Outer,
            value: meta_item,
            is_sugared_doc: false,
            span: DUMMY_SP,
        });
    }

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::NormalTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_ident_macro<F>(&mut self, name: &str, extension: F)
        where F: IdentMacroExpander + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::IdentTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_decorator<F>(&mut self, name: &str, extension: F)
        where F: MultiItemDecorator + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::MultiDecorator(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_modifier<F>(&mut self, name: &str, extension: F)
        where F: MultiItemModifier + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::MultiModifier(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_pre_expansion_pass(&mut self, pass: Pass) {
        self.pre_expansion_passes.push(Box::new(pass))
    }

    pub fn add_post_expansion_pass(&mut self, pass: Pass) {
        self.post_expansion_passes.push(Box::new(pass))
    }

    pub fn expand<S, D>(self, crate_name: &str, src: S, dst: D) -> Result<(), Error>
        where S: AsRef<Path>,
              D: AsRef<Path>,
    {
        let src = src.as_ref();
        let dst = dst.as_ref();

        let sess = parse::ParseSess::new();

        let krate = try!(parse::parse_crate_from_file(
            src,
            &sess));

        if sess.span_diagnostic.has_errors() {
            return Err(Error::Parse);
        }

        let src_name = src.to_str().unwrap().to_string();

        let out = try!(self.expand_crate(
                crate_name,
                &sess,
                src_name,
                krate));

        if sess.span_diagnostic.has_errors() {
            return Err(Error::Expand);
        }

        let mut dst = try!(File::create(dst));
        try!(dst.write_all(&out));
        Ok(())
    }

    /// This method will expand all macros in the source string `src`, and return the results in a
    /// string.
    pub fn expand_str(self,
                      crate_name: &str,
                      src_name: &str,
                      src: &str) -> Result<String, Error> {
        let sess = parse::ParseSess::new();

        let src_name = src_name.to_owned();

        let krate = try!(parse::parse_crate_from_source_str(
            src_name.clone(),
            src.to_owned(),
            &sess));

        let out = try!(self.expand_crate(crate_name, &sess, src_name, krate));

        Ok(String::from_utf8(out).unwrap())
    }

    fn expand_crate(self,
                    crate_name: &str,
                    sess: &parse::ParseSess,
                    src_name: String,
                    mut krate: ast::Crate) -> Result<Vec<u8>, Error> {
        krate.attrs.extend(self.attrs.iter().cloned());

        let features = feature_gate::get_features(
            &sess.span_diagnostic,
            &krate.attrs);

        let krate = self.pre_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let mut ecfg = expand::ExpansionConfig::default(crate_name.to_owned());
        ecfg.features = Some(&features);

        let mut resolver = resolver::Resolver::new(sess);

        for (name, ext) in self.syntax_exts {
            let ident = ast::Ident::with_empty_ctxt(name);
            resolver.add_ext(ident, Rc::new(ext));
        }

        let mut ecx = ExtCtxt::new(&sess, ecfg, &mut resolver);
        let krate = ecx.monotonic_expander().expand_crate(krate);

        let krate = self.post_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let src = sess.codemap()
            .get_filemap(&src_name)
            .unwrap()
            .src
            .as_ref()
            .unwrap()
            .as_bytes()
            .to_vec();

        let mut rdr = &src[..];

        let mut out = Vec::new();
        let annotation = pprust::NoAnn;

        try!(pprust::print_crate(
            sess.codemap(),
            &sess.span_diagnostic,
            &krate,
            src_name,
            &mut rdr,
            Box::new(&mut out),
            &annotation,
            false));

        Ok(out)
    }
}
<commit_msg>Fix macro_rules macros<commit_after>use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::rc::Rc;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::DUMMY_SP;
use syntex_syntax::ext::base::{
    ExtCtxt,
    IdentMacroExpander,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    Resolver,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse;
use syntex_syntax::print::pprust;
use syntex_syntax::symbol::Symbol;

use super::resolver;
use super::error::Error;

pub type Pass = fn(ast::Crate) -> ast::Crate;

pub struct Registry {
    syntax_exts: Vec<NamedSyntaxExtension>,
    pre_expansion_passes: Vec<Box<Pass>>,
    post_expansion_passes: Vec<Box<Pass>>,
    cfg: Vec<ast::MetaItem>,
    attrs: Vec<ast::Attribute>,
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            syntax_exts: Vec::new(),
            pre_expansion_passes: Vec::new(),
            post_expansion_passes: Vec::new(),
            cfg: Vec::new(),
            attrs: Vec::new(),
        }
    }

    pub fn add_cfg(&mut self, cfg: &str) {
        let parse_sess = parse::ParseSess::new();
        let meta_item = parse::parse_meta_from_source_str(
            "cfgspec".to_string(),
            cfg.to_string(),
            &parse_sess).unwrap();

        self.cfg.push(meta_item);
    }

    pub fn add_attr(&mut self, attr: &str) {
        let parse_sess = parse::ParseSess::new();
        let meta_item = parse::parse_meta_from_source_str(
            "attrspec".to_string(),
            attr.to_string(),
            &parse_sess).unwrap();

        self.attrs.push(ast::Attribute {
            id: attr::mk_attr_id(),
            style: ast::AttrStyle::Outer,
            value: meta_item,
            is_sugared_doc: false,
            span: DUMMY_SP,
        });
    }

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::NormalTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_ident_macro<F>(&mut self, name: &str, extension: F)
        where F: IdentMacroExpander + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::IdentTT(
            Box::new(extension),
            None,
            false
        );
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_decorator<F>(&mut self, name: &str, extension: F)
        where F: MultiItemDecorator + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::MultiDecorator(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_modifier<F>(&mut self, name: &str, extension: F)
        where F: MultiItemModifier + 'static
    {
        let name = Symbol::intern(name);
        let syntax_extension = SyntaxExtension::MultiModifier(Box::new(extension));
        self.syntax_exts.push((name, syntax_extension));
    }

    pub fn add_pre_expansion_pass(&mut self, pass: Pass) {
        self.pre_expansion_passes.push(Box::new(pass))
    }

    pub fn add_post_expansion_pass(&mut self, pass: Pass) {
        self.post_expansion_passes.push(Box::new(pass))
    }

    pub fn expand<S, D>(self, crate_name: &str, src: S, dst: D) -> Result<(), Error>
        where S: AsRef<Path>,
              D: AsRef<Path>,
    {
        let src = src.as_ref();
        let dst = dst.as_ref();

        let sess = parse::ParseSess::new();

        let krate = try!(parse::parse_crate_from_file(
            src,
            &sess));

        if sess.span_diagnostic.has_errors() {
            return Err(Error::Parse);
        }

        let src_name = src.to_str().unwrap().to_string();

        let out = try!(self.expand_crate(
                crate_name,
                &sess,
                src_name,
                krate));

        if sess.span_diagnostic.has_errors() {
            return Err(Error::Expand);
        }

        let mut dst = try!(File::create(dst));
        try!(dst.write_all(&out));
        Ok(())
    }

    /// This method will expand all macros in the source string `src`, and return the results in a
    /// string.
    pub fn expand_str(self,
                      crate_name: &str,
                      src_name: &str,
                      src: &str) -> Result<String, Error> {
        let sess = parse::ParseSess::new();

        let src_name = src_name.to_owned();

        let krate = try!(parse::parse_crate_from_source_str(
            src_name.clone(),
            src.to_owned(),
            &sess));

        let out = try!(self.expand_crate(crate_name, &sess, src_name, krate));

        Ok(String::from_utf8(out).unwrap())
    }

    fn expand_crate(self,
                    crate_name: &str,
                    sess: &parse::ParseSess,
                    src_name: String,
                    mut krate: ast::Crate) -> Result<Vec<u8>, Error> {
        krate.attrs.extend(self.attrs.iter().cloned());

        let features = feature_gate::get_features(
            &sess.span_diagnostic,
            &krate.attrs);

        let krate = self.pre_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let mut ecfg = expand::ExpansionConfig::default(crate_name.to_owned());
        ecfg.features = Some(&features);
        ecfg.keep_macs = true;

        let mut resolver = resolver::Resolver::new(sess);

        for (name, ext) in self.syntax_exts {
            let ident = ast::Ident::with_empty_ctxt(name);
            resolver.add_ext(ident, Rc::new(ext));
        }

        let mut ecx = ExtCtxt::new(&sess, ecfg, &mut resolver);
        let krate = ecx.monotonic_expander().expand_crate(krate);

        let krate = self.post_expansion_passes.iter()
            .fold(krate, |krate, f| (f)(krate));

        let src = sess.codemap()
            .get_filemap(&src_name)
            .unwrap()
            .src
            .as_ref()
            .unwrap()
            .as_bytes()
            .to_vec();

        let mut rdr = &src[..];

        let mut out = Vec::new();
        let annotation = pprust::NoAnn;

        try!(pprust::print_crate(
            sess.codemap(),
            &sess.span_diagnostic,
            &krate,
            src_name,
            &mut rdr,
            Box::new(&mut out),
            &annotation,
            false));

        Ok(out)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::hash::{Hash, Writer};
use std::fmt;

#[deriving(Show, PartialEq, Clone)]
pub enum Token<'a> {
    Definition {
        name: &'a str,
        arity: u32,
        body: &'a str,
    },
    Item(LangItem<'a>),
    Comment(&'a str),
}

#[deriving(PartialEq, Show, Clone)]
pub enum LangItem<'a> {
    PapyNumber(i32),
    PapyString(&'a str),
    PapyName(&'a str),
}

#[deriving(Show, PartialEq, Clone)]
struct Argument<'a> {
    name: &'a str,
    value: LangItem<'a>,
}

struct Symbol<'a> {
    name: &'a str,
    arity: u32,
    function: fn(name: &'a str, args: &Vec<Argument<'a>>, symbols: &SymbolTable<'a>) -> Vec<Token<'a>>,
}

pub struct SymbolTable<'a> {
    symbols: HashSet<Symbol<'a>>,
}

impl<'a> Eq for Symbol<'a> {}

impl<'a> Clone for Symbol<'a> {
    fn clone(&self) -> Symbol<'a> {
        Symbol {
            name: self.name.clone(),
            arity: self.arity.clone(),
            function: self.function,
        }
    }
}

impl<'a> PartialEq for Symbol<'a> {
    fn eq(&self, other: &Symbol) -> bool {
        self.name == other.name && self.arity == other.arity
    }
}

impl<'a, H: Writer> Hash<H> for Symbol<'a> {
 fn hash(&self, state: &mut H) {
    //TODO: learn2Hash, need to distribute moar i guess... stract says so, so it must be.
    self.name.hash(state);// AM I DOING THIS RIGHT? HOW DO HASH
 }
}

impl<'a> fmt::Show for Symbol<'a> {
    fn fmt(&self,f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Symbol {{name: {} }}", self.name)
    }
}

impl<'a> fmt::Show for SymbolTable<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SymbolTable {{symbols: {}}}", self.symbols)
    }
}

impl<'a> Clone for SymbolTable<'a> {
    fn clone(&self) -> SymbolTable<'a> {
        SymbolTable {
            symbols: self.symbols.clone()
        }
    }
}

impl<'a> SymbolTable<'a> {
    pub fn new() -> SymbolTable<'a> {
        let mut symbols: HashSet<Symbol<'a>> = HashSet::new();
        ////// builtin functions
        symbols.insert(Symbol {
            name: "+",
            arity: 2,
            function: { //need moar unboxed closures
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x + y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "*",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x * y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "/",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x / y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "-",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x - y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "switch",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x)), Item(PapyNumber(y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });

        SymbolTable {
            symbols: symbols,
        }
    }

    ///Takes a Definition Token and adds it to `self`
    pub fn add_symbol(&mut self, token: &Token<'a>) {

        self.symbols.insert(Symbol {
            //FIXME ugh
            name: match *token {
                Definition(name, _, _) => name,
                _ => fail!("token \"{}\" is not a definition!", token),
            },
            arity: match *token {
                Definition(_, arity, _) => arity,
                _ => fail!("token \"{}\" is not a definition!", token),
            },
            function: { //NEED MOAR UNBOXED CLOSURES to get rid of the symbols arg.
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, symbols: &SymbolTable<'a>) -> Vec<Token<'a>> {
                    let mut local_stack: Vec<Token<'a>> = vec![];
                    for arg in args.iter() {
                        match *arg {
                            Argument {name, value: PapyNumber(num)} => local_stack.push(Item(PapyNumber(num))),
                            Argument {name, value: PapyString(string)}=> local_stack.push(Item(PapyString(string))) ,
                            Argument {name: arg_name, value: PapyName(name)} => {
                                let sym = symbols.get(name);
                                let mut local_args = vec![];
                                for i in range(0, sym.arity) {
                                    local_args.push(match local_stack.pop() {
                                        Some(Item(val)) => {
                                            Argument {
                                                name: arg_name,
                                                value: val
                                            }
                                        },
                                        Some(_) => fail!("HOW DID WE GET HERE"),
                                        None => fail!("couldnt pop from local stack! not enough args")

                                    }); //FIXME unwrap
                                }
                                (sym.function)(sym.name, &local_args, symbols);
                            },
                        }
                    }
                    local_stack
                };
                func
            },

        });

    }
    fn contains_name(&self, name: &'a str ) -> bool {
        self.symbols.iter().any(|symbol| symbol.name == name)
    }
    fn get(&self, name: &'a str) -> Symbol<'a> { //TODO use Option instead of failure.
        match self.symbols.iter().filter(|symbol| symbol.name == name).last() {
            Some(val) => *val,
            None => fail!("symbol with name \"{}\" does not exist!", name)
        }
    }
}

pub fn tokenize_str<'a>(text: &'a str) -> Token<'a> {
    let cap = regex!(r##"(?:(?P<definition>^def .*:.*end)|(?P<comment>#.*)|(?P<item>\s?^[\w\+-\*\?!]*)|(?P<other>\W+))\s*"##)
        .captures(text).unwrap();

    if cap.pos(1).is_some() { //iterators instead?
        let whole_def = cap.name("definition").trim();
        println!("whole_def: {}", whole_def)
        let parts: Vec<&'a str> = whole_def.split_str(":").collect();
        let left = parts[0].split_str(" ").collect::<Vec<&'a str>>();
        let name = left[1];
        let arity = left[2..].len() as u32;
        let body = parts[1].split_str("end").collect::<Vec<&'a str>>()[0];
        println!("body of {}: {}", name, body);
        Definition {
            name: name,
            arity: arity,
            body: body,
        }
    }
    else if cap.pos(2).is_some() {
        Comment(cap.name("comment").trim())
    }
    else if cap.pos(3).is_some() {
        let item = cap.name("item");
        match from_str(item) { //TODO string support
            Some(val) => {Item(PapyNumber(val)) },
            None => { Item(PapyName(item)) },
        }
    }
    else  {
        fail!("unknown token in \"{}\". try again!", text)
    }
}

pub fn run_stack<'a>(tokens: Vec<Token<'a>>, symbol_table: &SymbolTable<'a>) -> Vec<Token<'a>>{
    let mut stack: Vec<Token<'a>> = vec![];
    for token in tokens.into_iter() {
        if let Item(item) = token {
            match item {
                PapyNumber(num) => {stack.push(Item(PapyNumber(num)))},
                PapyString(string) => {stack.push(Item(PapyString(string)))},
                PapyName(name) => {
                    if !symbol_table.contains_name(name) { // making this line was a lot of work D:
                        fail!("undefined symbol: \"{}\". aborting!", name)
                    }
                    let mut args = vec![];
                    let symbol = symbol_table.get(name);
                    for i in range(0, symbol.arity) {
                        args.push(match stack.pop() {
                            Some(Item(x)) => {
                                Argument {
                                    name: "",
                                    value: x,
                                }
                            },
                            Some(_) => fail!("HOW DID WE GET HERE!"),
                            None => fail!("failure to pop from stack!"),
                        });
                    }
                    let result = (symbol.function)(name, &args, symbol_table);
                    stack.extend(result.into_iter());
                }
            }
        }
    }
    stack
}
<commit_msg>removed other regex<commit_after>use std::collections::HashSet;
use std::hash::{Hash, Writer};
use std::fmt;

#[deriving(Show, PartialEq, Clone)]
pub enum Token<'a> {
    Definition {
        name: &'a str,
        arity: u32,
        body: &'a str,
    },
    Item(LangItem<'a>),
    Comment(&'a str),
}

#[deriving(PartialEq, Show, Clone)]
pub enum LangItem<'a> {
    PapyNumber(i32),
    PapyString(&'a str),
    PapyName(&'a str),
}

#[deriving(Show, PartialEq, Clone)]
struct Argument<'a> {
    name: &'a str,
    value: LangItem<'a>,
}

struct Symbol<'a> {
    name: &'a str,
    arity: u32,
    function: fn(name: &'a str, args: &Vec<Argument<'a>>, symbols: &SymbolTable<'a>) -> Vec<Token<'a>>,
}

pub struct SymbolTable<'a> {
    symbols: HashSet<Symbol<'a>>,
}

impl<'a> Eq for Symbol<'a> {}

impl<'a> Clone for Symbol<'a> {
    fn clone(&self) -> Symbol<'a> {
        Symbol {
            name: self.name.clone(),
            arity: self.arity.clone(),
            function: self.function,
        }
    }
}

impl<'a> PartialEq for Symbol<'a> {
    fn eq(&self, other: &Symbol) -> bool {
        self.name == other.name && self.arity == other.arity
    }
}

impl<'a, H: Writer> Hash<H> for Symbol<'a> {
 fn hash(&self, state: &mut H) {
    //TODO: learn2Hash, need to distribute moar i guess... stract says so, so it must be.
    self.name.hash(state);// AM I DOING THIS RIGHT? HOW DO HASH
 }
}

impl<'a> fmt::Show for Symbol<'a> {
    fn fmt(&self,f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Symbol {{name: {} }}", self.name)
    }
}

impl<'a> fmt::Show for SymbolTable<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SymbolTable {{symbols: {}}}", self.symbols)
    }
}

impl<'a> Clone for SymbolTable<'a> {
    fn clone(&self) -> SymbolTable<'a> {
        SymbolTable {
            symbols: self.symbols.clone()
        }
    }
}

impl<'a> SymbolTable<'a> {
    pub fn new() -> SymbolTable<'a> {
        let mut symbols: HashSet<Symbol<'a>> = HashSet::new();
        ////// builtin functions
        symbols.insert(Symbol {
            name: "+",
            arity: 2,
            function: { //need moar unboxed closures
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x + y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "*",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x * y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "/",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x / y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "-",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x - y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });
        symbols.insert(Symbol {
            name: "switch",
            arity: 2,
            function: {
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, _symbols: &SymbolTable) -> Vec<Token<'a>> {
                    match (args[0], args[1]) {
                        (Argument {name: _, value: PapyNumber(x)}, Argument {name: _,value: PapyNumber(y)}) => {
                            vec![Item(PapyNumber(x)), Item(PapyNumber(y))]
                        },
                        (Argument {name: _, value: PapyString(_) }, Argument {name: _, value: PapyString(_)}) => fail!("cant add strings! They also dont exist yet!"),
                        (_, _) => fail!("types need to be the same! Not PapyNumber + PapyNumber, or PapyString + PapyString!"),
                    }
                };
                func
            },
        });

        SymbolTable {
            symbols: symbols,
        }
    }

    ///Takes a Definition Token and adds it to `self`
    pub fn add_symbol(&mut self, token: &Token<'a>) {

        self.symbols.insert(Symbol {
            //FIXME ugh
            name: match *token {
                Definition(name, _, _) => name,
                _ => fail!("token \"{}\" is not a definition!", token),
            },
            arity: match *token {
                Definition(_, arity, _) => arity,
                _ => fail!("token \"{}\" is not a definition!", token),
            },
            function: { //NEED MOAR UNBOXED CLOSURES to get rid of the symbols arg.
                fn func<'a>(_name: &'a str, args: &Vec<Argument<'a>>, symbols: &SymbolTable<'a>) -> Vec<Token<'a>> {
                    let mut local_stack: Vec<Token<'a>> = vec![];
                    for arg in args.iter() {
                        match *arg {
                            Argument {name, value: PapyNumber(num)} => local_stack.push(Item(PapyNumber(num))),
                            Argument {name, value: PapyString(string)}=> local_stack.push(Item(PapyString(string))) ,
                            Argument {name: arg_name, value: PapyName(name)} => {
                                let sym = symbols.get(name);
                                let mut local_args = vec![];
                                for i in range(0, sym.arity) {
                                    local_args.push(match local_stack.pop() {
                                        Some(Item(val)) => {
                                            Argument {
                                                name: arg_name,
                                                value: val
                                            }
                                        },
                                        Some(_) => fail!("HOW DID WE GET HERE"),
                                        None => fail!("couldnt pop from local stack! not enough args")

                                    }); //FIXME unwrap
                                }
                                (sym.function)(sym.name, &local_args, symbols);
                            },
                        }
                    }
                    local_stack
                };
                func
            },

        });

    }
    fn contains_name(&self, name: &'a str ) -> bool {
        self.symbols.iter().any(|symbol| symbol.name == name)
    }
    fn get(&self, name: &'a str) -> Symbol<'a> { //TODO use Option instead of failure.
        match self.symbols.iter().filter(|symbol| symbol.name == name).last() {
            Some(val) => *val,
            None => fail!("symbol with name \"{}\" does not exist!", name)
        }
    }
}

/// Takes in an &str and returns a token representation of it
pub fn tokenize_str<'a>(text: &'a str) -> Token<'a> {
    let cap = regex!(r##"(?:(?P<definition>^def .*:.*end)|(?P<comment>#.*)|(?P<item>\s?^[\w\+-\*\?!]*))\s*"##)
        .captures(text).unwrap();

    if cap.pos(1).is_some() { //iterators instead?
        let whole_def = cap.name("definition").trim();
        println!("whole_def: {}", whole_def)
        let parts: Vec<&'a str> = whole_def.split_str(":").collect();
        let left = parts[0].split_str(" ").collect::<Vec<&'a str>>();
        let name = left[1];
        let arity = left[2..].len() as u32;
        let body = parts[1].split_str("end").collect::<Vec<&'a str>>()[0];
        println!("body of {}: {}", name, body);
        Definition {
            name: name,
            arity: arity,
            body: body,
        }
    }
    else if cap.pos(2).is_some() {
        Comment(cap.name("comment").trim())
    }
    else if cap.pos(3).is_some() {
        let item = cap.name("item");
        match from_str(item) { //TODO string support
            Some(val) => {Item(PapyNumber(val)) },
            None => { Item(PapyName(item)) },
        }
    }
    else  {
        fail!("unknown token in \"{}\". try again!", text)
    }
}

pub fn run_stack<'a>(tokens: Vec<Token<'a>>, symbol_table: &SymbolTable<'a>) -> Vec<Token<'a>>{
    let mut stack: Vec<Token<'a>> = vec![];
    for token in tokens.into_iter() {
        if let Item(item) = token {
            match item {
                PapyNumber(num) => {stack.push(Item(PapyNumber(num)))},
                PapyString(string) => {stack.push(Item(PapyString(string)))},
                PapyName(name) => {
                    if !symbol_table.contains_name(name) { // making this line was a lot of work D:
                        fail!("undefined symbol: \"{}\". aborting!", name)
                    }
                    let mut args = vec![];
                    let symbol = symbol_table.get(name);
                    for i in range(0, symbol.arity) {
                        args.push(match stack.pop() {
                            Some(Item(x)) => {
                                Argument {
                                    name: "",
                                    value: x,
                                }
                            },
                            Some(_) => fail!("HOW DID WE GET HERE!"),
                            None => fail!("failure to pop from stack!"),
                        });
                    }
                    let result = (symbol.function)(name, &args, symbol_table);
                    stack.extend(result.into_iter());
                }
            }
        }
    }
    stack
}
<|endoftext|>


<commit_before>use api::join;
use super::{ParallelIterator, ParallelIteratorState, ParallelLen, THRESHOLD};
use std::isize;
use std::ptr;

pub fn collect_into<PAR_ITER,T>(pi: PAR_ITER, v: &mut Vec<T>)
    where PAR_ITER: ParallelIterator<Item=T>, PAR_ITER::State: Send
{
    let (shared, mut state) = pi.state();
    let len = state.len();

    v.truncate(0); // clear any old data
    v.reserve(len.maximal_len); // reserve enough space
    let target = v.as_mut_ptr(); // get a raw ptr

    unsafe {
        collect_into_helper(state, &shared, len, CollectTarget(target));
    }

    unsafe {
        // TODO -- drops are not quite right here!
        v.set_len(len.maximal_len);
    }
}

unsafe fn collect_into_helper<STATE,T>(state: STATE,
                                       shared: &STATE::Shared,
                                       len: ParallelLen,
                                       target: CollectTarget<T>)
    where STATE: ParallelIteratorState<Item=T> + Send
{
    if len.cost > THRESHOLD && len.maximal_len > 1 {
        let mid = len.maximal_len / 2;
        let (left, right) = state.split_at(mid);
        let (left_target, right_target) = target.split_at(mid);
        join(|| collect_into_helper(left, shared, len.left_cost(mid), left_target),
             || collect_into_helper(right, shared, len.right_cost(mid), right_target));
    } else {
        let mut ptr = target.as_mut_ptr();
        state.for_each(shared, |item| {
            ptr::write(ptr, item);
            ptr = ptr.offset(1);
        });
    }
}

struct CollectTarget<T>(*mut T);

unsafe impl<T> Send for CollectTarget<T> { }

impl<T> CollectTarget<T> {
    unsafe fn split_at(self, mid: usize) -> (CollectTarget<T>, CollectTarget<T>) {
        assert!(mid < (isize::MAX) as usize);
        let mid = mid as isize;
        (CollectTarget(self.0), CollectTarget(self.0.offset(mid)))
    }

    fn as_mut_ptr(self) -> *mut T {
        self.0
    }
}

<commit_msg>make collect drop partially initialized results in the event of panic, which isn't really enough<commit_after>use api::join;
use super::{ParallelIterator, ParallelIteratorState, ParallelLen, THRESHOLD};
use std::isize;
use std::mem;
use std::ptr;

pub fn collect_into<PAR_ITER,T>(pi: PAR_ITER, v: &mut Vec<T>)
    where PAR_ITER: ParallelIterator<Item=T>, PAR_ITER::State: Send
{
    let (shared, mut state) = pi.state();
    let len = state.len();

    v.truncate(0); // clear any old data
    v.reserve(len.maximal_len); // reserve enough space
    let target = v.as_mut_ptr(); // get a raw ptr

    unsafe {
        collect_into_helper(state, &shared, len, CollectTarget(target));
    }

    unsafe {
        // TODO -- drops are not quite right here!
        v.set_len(len.maximal_len);
    }
}

unsafe fn collect_into_helper<STATE,T>(state: STATE,
                                       shared: &STATE::Shared,
                                       len: ParallelLen,
                                       target: CollectTarget<T>)
    where STATE: ParallelIteratorState<Item=T> + Send
{
    if len.cost > THRESHOLD && len.maximal_len > 1 {
        let mid = len.maximal_len / 2;
        let (left, right) = state.split_at(mid);
        let (left_target, right_target) = target.split_at(mid);
        join(|| collect_into_helper(left, shared, len.left_cost(mid), left_target),
             || collect_into_helper(right, shared, len.right_cost(mid), right_target));
    } else {
        let mut p = DropInitialized::new(target.as_mut_ptr());
        state.for_each(shared, |item| {
            ptr::write(p.next, item);
            p.bump();
        });
        mem::forget(p); // fully initialized, so don't run the destructor
    }
}

struct CollectTarget<T>(*mut T);

unsafe impl<T> Send for CollectTarget<T> { }

impl<T> CollectTarget<T> {
    unsafe fn split_at(self, mid: usize) -> (CollectTarget<T>, CollectTarget<T>) {
        assert!(mid < (isize::MAX) as usize);
        let mid = mid as isize;
        (CollectTarget(self.0), CollectTarget(self.0.offset(mid)))
    }

    fn as_mut_ptr(self) -> *mut T {
        self.0
    }
}

struct DropInitialized<T> {
    start: *mut T,
    next: *mut T,
}

impl<T> DropInitialized<T> {
    fn new(p: *mut T) -> DropInitialized<T> {
        DropInitialized { start: p, next: p }
    }

    unsafe fn bump(&mut self) {
        self.next = self.next.offset(1);
    }
}

impl<T> Drop for DropInitialized<T> {
    fn drop(&mut self) {
        unsafe {
            let mut p = self.start;
            while p != self.next {
                ptr::read(p);
                p = p.offset(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! [Parigot numerals](https://ir.uiowa.edu/cgi/viewcontent.cgi?article=5357&context=etd)

use term::{Term, abs};
use term::Term::*;
use parigot::convert::IntoParigot;

/// Produces a Parigot-encoded number zero.
///
/// ZERO := λsz.z = λ λ 1
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::zero;
/// use lambda_calculus::*;
///
/// assert_eq!(zero(), 0.into_parigot());
/// ```
pub fn zero() -> Term { abs!(2, Var(1)) }

/// Applied to a Parigot-encoded number it produces its successor.
///
/// SUCC := λnsz.s n (n s z) = λ λ λ 2 3 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::succ;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(succ(), 0.into_parigot()), NOR, 0), 1.into_parigot());
/// assert_eq!(beta(app(succ(), 1.into_parigot()), NOR, 0), 2.into_parigot());
/// ```
pub fn succ() -> Term {
    abs!(3, app!(Var(2), Var(3), app!(Var(3), Var(2), Var(1))))
}

/// Applied to a Parigot-encoded number it produces its predecessor.
///
/// PRED := λn.n (λxy.y) ZERO  = λ 1 (λ λ 1) ZERO
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::pred;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(pred(), 1.into_parigot()), NOR, 0), 0.into_parigot());
/// assert_eq!(beta(app(pred(), 3.into_parigot()), NOR, 0), 2.into_parigot());
/// ```
pub fn pred() -> Term {
    abs(app!(Var(1), abs!(2, Var(2)), zero()))
}

/// Applied to two Parigot-encoded numbers it produces their sum.
///
/// PLUS := λnm.n (λx.SUCC) m = λ λ 2 (λ SUCC) 1
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::plus;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(plus(), 1.into_parigot(), 2.into_parigot()), NOR, 0), 3.into_parigot());
/// assert_eq!(beta(app!(plus(), 2.into_parigot(), 3.into_parigot()), NOR, 0), 5.into_parigot());
/// ```
pub fn plus() -> Term {
    abs!(2, app!(Var(2), abs(succ()), Var(1)))
}

impl IntoParigot for usize {
    fn into_parigot(self) -> Term {
        let mut ret = zero();

        for _ in 0..self {
            ret = abs!(2, app!(Var(2), ret.clone(), ret.unabs().and_then(|r| r.unabs()).unwrap()));
        }

        ret
    }
}
<commit_msg>add parigot::{one, mult}<commit_after>//! [Parigot numerals](https://ir.uiowa.edu/cgi/viewcontent.cgi?article=5357&context=etd)

use term::{Term, abs, app};
use term::Term::*;
use parigot::convert::IntoParigot;

/// Produces a Parigot-encoded number zero.
///
/// ZERO := λsz.z = λ λ 1
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::zero;
/// use lambda_calculus::*;
///
/// assert_eq!(zero(), 0.into_parigot());
/// ```
pub fn zero() -> Term { abs!(2, Var(1)) }

/// Produces a Parigot-encoded number one.
///
/// ONE := λsz.s ZERO z = λ λ 2 ZERO 1
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::one;
/// use lambda_calculus::*;
///
/// assert_eq!(one(), 1.into_parigot());
/// ```
pub fn one() -> Term { abs!(2, app!(Var(2), zero(), Var(1))) }

/// Applied to a Parigot-encoded number it produces its successor.
///
/// SUCC := λnsz.s n (n s z) = λ λ λ 2 3 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::succ;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(succ(), 0.into_parigot()), NOR, 0), 1.into_parigot());
/// assert_eq!(beta(app(succ(), 1.into_parigot()), NOR, 0), 2.into_parigot());
/// ```
pub fn succ() -> Term {
    abs!(3, app!(Var(2), Var(3), app!(Var(3), Var(2), Var(1))))
}

/// Applied to a Parigot-encoded number it produces its predecessor.
///
/// PRED := λn.n (λxy.y) ZERO  = λ 1 (λ λ 1) ZERO
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::pred;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(pred(), 1.into_parigot()), NOR, 0), 0.into_parigot());
/// assert_eq!(beta(app(pred(), 3.into_parigot()), NOR, 0), 2.into_parigot());
/// ```
pub fn pred() -> Term {
    abs(app!(Var(1), abs!(2, Var(2)), zero()))
}

/// Applied to two Parigot-encoded numbers it produces their sum.
///
/// PLUS := λnm.n (λp.SUCC) m = λ λ 2 (λ SUCC) 1
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::plus;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(plus(), 1.into_parigot(), 2.into_parigot()), NOR, 0), 3.into_parigot());
/// assert_eq!(beta(app!(plus(), 2.into_parigot(), 3.into_parigot()), NOR, 0), 5.into_parigot());
/// ```
pub fn plus() -> Term {
    abs!(2, app!(Var(2), abs(succ()), Var(1)))
}

/// Applied to two Parigot-encoded numbers it yields their product.
///
/// MULT := λnm.n (λp.PLUS m) ZERO = λ λ 2 (λ PLUS 2) ZERO
///
/// # Example
/// ```
/// use lambda_calculus::parigot::numerals::mult;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(mult(), 1.into_parigot(), 2.into_parigot()), NOR, 0), 2.into_parigot());
/// assert_eq!(beta(app!(mult(), 2.into_parigot(), 3.into_parigot()), NOR, 0), 6.into_parigot());
/// ```
pub fn mult() -> Term {
    abs!(2, app!(Var(2), abs(app(plus(), Var(2))), zero()))
}

impl IntoParigot for usize {
    fn into_parigot(self) -> Term {
        let mut ret = zero();

        for _ in 0..self {
            ret = abs!(2, app!(Var(2), ret.clone(), ret.unabs().and_then(|r| r.unabs()).unwrap()));
        }

        ret
    }
}
<|endoftext|>


<commit_before>#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(alloc)]

#![no_std]

extern crate spin;
extern crate alloc;

mod block;
mod allocator;
mod locked_allocator;

pub use locked_allocator::LockedAllocator;

// #[cfg(not(test))]
// #[no_mangle]
// pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
//     unsafe {
//         let alloc_ref = ALLOCATOR.as_ref();
//         alloc_ref.expect("Allocator Not Initialized").lock().alloc(size, align).unwrap()
//     }
// }
//
// #[cfg(not(test))]
// #[no_mangle]
// pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
//     unsafe {
//         let alloc_ref = ALLOCATOR.as_ref();
//         alloc_ref.expect("Allocator Not Initialized").lock().usable_size(size, align)
//     }
// }
//
// #[cfg(not(test))]
// #[no_mangle]
// pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {
//     unsafe {
//         let alloc_ref = ALLOCATOR.as_ref();
//         alloc_ref.expect("Allocator Not Initialized").lock().dealloc(ptr, size, align);
//     }
// }
//
// #[cfg(not(test))]
// #[no_mangle]
// pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
//     align: usize) -> *mut u8 {
//     unsafe {
//         let alloc_ref = ALLOCATOR.as_ref();
//         alloc_ref.expect("Allocator Not Initialized").lock()
//             .realloc(ptr, size, new_size, align).unwrap()
//     }
// }
//
// #[cfg(not(test))]
// #[no_mangle]
// pub extern fn __rust_reallocate_inplace(ptr: *mut u8, size: usize, new_size: usize,
//     align: usize) -> usize {
//     unsafe {
//         let alloc_ref = ALLOCATOR.as_ref();
//         alloc_ref.expect("Allocator Not Initialized").lock()
//             .realloc_inplace(ptr, size, new_size, align)
//     }
// }

#[cfg(test)]
mod test;
<commit_msg>Export Allocator from alloc_opsys crate for use optionally in the kernal<commit_after>#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(alloc)]

#![no_std]

extern crate spin;
extern crate alloc;

mod block;
mod allocator;
mod locked_allocator;

pub use allocator::Allocator;
pub use locked_allocator::LockedAllocator;

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>use ast::*;
use type_sys;

use itertools::Itertools;

pub trait Print {
    fn pretty_print(&self, indent: usize) -> String;
}

impl Print for Expr {
    fn pretty_print(&self, indent: usize) -> String {
        use ast::Expr::*;
        use ast::BinaryOpCode::*;
        use ast::UnaryOpCode::*;

        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        match *self {
            Grouping(ref exprs) => {
                let mut fmt_exprs = exprs.pretty_print(indent + 2);

                // Add a comma for single expr grouping
                if exprs.exprs.len() == 1 {
                    fmt_exprs.pop();
                    fmt_exprs += ",\n";
                }

                format!("(\n{}{})", fmt_exprs, ws)
            }

            Let(ref bindings, ref function_decls, ref exprs) => {
                format!("let\n{}{}{}in\n{}{}end",
                        bindings
                            .iter()
                            .map(|binding| format!("{}\n", binding.pretty_print(indent + 2)))
                            .join(""),
                        function_decls
                            .iter()
                            .map(|binding| format!("{}\n", binding.pretty_print(indent + 2)))
                            .join(""),
                        ws,
                        exprs.pretty_print(indent + 2),
                        ws)
            }

            Assign {
                ref name,
                ref value,
                ..
            } => format!("{} := {}", name, value.pretty_print(indent)),

            PatternMatch {
                ref lhs,
                ref rhs,
                ..
            } => format!("(match {} := {})", lhs.pretty_print(indent), rhs.pretty_print(indent)),

            Function { ref name, ref args, .. } => {
                format!("{}({})",
                        name,
                        args.iter()
                            .map(|&(ref exp, _)| exp.pretty_print(indent))
                            .join(", "))
            }

            If {
                ref cond,
                ref true_branch,
                ref false_branch,
                ..
            } => {
                format!("(if {} then {} else {})",
                        cond.pretty_print(indent),
                        true_branch.pretty_print(indent),
                        false_branch.pretty_print(indent))
            }

            While { ref cond, ref expr, .. } => {
                format!("(while {} do {})",
                        cond.pretty_print(indent),
                        expr.pretty_print(indent))
            }

            For {
                ref binding,
                ref goal,
                ref expr,
                ..
            } => {
                format!("(for {} to {} do {})",
                        binding.pretty_print(indent),
                        goal.pretty_print(indent),
                        expr.pretty_print(indent))
            }

            BinaryOp {
                ref lhs,
                ref rhs,
                ref op,
                ..
            } => {
                let op_symbol = match *op {
                    Add => "+",
                    Sub => "-",
                    Mul => "*",
                    Div => "/",

                    Lt => "<",
                    Le => "<=",
                    Gt => ">",
                    Ge => ">=",
                    Eq => "=",
                    Ne => "<>",
                };

                format!("({} {} {})",
                        &lhs.pretty_print(indent),
                        op_symbol,
                        &rhs.pretty_print(indent))
            }

            UnaryOp { ref expr, ref op, .. } => {
                match *op {
                    Plus => format!("(+{})", expr.pretty_print(indent)),
                    Minus => format!("(-{})", expr.pretty_print(indent)),
                }
            }

            Cast { ref expr, ref dest, .. } => {
                format!("({} as {:?})", expr.pretty_print(indent), dest)
            }

            Variable { ref name, .. } => name.clone(),

            Array {
                ref values,
                ref declared_type,
                ..
            } => {
                format!("{:?}[{}]",
                        declared_type.clone().unwrap(),
                        values
                            .iter()
                            .map(|&(ref value, _)| value.pretty_print(indent))
                            .join(", "))
            }

            Tuple(ref values) => {
                format!("{{{}}}",
                        values
                            .iter()
                            .map(|value| value.pretty_print(indent))
                            .join(", "))
            }

            // For strings, use the debug trait to add quotes
            Value(type_sys::Value::Str(ref value)) => format!("{:?}", value),

            Value(ref value) => value.to_string(),

        }
    }
}

impl Print for Exprs {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        self.exprs
            .iter()
            .map(|exp| exp.pretty_print(indent))
            .map(|disp| format!("{}{}", ws, disp))
            .join(",\n") + "\n"
    }
}

impl Print for VariableDecl {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        format!("{}var {} := {}",
                ws,
                self.name,
                self.value.pretty_print(indent))
    }
}

impl Print for FunctionDecl {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        let args = self.args
            .iter()
            .map(|arg| arg.pretty_print(indent))
            .join(", ");

        format!("{}function {}({}) : {:?} := {}",
                ws,
                self.name,
                args,
                self.return_type,
                self.body.pretty_print(indent))
    }
}

impl Print for ArgumentDecl {
    fn pretty_print(&self, _indent: usize) -> String {
        format!("{}: {:?}", self.name, self.type_)
    }
}

#[cfg(test)]
mod tests {
    use super::Print;

    // Theses tests suppose the parser is correct so we don't have to manually input the AST
    use parser;

    macro_rules! perfect_coding {
        ( $expr:expr ) => {
            let expected = $expr;
            let expr = parser::parse_Expression($expr).unwrap();
            let result = expr.pretty_print(0);
            assert_eq!(expected, result);
        }
    }

    macro_rules! not_perfect_coding {
        ( $expr:expr ) => {
            let expected = $expr;
            let expr = parser::parse_Expression($expr).unwrap();
            let result = expr.pretty_print(0);
            assert_ne!(expected, result);
        }
    }

    #[test]
    fn simple_operators() {
        perfect_coding!("(2 + 2)");
        perfect_coding!("(2 - 2)");
        perfect_coding!("(2 * 2)");
        perfect_coding!("(2 / 2)");
        perfect_coding!("(2 < 2)");
        perfect_coding!("(2 <= 2)");
        perfect_coding!("(2 > 2)");
        perfect_coding!("(2 >= 2)");
        perfect_coding!("(-2)");
        perfect_coding!("(+2)");
    }

    #[test]
    fn chained_operators() {
        perfect_coding!("((2 + 2) + 2)");
        perfect_coding!("((2 + (+2)) - (-2))");
        perfect_coding!("((2 <> 2) > 2)");
    }

    #[test]
    fn grouping() {
        // Should not be parsed as a grouping, but as a simple parenthesis
        not_perfect_coding!("(
  2
)");

        // To resolve the ambiguity, simply add a comma at the end (Rust's tuples style)
        //
        // Seemingly useless, but forcing groupings to have at least 2 expressions is uglier in the
        // parser.
        perfect_coding!("(
  2,
)");

        perfect_coding!("(
  2,
  2
)");

        perfect_coding!("(
  2,
  2,
  2
)");

        perfect_coding!("(
  (
    2,
    2,
    2
  ),
  2,
  (
    2,
    2,
    2
  )
)");
    }

    #[test]
    fn let_block() {
        perfect_coding!("let
  var x := 2
in
  2
end");

        perfect_coding!("let
  function x(a: Integer, b: Integer) : Integer := (a * b)
in
  x(1, 2)
end");

        perfect_coding!("let
  var x := let
    var x := 2
  in
    2
  end
in
  let
    var x := 2
  in
    2
  end
end");

    }

    #[test]
    fn assign() {
        perfect_coding!("x := 1");
        perfect_coding!("x := y := 2");
    }

    #[test]
    fn function_call() {
        perfect_coding!("x()");
        perfect_coding!("x(1)");
        perfect_coding!("x(1, 2, 3)");
        perfect_coding!("x(y(1))");
        perfect_coding!("x(1, y(2), 3)");
    }

    #[test]
    fn if_block() {
        perfect_coding!("(if 1 then 1 else 0)");
        perfect_coding!("(if (if 1 then 1 else 0) then (if 1 then 1 else 0) else (if 1 then 1 else 0))");
        perfect_coding!("(if (
  0,
  1
) then (
  0,
  1
) else (
  0,
  1
))");
    }

    #[test]
    fn while_block() {
        perfect_coding!("(while 1 do 1)");
        perfect_coding!("(while (while 1 do 1) do (while 1 do 1))");
    }

    #[test]
    fn for_block() {
        perfect_coding!("(for var x := 1 to 1 do 1)");
        perfect_coding!("(for var x := (for var x := 1 to 2 do 1) to (for var x := 1 to 2 do 1) do (for var x := 1 to 2 do 1))");
    }

    #[test]
    fn cast() {
        perfect_coding!("((+2) as Str)");
        perfect_coding!("(+(2 as Str))");
        perfect_coding!("(+(2 as Str))");
    }

    #[test]
    fn variable() {
        perfect_coding!("hello");
        perfect_coding!("hello_world");
        perfect_coding!("hello_world2");
        // Should be catched by the parser's unit tests but hey, why not?
        not_perfect_coding!("hello-world2");
    }

    #[test]
    fn value() {
        perfect_coding!("true");
        perfect_coding!("false");
        perfect_coding!("0");
        perfect_coding!("1");
        perfect_coding!("42");
        perfect_coding!("69");
        perfect_coding!("1337");
        perfect_coding!("10.");
        perfect_coding!("13.37");
        perfect_coding!(r#""hello""#);
        perfect_coding!(r#""hel\"lo""#);
    }

}
<commit_msg>Pretty print escape sequences correctly<commit_after>use ast::*;
use type_sys;

use itertools::Itertools;

pub trait Print {
    fn pretty_print(&self, indent: usize) -> String;
}

impl Print for Expr {
    fn pretty_print(&self, indent: usize) -> String {
        use ast::Expr::*;
        use ast::BinaryOpCode::*;
        use ast::UnaryOpCode::*;

        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        match *self {
            Grouping(ref exprs) => {
                let mut fmt_exprs = exprs.pretty_print(indent + 2);

                // Add a comma for single expr grouping
                if exprs.exprs.len() == 1 {
                    fmt_exprs.pop();
                    fmt_exprs += ",\n";
                }

                format!("(\n{}{})", fmt_exprs, ws)
            }

            Let(ref bindings, ref function_decls, ref exprs) => {
                format!("let\n{}{}{}in\n{}{}end",
                        bindings
                            .iter()
                            .map(|binding| format!("{}\n", binding.pretty_print(indent + 2)))
                            .join(""),
                        function_decls
                            .iter()
                            .map(|binding| format!("{}\n", binding.pretty_print(indent + 2)))
                            .join(""),
                        ws,
                        exprs.pretty_print(indent + 2),
                        ws)
            }

            Assign {
                ref name,
                ref value,
                ..
            } => format!("{} := {}", name, value.pretty_print(indent)),

            PatternMatch {
                ref lhs,
                ref rhs,
                ..
            } => format!("(match {} := {})", lhs.pretty_print(indent), rhs.pretty_print(indent)),

            Function { ref name, ref args, .. } => {
                format!("{}({})",
                        name,
                        args.iter()
                            .map(|&(ref exp, _)| exp.pretty_print(indent))
                            .join(", "))
            }

            If {
                ref cond,
                ref true_branch,
                ref false_branch,
                ..
            } => {
                format!("(if {} then {} else {})",
                        cond.pretty_print(indent),
                        true_branch.pretty_print(indent),
                        false_branch.pretty_print(indent))
            }

            While { ref cond, ref expr, .. } => {
                format!("(while {} do {})",
                        cond.pretty_print(indent),
                        expr.pretty_print(indent))
            }

            For {
                ref binding,
                ref goal,
                ref expr,
                ..
            } => {
                format!("(for {} to {} do {})",
                        binding.pretty_print(indent),
                        goal.pretty_print(indent),
                        expr.pretty_print(indent))
            }

            BinaryOp {
                ref lhs,
                ref rhs,
                ref op,
                ..
            } => {
                let op_symbol = match *op {
                    Add => "+",
                    Sub => "-",
                    Mul => "*",
                    Div => "/",

                    Lt => "<",
                    Le => "<=",
                    Gt => ">",
                    Ge => ">=",
                    Eq => "=",
                    Ne => "<>",
                };

                format!("({} {} {})",
                        &lhs.pretty_print(indent),
                        op_symbol,
                        &rhs.pretty_print(indent))
            }

            UnaryOp { ref expr, ref op, .. } => {
                match *op {
                    Plus => format!("(+{})", expr.pretty_print(indent)),
                    Minus => format!("(-{})", expr.pretty_print(indent)),
                }
            }

            Cast { ref expr, ref dest, .. } => {
                format!("({} as {:?})", expr.pretty_print(indent), dest)
            }

            Variable { ref name, .. } => name.clone(),

            Array {
                ref values,
                ref declared_type,
                ..
            } => {
                format!("{:?}[{}]",
                        declared_type.clone().unwrap(),
                        values
                            .iter()
                            .map(|&(ref value, _)| value.pretty_print(indent))
                            .join(", "))
            }

            Tuple(ref values) => {
                format!("{{{}}}",
                        values
                            .iter()
                            .map(|value| value.pretty_print(indent))
                            .join(", "))
            }

            Value(type_sys::Value::Str(ref value)) => {
                let string = value.chars().map(|c| {
                    if c.is_control() {
                        format!("\\u{:04x}", c as usize)
                    } else if c == '"' {
                        "\\\"".to_string()
                    } else if c == '\\' {
                        "\\\\".to_string()
                    } else {
                        format!("{}", c)
                    }
                })
                .join("");

                format!(r#""{}""#, string)
            }

            Value(ref value) => value.to_string(),

        }
    }
}

impl Print for Exprs {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        self.exprs
            .iter()
            .map(|exp| exp.pretty_print(indent))
            .map(|disp| format!("{}{}", ws, disp))
            .join(",\n") + "\n"
    }
}

impl Print for VariableDecl {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        format!("{}var {} := {}",
                ws,
                self.name,
                self.value.pretty_print(indent))
    }
}

impl Print for FunctionDecl {
    fn pretty_print(&self, indent: usize) -> String {
        let strws = " ".repeat(indent);
        let ws = strws.as_str();

        let args = self.args
            .iter()
            .map(|arg| arg.pretty_print(indent))
            .join(", ");

        format!("{}function {}({}) : {:?} := {}",
                ws,
                self.name,
                args,
                self.return_type,
                self.body.pretty_print(indent))
    }
}

impl Print for ArgumentDecl {
    fn pretty_print(&self, _indent: usize) -> String {
        format!("{}: {:?}", self.name, self.type_)
    }
}

#[cfg(test)]
mod tests {
    use super::Print;

    // Theses tests suppose the parser is correct so we don't have to manually input the AST
    use parser;

    macro_rules! almost_perfect_coding {
        ( $input:expr, $output:expr ) => {
            let expected = $output;
            let expr = parser::parse_Expression($input).unwrap();
            let result = expr.pretty_print(0);
            assert_eq!(expected, result);
        }
    }

    macro_rules! perfect_coding {
        ( $expr:expr ) => {
            almost_perfect_coding!($expr, $expr);
        }
    }

    macro_rules! imperfect_coding {
        ( $expr:expr ) => {
            let expected = $expr;
            let expr = parser::parse_Expression($expr).unwrap();
            let result = expr.pretty_print(0);
            assert_ne!(expected, result);
        }
    }

    #[test]
    fn simple_operators() {
        perfect_coding!("(2 + 2)");
        perfect_coding!("(2 - 2)");
        perfect_coding!("(2 * 2)");
        perfect_coding!("(2 / 2)");
        perfect_coding!("(2 < 2)");
        perfect_coding!("(2 <= 2)");
        perfect_coding!("(2 > 2)");
        perfect_coding!("(2 >= 2)");
        perfect_coding!("(-2)");
        perfect_coding!("(+2)");
    }

    #[test]
    fn chained_operators() {
        perfect_coding!("((2 + 2) + 2)");
        perfect_coding!("((2 + (+2)) - (-2))");
        perfect_coding!("((2 <> 2) > 2)");
    }

    #[test]
    fn grouping() {
        // Should not be parsed as a grouping, but as a simple parenthesis
        imperfect_coding!("(
  2
)");

        // To resolve the ambiguity, simply add a comma at the end (Rust's tuples style)
        //
        // Seemingly useless, but forcing groupings to have at least 2 expressions is uglier in the
        // parser.
        perfect_coding!("(
  2,
)");

        perfect_coding!("(
  2,
  2
)");

        perfect_coding!("(
  2,
  2,
  2
)");

        perfect_coding!("(
  (
    2,
    2,
    2
  ),
  2,
  (
    2,
    2,
    2
  )
)");
    }

    #[test]
    fn let_block() {
        perfect_coding!("let
  var x := 2
in
  2
end");

        perfect_coding!("let
  function x(a: Integer, b: Integer) : Integer := (a * b)
in
  x(1, 2)
end");

        perfect_coding!("let
  var x := let
    var x := 2
  in
    2
  end
in
  let
    var x := 2
  in
    2
  end
end");

    }

    #[test]
    fn assign() {
        perfect_coding!("x := 1");
        perfect_coding!("x := y := 2");
    }

    #[test]
    fn function_call() {
        perfect_coding!("x()");
        perfect_coding!("x(1)");
        perfect_coding!("x(1, 2, 3)");
        perfect_coding!("x(y(1))");
        perfect_coding!("x(1, y(2), 3)");
    }

    #[test]
    fn if_block() {
        perfect_coding!("(if 1 then 1 else 0)");
        perfect_coding!("(if (if 1 then 1 else 0) then (if 1 then 1 else 0) else (if 1 then 1 else 0))");
        perfect_coding!("(if (
  0,
  1
) then (
  0,
  1
) else (
  0,
  1
))");
    }

    #[test]
    fn while_block() {
        perfect_coding!("(while 1 do 1)");
        perfect_coding!("(while (while 1 do 1) do (while 1 do 1))");
    }

    #[test]
    fn for_block() {
        perfect_coding!("(for var x := 1 to 1 do 1)");
        perfect_coding!("(for var x := (for var x := 1 to 2 do 1) to (for var x := 1 to 2 do 1) do (for var x := 1 to 2 do 1))");
    }

    #[test]
    fn cast() {
        perfect_coding!("((+2) as Str)");
        perfect_coding!("(+(2 as Str))");
        perfect_coding!("(+(2 as Str))");
    }

    #[test]
    fn variable() {
        perfect_coding!("hello");
        perfect_coding!("hello_world");
        perfect_coding!("hello_world2");
        // Should be catched by the parser's unit tests but hey, why not?
        imperfect_coding!("hello-world2");
    }

    #[test]
    fn value() {
        perfect_coding!("true");
        perfect_coding!("false");
        perfect_coding!("0");
        perfect_coding!("1");
        perfect_coding!("42");
        perfect_coding!("69");
        perfect_coding!("1337");
        perfect_coding!("10.");
        perfect_coding!("13.37");
        perfect_coding!(r#""hello""#);
        perfect_coding!(r#""hel\"lo""#);
        perfect_coding!(r#""hel\\lo""#);
        perfect_coding!(r#""hel\u001flo""#);
        almost_perfect_coding!(r#""hel\x1flo""#, r#""hel\u001flo""#);
    }

}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use gtk::signals::DeleteEvent;
use gtk::Connect;
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new().unwrap();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System, &mut gtk::TreeView)) -> i32 {
    println!("in !");
    let mut model = w.2.get_model().unwrap().clone();
    let mut iter = gtk::TreeIter::new().unwrap();

    w.1.refresh();
    if !model.get_iter_first(&mut iter) {
        return 1;
    }
    let useless = model.clone();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    //w.2.remove_model();

    loop {
        let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
        let mut to_delete = false;

        match entries.get(&(pid as usize)) {
            Some(p) => {
                //w.0.set_string(&iter, 1, &p.name);
                w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                w.0.set_string(&iter, 3, &format!("{}", p.memory));
                to_delete = true;
                return 1;
            }
            None => {
                w.0.remove(&iter);
                return 1;
            }
        }
        if to_delete {
            entries.remove(&(pid as usize));
        }
        if !model.iter_next(&mut iter) {
            break;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
        return 1;
    }
    //w.2.set_model(&model);
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("TreeView Sample");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);

    /*for _ in 0..10 {
        let mut iter = gtk::TreeIter::new().unwrap();
        left_store.append(&mut iter);
        left_store.set_string(&iter, 0, "I'm in a list");
    }*/

    // display the panes

    //let mut split_pane = gtk::Box::new(gtk::Orientation::Horizontal, 10).unwrap();

    //split_pane.set_size_request(-1, -1);
    //split_pane.add(&left_tree);

    timeout::add(1000, update_window, &mut (&mut list_store, &mut sys, &mut left_tree));

    window.add(&scroll);
    window.show_all();
    gtk::main();
}
<commit_msg>Remove unnecessary returns<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use gtk::signals::DeleteEvent;
use gtk::Connect;
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new().unwrap();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System, &mut gtk::TreeView)) -> i32 {
    println!("in !");
    let mut model = w.2.get_model().unwrap().clone();
    let mut iter = gtk::TreeIter::new().unwrap();

    w.1.refresh();
    if !model.get_iter_first(&mut iter) {
        return 1;
    }
    let useless = model.clone();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    //w.2.remove_model();

    loop {
        let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
        let mut to_delete = false;

        match entries.get(&(pid as usize)) {
            Some(p) => {
                //w.0.set_string(&iter, 1, &p.name);
                w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                w.0.set_string(&iter, 3, &format!("{}", p.memory));
                to_delete = true;
            }
            None => {
                w.0.remove(&iter);
            }
        }
        if to_delete {
            entries.remove(&(pid as usize));
        }
        if !model.iter_next(&mut iter) {
            break;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    //w.2.set_model(&model);
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("TreeView Sample");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);

    /*for _ in 0..10 {
        let mut iter = gtk::TreeIter::new().unwrap();
        left_store.append(&mut iter);
        left_store.set_string(&iter, 0, "I'm in a list");
    }*/

    // display the panes

    //let mut split_pane = gtk::Box::new(gtk::Orientation::Horizontal, 10).unwrap();

    //split_pane.set_size_request(-1, -1);
    //split_pane.add(&left_tree);

    timeout::add(1000, update_window, &mut (&mut list_store, &mut sys, &mut left_tree));

    window.add(&scroll);
    window.show_all();
    gtk::main();
}
<|endoftext|>