<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast;
use syntax::codemap::Spanned;
use syntax::ext::base::ExtCtxt;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::parse;
use syntax::print::pprust;
use syntax::ptr::P;

use syntax::ast::{TokenTree, Generics, Expr};

pub use syntax::parse::new_parser_from_tts;
pub use syntax::codemap::{BytePos, Span, dummy_spanned};

pub trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

/* Should be (when bugs in default methods are fixed):

trait ToSource : ToTokens {
    // Takes a thing and generates a string containing rust code for it.
    pub fn to_source() -> String;

    // If you can make source, you can definitely make tokens.
    pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
        cx.parse_tts(self.to_source())
    }
}

*/

// FIXME: Move this trait to pprust and get rid of *_to_str?
pub trait ToSource {
    // Takes a thing and generates a string containing rust code for it.
    fn to_source(&self) -> String;
}

// FIXME (Issue #16472): This should go away after ToToken impls
// are revised to go directly to token-trees.
trait ToSourceWithHygiene : ToSource {
    // Takes a thing and generates a string containing rust code
    // for it, encoding Idents as special byte sequences to
    // maintain hygiene across serialization and deserialization.
    fn to_source_with_hygiene(&self) -> String;
}

macro_rules! impl_to_source {
    (P<$t:ty>, $pp:ident) => (
        impl ToSource for P<$t> {
            fn to_source(&self) -> String {
                pprust::$pp(&**self)
            }
        }
        impl ToSourceWithHygiene for P<$t> {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(&**self)
            }
        }
    );
    ($t:ty, $pp:ident) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                pprust::$pp(self)
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(self)
            }
        }
    );
}

fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
    sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source_with_hygiene())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

macro_rules! impl_to_source_slice {
    ($t:ty, $sep:expr) => (
        impl ToSource for [$t] {
            fn to_source(&self) -> String {
                slice_to_source($sep, self)
            }
        }

        impl ToSourceWithHygiene for [$t] {
            fn to_source_with_hygiene(&self) -> String {
                slice_to_source_with_hygiene($sep, self)
            }
        }
    )
}

impl ToSource for ast::Ident {
    fn to_source(&self) -> String {
        token::get_ident(*self).to_string()
    }
}

impl ToSourceWithHygiene for ast::Ident {
    fn to_source_with_hygiene(&self) -> String {
        self.encode_with_hygiene()
    }
}

impl_to_source! { ast::Ty, ty_to_string }
impl_to_source! { ast::Block, block_to_string }
impl_to_source! { ast::Arg, arg_to_string }
impl_to_source! { Generics, generics_to_string }
impl_to_source! { P<ast::Item>, item_to_string }
impl_to_source! { P<ast::Stmt>, stmt_to_string }
impl_to_source! { P<ast::Expr>, expr_to_string }
impl_to_source! { P<ast::Pat>, pat_to_string }
impl_to_source! { ast::Arm, arm_to_string }
impl_to_source_slice! { ast::Ty, ", " }
impl_to_source_slice! { P<ast::Item>, "\n\n" }

impl ToSource for ast::Attribute_ {
    fn to_source(&self) -> String {
        pprust::attribute_to_string(&dummy_spanned(self.clone()))
    }
}
impl ToSourceWithHygiene for ast::Attribute_ {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for P<ast::ImplItem> {
    fn to_source(&self) -> String {
        pprust::to_string(|s| s.print_impl_item(self))
    }
}

impl ToSourceWithHygiene for P<ast::ImplItem> {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| s.print_impl_item(self))
    }
}

impl ToSource for ast::WhereClause {
    fn to_source(&self) -> String {
        pprust::to_string(|s| {
            s.print_where_clause(&ast::Generics {
                lifetimes: vec![],
                ty_params: OwnedSlice::empty(),
                where_clause: self.clone(),
            })
        })
    }
}

impl ToSourceWithHygiene for ast::WhereClause {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| {
            s.print_where_clause(&ast::Generics {
                lifetimes: vec![],
                ty_params: OwnedSlice::empty(),
                where_clause: self.clone(),
            })
        })
    }
}

