<commit_before>use regex::Regex;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenType {
    Number,
    ListStart,
    ListEnd,
    VectorStart,
    VectorEnd,
    HashMapStart,
    HashMapEnd,
    Symbol,
    Keyword,
    Str
}

lazy_static! {
    static ref COMMENT_REGEXP: Regex = Regex::new("^(\\s+|;.*?(\n|$))+").unwrap();
    static ref STR_REGEXP: Regex = Regex::new("^\".*?\"").unwrap();
    static ref SYMBOL_REGEXP: Regex = Regex::new(r"^[^\s\{\}()\[\]]+").unwrap();
    static ref NUMBER_REGEXP: Regex = Regex::new(r"^-?\d+").unwrap();
}

pub type Token = (TokenType, String);

pub struct Tokenizer {
    input: String,
    pos: usize
}

impl Tokenizer {
    pub fn new(input: &str) -> Tokenizer {
        Tokenizer { input: input.to_string(), pos: 0 }
    }
}

impl Iterator for Tokenizer {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        // Skip white space and comments
        if let Some(cap) = COMMENT_REGEXP.captures(&self.input[self.pos..]) {
            self.pos += cap[0].len();
        }

        let input = &self.input[self.pos..];

        if input.starts_with('(') {
            self.pos += 1;
            return Some(token(TokenType::ListStart, "("))
        }

        if input.starts_with(')') {
            self.pos += 1;
            return Some(token(TokenType::ListEnd, ")"))
        }

        if input.starts_with('[') {
            self.pos += 1;
            return Some(token(TokenType::VectorStart, "["))
        }

        if input.starts_with(']') {
            self.pos += 1;
            return Some(token(TokenType::VectorEnd, "]"));
        }

        if input.starts_with('{') {
            self.pos += 1;
            return Some(token(TokenType::HashMapStart, "{"))
        }

        if input.starts_with('}') {
            self.pos += 1;
            return Some(token(TokenType::HashMapEnd, "}"));
        }

        if let Some(cap) = STR_REGEXP.captures(input) {
            self.pos += cap[0].len();
            return Some(token(TokenType::Str, cap[0].to_string()))
        }

        if let Some(cap) = NUMBER_REGEXP.captures(input) {
            self.pos += cap[0].len();
            return Some(token(TokenType::Number, cap[0].to_string()))
        }

        if let Some(cap) = SYMBOL_REGEXP.captures(input) {
            self.pos += cap[0].len();
            let cap_string = cap[0].to_string();
            if cap_string.starts_with(':') {
                return Some((TokenType::Keyword, cap_string))
            } else {
                return Some((TokenType::Symbol, cap_string))
            }
        }

        None
    }
}

fn token<S: Into<String>>(token_type: TokenType, s: S) -> Token {
    (token_type, s.into())
}

/* ------------------------------ Tests ----------------------------------------------- */

#[allow(dead_code)]
pub fn tokenize(input: &str) -> Vec<Token> {
    Tokenizer::new(input).collect()
}

