<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use token::Token;
use error::{Result, Error, Source};
use logger::Logger;

use std::mem;
use std::fs::File;
use std::path::Path;
use std::convert::AsRef;
use std::io::Read;
use std::collections::HashMap;
use std::ops::BitOr;

use cmark::{Parser as CMParser, Event, Tag, Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
pub struct Features {
    pub image: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub footnote: bool,
    pub table: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    footnotes: HashMap<String, Vec<Token>>,
    source: Source,
    features: Features,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            footnotes: HashMap::new(),
            source: Source::empty(),
            features: Features::new(),
        }
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path)
            .map_err(|_| {
                Error::file_not_found(&self.source,
                                      lformat!("markdown file"),
                                      format!("{}", path.display()))
            })?;
        let mut s = String::new();

        f.read_to_string(&mut s)
            .map_err(|_| {
                Error::parser(&self.source,
                              lformat!("file {file} contains invalid UTF-8, could not parse it",
                                       file = path.display()))
            })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        opts.insert(OPTION_ENABLE_FOOTNOTES);
        let mut p = CMParser::new_ext(s, opts);

        let mut res = vec![];
        self.parse_events(&mut p, &mut res, None)?;

        self.parse_footnotes(&mut res)?;

        collapse(&mut res);

        find_standalone(&mut res);
        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    /// Replace footnote reference with their definition
    fn parse_footnotes(&mut self, v: &mut Vec<Token>) -> Result<()> {
        for token in v {
            match *token {
                Token::Footnote(ref mut content) => {
                    let reference = if let Token::Str(ref text) = content[0] {
                        text.clone()
                    } else {
                        panic!("Reference is not a vector of a single Token::Str");
                    };
                    if let Some(in_vec) = self.footnotes.get(&reference) {
                        *content = in_vec.clone();
                    } else {
                        return Err(Error::parser(&self.source,
                                                 lformat!("footnote reference {reference} does \
                                                           not have a matching definition",
                                                          reference = &reference)));
                    }
                }
                Token::Paragraph(ref mut vec) |
                Token::Header(_, ref mut vec) |
                Token::Emphasis(ref mut vec) |
                Token::Strong(ref mut vec) |
                Token::Code(ref mut vec) |
                Token::BlockQuote(ref mut vec) |
                Token::CodeBlock(_, ref mut vec) |
                Token::List(ref mut vec) |
                Token::OrderedList(_, ref mut vec) |
                Token::Item(ref mut vec) |
                Token::Table(_, ref mut vec) |
                Token::TableHead(ref mut vec) |
                Token::TableRow(ref mut vec) |
                Token::TableCell(ref mut vec) |
                Token::Link(_, _, ref mut vec) |
                Token::Image(_, _, ref mut vec) => self.parse_footnotes(vec)?,
                _ => (),
            }
        }
        Ok(())
    }

    fn parse_events<'a>(&mut self,
                        p: &mut CMParser<'a>,
                        v: &mut Vec<Token>,
                        current_tag: Option<&Tag>)
                        -> Result<()> {
        while let Some(event) = p.next() {
            match event {
                Event::Html(text) |
                Event::InlineHtml(text) |
                Event::Text(text) => {
                    v.push(Token::Str(text.into_owned()));
                }
                Event::Start(tag) => self.parse_tag(p, v, tag)?,
                Event::End(tag) => {
                    debug_assert!(format!("{:?}", Some(&tag)) == format!("{:?}", current_tag),
                                  format!("Error: opening and closing tags mismatch!\n{:?} ≠ \
                                           {:?}",
                                          tag,
                                          current_tag));
                    break;
                }
                Event::SoftBreak => v.push(Token::SoftBreak),
                Event::HardBreak => v.push(Token::HardBreak),
                Event::FootnoteReference(text) => {
                    v.push(Token::Footnote(vec![Token::Str(text.into_owned())]))
                }
            }
        }
        Ok(())
    }

    fn parse_tag<'a>(&mut self,
                     p: &mut CMParser<'a>,
                     v: &mut Vec<Token>,
                     tag: Tag<'a>)
                     -> Result<()> {
        let mut res = vec![];

        self.parse_events(p, &mut res, Some(&tag))?;

        let token = match tag {
            Tag::Paragraph => Token::Paragraph(res),
            Tag::Emphasis => Token::Emphasis(res),
            Tag::Strong => Token::Strong(res),
            Tag::Code => Token::Code(res),
            Tag::Header(x) => Token::Header(x, res),
            Tag::Link(url, title) => Token::Link(url.into_owned(), title.into_owned(), res),
            Tag::Image(url, title) => {
                self.features.image = true;
                Token::Image(url.into_owned(), title.into_owned(), res)
            },
            Tag::Rule => Token::Rule,
            Tag::List(opt) => {
                if let Some(n) = opt {
                    self.features.ordered_list = true;
                    Token::OrderedList(n, res)
                } else {
                    Token::List(res)
                }
            }
            Tag::Item => Token::Item(res),
            Tag::BlockQuote => {
                self.features.blockquote = true;
                Token::BlockQuote(res)
            },
            Tag::CodeBlock(language) => {
                self.features.codeblock = true;
                Token::CodeBlock(language.into_owned(), res)
            },
            Tag::Table(v) => {
                // TODO: actually use v's alignments
                Token::Table(v.len() as i32, res)
            },
            Tag::TableHead => Token::TableHead(res),
            Tag::TableRow => Token::TableRow(res),
            Tag::TableCell => Token::TableCell(res),
            Tag::FootnoteDefinition(reference) => {
                if self.footnotes.contains_key(reference.as_ref()) {
                    Logger::display_warning(lformat!("in {file}, found footnote definition for \
                                                      note '{reference}' but previous \
                                                      definition already exist, overriding it",
                                                     file = self.source,
                                                     reference = reference));
                }
                self.footnotes.insert(reference.into_owned(), res);
                Token::SoftBreak
            }
        };
        v.push(token);
        Ok(())
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    if ast.len() < 2 {
        return;
    }

    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i < ast.len() - 1 {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) = (&mut ast[i],
                                                                                token) {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                             Token::Rule) {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    continue;
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}
<commit_msg>Add url to list of features detected while parsing<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use token::Token;
use error::{Result, Error, Source};
use logger::Logger;

use std::mem;
use std::fs::File;
use std::path::Path;
use std::convert::AsRef;
use std::io::Read;
use std::collections::HashMap;
use std::ops::BitOr;

use cmark::{Parser as CMParser, Event, Tag, Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
pub struct Features {
    pub image: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub footnote: bool,
    pub table: bool,
    pub url: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
            url: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
            url: self.url | rhs.url,
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    footnotes: HashMap<String, Vec<Token>>,
    source: Source,
    features: Features,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            footnotes: HashMap::new(),
            source: Source::empty(),
            features: Features::new(),
        }
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path)
            .map_err(|_| {
                Error::file_not_found(&self.source,
                                      lformat!("markdown file"),
                                      format!("{}", path.display()))
            })?;
        let mut s = String::new();

        f.read_to_string(&mut s)
            .map_err(|_| {
                Error::parser(&self.source,
                              lformat!("file {file} contains invalid UTF-8, could not parse it",
                                       file = path.display()))
            })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        opts.insert(OPTION_ENABLE_FOOTNOTES);
        let mut p = CMParser::new_ext(s, opts);

        let mut res = vec![];
        self.parse_events(&mut p, &mut res, None)?;

        self.parse_footnotes(&mut res)?;

        collapse(&mut res);

        find_standalone(&mut res);
        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    /// Replace footnote reference with their definition
    fn parse_footnotes(&mut self, v: &mut Vec<Token>) -> Result<()> {
        for token in v {
            match *token {
                Token::Footnote(ref mut content) => {
                    let reference = if let Token::Str(ref text) = content[0] {
                        text.clone()
                    } else {
                        panic!("Reference is not a vector of a single Token::Str");
                    };
                    if let Some(in_vec) = self.footnotes.get(&reference) {
                        *content = in_vec.clone();
                    } else {
                        return Err(Error::parser(&self.source,
                                                 lformat!("footnote reference {reference} does \
                                                           not have a matching definition",
                                                          reference = &reference)));
                    }
                }
                Token::Paragraph(ref mut vec) |
                Token::Header(_, ref mut vec) |
                Token::Emphasis(ref mut vec) |
                Token::Strong(ref mut vec) |
                Token::Code(ref mut vec) |
                Token::BlockQuote(ref mut vec) |
                Token::CodeBlock(_, ref mut vec) |
                Token::List(ref mut vec) |
                Token::OrderedList(_, ref mut vec) |
                Token::Item(ref mut vec) |
                Token::Table(_, ref mut vec) |
                Token::TableHead(ref mut vec) |
                Token::TableRow(ref mut vec) |
                Token::TableCell(ref mut vec) |
                Token::Link(_, _, ref mut vec) |
                Token::Image(_, _, ref mut vec) => self.parse_footnotes(vec)?,
                _ => (),
            }
        }
        Ok(())
    }

    fn parse_events<'a>(&mut self,
                        p: &mut CMParser<'a>,
                        v: &mut Vec<Token>,
                        current_tag: Option<&Tag>)
                        -> Result<()> {
        while let Some(event) = p.next() {
            match event {
                Event::Html(text) |
                Event::InlineHtml(text) |
                Event::Text(text) => {
                    v.push(Token::Str(text.into_owned()));
                }
                Event::Start(tag) => self.parse_tag(p, v, tag)?,
                Event::End(tag) => {
                    debug_assert!(format!("{:?}", Some(&tag)) == format!("{:?}", current_tag),
                                  format!("Error: opening and closing tags mismatch!\n{:?} ≠ \
                                           {:?}",
                                          tag,
                                          current_tag));
                    break;
                }
                Event::SoftBreak => v.push(Token::SoftBreak),
                Event::HardBreak => v.push(Token::HardBreak),
                Event::FootnoteReference(text) => {
                    v.push(Token::Footnote(vec![Token::Str(text.into_owned())]))
                }
            }
        }
        Ok(())
    }

    fn parse_tag<'a>(&mut self,
                     p: &mut CMParser<'a>,
                     v: &mut Vec<Token>,
                     tag: Tag<'a>)
                     -> Result<()> {
        let mut res = vec![];

        self.parse_events(p, &mut res, Some(&tag))?;

        let token = match tag {
            Tag::Paragraph => Token::Paragraph(res),
            Tag::Emphasis => Token::Emphasis(res),
            Tag::Strong => Token::Strong(res),
            Tag::Code => Token::Code(res),
            Tag::Header(x) => Token::Header(x, res),
            Tag::Link(url, title) => {
                self.features.url = true;
                Token::Link(url.into_owned(), title.into_owned(), res)
            },
            Tag::Image(url, title) => {
                self.features.image = true;
                Token::Image(url.into_owned(), title.into_owned(), res)
            },
            Tag::Rule => Token::Rule,
            Tag::List(opt) => {
                if let Some(n) = opt {
                    self.features.ordered_list = true;
                    Token::OrderedList(n, res)
                } else {
                    Token::List(res)
                }
            }
            Tag::Item => Token::Item(res),
            Tag::BlockQuote => {
                self.features.blockquote = true;
                Token::BlockQuote(res)
            },
            Tag::CodeBlock(language) => {
                self.features.codeblock = true;
                Token::CodeBlock(language.into_owned(), res)
            },
            Tag::Table(v) => {
                self.features.table = true;
                // TODO: actually use v's alignments
                Token::Table(v.len() as i32, res)
            },
            Tag::TableHead => Token::TableHead(res),
            Tag::TableRow => Token::TableRow(res),
            Tag::TableCell => Token::TableCell(res),
            Tag::FootnoteDefinition(reference) => {
                if self.footnotes.contains_key(reference.as_ref()) {
                    Logger::display_warning(lformat!("in {file}, found footnote definition for \
                                                      note '{reference}' but previous \
                                                      definition already exist, overriding it",
                                                     file = self.source,
                                                     reference = reference));
                }
                self.footnotes.insert(reference.into_owned(), res);
                Token::SoftBreak
            }
        };
        v.push(token);
        Ok(())
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    if ast.len() < 2 {
        return;
    }

    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i < ast.len() - 1 {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) = (&mut ast[i],
                                                                                token) {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                             Token::Rule) {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    continue;
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}
<|endoftext|>


<commit_before>extern crate syntex_syntax;
extern crate syntex_errors as errors;

use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::{DUMMY_SP, respan};
use syntex_syntax::ext::base::{
    IdentMacroExpander,
    MacroLoader,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::base::ExtCtxt;
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse::{self, token};
use syntex_syntax::print::pprust;
use syntex_syntax::ptr::P;

mod error;
pub use error::Error;

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

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

struct SyntexMacroLoader {
    macros: Vec<ast::MacroDef>,
}

impl SyntexMacroLoader {
    fn new(macros: Vec<ast::MacroDef>) -> Self {
        SyntexMacroLoader {
            macros: macros
        }
    }
}

impl MacroLoader for SyntexMacroLoader {
    fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<ast::MacroDef> {
        self.macros.clone()
    }
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            macros: Vec::new(),
            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(),
            Vec::new(),
            &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(),
            Vec::new(),
            &parse_sess).unwrap();

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

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = token::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 = token::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 = token::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 = token::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,
            self.cfg.clone(),
            &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(),
            self.cfg.clone(),
            &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 cfg = Vec::new();
        let mut macro_loader = SyntexMacroLoader::new(self.macros.clone());
        let mut ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut macro_loader);

        let krate = expand::expand_crate(&mut ecx, self.syntax_exts, 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;

        {
            let out: &mut io::Write = &mut out;

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

        Ok(out)
    }
}
<commit_msg>Remove unneeded cast<commit_after>extern crate syntex_syntax;
extern crate syntex_errors as errors;

use std::fs::File;
use std::io::Write;
use std::path::Path;

use syntex_syntax::ast;
use syntex_syntax::attr;
use syntex_syntax::codemap::{DUMMY_SP, respan};
use syntex_syntax::ext::base::{
    IdentMacroExpander,
    MacroLoader,
    MultiItemDecorator,
    MultiItemModifier,
    NamedSyntaxExtension,
    SyntaxExtension,
    TTMacroExpander,
};
use syntex_syntax::ext::base::ExtCtxt;
use syntex_syntax::ext::expand;
use syntex_syntax::feature_gate;
use syntex_syntax::parse::{self, token};
use syntex_syntax::print::pprust;
use syntex_syntax::ptr::P;

mod error;
pub use error::Error;

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

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

struct SyntexMacroLoader {
    macros: Vec<ast::MacroDef>,
}

impl SyntexMacroLoader {
    fn new(macros: Vec<ast::MacroDef>) -> Self {
        SyntexMacroLoader {
            macros: macros
        }
    }
}

impl MacroLoader for SyntexMacroLoader {
    fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<ast::MacroDef> {
        self.macros.clone()
    }
}

impl Registry {
    pub fn new() -> Registry {
        Registry {
            macros: Vec::new(),
            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(),
            Vec::new(),
            &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(),
            Vec::new(),
            &parse_sess).unwrap();

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

    pub fn add_macro<F>(&mut self, name: &str, extension: F)
        where F: TTMacroExpander + 'static
    {
        let name = token::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 = token::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 = token::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 = token::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,
            self.cfg.clone(),
            &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(),
            self.cfg.clone(),
            &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 cfg = Vec::new();
        let mut macro_loader = SyntexMacroLoader::new(self.macros.clone());
        let mut ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut macro_loader);

        let krate = expand::expand_crate(&mut ecx, self.syntax_exts, 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 fall_tree::NodeType;

use tree_builder::{Node, TokenSequence};

use {SynRule, Expr, PrattVariant};

pub fn parse(
    node_types: &[NodeType],
    rules: &[SynRule],
    tokens: TokenSequence
) -> (Node, u64) {
    let start_rule = Expr::Rule(0);

    let defs = Defs {
        node_types: node_types,
        rules: rules,
        start_rule: &start_rule
    };

    let mut ctx = Ctx {
        ticks: 0,
        predicate_mode: false,
        contexts: [false; 16],
        args: [None; 16],
        prev: None,
        replacement: None,
    };

    parse_file(&defs, &mut ctx, tokens)
}

struct Defs<'p> {
    node_types: &'p [NodeType],
    rules: &'p [SynRule],
    start_rule: &'p Expr,
}

impl<'r> Defs<'r> {
    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}

struct Ctx<'p> {
    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16],
    prev: Option<NodeType>,
    replacement: Option<NodeType>,
}

impl<'p> Ctx<'p> {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

fn parse_file<'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, tokens: TokenSequence) -> (Node, u64) {
    let (mut file_node, mut leftover) =
        parse_exp(defs, ctx, defs.start_rule, tokens)
            .unwrap_or_else(|| {
                let ty = match defs.rules[0].body {
                    Expr::Pub { ty_idx, .. } => defs.node_type(ty_idx),
                    _ => panic!("First rule must be public"),
                };
                (ctx.create_composite_node(Some(ty)), tokens)
            });

    let mut error = ctx.create_error_node();
    let mut skipped = false;
    while leftover.current().is_some() {
        skipped = true;
        let p = ctx.create_leaf_node(leftover);
        leftover = p.1;
        ctx.push_child(&mut error, p.0)
    }
    if skipped {
        ctx.push_child(&mut file_node, error)
    }
    (file_node, ctx.ticks)
}

fn parse_exp<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                     -> Option<(Node, TokenSequence<'t>)> {
    ctx.ticks += 1;
    match *expr {
        Expr::Pub { ty_idx, ref body, replaceable } => {
            if replaceable {
                ctx.replacement = None;
            }
            match parse_exp(defs, ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = match (replaceable, ctx.replacement) {
                        (true, Some(ty)) => ty,
                        _ => defs.node_type(ty_idx),
                    };
                    let mut result = ctx.create_composite_node(Some(node_type));
                    ctx.push_child(&mut result, node);

                    ctx.prev = Some(node_type);
                    Some((result, ts))
                }
                _ => {
                    None
                }
            }
        }
        Expr::PubReplace { ty_idx, ref body } => {
            match parse_exp(defs, ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = defs.node_type(ty_idx);
                    ctx.replacement = Some(node_type);
                    Some((node, ts))
                }
                _ => {
                    None
                }
            }
        }

        Expr::Or(ref parts) => parse_any(defs, ctx, parts.iter(), tokens),

        Expr::And(ref parts, commit) => {
            let mut node = ctx.create_composite_node(None);
            let commit = commit.unwrap_or(parts.len());
            let mut tokens = tokens;
            for (i, p) in parts.iter().enumerate() {
                if let Some((n, ts)) = parse_exp(defs, ctx, p, tokens) {
                    tokens = ts;
                    ctx.push_child(&mut node, n);
                } else {
                    if i < commit {
                        return None;
                    }
                    let error_node = ctx.create_error_node();
                    ctx.push_child(&mut node, error_node);
                    break
                }
            }
            Some((node, tokens))
        }

        Expr::Rule(id) => parse_exp(defs, ctx, &defs.rules[id].body, tokens),

        Expr::Token(ty) => {
            if let Some(current) = tokens.current() {
                if defs.node_type(ty) == current.ty {
                    return Some(ctx.create_leaf_node(tokens));
                }
            }
            None
        }

        Expr::ContextualToken(ty, ref text) => {
            ctx.create_contextual_leaf_node(tokens, defs.node_type(ty), &*text)
        }

        Expr::Opt(ref body) => parse_exp(defs, ctx, body, tokens).or_else(|| {
            Some(ctx.create_success_node(tokens))
        }),
        Expr::Not(ref e) => if parse_exp(defs, ctx, e, tokens).is_some() {
            None
        } else {
            Some(ctx.create_success_node(tokens))
        },
        Expr::Eof => if tokens.current().is_none() {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },
        Expr::Any => if tokens.current().is_some() {
            Some(ctx.create_leaf_node(tokens))
        } else {
            None
        },
        Expr::Layer(ref l, ref e) => {
            if let Some(rest) = parse_exp_pred(defs, ctx, l, tokens) {
                let mut result = ctx.create_composite_node(None);
                let layer = tokens.prefix(rest);
                if let Some((layer_contents, mut leftovers)) = parse_exp(defs, ctx, e, layer) {
                    ctx.push_child(&mut result, layer_contents);
                    if leftovers.current().is_some() {
                        let mut error = ctx.create_error_node();
                        while leftovers.current().is_some() {
                            let p = ctx.create_leaf_node(leftovers);
                            ctx.push_child(&mut error, p.0);
                            leftovers = p.1;
                        }
                        ctx.push_child(&mut result, error)
                    }
                };
                return Some((result, rest));
            };
            None
        }

        Expr::Rep(ref body) => {
            let mut node = ctx.create_composite_node(None);
            let mut tokens = tokens;
            loop {
                if let Some((n, t)) = parse_exp(defs, ctx, body, tokens) {
                    ctx.push_child(&mut node, n);
                    tokens = t;
                } else {
                    break;
                }
            }
            Some((node, tokens))
        }

        Expr::WithSkip(ref first, ref body) => {
            let mut error = ctx.create_error_node();
            let mut result = ctx.create_composite_node(None);
            let mut skipped = false;
            let mut tokens = tokens;
            loop {
                if tokens.current().is_none() {
                    return None;
                }
                if let Some(_) = parse_exp_pred(defs, ctx, first, tokens) {
                    if let Some((node, ts)) = parse_exp(defs, ctx, body, tokens) {
                        if skipped {
                            ctx.push_child(&mut result, error);
                        }
                        ctx.push_child(&mut result, node);
                        return Some((result, ts));
                    }
                }

                skipped = true;
                let (node, new_tokens) = ctx.create_leaf_node(tokens);
                tokens = new_tokens;
                ctx.push_child(&mut error, node);
            }
        }

        Expr::Pratt(ref g) => parse_pratt(defs, ctx, &*g, tokens, 0),

        Expr::Enter(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = true;
            let result = parse_exp(defs, ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::Exit(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = false;
            let result = parse_exp(defs, ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },

        Expr::Call(ref body, ref args) => {
            let old = ctx.args;
            for &(arg_pos, ref arg) in args.iter() {
                let arg = match *arg {
                    Expr::Var(i) => ctx.args[i as usize].unwrap(),
                    _ => arg
                };

                ctx.args[arg_pos as usize] = Some(arg);
            }
            let result = parse_exp(defs, ctx, body, tokens);
            ctx.args = old;
            result
        }

        Expr::Var(i) => {
            let expr = ctx.args[i as usize].unwrap();
            parse_exp(defs, ctx, expr, tokens)
        }

        Expr::PrevIs(ref ts) => {
            if let Some(prev) = ctx.prev {
                for &t in ts {
                    let t = defs.node_type(t);
                    if t == prev {
                        return Some(ctx.create_success_node(tokens));
                    }
                }
            }
            None
        }
    }
}

fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(
    defs: &Defs<'p>,
    ctx: &mut Ctx<'p>,
    options: I,
    tokens: TokenSequence<'t>
) -> Option<(Node, TokenSequence<'t>)> {
    for p in options {
        if let Some(result) = parse_exp(defs, ctx, p, tokens) {
            return Some(result);
        }
    }
    None
}

fn parse_pratt<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, min_prior: u32)
                       -> Option<(Node, TokenSequence<'t>)> {
    let (mut lhs, mut tokens) = match parse_pratt_prefix(defs, ctx, expr_grammar, tokens) {
        Some(p) => p,
        None => return None,
    };

    'postfix: loop {
        let postfix = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Postfix { ty, ref op } => {
                    Some((defs.node_type(ty), op.as_ref()))
                }
                _ => None
            }
        });
        for (ty, op) in postfix {
            if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
                let mut node = ctx.create_composite_node(Some(ty));
                ::std::mem::swap(&mut node, &mut lhs);
                ctx.push_child(&mut lhs, node);
                ctx.push_child(&mut lhs, op_node);
                tokens = rest;
                ctx.prev = Some(ty);
                continue 'postfix;
            }
        }
        break;
    }

    'bin: loop {
        let bins = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                    Some((defs.node_type(ty), op.as_ref(), priority))
                }
                _ => None
            }
        });

        for (ty, op, p) in bins {
            if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
                if let Some((rhs_node, rest)) = parse_pratt(defs, ctx, expr_grammar, rest, p) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    ctx.push_child(&mut lhs, rhs_node);
                    tokens = rest;
                    ctx.prev = Some(ty);
                    continue 'bin;
                }
            }
        }
        break;
    }
    Some((lhs, tokens))
}

