<commit_before><commit_msg>Start port of relevant libcollectiontest tests<commit_after>extern crate pattern_api_v2 as pattern;

use pattern::Pattern;
use pattern::{Searcher, ReverseSearcher};
use pattern::SearchCursors;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum SearchResult {
    Match(usize, usize),
    Reject(usize, usize),
}

impl SearchResult {
    fn begin(&self) -> usize {
        match *self {
            Match(a, _) | Reject(a, _) => a,
        }
    }
    fn end(&self) -> usize {
        match *self {
            Match(_, b) | Reject(_, b) => b,
        }
    }
}

use SearchResult::{Match, Reject};

macro_rules! searcher_test {
    ($name:ident, $p:expr, $h:expr, double, is exact [$($e:expr,)*]) => {
        #[allow(unused_imports)]
        mod $name {
            use SearchResult::{Match, Reject};
            use super::{cmp_search_to_vec};

            #[test]
            fn fwd_exact() {
                cmp_search_to_vec(false, || $p, $h, Some(vec![$($e),*]));
            }
            #[test]
            fn bwd_exact() {
                cmp_search_to_vec(true, || $p, $h, Some(vec![$($e),*]));
            }
        }
    };
    ($name:ident, $p:expr, $h:expr, double, is valid) => {
        #[allow(unused_imports)]
        mod $name {
            use SearchResult::{Match, Reject};
            use super::{cmp_search_to_vec, compare};

            #[test]
            fn fwd_and_bwd_valid() {
                let left = &cmp_search_to_vec(false, || $p, $h, None);
                let right = &cmp_search_to_vec(true, || $p, $h, None);
                compare(left, right, $h);
            }
        }
    };
    ($name:ident, $p:expr, $h:expr, reverse, is exact [$($e:expr,)*], [$($f:expr,)*]) => {
        #[allow(unused_imports)]
        mod $name {
            use SearchResult::{Match, Reject};
            use super::{cmp_search_to_vec};

            #[test]
            fn fwd_exact() {
                cmp_search_to_vec(false, || $p, $h, Some(vec![$($e),*]));
            }
            #[test]
            fn bwd_exact() {
                cmp_search_to_vec(true, || $p, $h, Some(vec![$($f),*]));
            }
        }
    };
    ($name:ident, $p:expr, $h:expr, reverse, is valid) => {
        #[allow(unused_imports)]
        mod $name {
            use SearchResult::{Match, Reject};
            use super::{cmp_search_to_vec, compare};

            #[test]
            fn fwd_and_bwd_valid() {
                let left = &cmp_search_to_vec(false, || $p, $h, None);
                let right = &cmp_search_to_vec(true, || $p, $h, None);
            }
        }
    };
}

fn cmp_search_to_vec<'a, P, F>(rev: bool,
                               pat: F,
                               haystack: &'a str,
                               right: Option<Vec<SearchResult>>) -> Vec<SearchResult>
where P: Pattern<&'a str>,
      P::Searcher: ReverseSearcher<&'a str>,
      F: Fn() -> P,
{
    let mut matches = {
        let mut searcher = pat().into_searcher(haystack);
        let mut v = vec![];
        loop {
            match if !rev {searcher.next_match()} else {searcher.next_match_back()} {
                Some((a, b)) => v.push((a, b)),
                None => break,
            }
        }
        if rev {
            v.reverse();
        }
        v.into_iter().map(|(a, b)| {
            let haystack = haystack.into_haystack();
            (
                <&'a str>::offset_from_front(haystack, a),
                <&'a str>::offset_from_front(haystack, b),
            )
        })
    };

    let mut rejects = {
        let mut searcher = pat().into_searcher(haystack);
        let mut v = vec![];
        loop {
            match if !rev {searcher.next_reject()} else {searcher.next_reject_back()} {
                Some((a, b)) => v.push((a, b)),
                None => break,
            }
        }
        if rev {
            v.reverse();
        }
        v.into_iter().map(|(a, b)| {
            let haystack = haystack.into_haystack();
            (
                <&'a str>::offset_from_front(haystack, a),
                <&'a str>::offset_from_front(haystack, b),
            )
        })
    };

    let mut v = vec![];

    // Merge the two streams of results
    {
        let mut cur_match = matches.next();
        let mut cur_reject = rejects.next();

        loop {
            if cur_match.is_none() && cur_reject.is_none() {
                break;
            } else if cur_match.is_some() && cur_reject.is_some() {
                let m = cur_match.unwrap();
                let r = cur_reject.unwrap();

                if m.0 <= r.0 {
                    v.push(Match(m.0, m.1));
                    cur_match = matches.next();
                } else {
                    v.push(Reject(r.0, r.1));
                    cur_reject = rejects.next();
                }
            } else if cur_match.is_some() {
                let m = cur_match.unwrap();
                v.push(Match(m.0, m.1));
                cur_match = matches.next();
            } else if cur_reject.is_some() {
                let r = cur_reject.unwrap();
                v.push(Reject(r.0, r.1));
                cur_reject = rejects.next();
            }
        }
    }

    println!("");

    // Validate and emit diagnostics

    if is_malformed(&v, haystack) {
        panic!("searcher impl outputted invalid search results");
    }

    if let Some(right) = right {
        compare(&v, &right, haystack);
    }

    v
}

