use errors::{ParseError, Result};
use errors::ErrorType::Parse;
use position::Pos;
pub trait StrExt<'a> {
fn capitalize(&self) -> String;
fn rsplit_at(&'a self, index: usize) -> (&'a str, &'a str);
}
impl<'a> StrExt<'a> for &'a str {
fn capitalize(&self) -> String {
let mut chars = self.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
}
fn rsplit_at(&'a self, index: usize) -> (&'a str, &'a str) {
if self.len() > index {
self.split_at(self.len() - index)
}
else {
("", "")
}
}
}
#[derive(Debug, PartialEq)]
pub struct Word<'a> {
pub index: usize,
pub word: &'a str,
}
pub fn check_ident(string: String, pos: &Pos) -> Result<String> {
if string.chars().all(|character| character.is_alphanumeric() || character == '-' || character == '_') {
if let Some(true) = string.chars().next().map(|character| character.is_alphabetic()) {
return Ok(string)
}
}
Err(ParseError::new(Parse, string, "identifier".to_string(), pos.clone()))
}
pub fn maybe_word(input: &str) -> Option<Word> {
let word = word(input);
if word.word.is_empty() {
None
}
else {
Some(word)
}
}
pub fn word(input: &str) -> Word {
let start = input.chars().take_while(|c| c.is_whitespace()).count();
let end = input[start..].find(char::is_whitespace)
.map(|index| index + start)
.unwrap_or_else(|| input.len());
Word {
index: start,
word: &input[start..end],
}
}
pub fn words(input: &str, count: usize) -> Option<Vec<Word>> {
let mut vec = vec![];
let mut start_index = 0;
for (i, character) in input.chars().enumerate() {
if character.is_whitespace() {
let word = &input[start_index..i];
if !word.is_empty() {
vec.push(Word {
index: start_index,
word,
});
}
start_index = i + 1;
}
}
let len = input.len();
if start_index < len {
vec.push(Word {
index: start_index,
word: &input[start_index..len],
});
}
vec.truncate(count);
if vec.len() == count {
Some(vec)
}
else {
None
}
}
#[cfg(test)]
mod tests {
use super::{Word, word, words};
#[test]
fn test_word() {
let result = word("hello world");
assert_eq!(0, result.index);
assert_eq!("hello", result.word);
let result = word(" hello world");
assert_eq!(1, result.index);
assert_eq!("hello", result.word);
let result = word(" helloworld");
assert_eq!(1, result.index);
assert_eq!("helloworld", result.word);
}
#[test]
fn test_words() {
let word1 = Word {
index: 0,
word: "hello",
};
let word2 = Word {
index: 6,
word: "world",
};
assert_eq!(Some(vec![word1, word2]), words("hello world", 2));
assert_eq!(None, words("hello", 2));
let word1 = Word {
index: 0,
word: "hello",
};
let word2 = Word {
index: 6,
word: "the",
};
assert_eq!(Some(vec![word1, word2]), words("hello the world", 2));
let word1 = Word {
index: 1,
word: "hello",
};
let word2 = Word {
index: 7,
word: "world",
};
assert_eq!(Some(vec![word1, word2]), words(" hello world ", 2));
let word1 = Word {
index: 1,
word: "hello",
};
let word2 = Word {
index: 8,
word: "world",
};
assert_eq!(Some(vec![word1, word2]), words(" hello world ", 2));
}
}