<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use hyper;
use hyper::client::Client;
use mdo::option::{bind, ret};
use super::ToJson;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn bano2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let res: Vec<_> = es_wrapper.search_and_filter("20", |_| true).collect();
    assert_eq!(res.len(), 2);

    // after an import, we should have 1 index, and some aliases to this index
    let client = Client::new();
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(first_indexes.len(), 1);
    // our index should be aliased by the master_index + an alias over the document type + dataset
    let aliases = mdo! {
         s =<< raw_indexes.get(first_indexes.first().unwrap());
         s =<< s.as_object();
         s =<< s.get("aliases");
         s =<< s.as_object();
         ret ret(s.keys().cloned().collect())
     }
        .unwrap_or_else(Vec::new);
    // for the moment 'munin' is hard coded, but hopefully that will change
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);

    // then we import again the bano file:
    info!("importing again {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    // we should still have only one index (but a different one)
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let final_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(final_indexes.len(), 1);
    assert!(final_indexes != first_indexes);

    let aliases = mdo! {
        s =<< raw_indexes.get(final_indexes.first().unwrap());
        s =<< s.as_object();
        s =<< s.get("aliases");
        s =<< s.as_object();
        ret ret(s.keys().cloned().collect())
    }
        .unwrap_or_else(Vec::new);
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr"]);
}
<commit_msg>corrections tests<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use hyper;
use hyper::client::Client;
use mdo::option::{bind, ret};
use super::ToJson;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn bano2mimir_sample_test(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let res: Vec<_> = es_wrapper.search_and_filter("20", |_| true).collect();
    assert_eq!(res.len(), 2);

    // after an import, we should have 1 index, and some aliases to this index
    let client = Client::new();
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(first_indexes.len(), 1);
    // our index should be aliased by the master_index + an alias over the document type + dataset
    let aliases = mdo! {
         s =<< raw_indexes.get(first_indexes.first().unwrap());
         s =<< s.as_object();
         s =<< s.get("aliases");
         s =<< s.as_object();
         ret ret(s.keys().cloned().collect())
     }
        .unwrap_or_else(Vec::new);
    // for the moment 'munin' is hard coded, but hopefully that will change
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr", "munin_street_network"]);

    // then we import again the bano file:
    info!("importing again {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    // we should still have only one index (but a different one)
    let res = client.get(&format!("{host}/_aliases", host = es_wrapper.host()))
        .send()
        .unwrap();
    assert_eq!(res.status, hyper::Ok);

    let json = res.to_json();
    let raw_indexes = json.as_object().unwrap();
    let final_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    assert_eq!(final_indexes.len(), 1);
    assert!(final_indexes != first_indexes);

    let aliases = mdo! {
        s =<< raw_indexes.get(final_indexes.first().unwrap());
        s =<< s.as_object();
        s =<< s.get("aliases");
        s =<< s.as_object();
        ret ret(s.keys().cloned().collect())
    }
        .unwrap_or_else(Vec::new);
    assert_eq!(aliases, vec!["munin", "munin_addr", "munin_addr_fr", "munin_street_network"]);
}
<|endoftext|>


<commit_before>extern crate graph_match;
extern crate hyper;
extern crate rustc_serialize;

#[macro_use]
mod macros;
mod core_nlp;
mod graph_parser;
mod points;
mod frames;
mod verbs;

use graph_match::matching::EqualityRequirement;

fn main() {
    let frames = frames::frame_index();
    let verbs = verbs::verb_index();
    let banned_edges: Vec<String> = vec![String::from("advcl"), String::from("csubj"), String::from("ccomp"), String::from("dep"), String::from("parataxis")];

    let text = "The man ran home, he eat his food. He climbed the stairs.".to_string();
    let string_graphs = match core_nlp::graphs_for_text(&text) {
        Ok(graphs) => graphs,
        Err(message) => panic!("There was an error in building the graph string repoints ({})", message),
    };

    for g in string_graphs {
        let graph = match graph_parser::parse(&g) {
            Ok(g) => g,
            Err(message) => {
                println!("The following graph:\n\n{}\n\nfailed with the following message: {}", g, message);
                continue;
            }
        };

        let verb_indices = match points::find_verbs(&graph) {
            Some(indices) => indices,
            None => {
                println!("There were no verbs.");
                continue;
            }
        };

        let queries = match points::build_queries(&verb_indices, &graph, &verbs, &frames) {
            Some(queries) => queries,
            None => {
                println!("No queries could be generated.");
                continue;
            }
        };

        for query in queries {
            match frames.get(&query.1) {
                Some(frame) => {
                    println!("Pattern: {}", query.1);
                    for matched_components in graph_match::match_graph(&frame.1, frame.0, &graph, Some(query.0), &EqualityRequirement::Contains) {
                        println!("{:?}", points::matched_components_to_pattern(&matched_components, &graph));
                        let root_node_index = matched_components.list[0].node;
                        let node_indexes = graph_match::expand_subgraph(&graph, root_node_index, &banned_edges);
                        println!("{:?}", points::subgraph_nodes_to_extract_string(&node_indexes, &graph));
                    }
                },
                None => println!("Previously matched frame now missing."),
            }
        }
        print!("\n");
    }
}
<commit_msg>Correct error message typo<commit_after>extern crate graph_match;
extern crate hyper;
extern crate rustc_serialize;

#[macro_use]
mod macros;
mod core_nlp;
mod graph_parser;
mod points;
mod frames;
mod verbs;

use graph_match::matching::EqualityRequirement;

fn main() {
    let frames = frames::frame_index();
    let verbs = verbs::verb_index();
    let banned_edges: Vec<String> = vec![String::from("advcl"), String::from("csubj"), String::from("ccomp"), String::from("dep"), String::from("parataxis")];

    let text = "The man ran home, he eat his food. He climbed the stairs.".to_string();
    let string_graphs = match core_nlp::graphs_for_text(&text) {
        Ok(graphs) => graphs,
        Err(message) => panic!("There was an error in building the graph string ({})", message),
    };

    for g in string_graphs {
        let graph = match graph_parser::parse(&g) {
            Ok(g) => g,
            Err(message) => {
                println!("The following graph:\n\n{}\n\nfailed with the following message: {}", g, message);
                continue;
            }
        };

        let verb_indices = match points::find_verbs(&graph) {
            Some(indices) => indices,
            None => {
                println!("There were no verbs.");
                continue;
            }
        };

        let queries = match points::build_queries(&verb_indices, &graph, &verbs, &frames) {
            Some(queries) => queries,
            None => {
                println!("No queries could be generated.");
                continue;
            }
        };

        for query in queries {
            match frames.get(&query.1) {
                Some(frame) => {
                    println!("Pattern: {}", query.1);
                    for matched_components in graph_match::match_graph(&frame.1, frame.0, &graph, Some(query.0), &EqualityRequirement::Contains) {
                        println!("{:?}", points::matched_components_to_pattern(&matched_components, &graph));
                        let root_node_index = matched_components.list[0].node;
                        let node_indexes = graph_match::expand_subgraph(&graph, root_node_index, &banned_edges);
                        println!("{:?}", points::subgraph_nodes_to_extract_string(&node_indexes, &graph));
                    }
                },
                None => println!("Previously matched frame now missing."),
            }
        }
        print!("\n");
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// 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.

#![cfg(all(feature = "full", feature = "fold"))]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

#[macro_use]
extern crate quote;
extern crate rayon;
extern crate syn;
extern crate syntax;
extern crate walkdir;

use rayon::iter::{IntoParallelIterator, ParallelIterator};
use syntax::ast;
use syntax::ptr::P;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::{parse, respan};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::check_min_stack();
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.cmp(b))
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path.to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    for expr in exprs {
        let raw = quote!(#expr).to_string();

        let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
            e
        } else {
            failed += 1;
            errorf!("\nFAIL - libsyntax failed to parse raw\n");
            continue;
        };

        let syn_expr = syn_brackets(expr);
        let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
            e
        } else {
            failed += 1;
            errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
            continue;
        };

        let syn_ast = respan::respan_expr(syn_ast);
        let libsyntax_ast = respan::respan_expr(libsyntax_ast);

        if syn_ast == libsyntax_ast {
            passed += 1;
        } else {
            failed += 1;
            errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
        }
    }

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified form
/// of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::fold::{self, Folder};
    use syntax::util::ThinVec;
    use syntax::util::small_vector::SmallVector;
    use syntax::ext::quote::rt::DUMMY_SP;
    use syntax::codemap;

    fn expr(node: ExprKind) -> P<Expr> {
        P(Expr {
            id: ast::DUMMY_NODE_ID,
            node: node,
            span: DUMMY_SP,
            attrs: ThinVec::new(),
        })
    }

    struct BracketsFolder {
        failed: bool,
    };
    impl Folder for BracketsFolder {
        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| Expr {
                node: match e.node {
                    ExprKind::Paren(inner) => {
                        ExprKind::Paren(inner.map(|e| fold::noop_fold_expr(e, self)))
                    }
                    ExprKind::If(..) | ExprKind::Block(..) | ExprKind::IfLet(..) => {
                        return fold::noop_fold_expr(e, self);
                    }
                    node => ExprKind::Paren(expr(node).map(|e| fold::noop_fold_expr(e, self))),
                },
                ..e
            })
        }

        fn fold_field(&mut self, f: Field) -> Field {
            Field {
                ident: codemap::respan(f.ident.span, self.fold_ident(f.ident.node)),
                expr: if f.is_shorthand {
                    f.expr.map(|e| fold::noop_fold_expr(e, self))
                } else {
                    self.fold_expr(f.expr)
                },
                span: self.new_span(f.span),
                is_shorthand: f.is_shorthand,
                attrs: fold::fold_thin_attrs(f.attrs, self),
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
            pat
        }

        fn fold_ty(&mut self, ty: P<Ty>) -> P<Ty> {
            ty
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> SmallVector<Stmt> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(e) => StmtKind::Expr(e.map(|e| fold::noop_fold_expr(e, self))),
                StmtKind::Semi(e) => StmtKind::Semi(e.map(|e| fold::noop_fold_expr(e, self))),
                s => s,
            };

            SmallVector::one(Stmt { node: node, ..stmt })
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement fold_mac to just return the macro
            // unchanged.
            mac
        }
    }

    let mut folder = BracketsFolder { failed: false };
    let e = folder.fold_expr(libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(e)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified form
/// of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::*;
    use syn::fold::*;

    fn paren(folder: &mut BracketsFolder, mut node: Expr) -> Expr {
        let attrs = node.replace_attrs(Vec::new());
        Expr::Paren(ExprParen {
            attrs: attrs,
            expr: Box::new(fold_expr(folder, node)),
            paren_token: token::Paren::default(),
        })
    }

    struct BracketsFolder;
    impl Folder for BracketsFolder {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::Paren(p) => paren(self, *p.expr),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::IfLet(..) => {
                    fold_expr(self, expr)
                }
                node => paren(self, node),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(Box::new(fold_expr(self, *e))),
                Stmt::Semi(e, semi) => Stmt::Semi(Box::new(fold_expr(self, *e)), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = BracketsFolder;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::*;
    use syn::fold::*;
    use syn::punctuated::Punctuated;

    struct CollectExprsFolder(Vec<Expr>);
    impl Folder for CollectExprsFolder {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprsFolder(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>Rename test fold implementations<commit_after>// Copyright 2018 Syn Developers
//
// 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.

#![cfg(all(feature = "full", feature = "fold"))]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

#[macro_use]
extern crate quote;
extern crate rayon;
extern crate syn;
extern crate syntax;
extern crate walkdir;

use rayon::iter::{IntoParallelIterator, ParallelIterator};
use syntax::ast;
use syntax::ptr::P;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::{parse, respan};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::check_min_stack();
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.cmp(b))
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path.to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    for expr in exprs {
        let raw = quote!(#expr).to_string();

        let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
            e
        } else {
            failed += 1;
            errorf!("\nFAIL - libsyntax failed to parse raw\n");
            continue;
        };

        let syn_expr = syn_brackets(expr);
        let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
            e
        } else {
            failed += 1;
            errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
            continue;
        };

        let syn_ast = respan::respan_expr(syn_ast);
        let libsyntax_ast = respan::respan_expr(libsyntax_ast);

        if syn_ast == libsyntax_ast {
            passed += 1;
        } else {
            failed += 1;
            errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
        }
    }

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified form
/// of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::fold::{self, Folder};
    use syntax::util::ThinVec;
    use syntax::util::small_vector::SmallVector;
    use syntax::ext::quote::rt::DUMMY_SP;
    use syntax::codemap;

    fn expr(node: ExprKind) -> P<Expr> {
        P(Expr {
            id: ast::DUMMY_NODE_ID,
            node: node,
            span: DUMMY_SP,
            attrs: ThinVec::new(),
        })
    }

    struct BracketsFolder {
        failed: bool,
    };
    impl Folder for BracketsFolder {
        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| Expr {
                node: match e.node {
                    ExprKind::Paren(inner) => {
                        ExprKind::Paren(inner.map(|e| fold::noop_fold_expr(e, self)))
                    }
                    ExprKind::If(..) | ExprKind::Block(..) | ExprKind::IfLet(..) => {
                        return fold::noop_fold_expr(e, self);
                    }
                    node => ExprKind::Paren(expr(node).map(|e| fold::noop_fold_expr(e, self))),
                },
                ..e
            })
        }

        fn fold_field(&mut self, f: Field) -> Field {
            Field {
                ident: codemap::respan(f.ident.span, self.fold_ident(f.ident.node)),
                expr: if f.is_shorthand {
                    f.expr.map(|e| fold::noop_fold_expr(e, self))
                } else {
                    self.fold_expr(f.expr)
                },
                span: self.new_span(f.span),
                is_shorthand: f.is_shorthand,
                attrs: fold::fold_thin_attrs(f.attrs, self),
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
            pat
        }

        fn fold_ty(&mut self, ty: P<Ty>) -> P<Ty> {
            ty
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> SmallVector<Stmt> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(e) => StmtKind::Expr(e.map(|e| fold::noop_fold_expr(e, self))),
                StmtKind::Semi(e) => StmtKind::Semi(e.map(|e| fold::noop_fold_expr(e, self))),
                s => s,
            };

            SmallVector::one(Stmt { node: node, ..stmt })
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement fold_mac to just return the macro
            // unchanged.
            mac
        }
    }

    let mut folder = BracketsFolder { failed: false };
    let e = folder.fold_expr(libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(e)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified form
/// of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::*;
    use syn::fold::*;

    fn paren(folder: &mut ParenthesizeEveryExpr, mut node: Expr) -> Expr {
        let attrs = node.replace_attrs(Vec::new());
        Expr::Paren(ExprParen {
            attrs: attrs,
            expr: Box::new(fold_expr(folder, node)),
            paren_token: token::Paren::default(),
        })
    }

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::Paren(p) => paren(self, *p.expr),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::IfLet(..) => {
                    fold_expr(self, expr)
                }
                node => paren(self, node),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(Box::new(fold_expr(self, *e))),
                Stmt::Semi(e, semi) => Stmt::Semi(Box::new(fold_expr(self, *e)), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::*;
    use syn::fold::*;
    use syn::punctuated::Punctuated;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// 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.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! # #[macro_use]
//! # extern crate quote;
//! #
//! # extern crate syn;
//! # extern crate proc_macro2;
//! #
//! # use syn::Type;
//! # use syn::spanned::Spanned;
//! # use proc_macro2::Span;
//! #
//! # fn example(ty: Type) {
//! let def_site = Span::def_site();
//! let ty_span = ty.span().resolved_at(def_site);
//! let assert_sync = quote_spanned! {ty_span=>
//!     struct _AssertSync where #ty: Sync;
//! };
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type. But it is
//! **incredibly important** that the span for the assertion is **resolved** at
//! the procedural macro definition site rather than at the `Type`'s span. This
//! way we guarantee that it refers to the `Sync` trait that we expect. If the
//! assertion were **resolved** at the same place that `ty` is resolved, the
//! user could circumvent the check by defining their own `Sync` trait that is
//! implemented for their type.

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, Tokens};

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.1/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span,
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span,
            None => Span::call_site(),
        }
    }
}
<commit_msg>Show more context around the Spanned example<commit_after>// Copyright 2018 Syn Developers
//
// 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.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//!
//! extern crate syn;
//! extern crate proc_macro;
//! extern crate proc_macro2;
//!
//! use syn::Type;
//! use syn::spanned::Spanned;
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let def_site = Span::def_site();
//!     let ty_span = ty.span().resolved_at(def_site);
//!     let assert_sync = quote_spanned! {ty_span=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type. But it is
//! **incredibly important** that the span for the assertion is **resolved** at
//! the procedural macro definition site rather than at the `Type`'s span. This
//! way we guarantee that it refers to the `Sync` trait that we expect. If the
//! assertion were **resolved** at the same place that `ty` is resolved, the
//! user could circumvent the check by defining their own `Sync` trait that is
//! implemented for their type.

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, Tokens};

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.1/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span,
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span,
            None => Span::call_site(),
        }
    }
}
<|endoftext|>