fn is_malformed(v: &[SearchResult], haystack: &str) -> bool {
    let mut found = false;
    for (i, pair) in v.windows(2).enumerate() {
        if pair[0].end() < pair[1].begin() {
            println!("Gap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
        if pair[0].end() > pair[1].begin() {
            println!("Overlap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
    }

    for (i, &e) in v.iter().enumerate() {
        if let Reject(a, b) = e {
            if a == b {
                println!("Zero-length Reject detected at end of {:?}", &v[..i+1]);
                found = true;
            }
        }
    }

    if v.len() > 0 {
        if v[0].begin() != 0 {
            println!("First interval did not start at begin of haystack: [{:?}, ...]", &v[0]);
            found = true;
        }

        if v[v.len() - 1].end() != haystack.len() {
            println!("Last interval did not end at end of haystack: [..., {:?}]", &v[v.len() - 1]);
            found = true;
        }
    }

    found
}

fn compare(left: &[SearchResult], right: &[SearchResult], haystack: &str) {
    if is_malformed(&right, haystack) {
        panic!("should-be search result test input is malformed, check test code for correctness");
    }

    assert!(left == right, "\n  searcher:  {:?}\n  should-be: {:?}\n", left, right);
}

searcher_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", double, is exact [
    Reject(0, 1),
    Match (1, 3),
    Reject(3, 4),
    Match (4, 6),
    Reject(6, 7),
]);
searcher_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", double, is exact [
    Reject(0, 1),
    Match (1, 3),
    Reject(3, 4),
    Match (4, 6),
    Match (6, 8),
    Reject(8, 9),
]);
searcher_test!(str_searcher_ascii_haystack_ambiguity, "aa", "aaa", reverse, is exact [
    Match (0, 2),
    Reject(2, 3),
], [
    Reject(0, 1),
    Match (1, 3),
]);
searcher_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", double, is exact [
    Match (0, 0),
    Reject(0, 1),
    Match (1, 1),
    Reject(1, 2),
    Match (2, 2),
    Reject(2, 3),
    Match (3, 3),
    Reject(3, 4),
    Match (4, 4),
    Reject(4, 5),
    Match (5, 5),
    Reject(5, 6),
    Match (6, 6),
    Reject(6, 7),
    Match (7, 7),
]);
searcher_test!(str_searcher_mulibyte_haystack, " ", "├──", double, is exact [
    Reject(0, 3),
    Reject(3, 6),
    Reject(6, 9),
]);
searcher_test!(str_searcher_empty_needle_mulibyte_haystack, "", "├──", double, is exact [
    Match (0, 0),
    Reject(0, 3),
    Match (3, 3),
    Reject(3, 6),
    Match (6, 6),
    Reject(6, 9),
    Match (9, 9),
]);
searcher_test!(str_searcher_empty_needle_empty_haystack, "", "", double, is exact [
    Match(0, 0),
]);
searcher_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", double, is exact [
]);
searcher_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", double, is exact [
    Reject(0, 1),
    Match (1, 2),
    Match (2, 3),
    Reject(3, 4),
    Match (4, 5),
    Match (5, 6),
    Reject(6, 7),
]);
searcher_test!(char_searcher_mulibyte_haystack, ' ', "├──", double, is valid /* [
    Reject(0, 3),
    Reject(3, 6),
    Reject(6, 9),
]*/);
searcher_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", double, is exact [
    Reject(0, 1),
    Reject(1, 2),
    Reject(2, 3),
]);

<|endoftext|>


<commit_before><commit_msg>[test] add missing calc3 file.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// 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 oak::oak;
use self::Expression::*;
use self::BinOp::*;
use grammars::calc2;

pub type PExpr = Box<Expression>;

#[derive(Debug)]
pub enum Expression {
  Variable(String),
  Number(u32),
  BinaryExpr(BinOp, PExpr, PExpr),
  LetIn(String, PExpr, PExpr)
}

#[derive(Debug)]
pub enum BinOp {
  Add, Sub, Mul, Div, Exp
}

oak! {
  // #![debug_api]
  // #![show_api]

  // Optional stream declaration.
  type Stream<'a> = StrStream<'a>;

  program = spacing expression

  expression
    = term (term_op term)* > fold_left

  term
    = exponent (factor_op exponent)* > fold_left

  exponent
    = (factor exponent_op)* factor > fold_right

  factor: Box<Expression>
    = calc2::number > box Number
    / calc2::identifier > box Variable
    / let_expr > box LetIn
    / lparen expression rparen

  let_expr = let_kw let_binding in_kw expression
  let_binding = (calc2::identifier:String) bind_op expression

  term_op: BinOp
    = add_op > Add
    / sub_op > Sub

  factor_op: BinOp
    = mul_op > Mul
    / div_op > Div

  exponent_op: BinOp = exp_op > Exp

  spacing = [" \n\r\t"]*:(^)

  kw_tail = !calc2::ident_char spacing

  keyword = let_kw / in_kw
  let_kw = "let" kw_tail
  in_kw = "in" kw_tail

  bind_op = "=" spacing
  add_op = "+" spacing
  sub_op = "-" spacing
  mul_op = "*" spacing
  div_op = "/" spacing
  exp_op = "^" spacing
  lparen = "(" spacing
  rparen = ")" spacing

  fn fold_left(head: PExpr, rest: Vec<(BinOp, PExpr)>) -> PExpr {
    rest.into_iter().fold(head,
      |accu, (op, expr)| Box::new(BinaryExpr(op, accu, expr)))
  }

  fn fold_right(front: Vec<(PExpr, BinOp)>, last: PExpr) -> PExpr {
    front.into_iter().rev().fold(last,
      |accu, (expr, op)| Box::new(BinaryExpr(op, expr, accu)))
  }
}
<|endoftext|>


<commit_before><commit_msg>Fix Statement Parser Bugs<commit_after><|endoftext|>


<commit_before>import driver::session;
import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import syntax::attr;
import syntax::codemap::span;
import std::map::{map,hashmap,int_hash,hash_from_strs};
import std::smallintmap::{map,smallintmap};
import io::writer_util;
import syntax::print::pprust::expr_to_str;
export lint, ctypes, unused_imports;
export level, ignore, warn, error;
export lookup_lint, lint_dict, get_lint_dict;
export get_warning_level, get_warning_settings_level;
export check_crate, build_settings_crate, mk_warning_settings;
export warning_settings;

#[doc="

A 'lint' check is a kind of miscellaneous constraint that a user _might_ want
to enforce, but might reasonably want to permit as well, on a module-by-module
basis. They contrast with static constraints enforced by other phases of the
compiler, which are generally required to hold in order to compile the program
at all.

We also build up a table containing information about lint settings, in order
to allow other passes to take advantage of the warning attribute
infrastructure. To save space, the table is keyed by the id of /items/, not of
every expression. When an item has the default settings, the entry will be
omitted. If we start allowing warn attributes on expressions, we will start
having entries for expressions that do not share their enclosing items
settings.

This module then, exports two passes: one that populates the warning settings
table in the session and is run early in the compile process, and one that
does a variety of lint checks, and is run late in the compile process.

"]

enum lint {
    ctypes,
    unused_imports,
    while_true,
    path_statement,
    old_vecs,
    unrecognized_warning,
    non_implicitly_copyable_typarams,
    vecs_not_implicitly_copyable,
    implicit_copies,
}

// This is pretty unfortunate. We really want some sort of "deriving Enum"
// type of thing.
fn int_to_lint(i: int) -> lint {
    alt check i {
      0 { ctypes }
      1 { unused_imports }
      2 { while_true }
      3 { path_statement }
      4 { old_vecs }
      5 { unrecognized_warning }
      6 { non_implicitly_copyable_typarams }
      7 { vecs_not_implicitly_copyable }
      8 { implicit_copies }
    }
}

enum level {
    ignore, warn, error
}

type lint_spec = @{lint: lint,
                   desc: str,
                   default: level};

type lint_dict = hashmap<str,lint_spec>;

/*
  Pass names should not contain a '-', as the compiler normalizes
  '-' to '_' in command-line flags
 */