#[test]
fn test_tokenizer() {
    assert_eq!(tokenize("42"), vec![(TokenType::Number, "42".to_string())]);
    assert_eq!(tokenize("("), vec![(TokenType::ListStart, "(".to_string())]);
    assert_eq!(tokenize(")"), vec![(TokenType::ListEnd, ")".to_string())]);
    assert_eq!(tokenize("( )"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
    assert_eq!(tokenize("(\n)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
    assert_eq!(tokenize("(42)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::Number, "42".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
}

#[test]
fn test_tokenizer_symbol() {
    assert_eq!(tokenize("symbol"), vec![(TokenType::Symbol, "symbol".to_string())]);
    assert_eq!(tokenize("(+ 42)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::Symbol, "+".to_string()),
        (TokenType::Number, "42".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
}

#[test]
fn test_tokenizer_vector() {
    assert_eq!(tokenize("[]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::VectorEnd, "]")
    ]);
    assert_eq!(tokenize("[23 42]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::Number, "23"),
        token(TokenType::Number, "42"),
        token(TokenType::VectorEnd, "]")
    ]);
}

#[test]
fn test_empty_map() {
    assert_eq!(tokenize("{}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_map() {
    assert_eq!(tokenize("{:keyword 123}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::Keyword, ":keyword"),
        token(TokenType::Number, "123"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_map_ending_with_symbol_as_value() {
    assert_eq!(tokenize("{:keyword var}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::Keyword, ":keyword"),
        token(TokenType::Symbol, "var"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_list_ending_with_symbol() {
    assert_eq!(tokenize("(symbol)"), vec![
        token(TokenType::ListStart, "("),
        token(TokenType::Symbol, "symbol"),
        token(TokenType::ListEnd, ")")
    ]);
}

#[test]
fn test_vector_ending_with_symbol() {
    assert_eq!(tokenize("[symbol]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::Symbol, "symbol"),
        token(TokenType::VectorEnd, "]")
    ]);
}

#[test]
fn test_string() {
    assert_eq!(tokenize("\"string\" \"\""), vec![
        token(TokenType::Str, "\"string\""),
        token(TokenType::Str, "\"\""),
    ]);
}

#[test]
fn test_ignore_single_line_comment() {
    assert_eq!(tokenize("; comment"), vec![]);
    assert_eq!(tokenize("; comment\n"), vec![]);
    assert_eq!(tokenize("; comment\n 23"), vec![token(TokenType::Number, "23")]);
}<commit_msg>Tokenizer test for negative numbers<commit_after>use regex::Regex;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenType {
    Number,
    ListStart,
    ListEnd,
    VectorStart,
    VectorEnd,
    HashMapStart,
    HashMapEnd,
    Symbol,
    Keyword,
    Str
}

lazy_static! {
    static ref COMMENT_REGEXP: Regex = Regex::new("^(\\s+|;.*?(\n|$))+").unwrap();
    static ref STR_REGEXP: Regex = Regex::new("^\".*?\"").unwrap();
    static ref SYMBOL_REGEXP: Regex = Regex::new(r"^[^\s\{\}()\[\]]+").unwrap();
    static ref NUMBER_REGEXP: Regex = Regex::new(r"^-?\d+").unwrap();
}

pub type Token = (TokenType, String);

pub struct Tokenizer {
    input: String,
    pos: usize
}

impl Tokenizer {
    pub fn new(input: &str) -> Tokenizer {
        Tokenizer { input: input.to_string(), pos: 0 }
    }
}

impl Iterator for Tokenizer {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        // Skip white space and comments
        if let Some(cap) = COMMENT_REGEXP.captures(&self.input[self.pos..]) {
            self.pos += cap[0].len();
        }

        let input = &self.input[self.pos..];

        if input.starts_with('(') {
            self.pos += 1;
            return Some(token(TokenType::ListStart, "("))
        }

        if input.starts_with(')') {
            self.pos += 1;
            return Some(token(TokenType::ListEnd, ")"))
        }

        if input.starts_with('[') {
            self.pos += 1;
            return Some(token(TokenType::VectorStart, "["))
        }

        if input.starts_with(']') {
            self.pos += 1;
            return Some(token(TokenType::VectorEnd, "]"));
        }

        if input.starts_with('{') {
            self.pos += 1;
            return Some(token(TokenType::HashMapStart, "{"))
        }

        if input.starts_with('}') {
            self.pos += 1;
            return Some(token(TokenType::HashMapEnd, "}"));
        }

        if let Some(cap) = STR_REGEXP.captures(input) {
            self.pos += cap[0].len();
            return Some(token(TokenType::Str, cap[0].to_string()))
        }

        if let Some(cap) = NUMBER_REGEXP.captures(input) {
            self.pos += cap[0].len();
            return Some(token(TokenType::Number, cap[0].to_string()))
        }

        if let Some(cap) = SYMBOL_REGEXP.captures(input) {
            self.pos += cap[0].len();
            let cap_string = cap[0].to_string();
            if cap_string.starts_with(':') {
                return Some((TokenType::Keyword, cap_string))
            } else {
                return Some((TokenType::Symbol, cap_string))
            }
        }

        None
    }
}

fn token<S: Into<String>>(token_type: TokenType, s: S) -> Token {
    (token_type, s.into())
}

/* ------------------------------ Tests ----------------------------------------------- */

#[allow(dead_code)]
pub fn tokenize(input: &str) -> Vec<Token> {
    Tokenizer::new(input).collect()
}

#[test]
fn test_tokenizer() {
    assert_eq!(tokenize("42"), vec![(TokenType::Number, "42".to_string())]);
    assert_eq!(tokenize("("), vec![(TokenType::ListStart, "(".to_string())]);
    assert_eq!(tokenize(")"), vec![(TokenType::ListEnd, ")".to_string())]);
    assert_eq!(tokenize("( )"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
    assert_eq!(tokenize("(\n)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
    assert_eq!(tokenize("(42)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::Number, "42".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
}

#[test]
fn test_tokenizer_symbol() {
    assert_eq!(tokenize("symbol"), vec![(TokenType::Symbol, "symbol".to_string())]);
    assert_eq!(tokenize("(+ 42)"), vec![
        (TokenType::ListStart, "(".to_string()),
        (TokenType::Symbol, "+".to_string()),
        (TokenType::Number, "42".to_string()),
        (TokenType::ListEnd, ")".to_string())
    ]);
}

#[test]
fn test_tokenizer_vector() {
    assert_eq!(tokenize("[]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::VectorEnd, "]")
    ]);
    assert_eq!(tokenize("[23 42]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::Number, "23"),
        token(TokenType::Number, "42"),
        token(TokenType::VectorEnd, "]")
    ]);
}

#[test]
fn test_empty_map() {
    assert_eq!(tokenize("{}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_map() {
    assert_eq!(tokenize("{:keyword 123}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::Keyword, ":keyword"),
        token(TokenType::Number, "123"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_map_ending_with_symbol_as_value() {
    assert_eq!(tokenize("{:keyword var}"), vec![
        token(TokenType::HashMapStart, "{"),
        token(TokenType::Keyword, ":keyword"),
        token(TokenType::Symbol, "var"),
        token(TokenType::HashMapEnd, "}")
    ]);
}

#[test]
fn test_list_ending_with_symbol() {
    assert_eq!(tokenize("(symbol)"), vec![
        token(TokenType::ListStart, "("),
        token(TokenType::Symbol, "symbol"),
        token(TokenType::ListEnd, ")")
    ]);
}

#[test]
fn test_vector_ending_with_symbol() {
    assert_eq!(tokenize("[symbol]"), vec![
        token(TokenType::VectorStart, "["),
        token(TokenType::Symbol, "symbol"),
        token(TokenType::VectorEnd, "]")
    ]);
}

#[test]
fn test_string() {
    assert_eq!(tokenize("\"string\" \"\""), vec![
        token(TokenType::Str, "\"string\""),
        token(TokenType::Str, "\"\""),
    ]);
}

#[test]
fn test_ignore_single_line_comment() {
    assert_eq!(tokenize("; comment"), vec![]);
    assert_eq!(tokenize("; comment\n"), vec![]);
    assert_eq!(tokenize("; comment\n 23"), vec![token(TokenType::Number, "23")]);
}

#[test]
fn test_negative_int() {
    assert_eq!(tokenize("-23"), vec![token(TokenType::Number, "-23")]);
}<|endoftext|>


<commit_before>use entity::Entity;
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use std::{
    cell::{Ref, RefCell, RefMut}, ffi::OsStr, fmt::{Display, Formatter, Result}, fs::read_link,
    marker::PhantomData, path::PathBuf,
};
use walkdir::WalkDir;

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed entity description.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Description {
    pub description: Vec<String>,
}

impl Description {
    /// Creates a new Description instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let description = Description::new();
    ///
    /// assert!(description.description.is_empty());
    /// ```
    pub fn new() -> Self {
        Self {
            description: Vec::new(),
        }
    }

    /// Sets and formats the description.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let mut description = Description::new();
    /// description.set("# TESTCASE(c1::AddTwoNumbers)
    ///     unsigned int no1 = 5;
    ///     # EQ[this->class_inst->TL_FCT(no1: no1, no2: 10) => 15]
    ///     # LT[this->class_inst->TL_FCT(no1: no1, no2: 10) => 30]");
    ///
    /// assert_eq!(description.description.len(), 4);
    /// ```
    pub fn set(&mut self, description: &str) {
        self.description = description
            .split('\n')
            .map(|desc| {
                String::from(
                    desc.trim_left()
                        .trim_left_matches('*')
                        .trim_left_matches('/')
                        .trim_left(),
                )
            })
            .filter(|ref desc| !desc.is_empty() && desc.as_str() != "**")
            .map(|desc| {
                if desc.chars().next() == Some('#') {
                    desc.replace(" ", "")
                } else {
                    desc
                }
            })
            .collect();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
    pub value: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Self {
            name: name.into(),
            atype: atype.map(S::into),
            value: None,
        }
    }

    /// Sets a value to the argument.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// assert!(argument.value.is_some());
    ///
    /// ```
    pub fn set_value(&mut self, value: &str) {
        self.value = Some(String::from(value));
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Vec<Argument>,
    pub description: Option<Description>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_empty());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            return_type: None,
            arguments: Vec::new(),
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Fallible<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| err_msg("Function type can not be parsed from signature."))?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// # TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        if self.description.is_none() {
            self.description = Some(Description::new());
        }

        if let Some(desc) = &mut self.description {
            desc.set(description);
        }
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed enum argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Enum {
    pub name: String,
    pub etype: Option<String>,
    pub arguments: Vec<Argument>,
}

impl Enum {
    /// Creates a new Enum instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Enum;
    ///
    /// let enumeration = Enum::new("testEnum");
    ///
    /// assert_eq!(enumeration.name, String::from("testEnum"));
    /// assert!(enumeration.etype.is_none());
    /// assert!(enumeration.arguments.is_empty());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            etype: None,
            arguments: Vec::new(),
        }
    }

    /// Sets arguments for the Enum.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Argument, Enum};
    ///
    /// let mut enumeration = Enum::new("testEnum");
    /// let args = vec![Argument::new("Zero", Some("0")), Argument::new("Two", Some("2"))];
    /// enumeration.set_arguments(&args);
    ///
    /// assert_eq!(enumeration.arguments.len(), 2);
    /// ```
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed project file.
#[derive(Default, Clone, Debug)]
pub struct ProjectFile<T> {
    pub path: PathBuf,
    pub entities: RefCell<Vec<Entity>>,
    pub pf_type: PhantomData<T>,
}

impl<T> ProjectFile<T>
where
    T: LanguageType,
{
    /// Creates a new ProjectFile instance.
    ///
    /// # Example
    ///
    /// ```
    /// use std::path::PathBuf;
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    ///
    /// assert_eq!(project_file.path, PathBuf::from("test/project_file"));
    /// assert_eq!(project_file.entities().len(), 0);
    /// ```
    pub fn new<S: Into<PathBuf>>(path: S) -> Self {
        Self {
            path: path.into(),
            entities: RefCell::new(Vec::new()),
            pf_type: PhantomData,
        }
    }

    /// Returns a reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// assert_eq!(project_file.entities().len(), 1);
    /// ```
    pub fn entities(&self) -> Ref<Vec<Entity>> {
        self.entities.borrow()
    }

    /// Returns a mutable reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// let mut entities = project_file.entities_mut();
    /// assert_eq!(entities.len(), 1);
    ///
    /// entities.clear();
    /// assert_eq!(entities.len(), 0);
    /// ```
    pub fn entities_mut(&self) -> RefMut<Vec<Entity>> {
        self.entities.borrow_mut()
    }
}

impl<T> Display for ProjectFile<T>
where
    T: LanguageType,
{
    /// Formats a ProjectFile to be displayed by std output.
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(path) = self.path.to_str() {
            return write!(f, "{}", path);
        }
        write!(f, "Unable to stringify filename")
    }
}

////////////////////////////////////////////////////////////////////////////////

/// The analyzer which fulfills parsing and entity extraction tasks.
#[derive(Default, Debug)]
pub struct Analysis<T>
where
    T: LanguageType,
{
    pub file_types: &'static [&'static str],
    pub project_files: RefCell<Vec<ProjectFile<T>>>,
}

impl<T> Analysis<T>
where
    T: LanguageType,
{
    /// Creates a new Analysis instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Analysis;
    /// use thinlinelib::language_type::{C, LanguageType};
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    ///
    /// assert_eq!(analysis.file_types, C::file_types());
    /// assert_eq!(analysis.project_files().len(), 0);
    /// ```
    pub fn new() -> Self {
        Self {
            file_types: T::file_types(),
            project_files: RefCell::new(Vec::new()),
        }
    }

    /// Returns a reference to the collected project files for analysis.
    pub fn project_files(&self) -> Ref<Vec<ProjectFile<T>>> {
        self.project_files.borrow()
    }

    /// Returns a mutable reference to the collected project files for analysis.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Analysis, ProjectFile};
    /// use thinlinelib::language_type::C;
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    /// let mut project_files = analysis.project_files_mut();
    /// assert_eq!(project_files.len(), 0);
    ///
    /// project_files.push(ProjectFile::new("test/anotherFile"));
    /// assert_eq!(project_files.len(), 1);
    /// ```
    pub fn project_files_mut(&self) -> RefMut<Vec<ProjectFile<T>>> {
        self.project_files.borrow_mut()
    }

    /// Collects all the sources within the given project dir.
    /// Does also work for symlinked files.
    pub fn collect_sources(&self, project_dir: &PathBuf, search_dirs: &[String]) -> Fallible<()> {
        // Check the given project directory
        if !project_dir.exists() || !project_dir.is_dir() {
            return Err(format_err!(
                "The given project dir '{}' does not exist.",
                project_dir
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project dir path."))?
            ));
        }

        // Traverse through the files within the specified source directories
        // and store them for analyzing purposes
        for src_dir in search_dirs {
            for ext in self.file_types {
                for dir in WalkDir::new(project_dir.join(src_dir).to_str().unwrap_or(".")) {
                    let entry = dir?;
                    if !entry.path().is_dir() && entry.path().extension() == Some(OsStr::new(ext)) {
                        if entry.path_is_symlink() {
                            self.project_files_mut()
                                .push(ProjectFile::new(read_link(entry.path())?));
                        } else {
                            self.project_files_mut()
                                .push(ProjectFile::new(entry.path()));
                        }
                    }
                }
            }
        }

        Ok(())
    }

    /// Extracts function signatures and comments of thinlines parsed files.
    pub fn extract_entities(&self) -> Fallible<()> {
        T::extract_entities(&self)
    }
}
<commit_msg>Fix description doc test<commit_after>use entity::Entity;
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use std::{
    cell::{Ref, RefCell, RefMut}, ffi::OsStr, fmt::{Display, Formatter, Result}, fs::read_link,
    marker::PhantomData, path::PathBuf,
};
use walkdir::WalkDir;

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed entity description.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Description {
    pub description: Vec<String>,
}

impl Description {
    /// Creates a new Description instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let description = Description::new();
    ///
    /// assert!(description.description.is_empty());
    /// ```
    pub fn new() -> Self {
        Self {
            description: Vec::new(),
        }
    }

    /// Sets and formats the description.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let mut description = Description::new();
    /// description.set("EQ[this->class_inst->TL_FCT(no1: no1, no2: 10) => 15]");
    ///
    /// assert_eq!(description.description.len(), 4);
    /// ```
    pub fn set(&mut self, description: &str) {
        self.description = description
            .split('\n')
            .map(|desc| {
                String::from(
                    desc.trim_left()
                        .trim_left_matches('*')
                        .trim_left_matches('/')
                        .trim_left(),
                )
            })
            .filter(|ref desc| !desc.is_empty() && desc.as_str() != "**")
            .map(|desc| {
                if desc.chars().next() == Some('#') {
                    desc.replace(" ", "")
                } else {
                    desc
                }
            })
            .collect();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
    pub value: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Self {
            name: name.into(),
            atype: atype.map(S::into),
            value: None,
        }
    }

    /// Sets a value to the argument.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// assert!(argument.value.is_some());
    ///
    /// ```
    pub fn set_value(&mut self, value: &str) {
        self.value = Some(String::from(value));
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Vec<Argument>,
    pub description: Option<Description>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_empty());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            return_type: None,
            arguments: Vec::new(),
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Fallible<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| err_msg("Function type can not be parsed from signature."))?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// # TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        if self.description.is_none() {
            self.description = Some(Description::new());
        }

        if let Some(desc) = &mut self.description {
            desc.set(description);
        }
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed enum argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Enum {
    pub name: String,
    pub etype: Option<String>,
    pub arguments: Vec<Argument>,
}

impl Enum {
    /// Creates a new Enum instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Enum;
    ///
    /// let enumeration = Enum::new("testEnum");
    ///
    /// assert_eq!(enumeration.name, String::from("testEnum"));
    /// assert!(enumeration.etype.is_none());
    /// assert!(enumeration.arguments.is_empty());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            etype: None,
            arguments: Vec::new(),
        }
    }

    /// Sets arguments for the Enum.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Argument, Enum};
    ///
    /// let mut enumeration = Enum::new("testEnum");
    /// let args = vec![Argument::new("Zero", Some("0")), Argument::new("Two", Some("2"))];
    /// enumeration.set_arguments(&args);
    ///
    /// assert_eq!(enumeration.arguments.len(), 2);
    /// ```
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed project file.
#[derive(Default, Clone, Debug)]
pub struct ProjectFile<T> {
    pub path: PathBuf,
    pub entities: RefCell<Vec<Entity>>,
    pub pf_type: PhantomData<T>,
}

impl<T> ProjectFile<T>
where
    T: LanguageType,
{
    /// Creates a new ProjectFile instance.
    ///
    /// # Example
    ///
    /// ```
    /// use std::path::PathBuf;
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    ///
    /// assert_eq!(project_file.path, PathBuf::from("test/project_file"));
    /// assert_eq!(project_file.entities().len(), 0);
    /// ```
    pub fn new<S: Into<PathBuf>>(path: S) -> Self {
        Self {
            path: path.into(),
            entities: RefCell::new(Vec::new()),
            pf_type: PhantomData,
        }
    }

    /// Returns a reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// assert_eq!(project_file.entities().len(), 1);
    /// ```
    pub fn entities(&self) -> Ref<Vec<Entity>> {
        self.entities.borrow()
    }

    /// Returns a mutable reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// let mut entities = project_file.entities_mut();
    /// assert_eq!(entities.len(), 1);
    ///
    /// entities.clear();
    /// assert_eq!(entities.len(), 0);
    /// ```
    pub fn entities_mut(&self) -> RefMut<Vec<Entity>> {
        self.entities.borrow_mut()
    }
}

impl<T> Display for ProjectFile<T>
where
    T: LanguageType,
{
    /// Formats a ProjectFile to be displayed by std output.
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(path) = self.path.to_str() {
            return write!(f, "{}", path);
        }
        write!(f, "Unable to stringify filename")
    }
}

////////////////////////////////////////////////////////////////////////////////

/// The analyzer which fulfills parsing and entity extraction tasks.
#[derive(Default, Debug)]
pub struct Analysis<T>
where
    T: LanguageType,
{
    pub file_types: &'static [&'static str],
    pub project_files: RefCell<Vec<ProjectFile<T>>>,
}

impl<T> Analysis<T>
where
    T: LanguageType,
{
    /// Creates a new Analysis instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Analysis;
    /// use thinlinelib::language_type::{C, LanguageType};
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    ///
    /// assert_eq!(analysis.file_types, C::file_types());
    /// assert_eq!(analysis.project_files().len(), 0);
    /// ```
    pub fn new() -> Self {
        Self {
            file_types: T::file_types(),
            project_files: RefCell::new(Vec::new()),
        }
    }

    /// Returns a reference to the collected project files for analysis.
    pub fn project_files(&self) -> Ref<Vec<ProjectFile<T>>> {
        self.project_files.borrow()
    }

    /// Returns a mutable reference to the collected project files for analysis.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Analysis, ProjectFile};
    /// use thinlinelib::language_type::C;
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    /// let mut project_files = analysis.project_files_mut();
    /// assert_eq!(project_files.len(), 0);
    ///
    /// project_files.push(ProjectFile::new("test/anotherFile"));
    /// assert_eq!(project_files.len(), 1);
    /// ```
    pub fn project_files_mut(&self) -> RefMut<Vec<ProjectFile<T>>> {
        self.project_files.borrow_mut()
    }

    /// Collects all the sources within the given project dir.
    /// Does also work for symlinked files.
    pub fn collect_sources(&self, project_dir: &PathBuf, search_dirs: &[String]) -> Fallible<()> {
        // Check the given project directory
        if !project_dir.exists() || !project_dir.is_dir() {
            return Err(format_err!(
                "The given project dir '{}' does not exist.",
                project_dir
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project dir path."))?
            ));
        }

        // Traverse through the files within the specified source directories
        // and store them for analyzing purposes
        for src_dir in search_dirs {
            for ext in self.file_types {
                for dir in WalkDir::new(project_dir.join(src_dir).to_str().unwrap_or(".")) {
                    let entry = dir?;
                    if !entry.path().is_dir() && entry.path().extension() == Some(OsStr::new(ext)) {
                        if entry.path_is_symlink() {
                            self.project_files_mut()
                                .push(ProjectFile::new(read_link(entry.path())?));
                        } else {
                            self.project_files_mut()
                                .push(ProjectFile::new(entry.path()));
                        }
                    }
                }
            }
        }

        Ok(())
    }

    /// Extracts function signatures and comments of thinlines parsed files.
    pub fn extract_entities(&self) -> Fallible<()> {
        T::extract_entities(&self)
    }
}
<|endoftext|>


<commit_before>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::hashmap::HashSet;
use std::either::{Either, Left, Right};
use std::vec;
use super::get_writer;

type HeadingOrStatus = Either<&'static str, Status>;

struct Status {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn StatusC(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Right(Status { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn StatusN(code: uint, reason: &'static str) -> HeadingOrStatus {
    Right(Status { code: code, reason: reason, comment: None })
}

impl Status {
    fn ident(&self) -> ~str {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> ~str {
        self.ident() + " ".repeat(unsafe { longest_ident } - self.ident().len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> ~str {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result: ~[Ascii] = vec::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.iter() {
        let c = match capitalise {
            true => c.to_ascii().to_upper(),
            false => c.to_ascii().to_lower(),
        };
        // For a space, capitalise the next char
        capitalise = c.to_byte() == (' ' as u8);
        if !capitalise {  // And also, for a space, don't keep it
            result.push(c);
        }
    }
    result.to_str_ascii()
}

static mut longest_ident: uint = 0;

pub fn generate() {
    let out = get_writer("status.rs");
    let entries = [
        Left("1xx Informational"),
        StatusN(100, "Continue"),
        StatusN(101, "Switching Protocols"),
        StatusC(102, "Processing", "WebDAV; RFC 2518"),

        Left("2xx Success"),
        StatusN(200, "OK"),
        StatusN(201, "Created"),
        StatusN(202, "Accepted"),
        StatusC(203, "Non-Authoritative Information", "since HTTP/1.1"),
        StatusN(204, "No Content"),
        StatusN(205, "Reset Content"),
        StatusN(206, "Partial Content"),
        StatusC(207, "Multi-Status", "WebDAV; RFC 4918"),
        StatusC(208, "Already Reported", "WebDAV; RFC 5842"),
        StatusC(226, "IM Used", "RFC 3229"),

        Left("3xx Redirection"),
        StatusN(300, "Multiple Choices"),
        StatusN(301, "Moved Permanently"),
        StatusN(302, "Found"),
        StatusC(303, "See Other", "since HTTP/1.1"),
        StatusN(304, "Not Modified"),
        StatusC(305, "Use Proxy", "since HTTP/1.1"),
        StatusN(306, "Switch Proxy"),
        StatusC(307, "Temporary Redirect", "since HTTP/1.1"),
        StatusC(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Left("4xx Client Error"),
        StatusN(400, "Bad Request"),
        StatusN(401, "Unauthorized"),
        StatusN(402, "Payment Required"),
        StatusN(403, "Forbidden"),
        StatusN(404, "Not Found"),
        StatusN(405, "Method Not Allowed"),
        StatusN(406, "Not Acceptable"),
        StatusN(407, "Proxy Authentication Required"),
        StatusN(408, "Request Timeout"),
        StatusN(409, "Conflict"),
        StatusN(410, "Gone"),
        StatusN(411, "Length Required"),
        StatusN(412, "Precondition Failed"),
        StatusN(413, "Request Entity Too Large"),
        StatusN(414, "Request-URI Too Long"),
        StatusN(415, "Unsupported Media Type"),
        StatusN(416, "Requested Range Not Satisfiable"),
        StatusN(417, "Expectation Failed"),
        StatusC(418, "I'm a teapot", "RFC 2324"),
        StatusN(419, "Authentication Timeout"),
        StatusC(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        StatusC(423, "Locked", "WebDAV; RFC 4918"),
        StatusC(424, "Failed Dependency", "WebDAV; RFC 4918"),
        StatusC(424, "Method Failure", "WebDAV"),
        StatusC(425, "Unordered Collection", "Internet draft"),
        StatusC(426, "Upgrade Required", "RFC 2817"),
        StatusC(428, "Precondition Required", "RFC 6585"),
        StatusC(429, "Too Many Requests", "RFC 6585"),
        StatusC(431, "Request Header Fields Too Large", "RFC 6585"),
        StatusC(451, "Unavailable For Legal Reasons", "Internet draft"),

        Left("5xx Server Error"),
        StatusN(500, "Internal Server Error"),
        StatusN(501, "Not Implemented"),
        StatusN(502, "Bad Gateway"),
        StatusN(503, "Service Unavailable"),
        StatusN(504, "Gateway Timeout"),
        StatusN(505, "HTTP Version Not Supported"),
        StatusC(506, "Variant Also Negotiates", "RFC 2295"),
        StatusC(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        StatusC(508, "Loop Detected", "WebDAV; RFC 5842"),
        StatusC(510, "Not Extended", "RFC 2774"),
        StatusC(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().transform(|&e| match e {
            Left(_heading) => 0,
            Right(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
    }
    out.write_str("// This file is automatically generated file is used as rusthttpserver::status.

use std::num::IntConvertible;

/// HTTP status code
#[deriving(Eq)]
pub enum Status {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n    // %s\n", heading)),
            Right(status) => match status.comment {
                None => out.write_str(fmt!("    %s,\n", status.ident())),
                Some(comment) => out.write_str(fmt!("    %s,  // %s\n", status.ident(), comment)),
            },
        }
    }

    out.write_str("
    UnregisteredStatus(u16, ~str),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => out.write_str(fmt!("            %s => %u,\n",
                                                status.padded_ident(), status.code)),
        }
    }
    out.write_str("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> ~str {
        match *self {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => out.write_str(fmt!("            %s => ~\"%s\",\n",
                                                status.padded_ident(), status.reason))
        }
    }
    out.write_str("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }
}

impl ToStr for Status {
    /// Produce the HTTP status message incorporating both code and message,
    /// e.g. `ImATeapot.to_str() == \"418 I'm a teapot\"`
	pub fn to_str(&self) -> ~str {
		fmt!(\"%? %s\", self.code(), self.reason())
	}
}

impl IntConvertible for Status {

    /// Equivalent to `self.code()`
    pub fn to_int(&self) -> int {
        self.code() as int
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will fail if an unknown code is passed.
    ///
    /// For example, `from_int(200)` will return `OK`.
    pub fn from_int(n: int) -> Status {
        match n {
");
    let mut matched_numbers = HashSet::new::<uint>();
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    out.write_str(fmt!("            %u => %s,\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write_str("
            _   => { fail!(fmt!(\"No registered HTTP status code %d\", n)); }
        }
    }
}");
}
<commit_msg>Add Status::from_code_and_reason.<commit_after>// These are taken from http://en.wikipedia.org/wiki/List_of_HTTP_Status_Codes.
// Last updated on 2013-07-04
// Entries from third-party vendors not standardised upon are not included.
// If not specified otherwise, they are defined in RFC 2616.

// Yes, this is ugly code.
// No, I don't mind.
// That was easy. :-)

use std::ascii::to_ascii_lower;
use std::hashmap::HashSet;
use std::either::{Either, Left, Right};
use std::vec;
use super::get_writer;

type HeadingOrStatus = Either<&'static str, Status>;

struct Status {
    code: uint,
    reason: &'static str,
    comment: Option<&'static str>,
}

/// Status with comment
fn StatusC(code: uint, reason: &'static str, comment: &'static str) -> HeadingOrStatus {
    Right(Status { code: code, reason: reason, comment: Some(comment) })
}

/// Status without comment
fn StatusN(code: uint, reason: &'static str) -> HeadingOrStatus {
    Right(Status { code: code, reason: reason, comment: None })
}

impl Status {
    fn ident(&self) -> ~str {
        camel_case(self.reason)
    }

    fn padded_ident(&self) -> ~str {
        self.ident() + " ".repeat(unsafe { longest_ident } - self.ident().len())
    }

    fn reason_padding_spaces(&self) -> ~str {
        " ".repeat(unsafe { longest_reason } - self.reason.len())
    }
}

/// >>> camel_case("I'm a Tea-pot")
/// "ImATeaPot"
fn camel_case(msg: &str) -> ~str {
    let msg = msg.replace("-", " ").replace("'", "");
    let mut result: ~[Ascii] = vec::with_capacity(msg.len());
    let mut capitalise = true;
    for c in msg.iter() {
        let c = match capitalise {
            true => c.to_ascii().to_upper(),
            false => c.to_ascii().to_lower(),
        };
        // For a space, capitalise the next char
        capitalise = c.to_byte() == (' ' as u8);
        if !capitalise {  // And also, for a space, don't keep it
            result.push(c);
        }
    }
    result.to_str_ascii()
}

static mut longest_ident: uint = 0;
static mut longest_reason: uint = 0;

pub fn generate() {
    let out = get_writer("status.rs");
    let entries = [
        Left("1xx Informational"),
        StatusN(100, "Continue"),
        StatusN(101, "Switching Protocols"),
        StatusC(102, "Processing", "WebDAV; RFC 2518"),

        Left("2xx Success"),
        StatusN(200, "OK"),
        StatusN(201, "Created"),
        StatusN(202, "Accepted"),
        StatusC(203, "Non-Authoritative Information", "since HTTP/1.1"),
        StatusN(204, "No Content"),
        StatusN(205, "Reset Content"),
        StatusN(206, "Partial Content"),
        StatusC(207, "Multi-Status", "WebDAV; RFC 4918"),
        StatusC(208, "Already Reported", "WebDAV; RFC 5842"),
        StatusC(226, "IM Used", "RFC 3229"),

        Left("3xx Redirection"),
        StatusN(300, "Multiple Choices"),
        StatusN(301, "Moved Permanently"),
        StatusN(302, "Found"),
        StatusC(303, "See Other", "since HTTP/1.1"),
        StatusN(304, "Not Modified"),
        StatusC(305, "Use Proxy", "since HTTP/1.1"),
        StatusN(306, "Switch Proxy"),
        StatusC(307, "Temporary Redirect", "since HTTP/1.1"),
        StatusC(308, "Permanent Redirect", "approved as experimental RFC: http://tools.ietf.org/html/draft-reschke-http-status-308"),

        Left("4xx Client Error"),
        StatusN(400, "Bad Request"),
        StatusN(401, "Unauthorized"),
        StatusN(402, "Payment Required"),
        StatusN(403, "Forbidden"),
        StatusN(404, "Not Found"),
        StatusN(405, "Method Not Allowed"),
        StatusN(406, "Not Acceptable"),
        StatusN(407, "Proxy Authentication Required"),
        StatusN(408, "Request Timeout"),
        StatusN(409, "Conflict"),
        StatusN(410, "Gone"),
        StatusN(411, "Length Required"),
        StatusN(412, "Precondition Failed"),
        StatusN(413, "Request Entity Too Large"),
        StatusN(414, "Request-URI Too Long"),
        StatusN(415, "Unsupported Media Type"),
        StatusN(416, "Requested Range Not Satisfiable"),
        StatusN(417, "Expectation Failed"),
        StatusC(418, "I'm a teapot", "RFC 2324"),
        StatusN(419, "Authentication Timeout"),
        StatusC(422, "Unprocessable Entity", "WebDAV; RFC 4918"),
        StatusC(423, "Locked", "WebDAV; RFC 4918"),
        StatusC(424, "Failed Dependency", "WebDAV; RFC 4918"),
        StatusC(424, "Method Failure", "WebDAV"),
        StatusC(425, "Unordered Collection", "Internet draft"),
        StatusC(426, "Upgrade Required", "RFC 2817"),
        StatusC(428, "Precondition Required", "RFC 6585"),
        StatusC(429, "Too Many Requests", "RFC 6585"),
        StatusC(431, "Request Header Fields Too Large", "RFC 6585"),
        StatusC(451, "Unavailable For Legal Reasons", "Internet draft"),

        Left("5xx Server Error"),
        StatusN(500, "Internal Server Error"),
        StatusN(501, "Not Implemented"),
        StatusN(502, "Bad Gateway"),
        StatusN(503, "Service Unavailable"),
        StatusN(504, "Gateway Timeout"),
        StatusN(505, "HTTP Version Not Supported"),
        StatusC(506, "Variant Also Negotiates", "RFC 2295"),
        StatusC(507, "Insufficient Storage", "WebDAV; RFC 4918"),
        StatusC(508, "Loop Detected", "WebDAV; RFC 5842"),
        StatusC(510, "Not Extended", "RFC 2774"),
        StatusC(511, "Network Authentication Required", "RFC 6585"),
        ];
    unsafe {
        longest_ident = entries.iter().transform(|&e| match e {
            Left(_heading) => 0,
            Right(status) => status.ident().len(),
        }).max_by(|&i| i).unwrap();
        longest_reason = entries.iter().transform(|&e| match e {
            Left(_heading) => 0,
            Right(status) => status.reason.len(),
        }).max_by(|&i| i).unwrap();
    }
    out.write_str("// This file is automatically generated file is used as rusthttpserver::status.

use std::num::IntConvertible;
use std::ascii::to_ascii_lower;

/// HTTP status code
#[deriving(Eq)]
pub enum Status {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n    // %s\n", heading)),
            Right(status) => match status.comment {
                None => out.write_str(fmt!("    %s,\n", status.ident())),
                Some(comment) => out.write_str(fmt!("    %s,  // %s\n", status.ident(), comment)),
            },
        }
    }

    out.write_str("
    UnregisteredStatus(u16, ~str),
}

impl Status {

    /// Get the status code
    pub fn code(&self) -> u16 {
        match *self {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => out.write_str(fmt!("            %s => %u,\n",
                                                status.padded_ident(), status.code)),
        }
    }
    out.write_str("
            UnregisteredStatus(code, _)   => code,
        }
    }

    /// Get the reason phrase
    pub fn reason(&self) -> ~str {
        match *self {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => out.write_str(fmt!("            %s => ~\"%s\",\n",
                                                status.padded_ident(), status.reason))
        }
    }
    out.write_str("
            UnregisteredStatus(_, ref reason) => (*reason).clone(),
        }
    }

    /// Get a status from the code and reason
    pub fn from_code_and_reason(status: u16, reason: ~str) -> Status {
        let reason_lower = to_ascii_lower(reason);
        match (status, reason_lower.as_slice()) {
");
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => out.write_str(fmt!("            (%?, \"%s\")%s => %s,\n",
                                                status.code,
                                                to_ascii_lower(status.reason),
                                                status.reason_padding_spaces(),
                                                status.ident())),
        }
    }
    out.write_str("
            (_, _) => UnregisteredStatus(status, reason),
        }
    }
}

impl ToStr for Status {
    /// Produce the HTTP status message incorporating both code and message,
    /// e.g. `ImATeapot.to_str() == \"418 I'm a teapot\"`
	pub fn to_str(&self) -> ~str {
		fmt!(\"%? %s\", self.code(), self.reason())
	}
}

impl IntConvertible for Status {

    /// Equivalent to `self.code()`
    pub fn to_int(&self) -> int {
        self.code() as int
    }

    /// Get a *registered* status code from the number of its status code.
    ///
    /// This will fail if an unknown code is passed.
    ///
    /// For example, `from_int(200)` will return `OK`.
    pub fn from_int(n: int) -> Status {
        match n {
");
    let mut matched_numbers = HashSet::new::<uint>();
    for &entry in entries.iter() {
        match entry {
            Left(heading) => out.write_str(fmt!("\n            // %s\n", heading)),
            Right(status) => {
                if !matched_numbers.contains(&status.code) {
                    // Purpose: FailedDependency and MethodFailure both use 424,
                    // but clearly they mustn't both go in here
                    out.write_str(fmt!("            %u => %s,\n", status.code, status.ident()));
                    matched_numbers.insert(status.code);
                }
            },
        }
    }
    out.write_str("
            _   => { fail!(fmt!(\"No registered HTTP status code %d\", n)); }
        }
    }
}");
}
<|endoftext|>


<commit_before>//! Unwinding for *hermit* target.
//!
//! Right now we don't support this, so this is just stubs.

use alloc::boxed::Box;
use core::any::Any;
use core::ptr;

pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
    extern "C" {
        pub fn __rust_abort() -> !;
    }
    __rust_abort();
}

pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
    extern "C" {
        pub fn __rust_abort() -> !;
    }
    __rust_abort();
}
<commit_msg>remove unused imports<commit_after>//! Unwinding for *hermit* target.
//!
//! Right now we don't support this, so this is just stubs.

use alloc::boxed::Box;
use core::any::Any;

pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
    extern "C" {
        pub fn __rust_abort() -> !;
    }
    __rust_abort();
}

pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
    extern "C" {
        pub fn __rust_abort() -> !;
    }
    __rust_abort();
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>Rollup merge of #84330 - GuillaumeGomez:remove-footer, r=jyn514<commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" class=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<|endoftext|>


<commit_before>import std::map::{hashmap};
import ast_util::spanned;
import parser::parser;

type seq_sep = {
    sep: option<token::token>,
    trailing_opt: bool   // is trailing separator optional?
};

fn seq_sep(t: token::token) -> seq_sep {
    ret {sep: option::some(t), trailing_opt: false};
}
fn seq_sep_opt(t: token::token) -> seq_sep {
    ret {sep: option::some(t), trailing_opt: true};
}
fn seq_sep_none() -> seq_sep {
    ret {sep: option::none, trailing_opt: false};
}

fn token_to_str(reader: reader, ++token: token::token) -> str {
    token::to_str(*reader.interner, token)
}

// This should be done with traits, once traits work
impl parser_common for parser {

    fn unexpected_last(t: token::token) -> ! {
        self.span_fatal(
            copy self.last_span,
            "unexpected token: '" + token_to_str(self.reader, t) + "'");
    }

    fn unexpected() -> ! {
        self.fatal("unexpected token: '"
                   + token_to_str(self.reader, self.token) + "'");
    }

    fn expect(t: token::token) {
        if self.token == t {
            self.bump();
        } else {
            let mut s: str = "expecting '";
            s += token_to_str(self.reader, t);
            s += "' but found '";
            s += token_to_str(self.reader, self.token);
            self.fatal(s + "'");
        }
    }

    fn parse_ident() -> ast::ident {
        alt copy self.token {
          token::IDENT(i, _) { self.bump(); ret self.get_str(i); }
          _ { self.fatal("expecting ident, found "
                      + token_to_str(self.reader, self.token)); }
        }
    }

    fn parse_path_list_ident() -> ast::path_list_ident {
        let lo = self.span.lo;
        let ident = self.parse_ident();
        let hi = self.span.hi;
        ret spanned(lo, hi, {name: ident, id: self.get_id()});
    }

    fn parse_value_ident() -> ast::ident {
        self.check_restricted_keywords();
        ret self.parse_ident();
    }

    fn eat(tok: token::token) -> bool {
        ret if self.token == tok { self.bump(); true } else { false };
    }

    // A sanity check that the word we are asking for is a known keyword
    fn require_keyword(word: str) {
        if !self.keywords.contains_key(word) {
            self.bug(#fmt("unknown keyword: %s", word));
        }
    }

    fn token_is_keyword(word: str, ++tok: token::token) -> bool {
        self.require_keyword(word);
        alt tok {
          token::IDENT(sid, false) { str::eq(word, self.get_str(sid)) }
          _ { false }
        }
    }

    fn is_keyword(word: str) -> bool {
        self.token_is_keyword(word, self.token)
    }

    fn eat_keyword(word: str) -> bool {
        self.require_keyword(word);
        alt copy self.token {
          token::IDENT(sid, false) {
            if str::eq(word, self.get_str(sid)) {
                self.bump();
                ret true;
            } else { ret false; }
          }
          _ { ret false; }
        }
    }

    fn expect_keyword(word: str) {
        self.require_keyword(word);
        if !self.eat_keyword(word) {
            self.fatal("expecting " + word + ", found " +
                    token_to_str(self.reader, self.token));
    }
}

    fn is_restricted_keyword(word: str) -> bool {
        self.restricted_keywords.contains_key(word)
    }

    fn check_restricted_keywords() {
        alt self.token {
          token::IDENT(_, false) {
            let w = token_to_str(self.reader, self.token);
            self.check_restricted_keywords_(w);
          }
          _ { }
        }
    }

    fn check_restricted_keywords_(w: ast::ident) {
        if self.is_restricted_keyword(w) {
            self.fatal("found `" + w + "` in restricted position");
        }
    }

    fn expect_gt() {
        if self.token == token::GT {
            self.bump();
        } else if self.token == token::BINOP(token::SHR) {
            self.swap(token::GT, self.span.lo + 1u, self.span.hi);
        } else {
            let mut s: str = "expecting ";
            s += token_to_str(self.reader, token::GT);
            s += ", found ";
            s += token_to_str(self.reader, self.token);
            self.fatal(s);
        }
    }

    fn parse_seq_to_before_gt<T: copy>(sep: option<token::token>,
                                       f: fn(parser) -> T) -> [T] {
        let mut first = true;
        let mut v = [];
        while self.token != token::GT
            && self.token != token::BINOP(token::SHR) {
            alt sep {
              some(t) { if first { first = false; }
                       else { self.expect(t); } }
              _ { }
            }
            v += [f(self)];
        }

        ret v;
    }

    fn parse_seq_to_gt<T: copy>(sep: option<token::token>,
                                f: fn(parser) -> T) -> [T] {
        let v = self.parse_seq_to_before_gt(sep, f);
        self.expect_gt();

        ret v;
    }

    fn parse_seq_lt_gt<T: copy>(sep: option<token::token>,
                                f: fn(parser) -> T) -> spanned<[T]> {
        let lo = self.span.lo;
        self.expect(token::LT);
        let result = self.parse_seq_to_before_gt::<T>(sep, f);
        let hi = self.span.hi;
        self.expect_gt();
        ret spanned(lo, hi, result);
    }

    fn parse_seq_to_end<T: copy>(ket: token::token, sep: seq_sep,
                                 f: fn(parser) -> T) -> [T] {
        let val = self.parse_seq_to_before_end(ket, sep, f);
        self.bump();
        ret val;
    }

    fn parse_seq_to_before_end<T: copy>(ket: token::token, sep: seq_sep,
                                        f: fn(parser) -> T) -> [T] {
        let mut first: bool = true;
        let mut v: [T] = [];
        while self.token != ket {
            alt sep.sep {
              some(t) { if first { first = false; }
                        else { self.expect(t); } }
              _ { }
            }
            if sep.trailing_opt && self.token == ket { break; }
            v += [f(self)];
        }
        ret v;
    }

    fn parse_seq<T: copy>(bra: token::token, ket: token::token, sep: seq_sep,
                          f: fn(parser) -> T) -> spanned<[T]> {
        let lo = self.span.lo;
        self.expect(bra);
        let result = self.parse_seq_to_before_end::<T>(ket, sep, f);
        let hi = self.span.hi;
        self.bump();
        ret spanned(lo, hi, result);
    }
}<commit_msg>workaround LLVM bug #13042<commit_after>import std::map::{hashmap};
import ast_util::spanned;
import parser::parser;

type seq_sep = {
    sep: option<token::token>,
    trailing_opt: bool   // is trailing separator optional?
};

fn seq_sep(t: token::token) -> seq_sep {
    ret {sep: option::some(t), trailing_opt: false};
}
fn seq_sep_opt(t: token::token) -> seq_sep {
    ret {sep: option::some(t), trailing_opt: true};
}
fn seq_sep_none() -> seq_sep {
    ret {sep: option::none, trailing_opt: false};
}

fn token_to_str(reader: reader, ++token: token::token) -> str {
    token::to_str(*reader.interner, token)
}

// This should be done with traits, once traits work
impl parser_common for parser {

    fn unexpected_last(t: token::token) -> ! {
        self.span_fatal(
            copy self.last_span,
            "unexpected token: '" + token_to_str(self.reader, t) + "'");
    }

    fn unexpected() -> ! {
        self.fatal("unexpected token: '"
                   + token_to_str(self.reader, self.token) + "'");
    }

    fn expect(t: token::token) {
        if self.token == t {
            self.bump();
        } else {
            let mut s: str = "expecting '";
            s += token_to_str(self.reader, t);
            s += "' but found '";
            s += token_to_str(self.reader, self.token);
            self.fatal(s + "'");
        }
    }

    fn parse_ident() -> ast::ident {
        alt copy self.token {
          token::IDENT(i, _) { self.bump(); ret self.get_str(i); }
          _ { self.fatal("expecting ident, found "
                      + token_to_str(self.reader, self.token)); }
        }
    }

    fn parse_path_list_ident() -> ast::path_list_ident {
        let lo = self.span.lo;
        let ident = self.parse_ident();
        let hi = self.span.hi;
        ret spanned(lo, hi, {name: ident, id: self.get_id()});
    }

    fn parse_value_ident() -> ast::ident {
        self.check_restricted_keywords();
        ret self.parse_ident();
    }

    fn eat(tok: token::token) -> bool {
        ret if self.token == tok { self.bump(); true } else { false };
    }

    // A sanity check that the word we are asking for is a known keyword
    fn require_keyword(word: str) {
        if !self.keywords.contains_key(word) {
            self.bug(#fmt("unknown keyword: %s", word));
        }
    }

    fn token_is_keyword(word: str, ++tok: token::token) -> bool {
        self.require_keyword(word);
        alt tok {
          token::IDENT(sid, false) { str::eq(word, self.get_str(sid)) }
          _ { false }
        }
    }

    fn is_keyword(word: str) -> bool {
        self.token_is_keyword(word, self.token)
    }

    fn eat_keyword(word: str) -> bool {
        self.require_keyword(word);

        // FIXME: this gratuitous use of @ is to
        // workaround LLVM bug #13042
        alt @self.token {
          @token::IDENT(sid, false) {
            if str::eq(word, self.get_str(sid)) {
                self.bump();
                ret true;
            } else { ret false; }
          }
          _ { ret false; }
        }
    }

    fn expect_keyword(word: str) {
        self.require_keyword(word);
        if !self.eat_keyword(word) {
            self.fatal("expecting " + word + ", found " +
                    token_to_str(self.reader, self.token));
    }
}

    fn is_restricted_keyword(word: str) -> bool {
        self.restricted_keywords.contains_key(word)
    }

    fn check_restricted_keywords() {
        alt self.token {
          token::IDENT(_, false) {
            let w = token_to_str(self.reader, self.token);
            self.check_restricted_keywords_(w);
          }
          _ { }
        }
    }

    fn check_restricted_keywords_(w: ast::ident) {
        if self.is_restricted_keyword(w) {
            self.fatal("found `" + w + "` in restricted position");
        }
    }

    fn expect_gt() {
        if self.token == token::GT {
            self.bump();
        } else if self.token == token::BINOP(token::SHR) {
            self.swap(token::GT, self.span.lo + 1u, self.span.hi);
        } else {
            let mut s: str = "expecting ";
            s += token_to_str(self.reader, token::GT);
            s += ", found ";
            s += token_to_str(self.reader, self.token);
            self.fatal(s);
        }
    }

    fn parse_seq_to_before_gt<T: copy>(sep: option<token::token>,
                                       f: fn(parser) -> T) -> [T] {
        let mut first = true;
        let mut v = [];
        while self.token != token::GT
            && self.token != token::BINOP(token::SHR) {
            alt sep {
              some(t) { if first { first = false; }
                       else { self.expect(t); } }
              _ { }
            }
            v += [f(self)];
        }

        ret v;
    }

    fn parse_seq_to_gt<T: copy>(sep: option<token::token>,
                                f: fn(parser) -> T) -> [T] {
        let v = self.parse_seq_to_before_gt(sep, f);
        self.expect_gt();

        ret v;
    }

    fn parse_seq_lt_gt<T: copy>(sep: option<token::token>,
                                f: fn(parser) -> T) -> spanned<[T]> {
        let lo = self.span.lo;
        self.expect(token::LT);
        let result = self.parse_seq_to_before_gt::<T>(sep, f);
        let hi = self.span.hi;
        self.expect_gt();
        ret spanned(lo, hi, result);
    }

    fn parse_seq_to_end<T: copy>(ket: token::token, sep: seq_sep,
                                 f: fn(parser) -> T) -> [T] {
        let val = self.parse_seq_to_before_end(ket, sep, f);
        self.bump();
        ret val;
    }

    fn parse_seq_to_before_end<T: copy>(ket: token::token, sep: seq_sep,
                                        f: fn(parser) -> T) -> [T] {
        let mut first: bool = true;
        let mut v: [T] = [];
        while self.token != ket {
            alt sep.sep {
              some(t) { if first { first = false; }
                        else { self.expect(t); } }
              _ { }
            }
            if sep.trailing_opt && self.token == ket { break; }
            v += [f(self)];
        }
        ret v;
    }

    fn parse_seq<T: copy>(bra: token::token, ket: token::token, sep: seq_sep,
                          f: fn(parser) -> T) -> spanned<[T]> {
        let lo = self.span.lo;
        self.expect(bra);
        let result = self.parse_seq_to_before_end::<T>(ket, sep, f);
        let hi = self.span.hi;
        self.bump();
        ret spanned(lo, hi, result);
    }
}<|endoftext|>