<commit_before>use crate::ToTokens;
use proc_macro2::{Span, TokenStream};

pub trait Spanned {
    fn __span(&self) -> Span;
}

impl Spanned for Span {
    fn __span(&self) -> Span {
        *self
    }
}

impl<T: ?Sized + ToTokens> Spanned for T {
    fn __span(&self) -> Span {
        join_spans(self.into_token_stream())
    }
}

fn join_spans(tokens: TokenStream) -> Span {
    let mut iter = tokens.into_iter().filter_map(|tt| {
        // FIXME: This shouldn't be required, since optimally spans should
        // never be invalid. This filter_map can probably be removed when
        // https://github.com/rust-lang/rust/issues/43081 is resolved.
        let span = tt.span();
        let debug = format!("{:?}", span);
        if debug.ends_with("bytes(0..0)") {
            None
        } else {
            Some(span)
        }
    });

    let first = match iter.next() {
        Some(span) => span,
        None => return Span::call_site(),
    };

    #[cfg(procmacro2_semver_exempt)]
    return iter
        .fold(None, |_prev, next| Some(next))
        .and_then(|last| first.join(last))
        .unwrap_or(first);

    // We can't join spans without procmacro2_semver_exempt so just grab the
    // first one.
    #[cfg(not(procmacro2_semver_exempt))]
    return first;
}
<commit_msg>Can assume Span::join exists<commit_after>use crate::ToTokens;
use proc_macro2::{Span, TokenStream};