fn parse_pratt_prefix<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>)
                              -> Option<(Node, TokenSequence<'t>)> {
    let prefix = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Prefix { ty, ref op } => Some((defs.node_type(ty), op.as_ref())),
            _ => None
        }
    });

    for (ty, op) in prefix {
        if let Some((op_node, rest)) = parse_exp(defs, ctx, op, tokens) {
            let mut node = ctx.create_composite_node(Some(ty));
            ctx.push_child(&mut node, op_node);
            if let Some((expr, rest)) = parse_pratt(defs, ctx, expr_grammar, rest, 999) {
                ctx.push_child(&mut node, expr);
                ctx.prev = Some(ty);
                return Some((node, rest));
            }
        }
    }

    let atoms = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Atom { ref body } => Some(body.as_ref()),
            _ => None
        }
    });
    parse_any(defs, ctx, atoms, tokens)
}

fn parse_exp_pred<'t, 'p>(defs: &Defs<'p>, ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                          -> Option<(TokenSequence<'t>)> {
    let old_mode = ctx.predicate_mode;
    ctx.predicate_mode = true;
    let result = parse_exp(defs, ctx, expr, tokens);
    ctx.predicate_mode = old_mode;
    result.map(|(_, ts)| ts)
}
<commit_msg>Simplify parsing code<commit_after>use fall_tree::NodeType;

