(index<- )        ./libsyntax/util/parser_testing.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  use ast;
  12  use parse::{new_parse_sess};
  13  use parse::{ParseSess,string_to_filemap,filemap_to_tts};
  14  use parse::{new_parser_from_source_str};
  15  use parse::parser::Parser;
  16  use parse::token;
  17  
  18  // map a string to tts, using a made-up filename:
  19  pub fn string_to_tts(source_str: StrBuf) -> Vec<ast::TokenTree> {
  20      let ps = new_parse_sess();
  21      filemap_to_tts(&ps,
  22                     string_to_filemap(&ps, source_str, "bogofile".to_strbuf()))
  23  }
  24  
  25  // map string to parser (via tts)
  26  pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: StrBuf) -> Parser<'a> {
  27      new_parser_from_source_str(ps,
  28                                 Vec::new(),
  29                                 "bogofile".to_strbuf(),
  30                                 source_str)
  31  }
  32  
  33  fn with_error_checking_parse<T>(s: StrBuf, f: |&mut Parser| -> T) -> T {
  34      let ps = new_parse_sess();
  35      let mut p = string_to_parser(&ps, s);
  36      let x = f(&mut p);
  37      p.abort_if_errors();
  38      x
  39  }
  40  
  41  // parse a string, return a crate.
  42  pub fn string_to_crate (source_str : StrBuf) -> ast::Crate {
  43      with_error_checking_parse(source_str, |p| {
  44          p.parse_crate_mod()
  45      })
  46  }
  47  
  48  // parse a string, return an expr
  49  pub fn string_to_expr (source_str : StrBuf) -> @ast::Expr {
  50      with_error_checking_parse(source_str, |p| {
  51          p.parse_expr()
  52      })
  53  }
  54  
  55  // parse a string, return an item
  56  pub fn string_to_item (source_str : StrBuf) -> Option<@ast::Item> {
  57      with_error_checking_parse(source_str, |p| {
  58          p.parse_item(Vec::new())
  59      })
  60  }
  61  
  62  // parse a string, return a stmt
  63  pub fn string_to_stmt(source_str : StrBuf) -> @ast::Stmt {
  64      with_error_checking_parse(source_str, |p| {
  65          p.parse_stmt(Vec::new())
  66      })
  67  }
  68  
  69  // parse a string, return a pat. Uses "irrefutable"... which doesn't
  70  // (currently) affect parsing.
  71  pub fn string_to_pat(source_str: StrBuf) -> @ast::Pat {
  72      string_to_parser(&new_parse_sess(), source_str).parse_pat()
  73  }
  74  
  75  // convert a vector of strings to a vector of ast::Ident's
  76  pub fn strs_to_idents(ids: Vec<&str> ) -> Vec<ast::Ident> {
  77      ids.iter().map(|u| token::str_to_ident(*u)).collect()
  78  }
  79  
  80  // does the given string match the pattern? whitespace in the first string
  81  // may be deleted or replaced with other whitespace to match the pattern.
  82  // this function is unicode-ignorant; fortunately, the careful design of
  83  // UTF-8 mitigates this ignorance.  In particular, this function only collapses
  84  // sequences of \n, \r, ' ', and \t, but it should otherwise tolerate unicode
  85  // chars. Unsurprisingly, it doesn't do NKF-normalization(?).
  86  pub fn matches_codepattern(a : &str, b : &str) -> bool {
  87      let mut idx_a = 0;
  88      let mut idx_b = 0;
  89      loop {
  90          if idx_a == a.len() && idx_b == b.len() {
  91              return true;
  92          }
  93          else if idx_a == a.len() {return false;}
  94          else if idx_b == b.len() {
  95              // maybe the stuff left in a is all ws?
  96              if is_whitespace(a.char_at(idx_a)) {
  97                  return scan_for_non_ws_or_end(a,idx_a) == a.len();
  98              } else {
  99                  return false;
 100              }
 101          }
 102          // ws in both given and pattern:
 103          else if is_whitespace(a.char_at(idx_a))
 104             && is_whitespace(b.char_at(idx_b)) {
 105              idx_a = scan_for_non_ws_or_end(a,idx_a);
 106              idx_b = scan_for_non_ws_or_end(b,idx_b);
 107          }
 108          // ws in given only:
 109          else if is_whitespace(a.char_at(idx_a)) {
 110              idx_a = scan_for_non_ws_or_end(a,idx_a);
 111          }
 112          // *don't* silently eat ws in expected only.
 113          else if a.char_at(idx_a) == b.char_at(idx_b) {
 114              idx_a += 1;
 115              idx_b += 1;
 116          }
 117          else {
 118              return false;
 119          }
 120      }
 121  }
 122  
 123  // given a string and an index, return the first uint >= idx
 124  // that is a non-ws-char or is outside of the legal range of
 125  // the string.
 126  fn scan_for_non_ws_or_end(a : &str, idx: uint) -> uint {
 127      let mut i = idx;
 128      let len = a.len();
 129      while (i < len) && (is_whitespace(a.char_at(i))) {
 130          i += 1;
 131      }
 132      i
 133  }
 134  
 135  // copied from lexer.
 136  pub fn is_whitespace(c: char) -> bool {
 137      return c == ' ' || c == '\t' || c == '\r' || c == '\n';
 138  }
 139  
 140  #[cfg(test)]
 141  mod test {
 142      use super::*;
 143  
 144      #[test] fn eqmodws() {
 145          assert_eq!(matches_codepattern("",""),true);
 146          assert_eq!(matches_codepattern("","a"),false);
 147          assert_eq!(matches_codepattern("a",""),false);
 148          assert_eq!(matches_codepattern("a","a"),true);
 149          assert_eq!(matches_codepattern("a b","a   \n\t\r  b"),true);
 150          assert_eq!(matches_codepattern("a b ","a   \n\t\r  b"),true);
 151          assert_eq!(matches_codepattern("a b","a   \n\t\r  b "),false);
 152          assert_eq!(matches_codepattern("a   b","a b"),true);
 153          assert_eq!(matches_codepattern("ab","a b"),false);
 154          assert_eq!(matches_codepattern("a   b","ab"),true);
 155      }
 156  }