pub trait Spanned {
    fn __span(&self) -> Span;
}

impl Spanned for Span {
    fn __span(&self) -> Span {
        *self
    }
}

impl<T: ?Sized + ToTokens> Spanned for T {
    fn __span(&self) -> Span {
        join_spans(self.into_token_stream())
    }
}

fn join_spans(tokens: TokenStream) -> Span {
    let mut iter = tokens.into_iter().filter_map(|tt| {
        // FIXME: This shouldn't be required, since optimally spans should
        // never be invalid. This filter_map can probably be removed when
        // https://github.com/rust-lang/rust/issues/43081 is resolved.
        let span = tt.span();
        let debug = format!("{:?}", span);
        if debug.ends_with("bytes(0..0)") {
            None
        } else {
            Some(span)
        }
    });

    let first = match iter.next() {
        Some(span) => span,
        None => return Span::call_site(),
    };

    iter.fold(None, |_prev, next| Some(next))
        .and_then(|last| first.join(last))
        .unwrap_or(first)
}
<|endoftext|>


<commit_before>extern crate bio;
extern crate argparse;
use std::io;
use std::io::Write;
use std::cmp;
use bio::io::fasta;
use std::fmt;
use std::fs::File;
use argparse::{ArgumentParser, StoreTrue, Store, Print, Collect};

const EXIT_FILE_IO_ERROR: i32 = 1;
// exit status 2 currently used by argparse on failure of command
// line argument parsing.
const EXIT_FASTA_PARSE_ERROR: i32 = 3;
static PROGRAM_NAME: &'static str = "biotool";

fn exit_with_error(status :i32, message: &String) -> () {
   writeln!(&mut std::io::stderr(), "{} ERROR: {}!", PROGRAM_NAME, message).unwrap();
   std::process::exit(status);
}

pub struct FastaStats {
   min_len: u64,
   average_len: u64,
   max_len: u64,
   total: u64,
   num_seqs: u64,
}

pub enum StatsResult {
   StatsNone,
   StatsSome(FastaStats),
   StatsError(io::Error)
}

impl FastaStats {
   pub fn new<R: io::Read>(minlen: u64, reader: R) -> StatsResult {
      let fasta_reader = fasta::Reader::new(reader);
      let mut num_seqs:u64 = 0;
      let mut total:u64 = 0;
      let mut max_len:u64 = 0;
      let mut min_len:u64 = 0;
      let mut this_len:u64;

      for next in fasta_reader.records() {
         match next {
            Ok(record) => {
               this_len = record.seq().len() as u64;
               if this_len >= minlen {
                  num_seqs += 1;
                  total += this_len;
                  if num_seqs == 1 {
                     max_len = this_len;
                     min_len = this_len;
                  }
                  else {
                     max_len = cmp::max(max_len, this_len);
                     min_len = cmp::min(min_len, this_len);
                  }
               }
            },
            Err(error) => return StatsResult::StatsError(error)
         }
      }
      if num_seqs > 0 {
         let average_len = ((total as f64) / (num_seqs as f64)).floor() as u64;
         StatsResult::StatsSome(FastaStats { min_len: min_len,
                           average_len: average_len,
                           max_len: max_len,
                           total: total,
                           num_seqs: num_seqs })
      }
      else {
         StatsResult::StatsNone
      }
   }
}

impl fmt::Display for FastaStats {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "{}\t{}\t{}\t{}\t{}", self.num_seqs, self.total,
         self.min_len, self.average_len, self.max_len)
   }
}

struct Options {
    verbose: bool,
    minlen: u64,
    fasta_files: Vec<String>,
}

fn parse_options() -> Options {
   let mut options = Options { verbose: false, minlen: 0, fasta_files: Vec::new() };
   {  let mut ap = ArgumentParser::new();
       ap.set_description("Print fasta stats");
       ap.refer(&mut options.verbose)
           .add_option(&["-v", "--verbose"], StoreTrue,
           "Print more stuff about what's happening");
       ap.refer(&mut options.minlen)
           .add_option(&["--minlen"], Store,
           "Minimum length sequence to include in stats");
       ap.refer(&mut options.fasta_files)
           .add_argument(&"fasta_files", Collect,
           "Input FASTA files");
       ap.add_option(&["--version"],
          Print(env!("CARGO_PKG_VERSION").to_string()), "Show version");
       // XXX ideally we should be able to use our own exit status here. Currently uses 2.
       ap.parse_args_or_exit();
   }
   return options;
}

fn compute_print_stats<R: io::Read>(options: &Options, filename: &String, reader: R) -> () {
   match FastaStats::new(options.minlen, reader) {
      StatsResult::StatsSome(stats) => {
         println!("{}\t{}", filename, stats);
      },
      StatsResult::StatsNone => {
         println!("{}\t0\t0\t-\t-\t-", filename);
      }
      StatsResult::StatsError(error) => {
         exit_with_error(EXIT_FASTA_PARSE_ERROR, &format!("{}", error))
      }
   }
}