use tree_builder::{Node, TokenSequence};

use {SynRule, Expr, PrattVariant};

pub fn parse(
    node_types: &[NodeType],
    rules: &[SynRule],
    tokens: TokenSequence
) -> (Node, u64) {
    let start_rule = Expr::Rule(0);

    let mut ctx = Ctx {
        node_types,
        rules,
        start_rule: &start_rule,

        ticks: 0,
        predicate_mode: false,
        contexts: [false; 16],
        args: [None; 16],
        prev: None,
        replacement: None,
    };

    parse_file(&mut ctx, tokens)
}

struct Ctx<'p> {
    node_types: &'p [NodeType],
    rules: &'p [SynRule],
    start_rule: &'p Expr,

    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16],
    prev: Option<NodeType>,
    replacement: Option<NodeType>,
}

impl<'p> Ctx<'p> {
    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }

    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

fn parse_file<'p>(ctx: &mut Ctx<'p>, tokens: TokenSequence) -> (Node, u64) {
    let (mut file_node, mut leftover) =
        parse_exp(ctx, ctx.start_rule, tokens)
            .unwrap_or_else(|| {
                let ty = match ctx.rules[0].body {
                    Expr::Pub { ty_idx, .. } => ctx.node_type(ty_idx),
                    _ => panic!("First rule must be public"),
                };
                (ctx.create_composite_node(Some(ty)), tokens)
            });

    let mut error = ctx.create_error_node();
    let mut skipped = false;
    while leftover.current().is_some() {
        skipped = true;
        let p = ctx.create_leaf_node(leftover);
        leftover = p.1;
        ctx.push_child(&mut error, p.0)
    }
    if skipped {
        ctx.push_child(&mut file_node, error)
    }
    (file_node, ctx.ticks)
}