impl ToSource for str {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitStr(
                token::intern_and_get_ident(self), ast::CookedStr));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for str {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for () {
    fn to_source(&self) -> String {
        "()".to_string()
    }
}
impl ToSourceWithHygiene for () {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for bool {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitBool(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for bool {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for char {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitChar(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for char {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

macro_rules! impl_to_source_isize {
    (signed, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
}

impl_to_source_isize! { signed, isize, ast::TyIs(false) }
impl_to_source_isize! { signed, i8,  ast::TyI8 }
impl_to_source_isize! { signed, i16, ast::TyI16 }
impl_to_source_isize! { signed, i32, ast::TyI32 }
impl_to_source_isize! { signed, i64, ast::TyI64 }

impl_to_source_isize! { unsigned, usize, ast::TyUs(false) }
impl_to_source_isize! { unsigned, u8,   ast::TyU8 }
impl_to_source_isize! { unsigned, u16,  ast::TyU16 }
impl_to_source_isize! { unsigned, u32,  ast::TyU32 }
impl_to_source_isize! { unsigned, u64,  ast::TyU64 }

// Alas ... we write these out instead. All redundant.

macro_rules! impl_to_tokens {
    ($t:ty) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

macro_rules! impl_to_tokens_lifetime {
    ($t:ty) => (
        impl<'a> ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

impl_to_tokens! { ast::Ident }
impl_to_tokens! { P<ast::Item> }
impl_to_tokens! { P<ast::ImplItem> }
impl_to_tokens! { ast::WhereClause }
impl_to_tokens! { P<ast::Pat> }
impl_to_tokens! { ast::Arm }
impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
impl_to_tokens! { ast::Ty }
impl_to_tokens_lifetime! { &'a [ast::Ty] }
impl_to_tokens! { Generics }
impl_to_tokens! { P<ast::Stmt> }
impl_to_tokens! { P<ast::Expr> }
impl_to_tokens! { ast::Block }
impl_to_tokens! { ast::Arg }
impl_to_tokens! { ast::Attribute_ }
impl_to_tokens_lifetime! { &'a str }
impl_to_tokens! { () }
impl_to_tokens! { char }
impl_to_tokens! { bool }
impl_to_tokens! { isize }
impl_to_tokens! { i8 }
impl_to_tokens! { i16 }
impl_to_tokens! { i32 }
impl_to_tokens! { i64 }
impl_to_tokens! { usize }
impl_to_tokens! { u8 }
impl_to_tokens! { u16 }
impl_to_tokens! { u32 }
impl_to_tokens! { u64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

trait ExtParseUtilsWithHygiene {
    // FIXME (Issue #16472): This should go away after ToToken impls
    // are revised to go directly to token-trees.
    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          Vec::new(),
                                          self.parse_sess())
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}

impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {

    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
        use syntax::parse::with_hygiene::parse_tts_from_source_str;
        parse_tts_from_source_str("<quote expansion>".to_string(),
                                  s,
                                  self.cfg(),
                                  self.parse_sess())
    }
}
<commit_msg>Add unquoting paths<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast;
use syntax::codemap::Spanned;
use syntax::ext::base::ExtCtxt;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::parse;
use syntax::print::pprust;
use syntax::ptr::P;

use syntax::ast::{TokenTree, Generics, Expr};

pub use syntax::parse::new_parser_from_tts;
pub use syntax::codemap::{BytePos, Span, dummy_spanned};

pub trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

/* Should be (when bugs in default methods are fixed):

trait ToSource : ToTokens {
    // Takes a thing and generates a string containing rust code for it.
    pub fn to_source() -> String;

    // If you can make source, you can definitely make tokens.
    pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
        cx.parse_tts(self.to_source())
    }
}

*/

// FIXME: Move this trait to pprust and get rid of *_to_str?
pub trait ToSource {
    // Takes a thing and generates a string containing rust code for it.
    fn to_source(&self) -> String;
}

// FIXME (Issue #16472): This should go away after ToToken impls
// are revised to go directly to token-trees.
trait ToSourceWithHygiene : ToSource {
    // Takes a thing and generates a string containing rust code
    // for it, encoding Idents as special byte sequences to
    // maintain hygiene across serialization and deserialization.
    fn to_source_with_hygiene(&self) -> String;
}

macro_rules! impl_to_source {
    (P<$t:ty>, $pp:ident) => (
        impl ToSource for P<$t> {
            fn to_source(&self) -> String {
                pprust::$pp(&**self)
            }
        }
        impl ToSourceWithHygiene for P<$t> {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(&**self)
            }
        }
    );
    ($t:ty, $pp:ident) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                pprust::$pp(self)
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(self)
            }
        }
    );
}

fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
    sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source_with_hygiene())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

macro_rules! impl_to_source_slice {
    ($t:ty, $sep:expr) => (
        impl ToSource for [$t] {
            fn to_source(&self) -> String {
                slice_to_source($sep, self)
            }
        }

        impl ToSourceWithHygiene for [$t] {
            fn to_source_with_hygiene(&self) -> String {
                slice_to_source_with_hygiene($sep, self)
            }
        }
    )
}

impl ToSource for ast::Ident {
    fn to_source(&self) -> String {
        token::get_ident(*self).to_string()
    }
}

impl ToSourceWithHygiene for ast::Ident {
    fn to_source_with_hygiene(&self) -> String {
        self.encode_with_hygiene()
    }
}

impl_to_source! { ast::Path, path_to_string }
impl_to_source! { ast::Ty, ty_to_string }
impl_to_source! { ast::Block, block_to_string }
impl_to_source! { ast::Arg, arg_to_string }
impl_to_source! { Generics, generics_to_string }
impl_to_source! { P<ast::Item>, item_to_string }
impl_to_source! { P<ast::Stmt>, stmt_to_string }
impl_to_source! { P<ast::Expr>, expr_to_string }
impl_to_source! { P<ast::Pat>, pat_to_string }
impl_to_source! { ast::Arm, arm_to_string }
impl_to_source_slice! { ast::Ty, ", " }
impl_to_source_slice! { P<ast::Item>, "\n\n" }

impl ToSource for ast::Attribute_ {
    fn to_source(&self) -> String {
        pprust::attribute_to_string(&dummy_spanned(self.clone()))
    }
}
impl ToSourceWithHygiene for ast::Attribute_ {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for P<ast::ImplItem> {
    fn to_source(&self) -> String {
        pprust::to_string(|s| s.print_impl_item(self))
    }
}

impl ToSourceWithHygiene for P<ast::ImplItem> {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| s.print_impl_item(self))
    }
}

impl ToSource for ast::WhereClause {
    fn to_source(&self) -> String {
        pprust::to_string(|s| {
            s.print_where_clause(&ast::Generics {
                lifetimes: vec![],
                ty_params: OwnedSlice::empty(),
                where_clause: self.clone(),
            })
        })
    }
}

impl ToSourceWithHygiene for ast::WhereClause {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| {
            s.print_where_clause(&ast::Generics {
                lifetimes: vec![],
                ty_params: OwnedSlice::empty(),
                where_clause: self.clone(),
            })
        })
    }
}

impl ToSource for str {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitStr(
                token::intern_and_get_ident(self), ast::CookedStr));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for str {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for () {
    fn to_source(&self) -> String {
        "()".to_string()
    }
}
impl ToSourceWithHygiene for () {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for bool {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitBool(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for bool {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for char {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitChar(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for char {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

macro_rules! impl_to_source_isize {
    (signed, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
}

impl_to_source_isize! { signed, isize, ast::TyIs(false) }
impl_to_source_isize! { signed, i8,  ast::TyI8 }
impl_to_source_isize! { signed, i16, ast::TyI16 }
impl_to_source_isize! { signed, i32, ast::TyI32 }
impl_to_source_isize! { signed, i64, ast::TyI64 }

impl_to_source_isize! { unsigned, usize, ast::TyUs(false) }
impl_to_source_isize! { unsigned, u8,   ast::TyU8 }
impl_to_source_isize! { unsigned, u16,  ast::TyU16 }
impl_to_source_isize! { unsigned, u32,  ast::TyU32 }
impl_to_source_isize! { unsigned, u64,  ast::TyU64 }

// Alas ... we write these out instead. All redundant.

macro_rules! impl_to_tokens {
    ($t:ty) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

macro_rules! impl_to_tokens_lifetime {
    ($t:ty) => (
        impl<'a> ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

impl_to_tokens! { ast::Ident }
impl_to_tokens! { ast::Path }
impl_to_tokens! { P<ast::Item> }
impl_to_tokens! { P<ast::ImplItem> }
impl_to_tokens! { ast::WhereClause }
impl_to_tokens! { P<ast::Pat> }
impl_to_tokens! { ast::Arm }
impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
impl_to_tokens! { ast::Ty }
impl_to_tokens_lifetime! { &'a [ast::Ty] }
impl_to_tokens! { Generics }
impl_to_tokens! { P<ast::Stmt> }
impl_to_tokens! { P<ast::Expr> }
impl_to_tokens! { ast::Block }
impl_to_tokens! { ast::Arg }
impl_to_tokens! { ast::Attribute_ }
impl_to_tokens_lifetime! { &'a str }
impl_to_tokens! { () }
impl_to_tokens! { char }
impl_to_tokens! { bool }
impl_to_tokens! { isize }
impl_to_tokens! { i8 }
impl_to_tokens! { i16 }
impl_to_tokens! { i32 }
impl_to_tokens! { i64 }
impl_to_tokens! { usize }
impl_to_tokens! { u8 }
impl_to_tokens! { u16 }
impl_to_tokens! { u32 }
impl_to_tokens! { u64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

trait ExtParseUtilsWithHygiene {
    // FIXME (Issue #16472): This should go away after ToToken impls
    // are revised to go directly to token-trees.
    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          Vec::new(),
                                          self.parse_sess())
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}

impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {

    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
        use syntax::parse::with_hygiene::parse_tts_from_source_str;
        parse_tts_from_source_str("<quote expansion>".to_string(),
                                  s,
                                  self.cfg(),
                                  self.parse_sess())
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate string_cache;
extern crate html5ever;
extern crate unicode_width;

use std::io;
use std::io::Write;
use std::cmp::max;
use html5ever::{parse_document};
use html5ever::driver::ParseOpts;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom,Handle,Text,Element,Document,Comment};
use html5ever::tendril::TendrilSink;
use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};

/// A dummy writer which does nothing
struct Discard {}
impl Write for Discard {
    fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, io::Error> { Ok(bytes.len()) }
    fn flush(&mut self) -> std::result::Result<(), io::Error> { Ok(()) }
}

fn wrap_text(text: &str, width: usize) -> String {
    let mut result = String::new();
    let mut xpos = 0usize;
    for word in text.split_whitespace() {
        if width <= (xpos + 1) {
            result.push('\n');
            xpos = 0;
        }
        let space_left = width - xpos - 1;
        let word_width = UnicodeWidthStr::width(word);
        if word_width <= space_left {
            /* It fits; no problem.  Add a space if not at the
             * start of line.*/
            if xpos > 0 {
                result.push(' ');
                xpos += 1;
            }
            result.push_str(word);
            xpos += word_width;
            continue;
        }

        /* It doesn't fit.  If we're not at the start of the line,
         * then go to a new line. */
        if xpos > 0 {
            result.push('\n');
            xpos = 0;
        }

        /* We're now at the start of a line. */
        if word_width > width {
            /* It doesn't fit at all on the line, so break it. */
            for c in word.chars() {
                let c_width = UnicodeWidthChar::width(c).unwrap();
                if c_width + xpos > width {
                    /* Break here */
                    result.push('\n');
                    xpos = 0;
                }
                /* This might happen with really narrow spaces... */
                assert!(c_width <= width);

                result.push(c);
                xpos += c_width;
            }
        } else {
            result.push_str(word);
            xpos += word_width;
        }
    }
    /* Terminate with a newline if needed. */
    if xpos > 0 {
        result.push('\n');
    }
    result
}

fn get_text(handle: Handle) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    if let Text(ref tstr) = node.node {
        result.push_str(&tstr);
    } else {
        for child in node.children.iter() {
            result.push_str(&get_text(child.clone()));
        }
    }
    result
}

fn get_wrapped_text(handle: Handle, width: usize) -> String {
    let text = get_text(handle);
    wrap_text(&text, width)
}

fn dom_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    match node.node {
        Document => {},
        Element(ref name, _, _) => {
            match *name {
                qualname!(html, "html") |
                qualname!(html, "div") |
                qualname!(html, "span") |
                qualname!(html, "body") => {
                    /* process children, but don't add anything */
                },
                qualname!(html, "link") |
                qualname!(html, "meta") |
                qualname!(html, "hr") |
                qualname!(html, "script") |
                qualname!(html, "head") => {
                    /* Ignore the head and its children */
                    return result;
                },
                qualname!(html, "h1") |
                qualname!(html, "h2") |
                qualname!(html, "h3") |
                qualname!(html, "h4") |
                qualname!(html, "p") => {
                    return get_wrapped_text(handle.clone(), width) + "\n";
                },
                qualname!(html, "br") => {
                    result.push('\n');
                }
                qualname!(html, "table") => return table_to_string(handle.clone(), err_out, width),
                _ => {
                    write!(err_out, "Unhandled element: {:?}\n", name.local).unwrap();
                },
            }
          },
        Text(ref tstr) => {
            return wrap_text(tstr, width);
        }
        Comment(_) => {},
        _ => { write!(err_out, "Unhandled: {:?}\n", node).unwrap(); },
    }
    for child in node.children.iter() {
        result.push_str(&dom_to_string(child.clone(), err_out, width));
    }
    result
}

#[derive(Debug)]
struct TableCell {
    colspan: usize,
    content: Handle,
}

#[derive(Debug)]
struct TableRow {
    cells: Vec<TableCell>,
}

#[derive(Debug)]
struct Table {
    rows: Vec<TableRow>,
}

impl Table {
    pub fn new() -> Table {
        Table{ rows: Vec::new() }
    }
    pub fn push(&mut self, row: TableRow) {
        self.rows.push(row);
    }
    pub fn rows(&self) -> std::slice::Iter<TableRow> {
        self.rows.iter()
    }
}

impl TableRow {
    pub fn new() -> TableRow {
        TableRow{ cells: Vec::new() }
    }
    pub fn push(&mut self, cell: TableCell) {
        self.cells.push(cell);
    }
    pub fn cells(&self) -> std::slice::Iter<TableCell> {
        self.cells.iter()
    }
    /// Return an iterator over (column, &cell)s, which
    /// takes into account colspan.
    pub fn cell_columns(&self) -> Vec<(usize, &TableCell)> {
        let mut result = Vec::new();
        let mut colno = 0;
        for cell in &self.cells {
            result.push((colno, cell));
            colno += cell.colspan;
        }
        result
    }
    /// Count the number of cells in the row.
    /// Takes into account colspan.
    pub fn num_cells(&self) -> usize {
        self.cells.iter().map(|cell| cell.colspan).sum()
    }
}

impl TableCell {
    pub fn new(s: Handle) -> TableCell {
        if let Element(_, _, ref attrs) = s.borrow().node {
            let mut colspan = 1;
            for attr in attrs {
                if &attr.name.local == "colspan" {
                    let v:&str = &*attr.value;
                    colspan = v.parse().unwrap_or(1);
                } else {
                    //println!("Attr: {:?}", attr);
                }
            }
            TableCell{ content: s.clone(), colspan: colspan }
        } else {
            panic!("TableCell::new received a non-Element");
        }
    }
    pub fn render<T:Write>(&self, width: usize, err_out: &mut T) -> String
    {
        dom_to_string(self.content.clone(), err_out, width)
    }
}

fn handle_td(handle: Handle) -> TableCell {
    TableCell::new(handle)
}

fn handle_tr<T:Write>(handle: Handle, _: &mut T) -> TableRow {
    let node = handle.borrow();

    let mut row = TableRow::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "td") => {
                        row.push(handle_td(child.clone()));
                    },
                    _ => println!("  [[tr child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    row
}

fn handle_tbody<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();

    let mut table = Table::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tr") => {
                        table.push(handle_tr(child.clone(), err_out));
                    },
                    _ => println!("  [[tbody child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    /* Now lay out the table.  Use the simple option of giving each column
     * same width.  TODO: be cleverer, and handle multi-width cells, etc. */
    let num_columns = table.rows().map(|r| r.num_cells()).max().unwrap();

    let mut result = String::new();

    /* Heuristic: scale the column widths according to how much content there is. */
    let test_col_width = 1000;  // Render width for measurement; shouldn't make much difference.
    let min_width = 5;
    let mut col_sizes = vec![0usize; num_columns];

    for row in table.rows() {
        let mut colno = 0;
        for cell in row.cells() {
            let celldata = cell.render(test_col_width, &mut Discard{});
            // If the cell has a colspan>1, then spread its size between the
            // columns.
            let col_size = celldata.len() / cell.colspan;
            for i in 0..cell.colspan {
                col_sizes[colno + i] += col_size;
            }
            colno += cell.colspan;
        }
    }
    let tot_size: usize = col_sizes.iter().sum();
    let mut col_widths:Vec<usize> = col_sizes.iter()
                                         .map(|sz| {
                                             if *sz == 0 {
                                                 0
                                             } else {
                                                 max(sz * width / tot_size, min_width)
                                             }
                                          }).collect();
    /* The minimums may have put the total width too high */
    while col_widths.iter().cloned().sum::<usize>() > width {
        let (i, _) = col_widths.iter().cloned().enumerate().max_by_key(|k| k.1).unwrap();
        col_widths[i] -= 1;
    }
    if col_widths.len() > 0 {
        // Slight fudge; we're not drawing extreme edges, so one of the columns
        // can gets a free character cell from not having a border.
        // make it the last.
        let last = col_widths.len() - 1;
        col_widths[last] += 1;
    }

    let mut rowline = String::new();
    for width in col_widths.iter().cloned().filter(|w:&usize| *w > 0) {
        rowline.push_str(&(0..(width-1)).map(|_| '-').collect::<String>());
        rowline.push('+');
    }
    if rowline.len() > 0 {
        rowline.pop().unwrap();  // Remove the last '+'.
    }
    result.push_str(&rowline);
    result.push('\n');

    for row in table.rows() {
        let (used_widths, formatted_cells): (Vec<usize>, Vec<String>) = row.cell_columns()
                                              .into_iter()
                                              .flat_map(|(colno, cell)| {
                                                   let col_width:usize = col_widths[colno..colno+cell.colspan]
                                                                      .iter().sum();
                                                   if col_width > 0 {
                                                       Some((col_width, cell.render(col_width-1, err_out)))
                                                   } else {
                                                       None
                                                   }
                                               })
                                              .unzip();
        let line_sets: Vec<Vec<&str>> = formatted_cells.iter()
                                                       .map(|s| s.lines()
                                                                 .map(|line| line.trim_right())
                                                                 .collect())
                                                       .collect();
        let cell_height = line_sets.iter()
                                   .map(|v| v.len())
                                   .max().unwrap_or(0);
        for i in 0..cell_height {
            for (cellno, ls) in line_sets.iter().enumerate() {
                result.push_str(&format!("{: <width$}", ls.get(i).cloned().unwrap_or(""), width = used_widths[cellno]-1));
                if cellno == line_sets.len()-1 {
                    result.push('\n')
                } else {
                    result.push('|')
                }
            }
        }
        if cell_height > 0 {
            result.push_str(&rowline);
            result.push('\n');
        }
    }

    result
}

fn table_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let result = String::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tbody") => return handle_tbody(child.clone(), err_out, width),
                    _ => { writeln!(err_out, "  [[table child: {:?}]]", name).unwrap();},
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    result
}

pub fn from_read<R>(mut input: R, width: usize) -> String where R: io::Read {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };
    let dom = parse_document(RcDom::default(), opts)
                   .from_utf8()
                   .read_from(&mut input)
                   .unwrap();

    dom_to_string(dom.document, &mut Discard{} /* &mut io::stderr()*/, width)
}

#[cfg(test)]
mod tests {
    use super::{from_read,wrap_text};
    #[test]
    fn test_table() {
        assert_eq!(from_read(&br##"

           1
           2
           3

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
"#);
     }

     #[test]
     fn test_colspan() {
        assert_eq!(from_read(&br##"

           1
           2
           3

           12
           3

           1
           23

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
12     |3
---+---+----
1  |23
---+---+----
"#);
     }

     #[test]
     fn test_para() {
        assert_eq!(from_read(&b"
Hello
"[..], 10),
                   "Hello\n\n");
     }

     #[test]
     fn test_wrap() {
        assert_eq!(wrap_text("Hello", 10), "Hello\n");
     }
}
<commit_msg>Add failing blockquote test.<commit_after>#[macro_use]
extern crate string_cache;
extern crate html5ever;
extern crate unicode_width;

use std::io;
use std::io::Write;
use std::cmp::max;
use html5ever::{parse_document};
use html5ever::driver::ParseOpts;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom,Handle,Text,Element,Document,Comment};
use html5ever::tendril::TendrilSink;
use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};

/// A dummy writer which does nothing
struct Discard {}
impl Write for Discard {
    fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, io::Error> { Ok(bytes.len()) }
    fn flush(&mut self) -> std::result::Result<(), io::Error> { Ok(()) }
}

fn wrap_text(text: &str, width: usize) -> String {
    let mut result = String::new();
    let mut xpos = 0usize;
    for word in text.split_whitespace() {
        if width <= (xpos + 1) {
            result.push('\n');
            xpos = 0;
        }
        let space_left = width - xpos - 1;
        let word_width = UnicodeWidthStr::width(word);
        if word_width <= space_left {
            /* It fits; no problem.  Add a space if not at the
             * start of line.*/
            if xpos > 0 {
                result.push(' ');
                xpos += 1;
            }
            result.push_str(word);
            xpos += word_width;
            continue;
        }

        /* It doesn't fit.  If we're not at the start of the line,
         * then go to a new line. */
        if xpos > 0 {
            result.push('\n');
            xpos = 0;
        }

        /* We're now at the start of a line. */
        if word_width > width {
            /* It doesn't fit at all on the line, so break it. */
            for c in word.chars() {
                let c_width = UnicodeWidthChar::width(c).unwrap();
                if c_width + xpos > width {
                    /* Break here */
                    result.push('\n');
                    xpos = 0;
                }
                /* This might happen with really narrow spaces... */
                assert!(c_width <= width);

                result.push(c);
                xpos += c_width;
            }
        } else {
            result.push_str(word);
            xpos += word_width;
        }
    }
    /* Terminate with a newline if needed. */
    if xpos > 0 {
        result.push('\n');
    }
    result
}

fn get_text(handle: Handle) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    if let Text(ref tstr) = node.node {
        result.push_str(&tstr);
    } else {
        for child in node.children.iter() {
            result.push_str(&get_text(child.clone()));
        }
    }
    result
}

fn get_wrapped_text(handle: Handle, width: usize) -> String {
    let text = get_text(handle);
    wrap_text(&text, width)
}

fn dom_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    match node.node {
        Document => {},
        Element(ref name, _, _) => {
            match *name {
                qualname!(html, "html") |
                qualname!(html, "div") |
                qualname!(html, "span") |
                qualname!(html, "body") => {
                    /* process children, but don't add anything */
                },
                qualname!(html, "link") |
                qualname!(html, "meta") |
                qualname!(html, "hr") |
                qualname!(html, "script") |
                qualname!(html, "head") => {
                    /* Ignore the head and its children */
                    return result;
                },
                qualname!(html, "h1") |
                qualname!(html, "h2") |
                qualname!(html, "h3") |
                qualname!(html, "h4") |
                qualname!(html, "p") => {
                    return get_wrapped_text(handle.clone(), width) + "\n";
                },
                qualname!(html, "br") => {
                    result.push('\n');
                }
                qualname!(html, "table") => return table_to_string(handle.clone(), err_out, width),
                _ => {
                    write!(err_out, "Unhandled element: {:?}\n", name.local).unwrap();
                },
            }
          },
        Text(ref tstr) => {
            return wrap_text(tstr, width);
        }
        Comment(_) => {},
        _ => { write!(err_out, "Unhandled: {:?}\n", node).unwrap(); },
    }
    for child in node.children.iter() {
        result.push_str(&dom_to_string(child.clone(), err_out, width));
    }
    result
}

#[derive(Debug)]
struct TableCell {
    colspan: usize,
    content: Handle,
}

#[derive(Debug)]
struct TableRow {
    cells: Vec<TableCell>,
}

#[derive(Debug)]
struct Table {
    rows: Vec<TableRow>,
}

impl Table {
    pub fn new() -> Table {
        Table{ rows: Vec::new() }
    }
    pub fn push(&mut self, row: TableRow) {
        self.rows.push(row);
    }
    pub fn rows(&self) -> std::slice::Iter<TableRow> {
        self.rows.iter()
    }
}

impl TableRow {
    pub fn new() -> TableRow {
        TableRow{ cells: Vec::new() }
    }
    pub fn push(&mut self, cell: TableCell) {
        self.cells.push(cell);
    }
    pub fn cells(&self) -> std::slice::Iter<TableCell> {
        self.cells.iter()
    }
    /// Return an iterator over (column, &cell)s, which
    /// takes into account colspan.
    pub fn cell_columns(&self) -> Vec<(usize, &TableCell)> {
        let mut result = Vec::new();
        let mut colno = 0;
        for cell in &self.cells {
            result.push((colno, cell));
            colno += cell.colspan;
        }
        result
    }
    /// Count the number of cells in the row.
    /// Takes into account colspan.
    pub fn num_cells(&self) -> usize {
        self.cells.iter().map(|cell| cell.colspan).sum()
    }
}

impl TableCell {
    pub fn new(s: Handle) -> TableCell {
        if let Element(_, _, ref attrs) = s.borrow().node {
            let mut colspan = 1;
            for attr in attrs {
                if &attr.name.local == "colspan" {
                    let v:&str = &*attr.value;
                    colspan = v.parse().unwrap_or(1);
                } else {
                    //println!("Attr: {:?}", attr);
                }
            }
            TableCell{ content: s.clone(), colspan: colspan }
        } else {
            panic!("TableCell::new received a non-Element");
        }
    }
    pub fn render<T:Write>(&self, width: usize, err_out: &mut T) -> String
    {
        dom_to_string(self.content.clone(), err_out, width)
    }
}

fn handle_td(handle: Handle) -> TableCell {
    TableCell::new(handle)
}

fn handle_tr<T:Write>(handle: Handle, _: &mut T) -> TableRow {
    let node = handle.borrow();

    let mut row = TableRow::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "td") => {
                        row.push(handle_td(child.clone()));
                    },
                    _ => println!("  [[tr child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    row
}

fn handle_tbody<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();

    let mut table = Table::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tr") => {
                        table.push(handle_tr(child.clone(), err_out));
                    },
                    _ => println!("  [[tbody child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    /* Now lay out the table.  Use the simple option of giving each column
     * same width.  TODO: be cleverer, and handle multi-width cells, etc. */
    let num_columns = table.rows().map(|r| r.num_cells()).max().unwrap();

    let mut result = String::new();

    /* Heuristic: scale the column widths according to how much content there is. */
    let test_col_width = 1000;  // Render width for measurement; shouldn't make much difference.
    let min_width = 5;
    let mut col_sizes = vec![0usize; num_columns];

    for row in table.rows() {
        let mut colno = 0;
        for cell in row.cells() {
            let celldata = cell.render(test_col_width, &mut Discard{});
            // If the cell has a colspan>1, then spread its size between the
            // columns.
            let col_size = celldata.len() / cell.colspan;
            for i in 0..cell.colspan {
                col_sizes[colno + i] += col_size;
            }
            colno += cell.colspan;
        }
    }
    let tot_size: usize = col_sizes.iter().sum();
    let mut col_widths:Vec<usize> = col_sizes.iter()
                                         .map(|sz| {
                                             if *sz == 0 {
                                                 0
                                             } else {
                                                 max(sz * width / tot_size, min_width)
                                             }
                                          }).collect();
    /* The minimums may have put the total width too high */
    while col_widths.iter().cloned().sum::<usize>() > width {
        let (i, _) = col_widths.iter().cloned().enumerate().max_by_key(|k| k.1).unwrap();
        col_widths[i] -= 1;
    }
    if col_widths.len() > 0 {
        // Slight fudge; we're not drawing extreme edges, so one of the columns
        // can gets a free character cell from not having a border.
        // make it the last.
        let last = col_widths.len() - 1;
        col_widths[last] += 1;
    }

    let mut rowline = String::new();
    for width in col_widths.iter().cloned().filter(|w:&usize| *w > 0) {
        rowline.push_str(&(0..(width-1)).map(|_| '-').collect::<String>());
        rowline.push('+');
    }
    if rowline.len() > 0 {
        rowline.pop().unwrap();  // Remove the last '+'.
    }
    result.push_str(&rowline);
    result.push('\n');

    for row in table.rows() {
        let (used_widths, formatted_cells): (Vec<usize>, Vec<String>) = row.cell_columns()
                                              .into_iter()
                                              .flat_map(|(colno, cell)| {
                                                   let col_width:usize = col_widths[colno..colno+cell.colspan]
                                                                      .iter().sum();
                                                   if col_width > 0 {
                                                       Some((col_width, cell.render(col_width-1, err_out)))
                                                   } else {
                                                       None
                                                   }
                                               })
                                              .unzip();
        let line_sets: Vec<Vec<&str>> = formatted_cells.iter()
                                                       .map(|s| s.lines()
                                                                 .map(|line| line.trim_right())
                                                                 .collect())
                                                       .collect();
        let cell_height = line_sets.iter()
                                   .map(|v| v.len())
                                   .max().unwrap_or(0);
        for i in 0..cell_height {
            for (cellno, ls) in line_sets.iter().enumerate() {
                result.push_str(&format!("{: <width$}", ls.get(i).cloned().unwrap_or(""), width = used_widths[cellno]-1));
                if cellno == line_sets.len()-1 {
                    result.push('\n')
                } else {
                    result.push('|')
                }
            }
        }
        if cell_height > 0 {
            result.push_str(&rowline);
            result.push('\n');
        }
    }

    result
}

fn table_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let result = String::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tbody") => return handle_tbody(child.clone(), err_out, width),
                    _ => { writeln!(err_out, "  [[table child: {:?}]]", name).unwrap();},
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    result
}

pub fn from_read<R>(mut input: R, width: usize) -> String where R: io::Read {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };
    let dom = parse_document(RcDom::default(), opts)
                   .from_utf8()
                   .read_from(&mut input)
                   .unwrap();

    dom_to_string(dom.document, &mut Discard{} /* &mut io::stderr()*/, width)
}

#[cfg(test)]
mod tests {
    use super::{from_read,wrap_text};
    #[test]
    fn test_table() {
        assert_eq!(from_read(&br##"

           1
           2
           3

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
"#);
     }

     #[test]
     fn test_colspan() {
        assert_eq!(from_read(&br##"

           1
           2
           3

           12
           3

           1
           23

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
12     |3
---+---+----
1  |23
---+---+----
"#);
     }

     #[test]
     fn test_para() {
        assert_eq!(from_read(&b"
Hello
"[..], 10),
                   "Hello\n\n");
     }

     #[test]
     fn test_wrap() {
        assert_eq!(wrap_text("Hello", 10), "Hello\n");
     }

     #[test]
     fn test_blockquote() {
        assert_eq!(from_read(&br#"
Hello

One, two, three

foo

"#[..], 12), r#"Hello

> One, two,
> three

foo
"#);
     }
}
<|endoftext|>


<commit_before>use nom::*;

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

    #[test]
    fn c_ident_test() {
        let cid = "EALL_DUSasb18 ";
        let (_, cid1) = c_ident(cid).unwrap();

        assert_eq!("EALL_DUSasb18", cid1);
    }

    #[test]
    fn c_ident_vec_test() {
        let cid = "FZHL_DUSasb18 ";
        let (_, cid1) = c_ident_vec(cid).unwrap();

        assert_eq!(vec!("FZHL_DUSasb18".to_string()), cid1);

        let cid_vec = "FZHL_DUSasb19,xkask_3298 ";
        let (_, cid2) = c_ident_vec(cid_vec).unwrap();

        assert_eq!(
            vec!("FZHL_DUSasb19".to_string(), "xkask_3298".to_string()),
            cid2
        );
    }

    #[test]
    fn signal_test() {
        let signal_line = " SG_ NAME : 6|2@1- (1,0) [0|0] \"x\" ECALL_RUS\r\n\r\n";
        let signal1 = signal(signal_line).unwrap();
    }
    #[test]
    fn endianess_test() {
        let (_, big_endian) = endianess("0").expect("Failed to parse big endian");
        assert_eq!(Endianess::BigEndian, big_endian);

        let (_, little_endian) = endianess("1").expect("Failed to parse little endian");
        assert_eq!(Endianess::LittleEndian, little_endian);
    }

    #[test]
    fn signal_type_test() {
        let (_, multiplexer) = signal_type("m34920 ").expect("Failed to parse multiplexer");
        assert_eq!(SignalType::MultiplexedSignal(34920), multiplexer);

        let (_, multiplexor) = signal_type("M ").expect("Failed to parse multiplexor");
        assert_eq!(SignalType::Multiplexor, multiplexor);

        let (_, plain) = signal_type(" ").expect("Failed to parse plain");
        assert_eq!(SignalType::Plain, plain);
    }

    #[test]
    fn value_type_test() {
        let (_, vt) = value_type("- ").expect("Failed to parse value type");
        assert_eq!(ValueType::Signed, vt);

        let (_, vt) = value_type("+ ").expect("Failed to parse value type");
        assert_eq!(ValueType::Unsigned, vt);
    }

    #[test]
    fn message_definition_test() {
        let def = "BO_ 1 MCA_A1: 6 MFA
        SG_ ABC_1 : 9|2@1+ (1,0) [0|0] \"x\" XYZ_OUS
        SG_ BasL2 : 3|2@0- (1,0) [0|0] \"x\" DFA_FUS\r\n\r\n";
        let (_, message_def) = message_definition(def).expect("Failed to parse message definition");
    }
}

#[derive(Debug, PartialEq)]
pub struct Dbc(String);

#[derive(Debug, PartialEq)]
pub struct Label(String);

#[derive(Debug, PartialEq)]
pub struct Signal {
    name: String,
    signal_type: SignalType,
    offset: u64,
    length: u64,
    endianess: Endianess,
    value_type: ValueType,
    slope: f64,
    intercept: f64,
    min: f64,
    max: f64,
    unit: String,
    receivers: Vec<String>,
}

#[derive(Debug, PartialEq)]
pub struct SignalCommentId(i64);

#[derive(Debug, PartialEq)]
pub struct MessageId(u64);

#[derive(Debug, PartialEq)]
pub struct MessageTransmitter(String);

#[derive(Debug, PartialEq)]
pub struct Version(String);

#[derive(Debug, PartialEq)]
pub struct Symbol(String);

#[derive(Debug, PartialEq)]
pub enum SignalType {
    /// Multiplexor switch
    Multiplexor,
    /// Signal us being multiplexed by the multiplexer switch.
    MultiplexedSignal(u64),
    /// Normal signal
    Plain,
}

#[derive(Debug, PartialEq)]
pub enum Endianess {
    LittleEndian,
    BigEndian,
}

#[derive(Debug, PartialEq)]
pub enum ValueType {
    Signed,
    Unsigned,
}

#[derive(Debug, PartialEq)]
pub enum EnvType {
    EnvTypeFloat,
    EnvTypeu64,
    EnvTypeData,
}

#[derive(Debug, PartialEq)]
pub struct ECUDef(String);

type KeyValue = (String, i64);

#[derive(Debug, PartialEq)]
pub struct LabelDescription {
    id: u64,
    signalName: String,
    labels: Vec<Label>,
    extended: bool,
}

#[derive(Debug, PartialEq)]
pub enum Transmitter {
    TransmitterNodeName(String),
    TransmitterNoSender,
}

#[derive(Debug, PartialEq)]
pub enum AccessType {
    DUMMY_NODE_VECTOR0,
    DUMMY_NODE_VECTOR1,
    DUMMY_NODE_VECTOR2,
    DUMMY_NODE_VECTOR3,
}

#[derive(Debug, PartialEq)]
pub enum AccessNode {
    AccessNodeVectorXXX,
    AccessNodeName(String),
}

#[derive(Debug, PartialEq)]
pub enum SignalAttributeValue {
    Text(String),
    Int(i64),
}

#[derive(Debug, PartialEq)]
pub enum AttributeValuedForObjectType {
    RawAttributeValue(AttributeValue),
    NetworkNodeAttributeValue(String, AttributeValue),
    MessageDefinitionAttributeValue(MessageId, AttributeValue),
    SignalAttributeValue(MessageId, String, AttributeValue),
    EnvVariableAttributeValue(String, AttributeValue),
}

#[derive(Debug, PartialEq)]
pub enum AttributeValueType {
    AttributeValueTypeInt(i64, i64),
    AttributeValueTypeHex(i64, i64),
    AttributeValueTypeFloat(f64, f64),
    AttributeValueTypeString,
    AttributeValueTypeEnum(Vec<String>),
}

#[derive(Debug, PartialEq)]
pub struct ValueDescription {
    a: f64,
    b: String,
}

#[derive(Debug, PartialEq)]
pub struct AttributeDefault {
    name: String,
    value: AttributeValue,
}

#[derive(Debug, PartialEq)]
pub enum AttributeValue {
    AttributeValueUu64(u64),
    AttributeValueu64(u64),
    AttributeValuef64(f64),
    AttributeValueCharString(String),
}

#[derive(Debug, PartialEq)]
pub enum DbcElement {
    ValueTable(String, Vec<KeyValue>),
    NetworkNodeComment(String),
    MessageDefinitionComment(MessageId, String, String, bool),
    SignalComment(SignalCommentId, String, String, bool),
    EnvVarComment(String),
    Message(MessageId, bool, String, u64, String, Vec<Signal>),
    EnvVariable(
        String,
        EnvType,
        i64,
        i64,
        String,
        f64,
        i64,
        AccessType,
        Vec<AccessNode>,
    ),
    BitTimingSection,
    EnvVarData(String, u64),
    NetworkNode(Vec<String>),
    AttributeValueForObject(String, AttributeValuedForObjectType),
    Def,
    BODef,
    BUDef,
    ValueDescriptionsForSignal(MessageId, String, Vec<ValueDescription>),
    ValueDescriptionsForEnvVar(String, Vec<ValueDescription>),
}

#[derive(Debug, PartialEq)]
pub struct DbcDefinition {
    version: Version,
    symbols: Vec<Symbol>,
    elements: Vec<DbcElement>,
}

fn is_colon(chr: char) -> bool {
    chr == ':'
}

fn is_c_string_char(chr: char) -> bool {
    chr.is_digit(10) || chr.is_alphabetic() || chr == '_'
}

fn is_quote(chr: char) -> bool {
    chr == '"'
}

/// Single space
named!(ss<&str, char>, char!(' '));

/// Colon
named!(colon<&str,  char>, char!(':'));

/// Comma aka ','
named!(comma<&str,  char>, char!(','));

/// Quote aka '"'
named!(quote<&str,  char>, char!('"'));

named!(pipe<&str,  char>, char!('|'));

named!(at<&str,  char>, char!('@'));

/// brace open aka '('
named!(brc_open<&str,  char>, char!('('));

/// brace close aka '('
named!(brc_close<&str,  char>, char!(')'));

/// bracket open aka '['
named!(brk_open<&str,  char>, char!('['));

/// bracket close aka ']'
named!(brk_close<&str,  char>, char!(']'));

// TODO fix first character
/// C_String
/// a valid C_identifier. C_identifiers have to start with a  alphacharacter or an underscore
/// and may further consist of alphanumeric, characters and underscore
named!(c_ident<&str, &str>, take_while!(is_c_string_char));

named!(c_ident_vec<&str, Vec<String>>,
    map!(separated_nonempty_list!(comma, c_ident), |li| li.iter().map(|s| s.to_string()).collect())
);

named!(u64_digit<&str, u64>,
    map_res!(
        digit,
        std::str::FromStr::from_str
    )
);

named!(quoted<&str, &str>,
    do_parse!(
            quote                     >>
        s: take_till_s!(is_quote) >>
            quote                     >>
        (s)
    )
);

named!(little_endian<&str, Endianess>,
    do_parse!(
        char!('1') >>
        (Endianess::LittleEndian)
    )
);

named!(big_endian<&str, Endianess>,
    do_parse!(
        char!('0') >>
        (Endianess::BigEndian)
    )
);

named!(endianess<&str, Endianess>, alt!(little_endian | big_endian));

named!(pub message_id<&str, MessageId>,
    do_parse!(
        id:  u64_digit >>
        (MessageId(id))
    )
);

named!(signed<&str, ValueType>,
    do_parse!(
        char!('-') >>
        (ValueType::Signed)
    )
);

named!(unsigned<&str, ValueType>,
    do_parse!(
        char!('+') >>
        (ValueType::Unsigned)
    )
);

named!(value_type<&str, ValueType>, alt!(signed | unsigned));

named!(pub multiplexer<&str, SignalType>,
    do_parse!(
            char!('m') >>
        d: u64_digit >>
            ss >>
        (SignalType::MultiplexedSignal(d))
    )
);

named!(pub multiplexor<&str, SignalType>,
    do_parse!(
        char!('M') >>
        ss >>
        (SignalType::Multiplexor)
    )
);

named!(pub plain<&str, SignalType>,
    do_parse!(
        ss >>
        (SignalType::Plain)
    )
);

named!(pub signal_type<&str, SignalType>, alt!(multiplexer | multiplexor | plain));

named!(pub signal<&str, Signal>,
    do_parse!(
                             space >>
                              tag!("SG_") >>
                              ss                >>
        name:            c_ident        >>
        signal_type: signal_type >>
                              colon           >>
                              ss                >>
       offset:             u64_digit         >>
                              pipe             >>
       length:            u64_digit         >>
                              at                  >>
      endianess:    endianess    >>
       value_type:  value_type    >>
                             ss                 >>
                             brc_open      >>
       slope:            double_s             >>
                            comma          >>
       intercept:       double_s        >>
                             brc_close     >>
                             ss                 >>
                             brk_open      >>
       min:               double_s            >>
                             pipe               >>
       max:              double_s            >>
                             brk_close      >>
                             ss                  >>
       unit:               quoted           >>
                             ss                  >>
        receivers: c_ident_vec     >>
        (Signal {
            name: name.to_string(),
            signal_type: signal_type,
            offset: offset,
            length: length,
            endianess: endianess,
            value_type: value_type,
            slope: slope,
            intercept: intercept,
            min: min,
            max: max,
            unit:  unit.to_string(),
            receivers: receivers,
        })
    )
);

named!(pub message_definition<&str, DbcElement>,
  do_parse!(
    tag!("BO_") >>
    ss >>
    id:   message_id >>
    ss >>
    name: take_till_s!(is_colon) >>
    colon >>
    ss >>
    size:  u64_digit >>
    ss >>
    transmitter: c_ident >>
    line_ending >>
    signals: separated_nonempty_list!(line_ending, signal) >>
    (DbcElement::Message(id, false, name.to_string(), size, transmitter.to_string(), signals))
  )
);
<commit_msg>Add comment parser<commit_after>use nom::*;

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

    #[test]
    fn c_ident_test() {
        let cid = "EALL_DUSasb18 ";
        let (_, cid1) = c_ident(cid).unwrap();

        assert_eq!("EALL_DUSasb18", cid1);
    }

    #[test]
    fn c_ident_vec_test() {
        let cid = "FZHL_DUSasb18 ";
        let (_, cid1) = c_ident_vec(cid).unwrap();

        assert_eq!(vec!("FZHL_DUSasb18".to_string()), cid1);

        let cid_vec = "FZHL_DUSasb19,xkask_3298 ";
        let (_, cid2) = c_ident_vec(cid_vec).unwrap();

        assert_eq!(
            vec!("FZHL_DUSasb19".to_string(), "xkask_3298".to_string()),
            cid2
        );
    }

    #[test]
    fn signal_test() {
        let signal_line = " SG_ NAME : 6|2@1- (1,0) [0|0] \"x\" ECALL_RUS\r\n\r\n";
        let signal1 = signal(signal_line).unwrap();
    }
    #[test]
    fn endianess_test() {
        let (_, big_endian) = endianess("0").expect("Failed to parse big endian");
        assert_eq!(Endianess::BigEndian, big_endian);

        let (_, little_endian) = endianess("1").expect("Failed to parse little endian");
        assert_eq!(Endianess::LittleEndian, little_endian);
    }

    #[test]
    fn signal_type_test() {
        let (_, multiplexer) = signal_type("m34920 ").expect("Failed to parse multiplexer");
        assert_eq!(SignalType::MultiplexedSignal(34920), multiplexer);

        let (_, multiplexor) = signal_type("M ").expect("Failed to parse multiplexor");
        assert_eq!(SignalType::Multiplexor, multiplexor);

        let (_, plain) = signal_type(" ").expect("Failed to parse plain");
        assert_eq!(SignalType::Plain, plain);
    }

    #[test]
    fn value_type_test() {
        let (_, vt) = value_type("- ").expect("Failed to parse value type");
        assert_eq!(ValueType::Signed, vt);

        let (_, vt) = value_type("+ ").expect("Failed to parse value type");
        assert_eq!(ValueType::Unsigned, vt);
    }

    #[test]
    fn message_definition_test() {
        let def = "BO_ 1 MCA_A1: 6 MFA
        SG_ ABC_1 : 9|2@1+ (1,0) [0|0] \"x\" XYZ_OUS
        SG_ BasL2 : 3|2@0- (1,0) [0|0] \"x\" DFA_FUS\r\n\r\n";
        let (_, message_def) = message_definition(def).expect("Failed to parse message definition");
    }

    #[test]
    fn signal_comment_test() {
        let def1 = "CM_ SG_ 193 KLU_R_X \"This is a signal comment test\";";
        let id1 = SignalCommentId(193);
        let comment1 = DbcElement::SignalComment(id1, "KLU_R_X".to_string(), "This is a signal comment test".to_string(), false);
        let (_, comment1_def) = comment(def1).expect("Failed to parse signal comment definition");
        assert_eq!(comment1, comment1_def);
     }

     #[test]
    fn message_definition_comment_test() {
        let def1 = "CM_ BO_ 34544 XYZ \"Some Message comment\";";
        let id1 = MessageId(34544);
        let comment1 = DbcElement::MessageDefinitionComment(id1, "XYZ".to_string(), "Some Message comment".to_string(), false);
        let (_, comment1_def) = comment(def1).expect("Failed to parse message definition comment definition");
        assert_eq!(comment1, comment1_def);
     }
}

#[derive(Debug, PartialEq)]
pub struct Dbc(String);

#[derive(Debug, PartialEq)]
pub struct Label(String);

#[derive(Debug, PartialEq)]
pub struct Signal {
    name: String,
    signal_type: SignalType,
    offset: u64,
    length: u64,
    endianess: Endianess,
    value_type: ValueType,
    slope: f64,
    intercept: f64,
    min: f64,
    max: f64,
    unit: String,
    receivers: Vec<String>,
}

#[derive(Debug, PartialEq)]
pub struct SignalCommentId(u64);

#[derive(Debug, PartialEq)]
pub struct MessageId(u64);

#[derive(Debug, PartialEq)]
pub struct MessageTransmitter(String);

#[derive(Debug, PartialEq)]
pub struct Version(String);

#[derive(Debug, PartialEq)]
pub struct Symbol(String);

#[derive(Debug, PartialEq)]
pub enum SignalType {
    /// Multiplexor switch
    Multiplexor,
    /// Signal us being multiplexed by the multiplexer switch.
    MultiplexedSignal(u64),
    /// Normal signal
    Plain,
}

#[derive(Debug, PartialEq)]
pub enum Endianess {
    LittleEndian,
    BigEndian,
}

#[derive(Debug, PartialEq)]
pub enum ValueType {
    Signed,
    Unsigned,
}

#[derive(Debug, PartialEq)]
pub enum EnvType {
    EnvTypeFloat,
    EnvTypeu64,
    EnvTypeData,
}

#[derive(Debug, PartialEq)]
pub struct ECUDef(String);

type KeyValue = (String, i64);

#[derive(Debug, PartialEq)]
pub struct LabelDescription {
    id: u64,
    signalName: String,
    labels: Vec<Label>,
    extended: bool,
}

#[derive(Debug, PartialEq)]
pub enum Transmitter {
    TransmitterNodeName(String),
    TransmitterNoSender,
}

#[derive(Debug, PartialEq)]
pub enum AccessType {
    DUMMY_NODE_VECTOR0,
    DUMMY_NODE_VECTOR1,
    DUMMY_NODE_VECTOR2,
    DUMMY_NODE_VECTOR3,
}

#[derive(Debug, PartialEq)]
pub enum AccessNode {
    AccessNodeVectorXXX,
    AccessNodeName(String),
}

#[derive(Debug, PartialEq)]
pub enum SignalAttributeValue {
    Text(String),
    Int(i64),
}

#[derive(Debug, PartialEq)]
pub enum AttributeValuedForObjectType {
    RawAttributeValue(AttributeValue),
    NetworkNodeAttributeValue(String, AttributeValue),
    MessageDefinitionAttributeValue(MessageId, AttributeValue),
    SignalAttributeValue(MessageId, String, AttributeValue),
    EnvVariableAttributeValue(String, AttributeValue),
}

#[derive(Debug, PartialEq)]
pub enum AttributeValueType {
    AttributeValueTypeInt(i64, i64),
    AttributeValueTypeHex(i64, i64),
    AttributeValueTypeFloat(f64, f64),
    AttributeValueTypeString,
    AttributeValueTypeEnum(Vec<String>),
}

#[derive(Debug, PartialEq)]
pub struct ValueDescription {
    a: f64,
    b: String,
}

#[derive(Debug, PartialEq)]
pub struct AttributeDefault {
    name: String,
    value: AttributeValue,
}

#[derive(Debug, PartialEq)]
pub enum AttributeValue {
    AttributeValueUu64(u64),
    AttributeValueu64(u64),
    AttributeValuef64(f64),
    AttributeValueCharString(String),
}

#[derive(Debug, PartialEq)]
pub enum DbcElement {
    ValueTable(String, Vec<KeyValue>),
    NetworkNodeComment(String),
    MessageDefinitionComment(MessageId, String, String, bool),
    SignalComment(SignalCommentId, String, String, bool),
    EnvVarComment(String),
    Message(MessageId, bool, String, u64, String, Vec<Signal>),
    EnvVariable(
        String,
        EnvType,
        i64,
        i64,
        String,
        f64,
        i64,
        AccessType,
        Vec<AccessNode>,
    ),
    BitTimingSection,
    EnvVarData(String, u64),
    NetworkNode(Vec<String>),
    AttributeValueForObject(String, AttributeValuedForObjectType),
    Def,
    BODef,
    BUDef,
    ValueDescriptionsForSignal(MessageId, String, Vec<ValueDescription>),
    ValueDescriptionsForEnvVar(String, Vec<ValueDescription>),
}

#[derive(Debug, PartialEq)]
pub struct DbcDefinition {
    version: Version,
    symbols: Vec<Symbol>,
    elements: Vec<DbcElement>,
}

fn is_colon(chr: char) -> bool {
    chr == ':'
}

fn is_semi_colon(chr: char) -> bool {
    chr == ';'
}

fn is_space_s(chr: char) -> bool {
    chr == ' '
}

fn is_c_string_char(chr: char) -> bool {
    chr.is_digit(10) || chr.is_alphabetic() || chr == '_'
}

fn is_quote(chr: char) -> bool {
    chr == '"'
}

/// Single space
named!(ss<&str, char>, char!(' '));

/// Colon
named!(colon<&str,  char>, char!(':'));

/// Comma aka ','
named!(comma<&str,  char>, char!(','));

/// Comma aka ';'
named!(semi_colon<&str,  char>, char!(';'));

/// Quote aka '"'
named!(quote<&str,  char>, char!('"'));

named!(pipe<&str,  char>, char!('|'));

named!(at<&str,  char>, char!('@'));

/// brace open aka '('
named!(brc_open<&str,  char>, char!('('));

/// brace close aka '('
named!(brc_close<&str,  char>, char!(')'));

/// bracket open aka '['
named!(brk_open<&str,  char>, char!('['));

/// bracket close aka ']'
named!(brk_close<&str,  char>, char!(']'));

// TODO fix first character
/// C_String
/// a valid C_identifier. C_identifiers have to start with a  alphacharacter or an underscore
/// and may further consist of alphanumeric, characters and underscore
named!(c_ident<&str, &str>, take_while!(is_c_string_char));

named!(c_ident_vec<&str, Vec<String>>,
    map!(separated_nonempty_list!(comma, c_ident), |li| li.iter().map(|s| s.to_string()).collect())
);

named!(u64_digit<&str, u64>,
    map_res!(
        digit,
        std::str::FromStr::from_str
    )
);

named!(quoted<&str, &str>,
    do_parse!(
            quote                     >>
        s: take_till_s!(is_quote) >>
            quote                     >>
        (s)
    )
);

named!(little_endian<&str, Endianess>,
    do_parse!(
        char!('1') >>
        (Endianess::LittleEndian)
    )
);

named!(big_endian<&str, Endianess>,
    do_parse!(
        char!('0') >>
        (Endianess::BigEndian)
    )
);

named!(endianess<&str, Endianess>, alt!(little_endian | big_endian));

named!(pub message_id<&str, MessageId>,
    do_parse!(
        id:  u64_digit >>
        (MessageId(id))
    )
);

named!(pub signal_comment_id<&str, SignalCommentId>,
    do_parse!(
        id:  u64_digit >>
        (SignalCommentId(id))
    )
);

named!(signed<&str, ValueType>,
    do_parse!(
        char!('-') >>
        (ValueType::Signed)
    )
);

named!(unsigned<&str, ValueType>,
    do_parse!(
        char!('+') >>
        (ValueType::Unsigned)
    )
);

named!(value_type<&str, ValueType>, alt!(signed | unsigned));

named!(pub multiplexer<&str, SignalType>,
    do_parse!(
            char!('m') >>
        d: u64_digit >>
            ss >>
        (SignalType::MultiplexedSignal(d))
    )
);

named!(pub multiplexor<&str, SignalType>,
    do_parse!(
        char!('M') >>
        ss >>
        (SignalType::Multiplexor)
    )
);

named!(pub plain<&str, SignalType>,
    do_parse!(
        ss >>
        (SignalType::Plain)
    )
);

named!(pub signal_type<&str, SignalType>, alt!(multiplexer | multiplexor | plain));

named!(pub signal<&str, Signal>,
    do_parse!(
                             space >>
                              tag!("SG_") >>
                              ss                >>
        name:            c_ident        >>
        signal_type: signal_type >>
                              colon           >>
                              ss                >>
       offset:             u64_digit         >>
                              pipe             >>
       length:            u64_digit         >>
                              at                  >>
      endianess:    endianess    >>
       value_type:  value_type    >>
                             ss                 >>
                             brc_open      >>
       slope:            double_s             >>
                            comma          >>
       intercept:       double_s        >>
                             brc_close     >>
                             ss                 >>
                             brk_open      >>
       min:               double_s            >>
                             pipe               >>
       max:              double_s            >>
                             brk_close      >>
                             ss                  >>
       unit:               quoted           >>
                             ss                  >>
        receivers: c_ident_vec     >>
        (Signal {
            name: name.to_string(),
            signal_type: signal_type,
            offset: offset,
            length: length,
            endianess: endianess,
            value_type: value_type,
            slope: slope,
            intercept: intercept,
            min: min,
            max: max,
            unit:  unit.to_string(),
            receivers: receivers,
        })
    )
);

named!(pub message_definition<&str, DbcElement>,
  do_parse!(
    tag!("BO_") >>
    ss >>
    id:   message_id >>
    ss >>
    name: take_till_s!(is_colon) >>
    colon >>
    ss >>
    size:  u64_digit >>
    ss >>
    transmitter: c_ident >>
    line_ending >>
    signals: separated_nonempty_list!(line_ending, signal) >>
    (DbcElement::Message(id, false, name.to_string(), size, transmitter.to_string(), signals))
  )
);

named!(pub signal_comment<&str, DbcElement>,
    do_parse!(
        tag!("SG_") >>
        ss >>
        id: signal_comment_id >>
        ss >>
        name: c_ident >>
        ss >>
        comment: quoted >>
        (DbcElement::SignalComment(id, name.to_string(), comment.to_string(), false))
    )
);

named!(pub message_definition_comment<&str, DbcElement>,
    do_parse!(
        tag!("BO_") >>
        ss >>
        id: message_id >>
        ss >>
        // TODO not only c ident ?
        name: take_till_s!(is_space_s) >>
        ss >>
        comment: quoted >>
        (DbcElement::MessageDefinitionComment(id, name.to_string(), comment.to_string(), false))
    )
);

named!(pub comment<&str, DbcElement>,
    do_parse!(
        tag!("CM_") >>
        ss >>
        c: alt!(signal_comment | message_definition_comment) >>
        semi_colon >>
        (c)
    )
);<|endoftext|>


<commit_before>extern crate bit_vec;

mod traits;
#[macro_use] mod macros;
mod pages;
mod heap;

pub use heap::*;
pub use traits::{Mark, HeapInline, GCThing, GCRef};
pub use pages::HEAP_SIZE;

#[cfg(test)]
mod test;
<commit_msg>Eliminate a `use heap::*` by being specific.<commit_after>extern crate bit_vec;

mod traits;
#[macro_use] mod macros;
mod pages;
mod heap;

pub use heap::{Heap, with_heap, PinnedRef};
pub use traits::{Mark, HeapInline, GCThing, GCRef};
pub use pages::HEAP_SIZE;

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


<commit_before>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;

pub trait NodeType {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

pub struct Link<W: Clone> {
    pub node_idx: NodeIndex,
    pub weight: W,
}

pub struct Node<NT: NodeType, N, W: Clone> {
    pub node_type: NT,
    pub node_data: N,
    pub input_links: Vec<Link<W>>,
    pub output_links: Vec<Link<W>>,
}

pub struct Network<NT: NodeType, N, W: Clone> {
    nodes: Vec<Node<NT, N, W>>,
}

impl<NT: NodeType, N, W: Clone> Network<NT, N, W> {
    pub fn new() -> Network<NT, N, W> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: NT, node_data: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            node_data: node_data,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix;

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order;

        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !self.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    // The algorithm used in `link_would_cycle` and `find_random_unconnected_link_no_cycle`.  This
    // is mostly extracted to avoid repetetive memory allocations in
    // `find_random_unconnected_link_no_cycle`.
    fn cycle_algo(&self,
                  path_to: usize,
                  nodes_to_visit: &mut Vec<usize>,
                  seen_nodes: &mut FixedBitSet)
                  -> bool {
        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &self.nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        let mut seen_nodes = FixedBitSet::with_capacity(self.nodes.len());
        let mut nodes_to_visit = Vec::new();

        // We start at the target node and iterate all paths from there. If we hit the source node,
        // we found a cycle. Otherwise not.
        let start = target_node_idx.index();

        // We are looking for a path to this node.
        let path_to = source_node_idx.index();

        nodes_to_visit.push(start);
        seen_nodes.insert(start);

        self.cycle_algo(path_to, &mut nodes_to_visit, &mut seen_nodes)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: W) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let h1 = g.add_node(NodeT::Hidden, ());
        let h2 = g.add_node(NodeT::Hidden, ());
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let o1 = g.add_node(NodeT::Output, ());
        let o2 = g.add_node(NodeT::Output, ());

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<commit_msg>Extract code into struct CycleDetector. This allow full encapsulation of the algorithm and resetting of the helper structs in a safe way.<commit_after>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;

pub trait NodeType {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

pub struct Link<W: Clone> {
    pub node_idx: NodeIndex,
    pub weight: W,
}

pub struct Node<NT: NodeType, N, W: Clone> {
    pub node_type: NT,
    pub node_data: N,
    pub input_links: Vec<Link<W>>,
    pub output_links: Vec<Link<W>>,
}

pub struct Network<NT: NodeType, N, W: Clone> {
    nodes: Vec<Node<NT, N, W>>,
}

struct CycleDetector<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> {
    nodes: &'a [Node<NT, N, W>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> CycleDetector<'a, NT, N, W> {
    fn new(network: &'a Network<NT, N, W>) -> CycleDetector<'a, NT, N, W> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn detect_cycle(&mut self, path_from: usize, path_to: usize) -> bool {
        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from this node and iterate all paths from there. If we hit the target node,
        // we found a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

impl<NT: NodeType, N, W: Clone> Network<NT, N, W> {
    pub fn new() -> Network<NT, N, W> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: NT, node_data: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            node_data: node_data,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix;

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order;

        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !self.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).detect_cycle(target_node_idx.index(), source_node_idx.index())
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: W) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let h1 = g.add_node(NodeT::Hidden, ());
        let h2 = g.add_node(NodeT::Hidden, ());
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let o1 = g.add_node(NodeT::Output, ());
        let o2 = g.add_node(NodeT::Output, ());

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<|endoftext|>