fn main() {
   let options = parse_options();
   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");
   if options.fasta_files.len() == 0 {
      compute_print_stats(&options, &String::from("stdin"), io::stdin());
   }
   else {
      for filename in &options.fasta_files {
         match File::open(filename) {
            Ok(file) => {
               compute_print_stats(&options, filename, file);
            },
            Err(error) => {
               exit_with_error(EXIT_FILE_IO_ERROR, &format!("{}", error))
            }
         }
      }
   }
}

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

   #[test]
   fn test_zero_byte_input() {
      match FastaStats::new(0, "".as_bytes()) {
         StatsResult::StatsSome(_stats) => panic!("Zero byte input should produce no stats"),
         StatsResult::StatsError(_error) => panic!("Zero byte input should produce no stats, not an error"),
         StatsResult::StatsNone => ()
      }
   }

   #[test]
   fn test_single_newline_input() {
      match FastaStats::new(0, "\n".as_bytes()) {
         StatsResult::StatsSome(_stats) => panic!("Single newline input should produce an error"),
         StatsResult::StatsNone => panic!("Single newline input should produce an error, not no stats"),
         StatsResult::StatsError(_error) => ()
      }
   }
}
<commit_msg>Be explicit about exit status for command line parsing error<commit_after>extern crate bio;
extern crate argparse;
use std::io;
use std::io::Write;
use std::cmp;
use bio::io::fasta;
use std::fmt;
use std::fs::File;
use argparse::{ArgumentParser, StoreTrue, Store, Print, Collect};

const EXIT_FILE_IO_ERROR: i32 = 1;
const EXIT_COMMAND_LINE_ERROR: i32 = 2;
const EXIT_FASTA_PARSE_ERROR: i32 = 3;
static PROGRAM_NAME: &'static str = "biotool";

fn exit_with_error(status :i32, message: &String) -> () {
   writeln!(&mut std::io::stderr(), "{} ERROR: {}!", PROGRAM_NAME, message).unwrap();
   std::process::exit(status);
}

pub struct FastaStats {
   min_len: u64,
   average_len: u64,
   max_len: u64,
   total: u64,
   num_seqs: u64,
}

pub enum StatsResult {
   StatsNone,
   StatsSome(FastaStats),
   StatsError(io::Error)
}

impl FastaStats {
   pub fn new<R: io::Read>(minlen: u64, reader: R) -> StatsResult {
      let fasta_reader = fasta::Reader::new(reader);
      let mut num_seqs:u64 = 0;
      let mut total:u64 = 0;
      let mut max_len:u64 = 0;
      let mut min_len:u64 = 0;
      let mut this_len:u64;

      for next in fasta_reader.records() {
         match next {
            Ok(record) => {
               this_len = record.seq().len() as u64;
               if this_len >= minlen {
                  num_seqs += 1;
                  total += this_len;
                  if num_seqs == 1 {
                     max_len = this_len;
                     min_len = this_len;
                  }
                  else {
                     max_len = cmp::max(max_len, this_len);
                     min_len = cmp::min(min_len, this_len);
                  }
               }
            },
            Err(error) => return StatsResult::StatsError(error)
         }
      }
      if num_seqs > 0 {
         let average_len = ((total as f64) / (num_seqs as f64)).floor() as u64;
         StatsResult::StatsSome(FastaStats { min_len: min_len,
                           average_len: average_len,
                           max_len: max_len,
                           total: total,
                           num_seqs: num_seqs })
      }
      else {
         StatsResult::StatsNone
      }
   }
}

impl fmt::Display for FastaStats {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "{}\t{}\t{}\t{}\t{}", self.num_seqs, self.total,
         self.min_len, self.average_len, self.max_len)
   }
}

struct Options {
    verbose: bool,
    minlen: u64,
    fasta_files: Vec<String>,
}

fn parse_options() -> Options {
   let mut options = Options { verbose: false, minlen: 0, fasta_files: Vec::new() };
   {  let mut ap = ArgumentParser::new();
      ap.set_description("Print fasta stats");
      ap.refer(&mut options.verbose)
         .add_option(&["-v", "--verbose"], StoreTrue,
         "Print more stuff about what's happening");
      ap.refer(&mut options.minlen)
         .add_option(&["--minlen"], Store,
         "Minimum length sequence to include in stats");
      ap.refer(&mut options.fasta_files)
         .add_argument(&"fasta_files", Collect,
         "Input FASTA files");
      ap.add_option(&["--version"],
         Print(env!("CARGO_PKG_VERSION").to_string()), "Show version");
      match ap.parse_args() {
         Ok(()) => (),
         Err(0) => {
            // Help and version commands
            std::process::exit(0);
         },
         Err(_error_code) => {
            // Parse error
            std::process::exit(EXIT_COMMAND_LINE_ERROR);
         }
      }
   }
   return options
}

fn compute_print_stats<R: io::Read>(options: &Options, filename: &String, reader: R) -> () {
   match FastaStats::new(options.minlen, reader) {
      StatsResult::StatsSome(stats) => {
         println!("{}\t{}", filename, stats);
      },
      StatsResult::StatsNone => {
         println!("{}\t0\t0\t-\t-\t-", filename);
      }
      StatsResult::StatsError(error) => {
         exit_with_error(EXIT_FASTA_PARSE_ERROR, &format!("{}", error))
      }
   }
}

fn main() {
   let options = parse_options();
   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");
   if options.fasta_files.len() == 0 {
      compute_print_stats(&options, &String::from("stdin"), io::stdin());
   }
   else {
      for filename in &options.fasta_files {
         match File::open(filename) {
            Ok(file) => {
               compute_print_stats(&options, filename, file);
            },
            Err(error) => {
               exit_with_error(EXIT_FILE_IO_ERROR, &format!("{}", error))
            }
         }
      }
   }
}

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

   #[test]
   fn test_zero_byte_input() {
      match FastaStats::new(0, "".as_bytes()) {
         StatsResult::StatsSome(_stats) => panic!("Zero byte input should produce no stats"),
         StatsResult::StatsError(_error) => panic!("Zero byte input should produce no stats, not an error"),
         StatsResult::StatsNone => ()
      }
   }

   #[test]
   fn test_single_newline_input() {
      match FastaStats::new(0, "\n".as_bytes()) {
         StatsResult::StatsSome(_stats) => panic!("Single newline input should produce an error"),
         StatsResult::StatsNone => panic!("Single newline input should produce an error, not no stats"),
         StatsResult::StatsError(_error) => ()
      }
   }
}
<|endoftext|>


<commit_before>extern crate serde;

use serde::json::{self, Value};
use serde::json::error::*;
use std::io::{ErrorKind, Read, Write};

fn die<T: std::error::Error>(e: T) -> ! {
    writeln!(&mut std::io::stderr(), "error: {:?}", e).ok();
    std::process::exit(1)
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let mut reader = match args.len() {
        1 => Box::new(std::io::stdin()) as Box<Read>,
        2 => {
            match std::fs::File::open(&args[1]) {
                Ok(f) => Box::new(f) as Box<Read>,
                Err(e) => die(e)
            }
        },
        _ => die(std::io::Error::new(ErrorKind::InvalidInput, "too many args"))
    };
    let mut string = String::new();
    reader.read_to_string(&mut string).ok().unwrap();
    let data: Value = match json::from_str(&string) {
        Ok(v) => v,
        Err(Error::SyntaxError(ErrorCode::ExpectedSomeValue, _, _)) => {
            string = string.replace("infoCallback(", "").replace(");", "");
            match json::from_str(&string) {
                Ok(v) => v,
                Err(e) => die(e)
            }
        },
        Err(e) => die(e)
    };
    match json::ser::to_string_pretty(&data) {
        Ok(v) => print!("{}", v),
        Err(e) => die(e)
    };
}

<commit_msg>Fix from rustfmt<commit_after>extern crate serde;

use serde::json::{self, Value};
use serde::json::error::*;
use std::io::{ErrorKind, Read, Write};

fn die<T: std::error::Error>(e: T) -> ! {
    writeln!(&mut std::io::stderr(), "error: {:?}", e).ok();
    std::process::exit(1)
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let mut reader = match args.len() {
        1 => Box::new(std::io::stdin()) as Box<Read>,
        2 => {
            match std::fs::File::open(&args[1]) {
                Ok(f) => Box::new(f) as Box<Read>,
                Err(e) => die(e),
            }
        }
        _ => die(std::io::Error::new(ErrorKind::InvalidInput, "too many args")),
    };
    let mut string = String::new();
    reader.read_to_string(&mut string).ok().unwrap();
    let data: Value = match json::from_str(&string) {
        Ok(v) => v,
        Err(Error::SyntaxError(ErrorCode::ExpectedSomeValue, _, _)) => {
            string = string.replace("infoCallback(", "").replace(");", "");
            match json::from_str(&string) {
                Ok(v) => v,
                Err(e) => die(e),
            }
        }
        Err(e) => die(e),
    };
    match json::ser::to_string_pretty(&data) {
        Ok(v) => print!("{}", v),
        Err(e) => die(e),
    };
}
<|endoftext|>


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