fn parse_exp<'t, 'p>(ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                     -> Option<(Node, TokenSequence<'t>)> {
    ctx.ticks += 1;
    match *expr {
        Expr::Pub { ty_idx, ref body, replaceable } => {
            if replaceable {
                ctx.replacement = None;
            }
            match parse_exp(ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = match (replaceable, ctx.replacement) {
                        (true, Some(ty)) => ty,
                        _ => ctx.node_type(ty_idx),
                    };
                    let mut result = ctx.create_composite_node(Some(node_type));
                    ctx.push_child(&mut result, node);

                    ctx.prev = Some(node_type);
                    Some((result, ts))
                }
                _ => {
                    None
                }
            }
        }
        Expr::PubReplace { ty_idx, ref body } => {
            match parse_exp(ctx, body, tokens) {
                Some((node, ts)) => {
                    let node_type = ctx.node_type(ty_idx);
                    ctx.replacement = Some(node_type);
                    Some((node, ts))
                }
                _ => {
                    None
                }
            }
        }

        Expr::Or(ref parts) => parse_any(ctx, parts.iter(), tokens),

        Expr::And(ref parts, commit) => {
            let mut node = ctx.create_composite_node(None);
            let commit = commit.unwrap_or(parts.len());
            let mut tokens = tokens;
            for (i, p) in parts.iter().enumerate() {
                if let Some((n, ts)) = parse_exp(ctx, p, tokens) {
                    tokens = ts;
                    ctx.push_child(&mut node, n);
                } else {
                    if i < commit {
                        return None;
                    }
                    let error_node = ctx.create_error_node();
                    ctx.push_child(&mut node, error_node);
                    break
                }
            }
            Some((node, tokens))
        }

        Expr::Rule(id) => parse_exp(ctx, &ctx.rules[id].body, tokens),

        Expr::Token(ty) => {
            if let Some(current) = tokens.current() {
                if ctx.node_type(ty) == current.ty {
                    return Some(ctx.create_leaf_node(tokens));
                }
            }
            None
        }

        Expr::ContextualToken(ty, ref text) => {
            let ty = ctx.node_type(ty);
            ctx.create_contextual_leaf_node(tokens, ty, &*text)
        }

        Expr::Opt(ref body) => parse_exp(ctx, body, tokens).or_else(|| {
            Some(ctx.create_success_node(tokens))
        }),
        Expr::Not(ref e) => if parse_exp(ctx, e, tokens).is_some() {
            None
        } else {
            Some(ctx.create_success_node(tokens))
        },
        Expr::Eof => if tokens.current().is_none() {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },
        Expr::Any => if tokens.current().is_some() {
            Some(ctx.create_leaf_node(tokens))
        } else {
            None
        },
        Expr::Layer(ref l, ref e) => {
            if let Some(rest) = parse_exp_pred(ctx, l, tokens) {
                let mut result = ctx.create_composite_node(None);
                let layer = tokens.prefix(rest);
                if let Some((layer_contents, mut leftovers)) = parse_exp(ctx, e, layer) {
                    ctx.push_child(&mut result, layer_contents);
                    if leftovers.current().is_some() {
                        let mut error = ctx.create_error_node();
                        while leftovers.current().is_some() {
                            let p = ctx.create_leaf_node(leftovers);
                            ctx.push_child(&mut error, p.0);
                            leftovers = p.1;
                        }
                        ctx.push_child(&mut result, error)
                    }
                };
                return Some((result, rest));
            };
            None
        }

        Expr::Rep(ref body) => {
            let mut node = ctx.create_composite_node(None);
            let mut tokens = tokens;
            loop {
                if let Some((n, t)) = parse_exp(ctx, body, tokens) {
                    ctx.push_child(&mut node, n);
                    tokens = t;
                } else {
                    break;
                }
            }
            Some((node, tokens))
        }

        Expr::WithSkip(ref first, ref body) => {
            let mut error = ctx.create_error_node();
            let mut result = ctx.create_composite_node(None);
            let mut skipped = false;
            let mut tokens = tokens;
            loop {
                if tokens.current().is_none() {
                    return None;
                }
                if let Some(_) = parse_exp_pred(ctx, first, tokens) {
                    if let Some((node, ts)) = parse_exp(ctx, body, tokens) {
                        if skipped {
                            ctx.push_child(&mut result, error);
                        }
                        ctx.push_child(&mut result, node);
                        return Some((result, ts));
                    }
                }

                skipped = true;
                let (node, new_tokens) = ctx.create_leaf_node(tokens);
                tokens = new_tokens;
                ctx.push_child(&mut error, node);
            }
        }

        Expr::Pratt(ref g) => parse_pratt(ctx, &*g, tokens, 0),

        Expr::Enter(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = true;
            let result = parse_exp(ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::Exit(idx, ref e) => {
            let idx = idx as usize;
            let old = ctx.contexts[idx];
            ctx.contexts[idx] = false;
            let result = parse_exp(ctx, &*e, tokens);
            ctx.contexts[idx] = old;
            result
        }

        Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
            Some(ctx.create_success_node(tokens))
        } else {
            None
        },

        Expr::Call(ref body, ref args) => {
            let old = ctx.args;
            for &(arg_pos, ref arg) in args.iter() {
                let arg = match *arg {
                    Expr::Var(i) => ctx.args[i as usize].unwrap(),
                    _ => arg
                };

                ctx.args[arg_pos as usize] = Some(arg);
            }
            let result = parse_exp(ctx, body, tokens);
            ctx.args = old;
            result
        }

        Expr::Var(i) => {
            let expr = ctx.args[i as usize].unwrap();
            parse_exp(ctx, expr, tokens)
        }

        Expr::PrevIs(ref ts) => {
            if let Some(prev) = ctx.prev {
                for &t in ts {
                    let t = ctx.node_type(t);
                    if t == prev {
                        return Some(ctx.create_success_node(tokens));
                    }
                }
            }
            None
        }
    }
}

fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(
    ctx: &mut Ctx<'p>,
    options: I,
    tokens: TokenSequence<'t>
) -> Option<(Node, TokenSequence<'t>)> {
    for p in options {
        if let Some(result) = parse_exp(ctx, p, tokens) {
            return Some(result);
        }
    }
    None
}

fn parse_pratt<'t, 'p>(ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, min_prior: u32)
                       -> Option<(Node, TokenSequence<'t>)> {
    let (mut lhs, mut tokens) = match parse_pratt_prefix(ctx, expr_grammar, tokens) {
        Some(p) => p,
        None => return None,
    };

    'postfix: loop {
        let postfix = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Postfix { ty, ref op } => {
                    Some((ty, op.as_ref()))
                }
                _ => None
            }
        });
        for (ty, op) in postfix {
            let ty = ctx.node_type(ty);
            if let Some((op_node, rest)) = parse_exp(ctx, op, tokens) {
                let mut node = ctx.create_composite_node(Some(ty));
                ::std::mem::swap(&mut node, &mut lhs);
                ctx.push_child(&mut lhs, node);
                ctx.push_child(&mut lhs, op_node);
                tokens = rest;
                ctx.prev = Some(ty);
                continue 'postfix;
            }
        }
        break;
    }

    'bin: loop {
        let bins = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                    Some((ty, op.as_ref(), priority))
                }
                _ => None
            }
        });

        for (ty, op, p) in bins {
            let ty = ctx.node_type(ty);
            if let Some((op_node, rest)) = parse_exp(ctx, op, tokens) {
                if let Some((rhs_node, rest)) = parse_pratt(ctx, expr_grammar, rest, p) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    ctx.push_child(&mut lhs, rhs_node);
                    tokens = rest;
                    ctx.prev = Some(ty);
                    continue 'bin;
                }
            }
        }
        break;
    }
    Some((lhs, tokens))
}