fn get_lint_dict() -> lint_dict {
    let v = [
        ("ctypes",
         @{lint: ctypes,
           desc: "proper use of core::libc types in native modules",
           default: warn}),

        ("unused_imports",
         @{lint: unused_imports,
           desc: "imports that are never used",
           default: ignore}),

        ("while_true",
         @{lint: while_true,
           desc: "suggest using loop { } instead of while(true) { }",
           default: warn}),

        ("path_statement",
         @{lint: path_statement,
           desc: "path statements with no effect",
           default: warn}),

        ("old_vecs",
         @{lint: old_vecs,
           desc: "old (deprecated) vectors and strings",
           default: ignore}),

        ("unrecognized_warning",
         @{lint: unrecognized_warning,
           desc: "unrecognized warning attribute",
           default: warn}),

        ("non_implicitly_copyable_typarams",
         @{lint: non_implicitly_copyable_typarams,
           desc: "passing non implicitly copyable types as copy type params",
           default: warn}),

        ("vecs_not_implicitly_copyable",
         @{lint: vecs_not_implicitly_copyable,
           desc: "make vecs and strs not implicitly copyable\
                  ('err' is ignored; only checked at top level",
           default: warn}),

        ("implicit_copies",
         @{lint: implicit_copies,
           desc: "implicit copies of non implicitly copyable data",
           default: warn})

    ];
    hash_from_strs(v)
}

// This is a highly not-optimal set of data structure decisions.
type lint_modes = smallintmap<level>;
type lint_mode_map = hashmap<ast::node_id, lint_modes>;

// settings_map maps node ids of items with non-default warning settings
// to their settings; default_settings contains the settings for everything
// not in the map.
type warning_settings = {
    default_settings: lint_modes,
    settings_map: lint_mode_map
};

fn mk_warning_settings() -> warning_settings {
    {default_settings: std::smallintmap::mk(),
     settings_map: int_hash()}
}

fn get_warning_level(modes: lint_modes, lint: lint) -> level {
    alt modes.find(lint as uint) {
      some(c) { c }
      none { ignore }
    }
}

fn get_warning_settings_level(settings: warning_settings,
                              lint_mode: lint,
                              _expr_id: ast::node_id,
                              item_id: ast::node_id) -> level {
    alt settings.settings_map.find(item_id) {
      some(modes) { get_warning_level(modes, lint_mode) }
      none { get_warning_level(settings.default_settings, lint_mode) }
    }
}

// This is kind of unfortunate. It should be somewhere else, or we should use
// a persistent data structure...
fn clone_lint_modes(modes: lint_modes) -> lint_modes {
    @{v: copy modes.v}
}

type ctxt = {dict: lint_dict,
             curr: lint_modes,
             is_default: bool,
             sess: session};

impl methods for ctxt {
    fn get_level(lint: lint) -> level {
        get_warning_level(self.curr, lint)
    }

    fn set_level(lint: lint, level: level) {
        if level == ignore {
            self.curr.remove(lint as uint);
        } else {
            self.curr.insert(lint as uint, level);
        }
    }

    fn span_lint(level: level, span: span, msg: str) {
        self.sess.span_lint_level(level, span, msg);
    }

    #[doc="
          Merge the warnings specified by any `warn(...)` attributes into the
          current lint context, call the provided function, then reset the
          warnings in effect to their previous state.
    "]
    fn with_warn_attrs(attrs: [ast::attribute], f: fn(ctxt)) {

        let mut new_ctxt = self;

        let metas = attr::attr_metas(attr::find_attrs_by_name(attrs, "warn"));
        for metas.each {|meta|
            alt meta.node {
              ast::meta_list(_, metas) {
                for metas.each {|meta|
                    alt meta.node {
                      ast::meta_word(lintname) {
                        alt lookup_lint(self.dict, *lintname) {
                          (name, none) {
                            self.span_lint(
                                self.get_level(unrecognized_warning),
                                meta.span,
                                #fmt("unknown warning: '%s'", name));
                          }
                          (_, some((lint, new_level))) {
                            // we do multiple unneeded copies of the map
                            // if many attributes are set, but this shouldn't
                            // actually be a problem...
                            new_ctxt = {is_default: false,
                                        curr: clone_lint_modes(new_ctxt.curr)
                                        with new_ctxt};
                            new_ctxt.set_level(lint, new_level);
                          }
                        }
                      }
                      _ {
                        self.sess.span_err(
                            meta.span,
                            "malformed warning attribute");
                      }
                    }
                }
              }
              _ {
                self.sess.span_err(meta.span,
                                   "malformed warning attribute");
              }
            }
        }

        f(new_ctxt);
    }
}

fn lookup_lint(dict: lint_dict, s: str)
    -> (str, option<(lint, level)>) {
    let s = str::replace(s, "-", "_");
    let (name, level) = if s.starts_with("no_") {
        (s.substr(3u, s.len() - 3u), ignore)
    } else if s.starts_with("err_") {
        (s.substr(4u, s.len() - 4u), error)
    } else {
        (s, warn)
    };
    (name,
     alt dict.find(name) {
         none { none }
         some(spec) { some((spec.lint, level)) }
     })
}

fn build_settings_item(i: @ast::item, &&cx: ctxt, v: visit::vt<ctxt>) {
    cx.with_warn_attrs(i.attrs) {|cx|
        if !cx.is_default {
            cx.sess.warning_settings.settings_map.insert(i.id, cx.curr);
        }
        visit::visit_item(i, cx, v);
    }
}

fn build_settings_crate(sess: session::session, crate: @ast::crate) {

    let cx = {dict: get_lint_dict(),
              curr: std::smallintmap::mk(),
              is_default: true,
              sess: sess};

    // Install defaults.
    for cx.dict.each {|_k, spec| cx.set_level(spec.lint, spec.default); }

    // Install command-line options, overriding defaults.
    for sess.opts.lint_opts.each {|pair|
        let (lint,level) = pair;
        cx.set_level(lint, level);
    }

    cx.with_warn_attrs(crate.node.attrs) {|cx|
        // Copy out the default settings
        for cx.curr.each {|k, v|
            sess.warning_settings.default_settings.insert(k, v);
        }

        let cx = {is_default: true with cx};

        let visit = visit::mk_vt(@{
            visit_item: build_settings_item
            with *visit::default_visitor()
        });
        visit::visit_crate(*crate, cx, visit);
    }

    sess.abort_if_errors();
}

fn check_item(i: @ast::item, cx: ty::ctxt) {
    check_item_ctypes(cx, i);
    check_item_while_true(cx, i);
    check_item_path_statement(cx, i);
    check_item_old_vecs(cx, i);
}

// Take a visitor, and modify it so that it will not proceed past subitems.
// This is used to make the simple visitors used for the lint passes
// not traverse into subitems, since that is handled by the outer
// lint visitor.
fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
    visit::mk_vt(@{visit_item: {|_i, _e, _v| } with **v})
}

fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_expr: fn@(e: @ast::expr) {
           alt e.node {
             ast::expr_while(cond, _) {
                alt cond.node {
                    ast::expr_lit(@{node: ast::lit_bool(true),_}) {
                            cx.sess.span_lint(
                                while_true, e.id, it.id,
                                e.span,
                                "denote infinite loops with loop { ... }");
                    }
                    _ {}
                }
             }
             _ {}
          }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {

    fn check_native_fn(cx: ty::ctxt, fn_id: ast::node_id,
                       decl: ast::fn_decl) {
        let tys = vec::map(decl.inputs) {|a| a.ty };
        for vec::each(tys + [decl.output]) {|ty|
            alt ty.node {
              ast::ty_path(_, id) {
                alt cx.def_map.get(id) {
                  ast::def_prim_ty(ast::ty_int(ast::ty_i)) {
                    cx.sess.span_lint(
                        ctypes, id, fn_id,
                        ty.span,
                        "found rust type `int` in native module, while \
                         libc::c_int or libc::c_long should be used");
                  }
                  ast::def_prim_ty(ast::ty_uint(ast::ty_u)) {
                    cx.sess.span_lint(
                        ctypes, id, fn_id,
                        ty.span,
                        "found rust type `uint` in native module, while \
                         libc::c_uint or libc::c_ulong should be used");
                  }
                  _ { }
                }
              }
              _ { }
            }
        }
    }

    alt it.node {
      ast::item_native_mod(nmod) if attr::native_abi(it.attrs) !=
      either::right(ast::native_abi_rust_intrinsic) {
        for nmod.items.each {|ni|
            alt ni.node {
              ast::native_item_fn(decl, tps) {
                check_native_fn(cx, it.id, decl);
              }
            }
        }
      }
      _ {/* nothing to do */ }
    }
}

fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_stmt: fn@(s: @ast::stmt) {
            alt s.node {
              ast::stmt_semi(@{id: id,
                               node: ast::expr_path(@path),
                               span: _}, _) {
                cx.sess.span_lint(
                    path_statement, id, it.id,
                    s.span,
                    "path statement with no effect");
              }
              _ {}
            }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_old_vecs(cx: ty::ctxt, it: @ast::item) {
    let uses_vstore = int_hash();

    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{

        visit_expr:fn@(e: @ast::expr) {
            alt e.node {
              ast::expr_vec(_, _) |
              ast::expr_lit(@{node: ast::lit_str(_), span:_})
              if ! uses_vstore.contains_key(e.id) {
                cx.sess.span_lint(
                    old_vecs, e.id, it.id,
                    e.span, "deprecated vec/str expr");
              }
              ast::expr_vstore(@inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        },

        visit_ty: fn@(t: @ast::ty) {
            alt t.node {
              ast::ty_vec(_)
              if ! uses_vstore.contains_key(t.id) {
                cx.sess.span_lint(
                    old_vecs, t.id, it.id,
                    t.span, "deprecated vec type");
              }

              ast::ty_path(@{span: _, global: _, idents: ids,
                             rp: none, types: _}, _)
              if ids == [@"str"] && (! uses_vstore.contains_key(t.id)) {
                cx.sess.span_lint(
                    old_vecs, t.id, it.id,
                    t.span, "deprecated str type");
              }

              ast::ty_vstore(inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        }

        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {

    let v = visit::mk_simple_visitor(@{
        visit_item: fn@(it: @ast::item) { check_item(it, tcx); }
        with *visit::default_simple_visitor()
    });
    visit::visit_crate(*crate, (), v);

    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Split deprecated str and vec warnings into two flags, enable old_vecs by default.<commit_after>import driver::session;
import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import syntax::attr;
import syntax::codemap::span;
import std::map::{map,hashmap,int_hash,hash_from_strs};
import std::smallintmap::{map,smallintmap};
import io::writer_util;
import syntax::print::pprust::expr_to_str;
export lint, ctypes, unused_imports;
export level, ignore, warn, error;
export lookup_lint, lint_dict, get_lint_dict;
export get_warning_level, get_warning_settings_level;
export check_crate, build_settings_crate, mk_warning_settings;
export warning_settings;

#[doc="

A 'lint' check is a kind of miscellaneous constraint that a user _might_ want
to enforce, but might reasonably want to permit as well, on a module-by-module
basis. They contrast with static constraints enforced by other phases of the
compiler, which are generally required to hold in order to compile the program
at all.

We also build up a table containing information about lint settings, in order
to allow other passes to take advantage of the warning attribute
infrastructure. To save space, the table is keyed by the id of /items/, not of
every expression. When an item has the default settings, the entry will be
omitted. If we start allowing warn attributes on expressions, we will start
having entries for expressions that do not share their enclosing items
settings.

This module then, exports two passes: one that populates the warning settings
table in the session and is run early in the compile process, and one that
does a variety of lint checks, and is run late in the compile process.

"]

enum lint {
    ctypes,
    unused_imports,
    while_true,
    path_statement,
    old_vecs,
    unrecognized_warning,
    non_implicitly_copyable_typarams,
    vecs_not_implicitly_copyable,
    implicit_copies,
    old_strs,
}

// This is pretty unfortunate. We really want some sort of "deriving Enum"
// type of thing.
fn int_to_lint(i: int) -> lint {
    alt check i {
      0 { ctypes }
      1 { unused_imports }
      2 { while_true }
      3 { path_statement }
      4 { old_vecs }
      5 { unrecognized_warning }
      6 { non_implicitly_copyable_typarams }
      7 { vecs_not_implicitly_copyable }
      8 { implicit_copies }
      9 { old_strs }
    }
}

enum level {
    ignore, warn, error
}

type lint_spec = @{lint: lint,
                   desc: str,
                   default: level};

type lint_dict = hashmap<str,lint_spec>;

/*
  Pass names should not contain a '-', as the compiler normalizes
  '-' to '_' in command-line flags
 */
fn get_lint_dict() -> lint_dict {
    let v = [
        ("ctypes",
         @{lint: ctypes,
           desc: "proper use of core::libc types in native modules",
           default: warn}),

        ("unused_imports",
         @{lint: unused_imports,
           desc: "imports that are never used",
           default: ignore}),

        ("while_true",
         @{lint: while_true,
           desc: "suggest using loop { } instead of while(true) { }",
           default: warn}),

        ("path_statement",
         @{lint: path_statement,
           desc: "path statements with no effect",
           default: warn}),

        ("old_vecs",
         @{lint: old_vecs,
           desc: "old (deprecated) vectors",
           default: warn}),

        ("old_strs",
         @{lint: old_strs,
           desc: "old (deprecated) strings",
           default: ignore}),

        ("unrecognized_warning",
         @{lint: unrecognized_warning,
           desc: "unrecognized warning attribute",
           default: warn}),

        ("non_implicitly_copyable_typarams",
         @{lint: non_implicitly_copyable_typarams,
           desc: "passing non implicitly copyable types as copy type params",
           default: warn}),

        ("vecs_not_implicitly_copyable",
         @{lint: vecs_not_implicitly_copyable,
           desc: "make vecs and strs not implicitly copyable\
                  ('err' is ignored; only checked at top level",
           default: warn}),

        ("implicit_copies",
         @{lint: implicit_copies,
           desc: "implicit copies of non implicitly copyable data",
           default: warn})

    ];
    hash_from_strs(v)
}

// This is a highly not-optimal set of data structure decisions.
type lint_modes = smallintmap<level>;
type lint_mode_map = hashmap<ast::node_id, lint_modes>;

// settings_map maps node ids of items with non-default warning settings
// to their settings; default_settings contains the settings for everything
// not in the map.
type warning_settings = {
    default_settings: lint_modes,
    settings_map: lint_mode_map
};

fn mk_warning_settings() -> warning_settings {
    {default_settings: std::smallintmap::mk(),
     settings_map: int_hash()}
}

fn get_warning_level(modes: lint_modes, lint: lint) -> level {
    alt modes.find(lint as uint) {
      some(c) { c }
      none { ignore }
    }
}

fn get_warning_settings_level(settings: warning_settings,
                              lint_mode: lint,
                              _expr_id: ast::node_id,
                              item_id: ast::node_id) -> level {
    alt settings.settings_map.find(item_id) {
      some(modes) { get_warning_level(modes, lint_mode) }
      none { get_warning_level(settings.default_settings, lint_mode) }
    }
}

// This is kind of unfortunate. It should be somewhere else, or we should use
// a persistent data structure...
fn clone_lint_modes(modes: lint_modes) -> lint_modes {
    @{v: copy modes.v}
}

type ctxt = {dict: lint_dict,
             curr: lint_modes,
             is_default: bool,
             sess: session};

impl methods for ctxt {
    fn get_level(lint: lint) -> level {
        get_warning_level(self.curr, lint)
    }

    fn set_level(lint: lint, level: level) {
        if level == ignore {
            self.curr.remove(lint as uint);
        } else {
            self.curr.insert(lint as uint, level);
        }
    }

    fn span_lint(level: level, span: span, msg: str) {
        self.sess.span_lint_level(level, span, msg);
    }

    #[doc="
          Merge the warnings specified by any `warn(...)` attributes into the
          current lint context, call the provided function, then reset the
          warnings in effect to their previous state.
    "]
    fn with_warn_attrs(attrs: [ast::attribute], f: fn(ctxt)) {

        let mut new_ctxt = self;

        let metas = attr::attr_metas(attr::find_attrs_by_name(attrs, "warn"));
        for metas.each {|meta|
            alt meta.node {
              ast::meta_list(_, metas) {
                for metas.each {|meta|
                    alt meta.node {
                      ast::meta_word(lintname) {
                        alt lookup_lint(self.dict, *lintname) {
                          (name, none) {
                            self.span_lint(
                                self.get_level(unrecognized_warning),
                                meta.span,
                                #fmt("unknown warning: '%s'", name));
                          }
                          (_, some((lint, new_level))) {
                            // we do multiple unneeded copies of the map
                            // if many attributes are set, but this shouldn't
                            // actually be a problem...
                            new_ctxt = {is_default: false,
                                        curr: clone_lint_modes(new_ctxt.curr)
                                        with new_ctxt};
                            new_ctxt.set_level(lint, new_level);
                          }
                        }
                      }
                      _ {
                        self.sess.span_err(
                            meta.span,
                            "malformed warning attribute");
                      }
                    }
                }
              }
              _ {
                self.sess.span_err(meta.span,
                                   "malformed warning attribute");
              }
            }
        }

        f(new_ctxt);
    }
}

fn lookup_lint(dict: lint_dict, s: str)
    -> (str, option<(lint, level)>) {
    let s = str::replace(s, "-", "_");
    let (name, level) = if s.starts_with("no_") {
        (s.substr(3u, s.len() - 3u), ignore)
    } else if s.starts_with("err_") {
        (s.substr(4u, s.len() - 4u), error)
    } else {
        (s, warn)
    };
    (name,
     alt dict.find(name) {
         none { none }
         some(spec) { some((spec.lint, level)) }
     })
}

fn build_settings_item(i: @ast::item, &&cx: ctxt, v: visit::vt<ctxt>) {
    cx.with_warn_attrs(i.attrs) {|cx|
        if !cx.is_default {
            cx.sess.warning_settings.settings_map.insert(i.id, cx.curr);
        }
        visit::visit_item(i, cx, v);
    }
}

fn build_settings_crate(sess: session::session, crate: @ast::crate) {

    let cx = {dict: get_lint_dict(),
              curr: std::smallintmap::mk(),
              is_default: true,
              sess: sess};

    // Install defaults.
    for cx.dict.each {|_k, spec| cx.set_level(spec.lint, spec.default); }

    // Install command-line options, overriding defaults.
    for sess.opts.lint_opts.each {|pair|
        let (lint,level) = pair;
        cx.set_level(lint, level);
    }

    cx.with_warn_attrs(crate.node.attrs) {|cx|
        // Copy out the default settings
        for cx.curr.each {|k, v|
            sess.warning_settings.default_settings.insert(k, v);
        }

        let cx = {is_default: true with cx};

        let visit = visit::mk_vt(@{
            visit_item: build_settings_item
            with *visit::default_visitor()
        });
        visit::visit_crate(*crate, cx, visit);
    }

    sess.abort_if_errors();
}

fn check_item(i: @ast::item, cx: ty::ctxt) {
    check_item_ctypes(cx, i);
    check_item_while_true(cx, i);
    check_item_path_statement(cx, i);
    check_item_old_vecs(cx, i);
}

// Take a visitor, and modify it so that it will not proceed past subitems.
// This is used to make the simple visitors used for the lint passes
// not traverse into subitems, since that is handled by the outer
// lint visitor.
fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
    visit::mk_vt(@{visit_item: {|_i, _e, _v| } with **v})
}

fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_expr: fn@(e: @ast::expr) {
           alt e.node {
             ast::expr_while(cond, _) {
                alt cond.node {
                    ast::expr_lit(@{node: ast::lit_bool(true),_}) {
                            cx.sess.span_lint(
                                while_true, e.id, it.id,
                                e.span,
                                "denote infinite loops with loop { ... }");
                    }
                    _ {}
                }
             }
             _ {}
          }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {

    fn check_native_fn(cx: ty::ctxt, fn_id: ast::node_id,
                       decl: ast::fn_decl) {
        let tys = vec::map(decl.inputs) {|a| a.ty };
        for vec::each(tys + [decl.output]) {|ty|
            alt ty.node {
              ast::ty_path(_, id) {
                alt cx.def_map.get(id) {
                  ast::def_prim_ty(ast::ty_int(ast::ty_i)) {
                    cx.sess.span_lint(
                        ctypes, id, fn_id,
                        ty.span,
                        "found rust type `int` in native module, while \
                         libc::c_int or libc::c_long should be used");
                  }
                  ast::def_prim_ty(ast::ty_uint(ast::ty_u)) {
                    cx.sess.span_lint(
                        ctypes, id, fn_id,
                        ty.span,
                        "found rust type `uint` in native module, while \
                         libc::c_uint or libc::c_ulong should be used");
                  }
                  _ { }
                }
              }
              _ { }
            }
        }
    }

    alt it.node {
      ast::item_native_mod(nmod) if attr::native_abi(it.attrs) !=
      either::right(ast::native_abi_rust_intrinsic) {
        for nmod.items.each {|ni|
            alt ni.node {
              ast::native_item_fn(decl, tps) {
                check_native_fn(cx, it.id, decl);
              }
            }
        }
      }
      _ {/* nothing to do */ }
    }
}

fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_stmt: fn@(s: @ast::stmt) {
            alt s.node {
              ast::stmt_semi(@{id: id,
                               node: ast::expr_path(@path),
                               span: _}, _) {
                cx.sess.span_lint(
                    path_statement, id, it.id,
                    s.span,
                    "path statement with no effect");
              }
              _ {}
            }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_old_vecs(cx: ty::ctxt, it: @ast::item) {
    let uses_vstore = int_hash();

    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{

        visit_expr:fn@(e: @ast::expr) {
            alt e.node {
              ast::expr_vec(_, _)
              if ! uses_vstore.contains_key(e.id) {
                cx.sess.span_lint(
                    old_vecs, e.id, it.id,
                    e.span, "deprecated vec expr");
              }
              ast::expr_lit(@{node: ast::lit_str(_), span:_})
              if ! uses_vstore.contains_key(e.id) {
                cx.sess.span_lint(
                    old_strs, e.id, it.id,
                    e.span, "deprecated str expr");
              }

              ast::expr_vstore(@inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        },

        visit_ty: fn@(t: @ast::ty) {
            alt t.node {
              ast::ty_vec(_)
              if ! uses_vstore.contains_key(t.id) {
                cx.sess.span_lint(
                    old_vecs, t.id, it.id,
                    t.span, "deprecated vec type");
              }
              ast::ty_path(@{span: _, global: _, idents: ids,
                             rp: none, types: _}, _)
              if ids == [@"str"] && (! uses_vstore.contains_key(t.id)) {
                cx.sess.span_lint(
                    old_strs, t.id, it.id,
                    t.span, "deprecated str type");
              }
              ast::ty_vstore(inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        }

        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {

    let v = visit::mk_simple_visitor(@{
        visit_item: fn@(it: @ast::item) { check_item(it, tcx); }
        with *visit::default_simple_visitor()
    });
    visit::visit_crate(*crate, (), v);

    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
o!(comment_body<&[u8],&[u8]> semicolon ~ [ not_line_ending]);
o!(comment<&[u8], ()> comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment<&[u8],&[u8]> comment_body);

tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
fn category_name(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in 0..input.len() {
    if input[idx] == ']' as u8 {
      return Done(&input[idx..], &input[0..idx]).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}
o!(category<&[u8], &str> lsb ~ [ category_name ] ~ rsb ~ opt_multispace);

tag!(equal "=".as_bytes());
fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in 0..input.len() {
    if input[idx] == '=' as u8 {
      return Done(&input[idx..], &input[0..idx])
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in 0..input.len() {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(&input[idx..], &input[0..idx]).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

opt!(opt_multispace<&[u8],&[u8]> multispace);
o!(value<&[u8],&str> space ~ equal ~ space ~ [ value_parser ] ~ space ~ opt_comment ~ opt_multispace);
chain!(key_value<&[u8],(&str,&str)>, ||{(key, val)},  key: parameter_parser, val: value,);

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,move ||{(category, keys)},  category: category, keys: keys_and_values_wrapper,);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<commit_msg>clean the ini parsing code<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
tag!(equal "=".as_bytes());

fn category_name(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in 0..input.len() {
    if input[idx] == ']' as u8 {
      return Done(&input[idx..], &input[0..idx]).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}

fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in 0..input.len() {
    if input[idx] == '=' as u8 {
      return Done(&input[idx..], &input[0..idx])
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in 0..input.len() {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(&input[idx..], &input[0..idx]).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

o!(comment_body     <&[u8], &[u8]>       semicolon ~ [ not_line_ending]);
o!(comment          <&[u8], ()>          comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment    <&[u8], &[u8]>       comment_body);
o!(category         <&[u8], &str>        lsb ~ [ category_name ] ~ rsb ~ opt_multispace);
opt!(opt_multispace <&[u8], &[u8]>       multispace);
o!(value            <&[u8],&str>         space ~ equal ~ space ~ [ value_parser ] ~ space ~ opt_comment ~ opt_multispace);
chain!(key_value    <&[u8],(&str,&str)>, ||{(key, val)},
    key: parameter_parser,
    val: value,
);
chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,move ||{(category, keys)},
    category: category,
    keys: keys_and_values_wrapper,
);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<|endoftext|>


<commit_before><commit_msg>testsuite: Add an xfailed test case for the new `extern mod` syntax<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Just a test that new-style extern mods parse

// xfail-test
extern mod test = "github.com/catamorphism/test-pkg";

fn main() {}<|endoftext|>


<commit_before><commit_msg>Add CLI take notes<commit_after>extern crate time;

use std::fs::{OpenOptions};
use std::io::{BufReader, BufWriter};
use std::io::prelude::*;
use std::env;

fn show_notes() {
    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("NOTES.TXT")
        .unwrap();
    let mut buf_reader = BufReader::new(file);
    let mut contents = String::new();
    buf_reader.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

fn add_to_notes(note: &str) {
    let file = OpenOptions::new()
        .append(true)
        .create(true)
        .open("NOTES.TXT")
        .unwrap();
    let mut buf_writer = BufWriter::new(file);

    let now = time::now();
    let date_and_time = now.asctime();
    writeln!(buf_writer, "{}", date_and_time).unwrap();

    writeln!(buf_writer, "\t{}", note).unwrap();
}

fn main() {
    let note = env::args().skip(1).collect::<Vec<_>>();

    if note.is_empty() {
        show_notes();
    } else {
        add_to_notes(&note.join(" "));
    }
}
<|endoftext|>


<commit_before><commit_msg>Add hyper_client example<commit_after>extern crate hyper;
extern crate multipart;

use hyper::client::Request;
use hyper::method::Method;
use hyper::net::Streaming;

use multipart::client::Multipart;

fn main() {
    let url = "http://localhost:80".parse()
        .expect("Failed to parse URL");

    let request = Request::new(Method::Post, url)
        .expect("Failed to create request");

    let mut multipart = Multipart::from_request(request)
        .expect("Failed to create Multipart");

    write_body(&mut multipart)
        .expect("Failed to write multipart body");

    let _response = multipart.send().expect("Failed to send multipart request");

    // Optional: read out response
}

fn write_body(multi: &mut Multipart<Request<Streaming>>) -> hyper::Result<()> {
    let mut binary = "Hello world from binary!".as_bytes();

    try!(multi.write_text("text", "Hello, world!"));
    try!(multi.write_file("file", "lorem_ipsum.txt"));
    // &[u8] impl Read
    multi.write_stream("binary", &mut binary, None, None)
        .and(Ok(()))
}<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;
use std::time::duration::Duration;

use input;
use GameWindow;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Input event.
    Input(input::InputEvent),
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( Duration::nanoseconds((next_event - current_time) as i32) );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        None => {
                            self.state = UpdateState;
                            // Explicitly continue because otherwise the result
                            // of this match is immediately returned.
                            continue;
                        },
                        Some(x) => Some(Input(x)),
                    }
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<commit_msg>Made game loop nicer<commit_after>use time;
use std::io::timer::sleep;
use std::time::duration::Duration;

use input;
use GameWindow;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Input event.
    Input(input::InputEvent),
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W: 'a> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            self.state = match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                            width: w,
                            height: h,
                        }));
                    }

                    UpdateLoopState
                }
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    UpdateLoopState
                }
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( Duration::nanoseconds((next_event - current_time) as i64) );
                        UpdateLoopState
                    } else if next_event == next_frame {
                        RenderState
                    } else {
                        HandleEventsState
                    }
                }
                HandleEventsState => {
                    // Handle all events before updating.
                    match self.game_window.poll_event() {
                        None => UpdateState,
                        Some(x) => { return Some(Input(x)); },
                    }
                }
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{ dt: self.dt }));
                }
            };
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>parse relationship<commit_after><|endoftext|>


<commit_before><commit_msg>Bugfix in pam-sys<commit_after><|endoftext|>


<commit_before><commit_msg>adds demo.rs<commit_after>extern mod sdl;
extern mod gfx;

use std::i16;
use sdl::video;
use gfx::*;
use sdl::wm;
use sdl::event;

use std::rand::RngUtil;
use std::rand;

use std::libc::{c_int};
pub extern {
	fn usleep(n : c_int) -> c_int;
}

fn main() {
	do sdl::start {
		sdl_main();
	}
}

fn sdl_main() {
	sdl::init([sdl::InitEverything]);
	wm::set_caption("rust-gfx test", "rust-gfx");
	let screen = match sdl::video::set_video_mode(1200, 800, 32, [sdl::video::HWSurface], [sdl::video::DoubleBuf]) {
		Ok(screen) => screen,
		Err(err) => fail!(fmt!("failed to set video mode: %s", err))
	};
	let mut rng = rand::rng();

	let bg = video::RGB(0, 0, 0);
	screen.fill(bg);
	loop {
		for i16::range(0, 100) |_i| {
			gfx::filled_circle(screen, rand(10, 1190), rand(10, 790), rand(20, 60), &rng.gen::<sdl::video::Color>());
		}
		if check_exit_input() == true {
			break;
		}
		screen.flip();
		unsafe {
			usleep(90000);
		}
	}
	sdl::quit();
}

fn rand(min: i16, max: i16) -> i16 {
	let diff = max - min;
	let mut r = rand::random::<i16>();
	r = r % diff;
	r = r + min;
	r
}

fn wait_for_exit() {
	loop {
		match event::wait_event() {
			event::KeyEvent(key, true , _, _) => {
				match (key) {
					event::EscapeKey => return,
					_ => ()
				}
			},
			_ => ()
		};
	}
}

fn check_exit_input() -> bool {
	loop {
		match event::poll_event() {
			event::KeyEvent(key, true , _, _) => {
				match (key) {
					event::EscapeKey => return true,
					_ => ()
				}
			},
			event::NoEvent => return false,
			_ => ()
		};
	}
}<|endoftext|>


<commit_before><commit_msg>Remove irrelevant tests<commit_after><|endoftext|>


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

use syntax::abi::{Abi};
use syntax::ast;
use syntax_pos::Span;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir, LocalKind};
use rustc_data_structures::indexed_vec::Idx;

use super::super::gather_moves::{MovePathIndex, LookupResult};
use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    for bb in mir.basic_blocks().indices() {
        each_block(tcx, mir, flow_ctxt, results, bb);
    }
}

fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           mir: &Mir<'tcx>,
                           ctxt: &O::Ctxt,
                           results: &DataflowResults<O>,
                           bb: repr::BasicBlock) where
    O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
{
    let move_data = &ctxt.move_data;
    let repr::BasicBlockData { ref statements,
                               ref terminator,
                               is_cleanup: _ } = mir[bb];

    let (args, span) = match is_rustc_peek(tcx, terminator) {
        Some(args_and_span) => args_and_span,
        None => return,
    };
    assert!(args.len() == 1);
    let peek_arg_lval = match args[0] {
        repr::Operand::Consume(ref lval) => match *lval {
             repr::Lvalue::Local(local) if mir.local_kind(local) == LocalKind::Temp => {
                 Some(lval)
             }
             _ => None
        },
        repr::Operand::Constant(_) => {
            None
        }
    };

    let peek_arg_lval = match peek_arg_lval {
        Some(arg) => arg,
        None => {
            tcx.sess.diagnostic().span_err(
                span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            return;
        }
    };

    let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
    let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
    let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

    // Emulate effect of all statements in the block up to (but not
    // including) the borrow within `peek_arg_lval`. Do *not* include
    // call to `peek_arg_lval` itself (since we are peeking the state
    // of the argument at time immediate preceding Call to
    // `rustc_peek`).

    let mut sets = super::BlockSets { on_entry: &mut entry,
                                      gen_set: &mut gen,
                                      kill_set: &mut kill };

    for (j, stmt) in statements.iter().enumerate() {
        debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
        let (lvalue, rvalue) = match stmt.kind {
            repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                (lvalue, rvalue)
            }
            repr::StatementKind::StorageLive(_) |
            repr::StatementKind::StorageDead(_) |
            repr::StatementKind::Nop => continue,
            repr::StatementKind::SetDiscriminant{ .. } =>
                span_bug!(stmt.source_info.span,
                          "sanity_check should run before Deaggregator inserts SetDiscriminant"),
        };

        if lvalue == peek_arg_lval {
            if let repr::Rvalue::Ref(_,
                                     repr::BorrowKind::Shared,
                                     ref peeking_at_lval) = *rvalue {
                // Okay, our search is over.
                match move_data.rev_lookup.find(peeking_at_lval) {
                    LookupResult::Exact(peek_mpi) => {
                        let bit_state = sets.on_entry.contains(&peek_mpi);
                        debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                               lvalue, peeking_at_lval, bit_state);
                        if !bit_state {
                            tcx.sess.span_err(span, "rustc_peek: bit not set");
                        }
                    }
                    LookupResult::Parent(..) => {
                        tcx.sess.span_err(span, "rustc_peek: argument untracked");
                    }
                }
                return;
            } else {
                // Our search should have been over, but the input
                // does not match expectations of `rustc_peek` for
                // this sanity_check.
                let msg = "rustc_peek: argument expression \
                           must be immediate borrow of form `&expr`";
                tcx.sess.span_err(span, msg);
            }
        }

        let lhs_mpi = move_data.rev_lookup.find(lvalue);

        debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
               lvalue, lhs_mpi, stmt);
        // reset GEN and KILL sets before emulating their effect.
        for e in sets.gen_set.words_mut() { *e = 0; }
        for e in sets.kill_set.words_mut() { *e = 0; }
        results.0.operator.statement_effect(ctxt, &mut sets, bb, j);
        sets.on_entry.union(sets.gen_set);
        sets.on_entry.subtract(sets.kill_set);
    }

    tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                      anticipated pattern; note that \
                                      rustc_peek expects input of \
                                      form `&expr`"));
}

fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           terminator: &'a Option<repr::Terminator<'tcx>>)
                           -> Option<(&'a [repr::Operand<'tcx>], Span)> {
    if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator {
        if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
        {
            if let repr::Operand::Constant(ref func) = *oper
            {
                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                {
                    let name = tcx.item_name(def_id);
                    if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                        if name.as_str() == "rustc_peek" {
                            return Some((args, source_info.span));
                        }
                    }
                }
            }
        }
    }
    return None;
}
<commit_msg>Ignore local kind in MIR dataflow<commit_after>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::abi::{Abi};
use syntax::ast;
use syntax_pos::Span;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use rustc_data_structures::indexed_vec::Idx;

use super::super::gather_moves::{MovePathIndex, LookupResult};
use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    for bb in mir.basic_blocks().indices() {
        each_block(tcx, mir, flow_ctxt, results, bb);
    }
}

fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           mir: &Mir<'tcx>,
                           ctxt: &O::Ctxt,
                           results: &DataflowResults<O>,
                           bb: repr::BasicBlock) where
    O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
{
    let move_data = &ctxt.move_data;
    let repr::BasicBlockData { ref statements,
                               ref terminator,
                               is_cleanup: _ } = mir[bb];

    let (args, span) = match is_rustc_peek(tcx, terminator) {
        Some(args_and_span) => args_and_span,
        None => return,
    };
    assert!(args.len() == 1);
    let peek_arg_lval = match args[0] {
        repr::Operand::Consume(ref lval @ repr::Lvalue::Local(_)) => Some(lval),
        _ => None,
    };

    let peek_arg_lval = match peek_arg_lval {
        Some(arg) => arg,
        None => {
            tcx.sess.diagnostic().span_err(
                span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            return;
        }
    };

    let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
    let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
    let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

    // Emulate effect of all statements in the block up to (but not
    // including) the borrow within `peek_arg_lval`. Do *not* include
    // call to `peek_arg_lval` itself (since we are peeking the state
    // of the argument at time immediate preceding Call to
    // `rustc_peek`).

    let mut sets = super::BlockSets { on_entry: &mut entry,
                                      gen_set: &mut gen,
                                      kill_set: &mut kill };

    for (j, stmt) in statements.iter().enumerate() {
        debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
        let (lvalue, rvalue) = match stmt.kind {
            repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                (lvalue, rvalue)
            }
            repr::StatementKind::StorageLive(_) |
            repr::StatementKind::StorageDead(_) |
            repr::StatementKind::Nop => continue,
            repr::StatementKind::SetDiscriminant{ .. } =>
                span_bug!(stmt.source_info.span,
                          "sanity_check should run before Deaggregator inserts SetDiscriminant"),
        };

        if lvalue == peek_arg_lval {
            if let repr::Rvalue::Ref(_,
                                     repr::BorrowKind::Shared,
                                     ref peeking_at_lval) = *rvalue {
                // Okay, our search is over.
                match move_data.rev_lookup.find(peeking_at_lval) {
                    LookupResult::Exact(peek_mpi) => {
                        let bit_state = sets.on_entry.contains(&peek_mpi);
                        debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                               lvalue, peeking_at_lval, bit_state);
                        if !bit_state {
                            tcx.sess.span_err(span, "rustc_peek: bit not set");
                        }
                    }
                    LookupResult::Parent(..) => {
                        tcx.sess.span_err(span, "rustc_peek: argument untracked");
                    }
                }
                return;
            } else {
                // Our search should have been over, but the input
                // does not match expectations of `rustc_peek` for
                // this sanity_check.
                let msg = "rustc_peek: argument expression \
                           must be immediate borrow of form `&expr`";
                tcx.sess.span_err(span, msg);
            }
        }

        let lhs_mpi = move_data.rev_lookup.find(lvalue);

        debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
               lvalue, lhs_mpi, stmt);
        // reset GEN and KILL sets before emulating their effect.
        for e in sets.gen_set.words_mut() { *e = 0; }
        for e in sets.kill_set.words_mut() { *e = 0; }
        results.0.operator.statement_effect(ctxt, &mut sets, bb, j);
        sets.on_entry.union(sets.gen_set);
        sets.on_entry.subtract(sets.kill_set);
    }

    tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                      anticipated pattern; note that \
                                      rustc_peek expects input of \
                                      form `&expr`"));
}

fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           terminator: &'a Option<repr::Terminator<'tcx>>)
                           -> Option<(&'a [repr::Operand<'tcx>], Span)> {
    if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator {
        if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
        {
            if let repr::Operand::Constant(ref func) = *oper
            {
                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                {
                    let name = tcx.item_name(def_id);
                    if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                        if name.as_str() == "rustc_peek" {
                            return Some((args, source_info.span));
                        }
                    }
                }
            }
        }
    }
    return None;
}
<|endoftext|>


<commit_before><commit_msg>Add Automorphic number in Rust<commit_after>// In mathematics an automorphic number (sometimes referred to as a circular number)
// is a number whose square "ends" in the same digits as the number itself.

fn list_automorphic_numbers(start: i32, end: i32) {
    (start..end)
        .filter(|&n| is_automorphic(n as i128))
        .for_each(|n| println!("{}\t=>\t{}", n, n.pow(2)))
}

fn is_automorphic(n: i128) -> bool {
    let n_str = n.to_string();
    let sq_str = n.pow(2).to_string();
    n_str == sq_str[(sq_str.len() - n_str.len())..]
}

fn main() {
    list_automorphic_numbers(1, 10000)
}

#[test]
fn simple_test() {
    assert!(is_automorphic(5));
    assert!(is_automorphic(6));
    assert!(is_automorphic(76));
    assert!(is_automorphic(376));
    assert!(is_automorphic(890625));
}
<|endoftext|>