use std::cmp::{min,max};

use serde_json::Value;
use serde_json::builder::{ArrayBuilder,ObjectBuilder};

use xi_rope::rope::{Rope, LinesMetric, RopeInfo};
use xi_rope::delta::{Delta};
use xi_rope::tree::Cursor;
use xi_rope::breaks::{Breaks, BreaksMetric, BreaksBaseMetric};
use xi_rope::interval::Interval;
use xi_rope::spans::{Spans, SpansBuilder};

use linewrap;

const SCROLL_SLOP: usize = 2;

pub struct View {
    pub sel_start: usize,
    pub sel_end: usize,
    first_line: usize,  // vertical scroll position
    height: usize,  // height of visible portion
    breaks: Option<Breaks>,
    fg_spans: Spans<u32>,
    cols: usize,
}

impl Default for View {
    fn default() -> View {
        View {
            sel_start: 0,
            sel_end: 0,
            first_line: 0,
            height: 10,
            breaks: None,
            fg_spans: Spans::default(),
            cols: 0,
        }
    }
}

impl View {
    pub fn new() -> View {
        View::default()
    }

    pub fn set_scroll(&mut self, first: usize, last: usize) {
        self.first_line = first;
        self.height = last - first;
    }

    pub fn scroll_height(&self) -> usize {
        self.height
    }

    pub fn sel_min(&self) -> usize {
        min(self.sel_start, self.sel_end)
    }

    pub fn sel_max(&self) -> usize {
        max(self.sel_start, self.sel_end)
    }

    pub fn scroll_to_cursor(&mut self, text: &Rope) {
        let (line, _) = self.offset_to_line_col(text, self.sel_end);
        if line < self.first_line {
            self.first_line = line;
        } else if self.first_line + self.height <= line {
            self.first_line = line - (self.height - 1);
        }
    }

    pub fn render_lines(&self, text: &Rope, first_line: usize, last_line: usize) -> Value {
        let mut builder = ArrayBuilder::new();
        let (cursor_line, cursor_col) = self.offset_to_line_col(text, self.sel_end);
        let sel_min_line = if self.sel_start == self.sel_end {
            cursor_line
        } else {
            self.line_of_offset(text, self.sel_min())
        };
        let sel_max_line = if self.sel_start == self.sel_end {
            cursor_line
        } else {
            self.line_of_offset(text, self.sel_max())
        };
        let first_line_offset = self.offset_of_line(text, first_line);
        let mut cursor = Cursor::new(text, first_line_offset);
        let mut breaks_cursor = self.breaks.as_ref().map(|breaks|
            Cursor::new(breaks, first_line_offset)
        );
        let mut line_num = first_line;
        loop {
            let mut line_builder = ArrayBuilder::new();
            let start_pos = cursor.pos();
            let pos = match breaks_cursor {
                Some(ref mut bc) => {
                    let pos = bc.next::<BreaksMetric>();
                    if let Some(pos) = pos {
                        cursor.set(pos);
                    }
                    pos
                }
                None => cursor.next::<LinesMetric>()
            };
            let mut is_last_line = false;
            let pos = match pos {
                Some(pos) => pos,
                None => {
                    if start_pos == text.len() {
                        break;
                    }
                    is_last_line = true;
                    text.len()
                }
            };
            let l_str = text.slice_to_string(start_pos, pos);
            let l = &l_str;
            // TODO: strip trailing line end
            let l_len = l.len();
            line_builder = line_builder.push(l);
            line_builder = self.render_spans(line_builder, start_pos, pos);
            if line_num >= sel_min_line && line_num <= sel_max_line && self.sel_start != self.sel_end {
                let sel_start_ix = if line_num == sel_min_line {
                    self.sel_min() - self.offset_of_line(text, line_num)
                } else {
                    0
                };
                let sel_end_ix = if line_num == sel_max_line {
                    self.sel_max() - self.offset_of_line(text, line_num)
                } else {
                    l_len
                };
                line_builder = line_builder.push_array(|builder|
                    builder.push("sel")
                        .push(sel_start_ix)
                        .push(sel_end_ix)
                );
            }
            if line_num == cursor_line {
                line_builder = line_builder.push_array(|builder|
                    builder.push("cursor")
                        .push(cursor_col)
                );
            }
            builder = builder.push(line_builder.unwrap());
            line_num += 1;
            if is_last_line || line_num == last_line {
                break;
            }
        }
        if line_num == cursor_line {
            builder = builder.push_array(|builder|
                builder.push("")
                    .push_array(|builder|
                        builder.push("cursor").push(0)));
        }
        builder.unwrap()
    }

    pub fn render_spans(&self, mut builder: ArrayBuilder, start: usize, end: usize) -> ArrayBuilder {
        let fg_spans = self.fg_spans.subseq(Interval::new_closed_open(start, end));
        for (iv, fg) in fg_spans.iter() {
            builder = builder.push_array(|builder|
                builder.push("fg")
                    .push(iv.start())
                    .push(iv.end())
                    .push(fg));
        }
        builder
    }

    pub fn render(&self, text: &Rope, scroll_to: Option<usize>) -> Value {
        let first_line = max(self.first_line, SCROLL_SLOP) - SCROLL_SLOP;
        let last_line = self.first_line + self.height + SCROLL_SLOP;
        let lines = self.render_lines(text, first_line, last_line);
        let height = self.offset_to_line_col(text, text.len()).0 + 1;
        let mut builder = ObjectBuilder::new()
            .insert("lines", lines)
            .insert("first_line", first_line)
            .insert("height", height);
        if let Some(scrollto) = scroll_to {
            let (line, col) = self.offset_to_line_col(text, scrollto);
            builder = builder.insert_array("scrollto", |builder|
                builder.push(line).push(col));
        }
        builder.unwrap()
    }

    // How should we count "column"? Valid choices include:
    // * Unicode codepoints
    // * grapheme clusters
    // * Unicode width (so CJK counts as 2)
    // * Actual measurement in text layout
    // * Code units in some encoding
    //
    // Of course, all these are identical for ASCII. For now we use UTF-8 code units
    // for simplicity.

    pub fn offset_to_line_col(&self, text: &Rope, offset: usize) -> (usize, usize) {
        let line = self.line_of_offset(text, offset);
        (line, offset - self.offset_of_line(text, line))
    }

    pub fn line_col_to_offset(&self, text: &Rope, line: usize, col: usize) -> usize {
        let mut offset = self.offset_of_line(text, line).saturating_add(col);
        if offset >= text.len() {
            offset = text.len();
            if self.line_of_offset(text, offset) <= line {
                return offset;
            }
        } else {
            // Snap to grapheme cluster boundary
            offset = text.prev_grapheme_offset(offset + 1).unwrap();
        }

        // clamp to end of line
        let next_line_offset = self.offset_of_line(text, line + 1);
        if offset >= next_line_offset {
            if let Some(prev) = text.prev_grapheme_offset(next_line_offset) {
                offset = prev;
            }
        }
        offset
    }

    // Move up or down by `line_delta` lines and return offset where the
    // cursor lands. The `col` argument should probably move into the View
    // struct.
    pub fn vertical_motion(&self, text: &Rope, line_delta: isize, col: usize) -> usize {
        // This code is quite careful to avoid integer overflow.
        // TODO: write tests to verify
        let line = self.line_of_offset(text, self.sel_end);
        if line_delta < 0 && (-line_delta as usize) > line {
            return 0;
        }
        let line = if line_delta < 0 {
            line - (-line_delta as usize)
        } else {
            line.saturating_add(line_delta as usize)
        };
        let n_lines = self.line_of_offset(text, text.len());
        if line > n_lines {
            return text.len();
        }
        self.line_col_to_offset(text, line, col)
    }