fn parse_pratt_prefix<'t, 'p>(ctx: &mut Ctx<'p>, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>)
                              -> Option<(Node, TokenSequence<'t>)> {
    let prefix = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Prefix { ty, ref op } => Some((ty, op.as_ref())),
            _ => None
        }
    });

    for (ty, op) in prefix {
        let ty = ctx.node_type(ty);
        if let Some((op_node, rest)) = parse_exp(ctx, op, tokens) {
            let mut node = ctx.create_composite_node(Some(ty));
            ctx.push_child(&mut node, op_node);
            if let Some((expr, rest)) = parse_pratt(ctx, expr_grammar, rest, 999) {
                ctx.push_child(&mut node, expr);
                ctx.prev = Some(ty);
                return Some((node, rest));
            }
        }
    }

    let atoms = expr_grammar.iter().filter_map(|v| {
        match *v {
            PrattVariant::Atom { ref body } => Some(body.as_ref()),
            _ => None
        }
    });
    parse_any(ctx, atoms, tokens)
}

fn parse_exp_pred<'t, 'p>(ctx: &mut Ctx<'p>, expr: &'p Expr, tokens: TokenSequence<'t>)
                          -> Option<(TokenSequence<'t>)> {
    let old_mode = ctx.predicate_mode;
    ctx.predicate_mode = true;
    let result = parse_exp(ctx, expr, tokens);
    ctx.predicate_mode = old_mode;
    result.map(|(_, ts)| ts)
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core;
extern crate grin_chain;
extern crate env_logger;
extern crate time;
extern crate rand;
extern crate secp256k1zkp as secp;

use std::sync::Arc;
use std::thread;
use rand::os::OsRng;

use grin_chain::types::*;
use grin_core::core::hash::Hashed;
use grin_core::core::target::Difficulty;
use grin_core::pow;
use grin_core::core;
use grin_core::consensus;

#[test]
fn mine_empty_chain() {
  env_logger::init().unwrap();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	gen.header.cuckoo_len = 16;
	let diff = gen.header.difficulty.clone();
	pow::pow(&mut gen, diff).unwrap();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);

		let (difficulty, _) = consensus::next_target(b.header.timestamp.to_timespec().sec,
		                                             prev.header.timestamp.to_timespec().sec,
		                                             prev.header.difficulty.clone(),
		                                             prev.header.cuckoo_len);
		b.header.difficulty = difficulty.clone();

		pow::pow(&mut b, difficulty).unwrap();
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::NONE)
			.unwrap();

		// checking our new head
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n);
		assert_eq!(head.last_block_h, b.hash());

		prev = b;
	}
}

#[test]
fn mine_forks() {
  env_logger::init().unwrap();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin2".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n+1);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		prev = b;
	}
}
<commit_msg>Ignore log initialization failure.<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core;
extern crate grin_chain;
extern crate env_logger;
extern crate time;
extern crate rand;
extern crate secp256k1zkp as secp;

use std::sync::Arc;
use std::thread;
use rand::os::OsRng;

use grin_chain::types::*;
use grin_core::core::hash::Hashed;
use grin_core::core::target::Difficulty;
use grin_core::pow;
use grin_core::core;
use grin_core::consensus;

#[test]
fn mine_empty_chain() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	gen.header.cuckoo_len = 16;
	let diff = gen.header.difficulty.clone();
	pow::pow(&mut gen, diff).unwrap();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);

		let (difficulty, _) = consensus::next_target(b.header.timestamp.to_timespec().sec,
		                                             prev.header.timestamp.to_timespec().sec,
		                                             prev.header.difficulty.clone(),
		                                             prev.header.cuckoo_len);
		b.header.difficulty = difficulty.clone();

		pow::pow(&mut b, difficulty).unwrap();
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::NONE)
			.unwrap();

		// checking our new head
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n);
		assert_eq!(head.last_block_h, b.hash());

		prev = b;
	}
}