    // use own breaks if present, or text if not (no line wrapping)

    fn line_of_offset(&self, text: &Rope, offset: usize) -> usize {
        match self.breaks {
            Some(ref breaks) => {
                let line = breaks.convert_metrics::<BreaksBaseMetric, BreaksMetric>(offset);
                //print_err!("line_of_offset({}) = {}", offset, line);
                line
            }
            None => text.line_of_offset(offset)
        }
    }

    fn offset_of_line(&self, text: &Rope, offset: usize) -> usize {
        match self.breaks {
            Some(ref breaks) => {
                breaks.convert_metrics::<BreaksMetric, BreaksBaseMetric>(offset)
            }
            None => text.offset_of_line(offset)
        }
    }

    pub fn rewrap(&mut self, text: &Rope, cols: usize) {
        self.breaks = Some(linewrap::linewrap(text, cols));
        self.cols = cols;
    }

    pub fn before_edit(&mut self, _text: &Rope, _delta: &Delta<RopeInfo>) {

    }

    pub fn after_edit(&mut self, text: &Rope, delta: &Delta<RopeInfo>) {
        let cols = self.cols;
        if self.breaks.is_some() {
            if delta.len() == 1 {
                let item = delta.iter().next().unwrap();
                linewrap::rewrap(self.breaks.as_mut().unwrap(), text, item.interval, item.rope.len(), cols);
            } else {
                self.rewrap(text, cols);
            }
        }
    }

    pub fn reset_breaks(&mut self) {
        self.breaks = None;
    }

    pub fn set_test_fg_spans(&mut self) {
        let mut sb = SpansBuilder::new(15);
        sb.add_span(Interval::new_closed_open(5, 10), 0xffc00000);
        self.fg_spans = sb.build();
    }
}
<commit_msg>Include last line in rendered lines even if blank<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::{min,max};

use serde_json::Value;
use serde_json::builder::{ArrayBuilder,ObjectBuilder};

use xi_rope::rope::{Rope, LinesMetric, RopeInfo};
use xi_rope::delta::{Delta};
use xi_rope::tree::Cursor;
use xi_rope::breaks::{Breaks, BreaksMetric, BreaksBaseMetric};
use xi_rope::interval::Interval;
use xi_rope::spans::{Spans, SpansBuilder};

use linewrap;

const SCROLL_SLOP: usize = 2;

pub struct View {
    pub sel_start: usize,
    pub sel_end: usize,
    first_line: usize,  // vertical scroll position
    height: usize,  // height of visible portion
    breaks: Option<Breaks>,
    fg_spans: Spans<u32>,
    cols: usize,
}

impl Default for View {
    fn default() -> View {
        View {
            sel_start: 0,
            sel_end: 0,
            first_line: 0,
            height: 10,
            breaks: None,
            fg_spans: Spans::default(),
            cols: 0,
        }
    }
}

impl View {
    pub fn new() -> View {
        View::default()
    }

    pub fn set_scroll(&mut self, first: usize, last: usize) {
        self.first_line = first;
        self.height = last - first;
    }

    pub fn scroll_height(&self) -> usize {
        self.height
    }

    pub fn sel_min(&self) -> usize {
        min(self.sel_start, self.sel_end)
    }

    pub fn sel_max(&self) -> usize {
        max(self.sel_start, self.sel_end)
    }

    pub fn scroll_to_cursor(&mut self, text: &Rope) {
        let (line, _) = self.offset_to_line_col(text, self.sel_end);
        if line < self.first_line {
            self.first_line = line;
        } else if self.first_line + self.height <= line {
            self.first_line = line - (self.height - 1);
        }
    }

    pub fn render_lines(&self, text: &Rope, first_line: usize, last_line: usize) -> Value {
        let mut builder = ArrayBuilder::new();
        let (cursor_line, cursor_col) = self.offset_to_line_col(text, self.sel_end);
        let sel_min_line = if self.sel_start == self.sel_end {
            cursor_line
        } else {
            self.line_of_offset(text, self.sel_min())
        };
        let sel_max_line = if self.sel_start == self.sel_end {
            cursor_line
        } else {
            self.line_of_offset(text, self.sel_max())
        };
        let first_line_offset = self.offset_of_line(text, first_line);
        let mut cursor = Cursor::new(text, first_line_offset);
        let mut breaks_cursor = self.breaks.as_ref().map(|breaks|
            Cursor::new(breaks, first_line_offset)
        );
        let mut line_num = first_line;
        loop {
            let mut line_builder = ArrayBuilder::new();
            let start_pos = cursor.pos();
            let pos = match breaks_cursor {
                Some(ref mut bc) => {
                    let pos = bc.next::<BreaksMetric>();
                    if let Some(pos) = pos {
                        cursor.set(pos);
                    }
                    pos
                }
                None => cursor.next::<LinesMetric>()
            };
            let mut is_last_line = false;
            let pos = match pos {
                Some(pos) => pos,
                None => {
                    is_last_line = true;
                    text.len()
                }
            };
            let l_str = text.slice_to_string(start_pos, pos);
            let l = &l_str;
            // TODO: strip trailing line end
            let l_len = l.len();
            line_builder = line_builder.push(l);
            line_builder = self.render_spans(line_builder, start_pos, pos);
            if line_num >= sel_min_line && line_num <= sel_max_line && self.sel_start != self.sel_end {
                let sel_start_ix = if line_num == sel_min_line {
                    self.sel_min() - self.offset_of_line(text, line_num)
                } else {
                    0
                };
                let sel_end_ix = if line_num == sel_max_line {
                    self.sel_max() - self.offset_of_line(text, line_num)
                } else {
                    l_len
                };
                line_builder = line_builder.push_array(|builder|
                    builder.push("sel")
                        .push(sel_start_ix)
                        .push(sel_end_ix)
                );
            }
            if line_num == cursor_line {
                line_builder = line_builder.push_array(|builder|
                    builder.push("cursor")
                        .push(cursor_col)
                );
            }            builder = builder.push(line_builder.unwrap());
            line_num += 1;
            if is_last_line || line_num == last_line {
                break;
            }
        }
        builder.unwrap()
    }

    pub fn render_spans(&self, mut builder: ArrayBuilder, start: usize, end: usize) -> ArrayBuilder {
        let fg_spans = self.fg_spans.subseq(Interval::new_closed_open(start, end));
        for (iv, fg) in fg_spans.iter() {
            builder = builder.push_array(|builder|
                builder.push("fg")
                    .push(iv.start())
                    .push(iv.end())
                    .push(fg));
        }
        builder
    }

    pub fn render(&self, text: &Rope, scroll_to: Option<usize>) -> Value {
        let first_line = max(self.first_line, SCROLL_SLOP) - SCROLL_SLOP;
        let last_line = self.first_line + self.height + SCROLL_SLOP;
        let lines = self.render_lines(text, first_line, last_line);
        let height = self.offset_to_line_col(text, text.len()).0 + 1;
        let mut builder = ObjectBuilder::new()
            .insert("lines", lines)
            .insert("first_line", first_line)
            .insert("height", height);
        if let Some(scrollto) = scroll_to {
            let (line, col) = self.offset_to_line_col(text, scrollto);
            builder = builder.insert_array("scrollto", |builder|
                builder.push(line).push(col));
        }
        builder.unwrap()
    }

    // How should we count "column"? Valid choices include:
    // * Unicode codepoints
    // * grapheme clusters
    // * Unicode width (so CJK counts as 2)
    // * Actual measurement in text layout
    // * Code units in some encoding
    //
    // Of course, all these are identical for ASCII. For now we use UTF-8 code units
    // for simplicity.

    pub fn offset_to_line_col(&self, text: &Rope, offset: usize) -> (usize, usize) {
        let line = self.line_of_offset(text, offset);
        (line, offset - self.offset_of_line(text, line))
    }