#[test]
fn mine_forks() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin2".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n+1);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		prev = b;
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core;
extern crate grin_chain;
extern crate env_logger;
extern crate time;
extern crate rand;
extern crate secp256k1zkp as secp;

use std::sync::Arc;
use std::thread;
use rand::os::OsRng;

use grin_chain::types::*;
use grin_core::core::hash::Hashed;
use grin_core::core::target::Difficulty;
use grin_core::pow;
use grin_core::core;
use grin_core::consensus;

#[test]
fn mine_empty_chain() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	gen.header.cuckoo_len = 16;
	let diff = gen.header.difficulty.clone();
	pow::pow(&mut gen.header, diff).unwrap();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);

		let (difficulty, _) = consensus::next_target(b.header.timestamp.to_timespec().sec,
		                                             prev.header.timestamp.to_timespec().sec,
		                                             prev.header.difficulty.clone(),
		                                             prev.header.cuckoo_len);
		b.header.difficulty = difficulty.clone();

		pow::pow(&mut b.header, difficulty).unwrap();
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::NONE)
			.unwrap();

		// checking our new head
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n);
		assert_eq!(head.last_block_h, b.hash());

		prev = b;
	}
}

#[test]
fn mine_forks() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin2".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();
  println!("WRITTEN HEAD");

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n+1);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		prev = b;
	}
}
<commit_msg>Lower cuckoo graph size for test.<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core;
extern crate grin_chain;
extern crate env_logger;
extern crate time;
extern crate rand;
extern crate secp256k1zkp as secp;

use std::sync::Arc;
use std::thread;
use rand::os::OsRng;

use grin_chain::types::*;
use grin_core::core::hash::Hashed;
use grin_core::core::target::Difficulty;
use grin_core::pow;
use grin_core::core;
use grin_core::consensus;

#[test]
fn mine_empty_chain() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	gen.header.cuckoo_len = 12;
	let diff = gen.header.difficulty.clone();
	pow::pow(&mut gen.header, diff).unwrap();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);

		let (difficulty, _) = consensus::next_target(b.header.timestamp.to_timespec().sec,
		                                             prev.header.timestamp.to_timespec().sec,
		                                             prev.header.difficulty.clone(),
		                                             prev.header.cuckoo_len);
		b.header.difficulty = difficulty.clone();

		pow::pow(&mut b.header, difficulty).unwrap();
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::NONE)
			.unwrap();

		// checking our new head
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n);
		assert_eq!(head.last_block_h, b.hash());

		prev = b;
	}
}

#[test]
fn mine_forks() {
  env_logger::init();
	let mut rng = OsRng::new().unwrap();
	let store = grin_chain::store::ChainKVStore::new(".grin2".to_string()).unwrap();

	// save a genesis block
	let mut gen = grin_core::genesis::genesis();
	gen.header.cuckoo_len = 12;
	let diff = gen.header.difficulty.clone();
	pow::pow(&mut gen.header, diff).unwrap();
	store.save_block(&gen).unwrap();

	// setup a new head tip
	let tip = Tip::new(gen.hash());
	store.save_head(&tip).unwrap();

	// mine and add a few blocks
	let mut prev = gen;
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
	let arc_store = Arc::new(store);
	let adapter = Arc::new(NoopAdapter {});

	for n in 1..4 {
		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
		b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
    b.header.total_difficulty = Difficulty::from_num(2*n+1);
		grin_chain::pipe::process_block(&b,
		                                arc_store.clone(),
		                                adapter.clone(),
		                                grin_chain::pipe::SKIP_POW)
			.unwrap();

		// checking our new head
    thread::sleep(::std::time::Duration::from_millis(50));
		let head = arc_store.clone().head().unwrap();
		assert_eq!(head.height, n as u64);
		assert_eq!(head.last_block_h, b.hash());
		assert_eq!(head.prev_block_h, prev.hash());

		prev = b;
	}
}
<|endoftext|>