    pub fn line_col_to_offset(&self, text: &Rope, line: usize, col: usize) -> usize {
        let mut offset = self.offset_of_line(text, line).saturating_add(col);
        if offset >= text.len() {
            offset = text.len();
            if self.line_of_offset(text, offset) <= line {
                return offset;
            }
        } else {
            // Snap to grapheme cluster boundary
            offset = text.prev_grapheme_offset(offset + 1).unwrap();
        }

        // clamp to end of line
        let next_line_offset = self.offset_of_line(text, line + 1);
        if offset >= next_line_offset {
            if let Some(prev) = text.prev_grapheme_offset(next_line_offset) {
                offset = prev;
            }
        }
        offset
    }

    // Move up or down by `line_delta` lines and return offset where the
    // cursor lands. The `col` argument should probably move into the View
    // struct.
    pub fn vertical_motion(&self, text: &Rope, line_delta: isize, col: usize) -> usize {
        // This code is quite careful to avoid integer overflow.
        // TODO: write tests to verify
        let line = self.line_of_offset(text, self.sel_end);
        if line_delta < 0 && (-line_delta as usize) > line {
            return 0;
        }
        let line = if line_delta < 0 {
            line - (-line_delta as usize)
        } else {
            line.saturating_add(line_delta as usize)
        };
        let n_lines = self.line_of_offset(text, text.len());
        if line > n_lines {
            return text.len();
        }
        self.line_col_to_offset(text, line, col)
    }

    // use own breaks if present, or text if not (no line wrapping)

    fn line_of_offset(&self, text: &Rope, offset: usize) -> usize {
        match self.breaks {
            Some(ref breaks) => {
                let line = breaks.convert_metrics::<BreaksBaseMetric, BreaksMetric>(offset);
                //print_err!("line_of_offset({}) = {}", offset, line);
                line
            }
            None => text.line_of_offset(offset)
        }
    }

    fn offset_of_line(&self, text: &Rope, offset: usize) -> usize {
        match self.breaks {
            Some(ref breaks) => {
                breaks.convert_metrics::<BreaksMetric, BreaksBaseMetric>(offset)
            }
            None => text.offset_of_line(offset)
        }
    }

    pub fn rewrap(&mut self, text: &Rope, cols: usize) {
        self.breaks = Some(linewrap::linewrap(text, cols));
        self.cols = cols;
    }

    pub fn before_edit(&mut self, _text: &Rope, _delta: &Delta<RopeInfo>) {

    }

    pub fn after_edit(&mut self, text: &Rope, delta: &Delta<RopeInfo>) {
        let cols = self.cols;
        if self.breaks.is_some() {
            if delta.len() == 1 {
                let item = delta.iter().next().unwrap();
                linewrap::rewrap(self.breaks.as_mut().unwrap(), text, item.interval, item.rope.len(), cols);
            } else {
                self.rewrap(text, cols);
            }
        }
    }

    pub fn reset_breaks(&mut self) {
        self.breaks = None;
    }

    pub fn set_test_fg_spans(&mut self) {
        let mut sb = SpansBuilder::new(15);
        sb.add_span(Interval::new_closed_open(5, 10), 0xffc00000);
        self.fg_spans = sb.build();
    }
}
<|endoftext|>


<commit_before><commit_msg>Simpler expression for making an empty slice<commit_after><|endoftext|>


<commit_before>use std::str::FromStr;
use board::{Edge, Hint};
use geom::{Point, Size, LEFT, UP};
use util;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum Pattern {
    Hint(Hint, Point),
    Edge(Edge, Point, Point)
}

impl Pattern {
    fn normalized(self) -> Pattern {
        match self {
            Pattern::Edge(edge, p0, p1) if p1 < p0 => {
                Pattern::Edge(edge, p1, p0)
            }
            x => x
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Theorem {
    size: Size,
    matcher: Vec<Pattern>,
    result: Vec<Pattern>
}

impl FromStr for Theorem {
    fn from_str(s: &str) -> Option<Theorem> {
        let mut matcher_lines = vec![];
        let mut result_lines = vec![];

        let mut lines = s.lines()
            .map(|l| l.trim_matches('\n'))
            .filter(|s| !s.is_empty());

        for line in lines {
            let mut it = line.splitn(2, '!');
            if let Some(l) = it.next() {
                matcher_lines.push(l.chars().collect());
            } else {
                return None
            }

            if let Some(l) = it.next() {
                result_lines.push(l.chars().collect());
            } else {
                return None
            }
        }

        let (m_size, m_pat) = match parse_lines(&matcher_lines[]) {
            Some(x) => x, None => return None
        };
        let (r_size, mut r_pat) = match parse_lines(&result_lines[]) {
            Some(x) => x, None => return None
        };

        if m_size != r_size { return None }

        let mut idx = 0;
        for &p in m_pat.iter() {
            match r_pat[idx ..].iter().position(|&x| x == p) {
                Some(i) => {
                    idx += i;
                    let _ = r_pat.remove(idx);
                }
                None => { return None }
            }
        }

        return Some(Theorem { size: m_size, matcher: m_pat, result: r_pat });

        fn parse_lines(lines: &[Vec<char>]) -> Option<(Size, Vec<Pattern>)> {
            use util::{VEdges, HEdges, Cells};

            let (rows, cols) = match util::find_lattice(lines) {
                Some(x) => x, None => return None
            };

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);

            let mut pat = vec![];

            for (p, s) in VEdges::new(lines, &rows[], &cols[]) {
                if s.is_empty() {
                    continue
                }
                if s.chars().all(|c| c == 'x') {
                    pat.push(Pattern::Edge(Edge::Cross, p + LEFT, p));
                    continue
                }
                if s.chars().all(|c| c == '|') {
                    pat.push(Pattern::Edge(Edge::Line, p + LEFT, p));
                    continue
                }
            }

            for (p, s) in HEdges::new(lines, &rows[], &cols[]) {
                if s.is_empty() {
                    continue
                }
                if s.chars().all(|c| c == 'x') {
                    pat.push(Pattern::Edge(Edge::Cross, p + UP, p));
                    continue
                }
                if s.chars().all(|c| c == '-') {
                    pat.push(Pattern::Edge(Edge::Line, p + UP, p));
                    continue
                }
            }

            for (p, s) in Cells::new(lines, &rows[], &cols[]) {
                match s.trim_matches(' ') {
                    "" => {},
                    "0" => { pat.push(Pattern::Hint(Some(0), p)); }
                    "1" => { pat.push(Pattern::Hint(Some(1), p)); }
                    "2" => { pat.push(Pattern::Hint(Some(2), p)); }
                    "3" => { pat.push(Pattern::Hint(Some(3), p)); }
                    _ => {}
                }
            }

            let mut pat = pat.map_in_place(|p| p.normalized());
            pat.sort();
            Some((size, pat))
        }
    }
}

#[cfg(test)]
mod tests {
    use geom::{Point, Size};
    use board::Edge;
    use super::{Pattern, Theorem};

    #[test]
    fn parse() {
        fn check(size: Size, matcher: Vec<Pattern>, result: Vec<Pattern>,
                 input: &str)
        {
            let mut matcher = matcher.map_in_place(|p| p.normalized());
            let mut result = result.map_in_place(|p| p.normalized());
            matcher.sort();
            result.sort();
            assert_eq!(Some(Theorem { size: size, matcher: matcher, result: result }),
                       input.parse::<Theorem>())
        }

        check(Size(1, 1),
              vec![Pattern::Hint(Some(0), Point(0, 0))],
              vec![Pattern::Edge(Edge::Cross, Point(0, 0), Point(0, -1)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(-1, 0)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(0, 1)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(1, 0))],"
+ + ! +x+
 0  ! x0x
+ + ! +x+
");
    }
}
<commit_msg>[WIP] solver: Complete `Theorem` parser<commit_after>use std::str::FromStr;
use board::{Edge, Hint};
use geom::{Point, Size, LEFT, UP};
use util;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum Pattern {
    Hint(Hint, Point),
    Edge(Edge, Point, Point)
}

impl Pattern {
    fn normalized(self) -> Pattern {
        match self {
            Pattern::Edge(edge, p0, p1) if p1 < p0 => {
                Pattern::Edge(edge, p1, p0)
            }
            x => x
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Theorem {
    size: Size,
    matcher: Vec<Pattern>,
    result: Vec<Pattern>
}

impl FromStr for Theorem {
    fn from_str(s: &str) -> Option<Theorem> {
        let mut matcher_lines = vec![];
        let mut result_lines = vec![];

        let mut lines = s.lines()
            .map(|l| l.trim_matches('\n'))
            .filter(|s| !s.is_empty());

        for line in lines {
            let mut it = line.splitn(2, '!');
            if let Some(l) = it.next() {
                matcher_lines.push(l.chars().collect());
            } else {
                return None
            }

            if let Some(l) = it.next() {
                result_lines.push(l.chars().collect());
            } else {
                return None
            }
        }

        let (m_size, m_pat) = match parse_lines(&matcher_lines[]) {
            Some(x) => x, None => return None
        };
        let (r_size, mut r_pat) = match parse_lines(&result_lines[]) {
            Some(x) => x, None => return None
        };

        if m_size != r_size { return None }

        let mut idx = 0;
        for &p in m_pat.iter() {
            match r_pat[idx ..].iter().position(|&x| x == p) {
                Some(i) => {
                    idx += i;
                    let _ = r_pat.remove(idx);
                }
                None => { return None }
            }
        }

        return Some(Theorem { size: m_size, matcher: m_pat, result: r_pat });

        fn parse_lines(lines: &[Vec<char>]) -> Option<(Size, Vec<Pattern>)> {
            use util::{VEdges, HEdges, Cells};

            let (rows, cols) = match util::find_lattice(lines) {
                Some(x) => x, None => return None
            };

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);

            let mut pat = vec![];

            for (p, s) in VEdges::new(lines, &rows[], &cols[]) {
                if s.is_empty() {
                    continue
                }
                if s.chars().all(|c| c == 'x') {
                    pat.push(Pattern::Edge(Edge::Cross, p + LEFT, p));
                    continue
                }
                if s.chars().all(|c| c == '|') {
                    pat.push(Pattern::Edge(Edge::Line, p + LEFT, p));
                    continue
                }
            }

            for (p, s) in HEdges::new(lines, &rows[], &cols[]) {
                if s.is_empty() {
                    continue
                }
                if s.chars().all(|c| c == 'x') {
                    pat.push(Pattern::Edge(Edge::Cross, p + UP, p));
                    continue
                }
                if s.chars().all(|c| c == '-') {
                    pat.push(Pattern::Edge(Edge::Line, p + UP, p));
                    continue
                }
            }

            let mut pairs: Vec<(char, Vec<Point>, Vec<Point>)> = vec![];

            for (p, s) in Cells::new(lines, &rows[], &cols[]) {
                for c in s.trim_matches(' ').chars() {
                    match c {
                        '0' => { pat.push(Pattern::Hint(Some(0), p)); }
                        '1' => { pat.push(Pattern::Hint(Some(1), p)); }
                        '2' => { pat.push(Pattern::Hint(Some(2), p)); }
                        '3' => { pat.push(Pattern::Hint(Some(3), p)); }
                        _ if c.is_alphabetic() => {
                            let key = c.to_lowercase();
                            match pairs.iter().position(|&(k, _, _)| k == key) {
                                Some(idx) => {
                                    if c.is_lowercase() {
                                        pairs[idx].1.push(p);
                                    } else {
                                        pairs[idx].2.push(p);
                                    }
                                }
                                None => {
                                    let (lower, upper) = if c.is_lowercase() {
                                        (vec![p], vec![])
                                    } else {
                                        (vec![], vec![])
                                    };
                                    pairs.push((key, lower, upper));
                                }
                            }
                        }
                        _ => {}
                    }
                }
            }

            for &(_, ref ps0, ref ps1) in pairs.iter() {
                if !ps0.is_empty() && !ps1.is_empty() {
                    pat.push(Pattern::Edge(Edge::Line, ps0[0], ps1[0]));
                }

                if ps0.len() > 0 {
                    for &p in ps0[1 ..].iter() {
                        pat.push(Pattern::Edge(Edge::Cross, ps0[0], p));
                    }
                }
                if ps1.len() > 0 {
                    for &p in ps1[1 ..].iter() {
                        pat.push(Pattern::Edge(Edge::Cross, ps1[0], p));
                    }
                }
            }

            let mut pat = pat.map_in_place(|p| p.normalized());
            pat.sort();
            Some((size, pat))
        }
    }
}

#[cfg(test)]
mod tests {
    use geom::{Point, Size};
    use board::Edge;
    use super::{Pattern, Theorem};

    #[test]
    fn parse() {
        fn check(size: Size, matcher: Vec<Pattern>, result: Vec<Pattern>,
                 input: &str)
        {
            let mut matcher = matcher.map_in_place(|p| p.normalized());
            let mut result = result.map_in_place(|p| p.normalized());
            matcher.sort();
            result.sort();
            assert_eq!(Some(Theorem { size: size, matcher: matcher, result: result }),
                       input.parse::<Theorem>())
        }

        check(Size(1, 1),
              vec![Pattern::Hint(Some(0), Point(0, 0))],
              vec![Pattern::Edge(Edge::Cross, Point(0, 0), Point(0, -1)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(0, 1)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(-1, 0)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(1, 0))],"
+ + ! +x+
 0  ! x0x
+ + ! +x+
");
        check(Size(3, 3),
              vec![Pattern::Hint(Some(0), Point(1, 0)),
                   Pattern::Hint(Some(3), Point(1, 1))],
              vec![Pattern::Edge(Edge::Cross, Point(1, 0), Point(1, -1)),
                   Pattern::Edge(Edge::Cross, Point(1, 0), Point(1, 1)),
                   Pattern::Edge(Edge::Cross, Point(1, 0), Point(0, 0)),
                   Pattern::Edge(Edge::Cross, Point(1, 0), Point(2, 0)),
                   Pattern::Edge(Edge::Cross, Point(0, 1), Point(0, 2)),
                   Pattern::Edge(Edge::Cross, Point(1, 2), Point(0, 2)),
                   Pattern::Edge(Edge::Cross, Point(1, 2), Point(2, 2)),
                   Pattern::Edge(Edge::Cross, Point(2, 1), Point(2, 2)),
                   Pattern::Edge(Edge::Line, Point(0, 0), Point(0, 1)),
                   Pattern::Edge(Edge::Line, Point(0, 1), Point(1, 1)),
                   Pattern::Edge(Edge::Line, Point(1, 1), Point(1, 2)),
                   Pattern::Edge(Edge::Line, Point(1, 1), Point(2, 1)),
                   Pattern::Edge(Edge::Line, Point(2, 0), Point(2, 1))], "
+ + + + ! + + + +
        !   | x
+ + + + ! +x+-+x+
 0 3    ! x0x3|
+ + + + ! +x+-+x+
        !   | x
+ + + + ! + + + +
");
        check(Size(2, 2),
              vec![Pattern::Hint(Some(1), Point(1, 1)),
                   Pattern::Edge(Edge::Line, Point(1, 0), Point(0, 1))],
              vec![Pattern::Edge(Edge::Cross, Point(1, 1), Point(1, 2)),
                   Pattern::Edge(Edge::Cross, Point(1, 1), Point(2, 1))], "
+ + + ! + + +
   a  !    a
+ + + ! + + +
 A 1  !  A 1x
+ + + ! + +x+
");
        check(Size(3, 3),
              vec![Pattern::Hint(Some(3), Point(1, 1)),
                   Pattern::Edge(Edge::Cross, Point(1, 0), Point(0, 1))],
              vec![Pattern::Edge(Edge::Cross, Point(0, 0), Point(0, 1)),
                   Pattern::Edge(Edge::Cross, Point(0, 0), Point(1, 0)),
                   Pattern::Edge(Edge::Line, Point(0, 1), Point(1, 1)),
                   Pattern::Edge(Edge::Line, Point(1, 0), Point(1, 1)),
                   Pattern::Edge(Edge::Line, Point(1, 2), Point(2, 1))], "
+ + + + ! + + + +
   a    !   xa
+ + + + ! +x+-+ +
 a 3    !  a|3 b
+ + + + ! + + + +
        !    B
+ + + + ! + + + +
");
    }
}
<|endoftext|>