<commit_before>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters (in non-Rust files).
//! * No files with over 3000 lines (in non-Rust files).
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! Note that some of these rules are excluded from Rust files because we enforce rustfmt. It is
//! preferable to be formatted rather than tidy-clean.
//!
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.

use std::path::Path;

const ERROR_CODE_COLS: usize = 80;
const COLS: usize = 100;

const LINES: usize = 3000;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(columns: usize, line: &str) -> bool {
    // more basic check for error_codes.rs, to avoid complexity in implementing two state machines
    if columns == ERROR_CODE_COLS {
        return line.starts_with('[') && line.contains("]:") && line.contains("http");
    }

    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;
    let is_url = |w: &str| w.starts_with("http://") || w.starts_with("https://");

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") | (EXP_COMMENT_START, "///") | (EXP_COMMENT_START, "//!") => {
                state = EXP_LINK_LABEL_OR_URL
            }

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:") =>
            {
                state = EXP_URL
            }

            (EXP_LINK_LABEL_OR_URL, w) if is_url(w) => state = EXP_END,

            (EXP_URL, w) if is_url(w) || w.starts_with("../") => state = EXP_END,

            (_, w) if w.len() > columns && is_url(w) => state = EXP_END,

            (_, _) => {}
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(max_columns: usize, line: &str) -> bool {
    if line_is_url(max_columns, line) {
        return true;
    }

    false
}

enum Directive {
    /// By default, tidy always warns against style issues.
    Deny,

    /// `Ignore(false)` means that an `ignore-tidy-*` directive
    /// has been provided, but is unnecessary. `Ignore(true)`
    /// means that it is necessary (i.e. a warning would be
    /// produced if `ignore-tidy-*` was not present).
    Ignore(bool),
}

fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
    if !can_contain {
        return Directive::Deny;
    }
    // Update `can_contain` when changing this
    if contents.contains(&format!("// ignore-tidy-{}", check))
        || contents.contains(&format!("# ignore-tidy-{}", check))
    {
        Directive::Ignore(false)
    } else {
        Directive::Deny
    }
}

macro_rules! suppressible_tidy_err {
    ($err:ident, $skip:ident, $msg:expr) => {
        if let Directive::Deny = $skip {
            $err($msg);
        } else {
            $skip = Directive::Ignore(true);
        }
    };
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md"];
        if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
            return;
        }

        let under_rustfmt = filename.ends_with(".rs") &&
            // This list should ideally be sourced from rustfmt.toml but we don't want to add a toml
            // parser to tidy.
            !file.ancestors().any(|a| {
                a.ends_with("src/test") ||
                    a.ends_with("src/libstd/sys/cloudabi") ||
                    a.ends_with("src/doc/book")
            });

        if filename.ends_with(".md")
            && file.parent().unwrap().file_name().unwrap().to_string_lossy() != "error_codes"
        {
            // We don't want to check all ".md" files (almost of of them aren't compliant
            // currently), just the long error code explanation ones.
            return;
        }

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let max_columns = if filename == "error_codes.rs" || filename.ends_with(".md") {
            ERROR_CODE_COLS
        } else {
            COLS
        };

        let can_contain =
            contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-");
        // Enable testing ICE's that require specific (untidy)
        // file formats easily eg. `issue-1234-ignore-tidy.rs`
        if filename.contains("ignore-tidy") {
            return;
        }
        let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
        let mut skip_undocumented_unsafe =
            contains_ignore_directive(can_contain, &contents, "undocumented-unsafe");
        let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
        let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
        let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
        let mut skip_end_whitespace =
            contains_ignore_directive(can_contain, &contents, "end-whitespace");
        let mut skip_trailing_newlines =
            contains_ignore_directive(can_contain, &contents, "trailing-newlines");
        let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        let mut lines = 0;
        let mut last_safety_comment = false;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if !under_rustfmt
                && line.chars().count() > max_columns
                && !long_line_is_ok(max_columns, line)
            {
                suppressible_tidy_err!(
                    err,
                    skip_line_length,
                    &format!("line longer than {} chars", max_columns)
                );
            }
            if line.contains('\t') {
                suppressible_tidy_err!(err, skip_tab, "tab character");
            }
            if line.ends_with(' ') || line.ends_with('\t') {
                suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace");
            }
            if line.contains('\r') {
                suppressible_tidy_err!(err, skip_cr, "CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            let is_test = || file.components().any(|c| c.as_os_str() == "tests");
            // for now we just check libcore
            if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
                if file.components().any(|c| c.as_os_str() == "libcore") && !is_test() {
                    suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
                }
            }
            if line.contains("// SAFETY: ") || line.contains("// Safety: ") {
                last_safety_comment = true;
            } else if line.trim().starts_with("//") || line.trim().is_empty() {
                // keep previous value
            } else {
                last_safety_comment = false;
            }
            if (line.starts_with("// Copyright")
                || line.starts_with("# Copyright")
                || line.starts_with("Copyright"))
                && (line.contains("Rust Developers") || line.contains("Rust Project Developers"))
            {
                suppressible_tidy_err!(
                    err,
                    skip_copyright,
                    "copyright notices attributed to the Rust Project Developers are deprecated"
                );
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
            lines = i;
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        let mut err = |msg: &str| {
            tidy_error!(bad, "{}: {}", file.display(), msg);
        };
        match trailing_new_lines {
            0 => suppressible_tidy_err!(err, skip_trailing_newlines, "missing trailing newline"),
            1 => {}
            n => suppressible_tidy_err!(
                err,
                skip_trailing_newlines,
                &format!("too many trailing newlines ({})", n)
            ),
        };
        if lines > LINES {
            let mut err = |_| {
                tidy_error!(
                    bad,
                    "{}: too many lines ({}) (add `// \
                     ignore-tidy-filelength` to the file to suppress this error)",
                    file.display(),
                    lines
                );
            };
            suppressible_tidy_err!(err, skip_file_length, "");
        }

        if let Directive::Ignore(false) = skip_cr {
            tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_tab {
            tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_line_length {
            tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_file_length {
            tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_end_whitespace {
            tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_trailing_newlines {
            tidy_error!(bad, "{}: ignoring trailing newlines unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_copyright {
            tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
        }
    })
}
<commit_msg>Add tidy checks for rustdoc css files<commit_after>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters (in non-Rust files).
//! * No files with over 3000 lines (in non-Rust files).
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! Note that some of these rules are excluded from Rust files because we enforce rustfmt. It is
//! preferable to be formatted rather than tidy-clean.
//!
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.

use std::path::Path;

const ERROR_CODE_COLS: usize = 80;
const COLS: usize = 100;

const LINES: usize = 3000;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(columns: usize, line: &str) -> bool {
    // more basic check for error_codes.rs, to avoid complexity in implementing two state machines
    if columns == ERROR_CODE_COLS {
        return line.starts_with('[') && line.contains("]:") && line.contains("http");
    }

    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;
    let is_url = |w: &str| w.starts_with("http://") || w.starts_with("https://");

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") | (EXP_COMMENT_START, "///") | (EXP_COMMENT_START, "//!") => {
                state = EXP_LINK_LABEL_OR_URL
            }

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:") =>
            {
                state = EXP_URL
            }

            (EXP_LINK_LABEL_OR_URL, w) if is_url(w) => state = EXP_END,

            (EXP_URL, w) if is_url(w) || w.starts_with("../") => state = EXP_END,

            (_, w) if w.len() > columns && is_url(w) => state = EXP_END,

            (_, _) => {}
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(max_columns: usize, line: &str) -> bool {
    if line_is_url(max_columns, line) {
        return true;
    }

    false
}

enum Directive {
    /// By default, tidy always warns against style issues.
    Deny,

    /// `Ignore(false)` means that an `ignore-tidy-*` directive
    /// has been provided, but is unnecessary. `Ignore(true)`
    /// means that it is necessary (i.e. a warning would be
    /// produced if `ignore-tidy-*` was not present).
    Ignore(bool),
}

fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
    if !can_contain {
        return Directive::Deny;
    }
    // Update `can_contain` when changing this
    if contents.contains(&format!("// ignore-tidy-{}", check))
        || contents.contains(&format!("# ignore-tidy-{}", check))
        || contents.contains(&format!("/* ignore-tidy-{} */", check))
    {
        Directive::Ignore(false)
    } else {
        Directive::Deny
    }
}

macro_rules! suppressible_tidy_err {
    ($err:ident, $skip:ident, $msg:expr) => {
        if let Directive::Deny = $skip {
            $err($msg);
        } else {
            $skip = Directive::Ignore(true);
        }
    };
}

pub fn is_in(full_path: &Path, parent_folder_to_find: &str, folder_to_find: &str) -> bool {
    if let Some(parent) = full_path.parent() {
        if parent.file_name().map_or_else(
            || false,
            |f| {
                f.to_string_lossy() == folder_to_find
                    && parent
                        .parent()
                        .and_then(|f| f.file_name())
                        .map_or_else(|| false, |f| f == parent_folder_to_find)
            },
        ) {
            true
        } else {
            is_in(parent, parent_folder_to_find, folder_to_find)
        }
    } else {
        false
    }
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css"];
        if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
            return;
        }

        let is_style_file = filename.ends_with(".css");
        let under_rustfmt = filename.ends_with(".rs") &&
            // This list should ideally be sourced from rustfmt.toml but we don't want to add a toml
            // parser to tidy.
            !file.ancestors().any(|a| {
                a.ends_with("src/test") ||
                    a.ends_with("src/libstd/sys/cloudabi") ||
                    a.ends_with("src/doc/book")
            });

        if filename.ends_with(".md")
            && file.parent().unwrap().file_name().unwrap().to_string_lossy() != "error_codes"
        {
            // We don't want to check all ".md" files (almost of of them aren't compliant
            // currently), just the long error code explanation ones.
            return;
        }
        if is_style_file && !is_in(file, "src", "librustdoc") {
            // We only check CSS files in rustdoc.
            return;
        }

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let max_columns = if filename == "error_codes.rs" || filename.ends_with(".md") {
            ERROR_CODE_COLS
        } else {
            COLS
        };

        let can_contain = contents.contains("// ignore-tidy-")
            || contents.contains("# ignore-tidy-")
            || contents.contains("/* ignore-tidy-");
        // Enable testing ICE's that require specific (untidy)
        // file formats easily eg. `issue-1234-ignore-tidy.rs`
        if filename.contains("ignore-tidy") {
            return;
        }
        let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
        let mut skip_undocumented_unsafe =
            contains_ignore_directive(can_contain, &contents, "undocumented-unsafe");
        let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
        let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
        let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
        let mut skip_end_whitespace =
            contains_ignore_directive(can_contain, &contents, "end-whitespace");
        let mut skip_trailing_newlines =
            contains_ignore_directive(can_contain, &contents, "trailing-newlines");
        let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        let mut lines = 0;
        let mut last_safety_comment = false;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if !under_rustfmt
                && line.chars().count() > max_columns
                && !long_line_is_ok(max_columns, line)
            {
                suppressible_tidy_err!(
                    err,
                    skip_line_length,
                    &format!("line longer than {} chars", max_columns)
                );
            }
            if !is_style_file && line.contains('\t') {
                suppressible_tidy_err!(err, skip_tab, "tab character");
            }
            if line.ends_with(' ') || line.ends_with('\t') {
                suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace");
            }
            if is_style_file && line.starts_with(' ') {
                err("CSS files use tabs for indent");
            }
            if line.contains('\r') {
                suppressible_tidy_err!(err, skip_cr, "CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            let is_test = || file.components().any(|c| c.as_os_str() == "tests");
            // for now we just check libcore
            if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
                if file.components().any(|c| c.as_os_str() == "libcore") && !is_test() {
                    suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
                }
            }
            if line.contains("// SAFETY: ") || line.contains("// Safety: ") {
                last_safety_comment = true;
            } else if line.trim().starts_with("//") || line.trim().is_empty() {
                // keep previous value
            } else {
                last_safety_comment = false;
            }
            if (line.starts_with("// Copyright")
                || line.starts_with("# Copyright")
                || line.starts_with("Copyright"))
                && (line.contains("Rust Developers") || line.contains("Rust Project Developers"))
            {
                suppressible_tidy_err!(
                    err,
                    skip_copyright,
                    "copyright notices attributed to the Rust Project Developers are deprecated"
                );
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
            lines = i;
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        let mut err = |msg: &str| {
            tidy_error!(bad, "{}: {}", file.display(), msg);
        };
        match trailing_new_lines {
            0 => suppressible_tidy_err!(err, skip_trailing_newlines, "missing trailing newline"),
            1 => {}
            n => suppressible_tidy_err!(
                err,
                skip_trailing_newlines,
                &format!("too many trailing newlines ({})", n)
            ),
        };
        if lines > LINES {
            let mut err = |_| {
                tidy_error!(
                    bad,
                    "{}: too many lines ({}) (add `// \
                     ignore-tidy-filelength` to the file to suppress this error)",
                    file.display(),
                    lines
                );
            };
            suppressible_tidy_err!(err, skip_file_length, "");
        }

        if let Directive::Ignore(false) = skip_cr {
            tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_tab {
            tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_line_length {
            tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_file_length {
            tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_end_whitespace {
            tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_trailing_newlines {
            tidy_error!(bad, "{}: ignoring trailing newlines unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_copyright {
            tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
        }
    })
}
<|endoftext|>


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

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

In general, it's not legal to directly import methods belonging to a
trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type params are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement a non-trait object on an object. Example of erroneous
code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify you didn't mispelled the trait's name or used the wrong object.
Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
You tried to implement an undefined trait on an object. Example of
erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0407, // method is not a member of trait
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0428, // duplicate definition of ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0433, // failed to resolve
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<commit_msg>Add E0407 error explanation<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

In general, it's not legal to directly import methods belonging to a
trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type params are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement a non-trait object on an object. Example of erroneous
code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify you didn't mispelled the trait's name or used the wrong object.
Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
A non-trait was implemented. Example of erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##,

E0407: r##"
A definition of a method not in the implemented trait was given. Example of
erroneous code:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // error: method `b` is not a member of trait `Foo`
}
```

Please verify you didn't mispelled the method name and you used the good
trait. Example:

```
trait Foo {
    fn a();
    fn b();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // ok!
}
```
"##,

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0428, // duplicate definition of ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0433, // failed to resolve
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<|endoftext|>


<commit_before>use library::*;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeKind {
    Direct,     //coded without conversion
    Converted,  //coded with from_glib
    Pointer,    //coded with from_glib_xxx
    Object,     //coded with from_glib_xxx
    Interface,  //coded with from_glib_xxx
    Enumeration,//coded without conversion
    Unknown,
}

impl Default for TypeKind {
    fn default() -> Self { TypeKind::Unknown }
}

impl TypeKind {
    pub fn of(library: &Library, type_id: TypeId) -> TypeKind {
        use library::Type::*;
        use library::Fundamental::*;
        match library.type_(type_id) {
            &Fundamental(fund) => match fund {
                Boolean => TypeKind::Converted,
                Int8 => TypeKind::Direct,
                UInt8 => TypeKind::Direct,
                Int16 => TypeKind::Direct,
                UInt16 => TypeKind::Direct,
                Int32 => TypeKind::Direct,
                UInt32 => TypeKind::Direct,
                Int64 => TypeKind::Direct,
                UInt64 => TypeKind::Direct,
                Char => TypeKind::Converted,
                UChar => TypeKind::Converted,
                Short => TypeKind::Direct,
                UShort => TypeKind::Direct,
                Int => TypeKind::Direct,
                UInt => TypeKind::Direct,
                Long => TypeKind::Direct,
                ULong => TypeKind::Direct,
                Size => TypeKind::Direct,
                SSize => TypeKind::Direct,
                Float => TypeKind::Direct,
                Double => TypeKind::Direct,
                UniChar => TypeKind::Unknown,
                Pointer => TypeKind::Pointer,
                VarArgs => TypeKind::Unknown,
                Utf8 => TypeKind::Pointer,
                Filename => TypeKind::Pointer,
                Type => TypeKind::Enumeration,
                None => TypeKind::Unknown,
                Unsupported => TypeKind::Unknown,
            },
            &Enumeration(_) => TypeKind::Enumeration,
            &Interface(_) => TypeKind::Interface,
            &Class(_) => TypeKind::Object,
            _ => TypeKind::Unknown,
        }
    }
}
<commit_msg>There are conversions for GType in the glib crate<commit_after>use library::*;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeKind {
    Direct,     //coded without conversion
    Converted,  //coded with from_glib
    Pointer,    //coded with from_glib_xxx
    Object,     //coded with from_glib_xxx
    Interface,  //coded with from_glib_xxx
    Enumeration,//coded without conversion
    Unknown,
}

impl Default for TypeKind {
    fn default() -> Self { TypeKind::Unknown }
}

impl TypeKind {
    pub fn of(library: &Library, type_id: TypeId) -> TypeKind {
        use library::Type::*;
        use library::Fundamental::*;
        match library.type_(type_id) {
            &Fundamental(fund) => match fund {
                Boolean => TypeKind::Converted,
                Int8 => TypeKind::Direct,
                UInt8 => TypeKind::Direct,
                Int16 => TypeKind::Direct,
                UInt16 => TypeKind::Direct,
                Int32 => TypeKind::Direct,
                UInt32 => TypeKind::Direct,
                Int64 => TypeKind::Direct,
                UInt64 => TypeKind::Direct,
                Char => TypeKind::Converted,
                UChar => TypeKind::Converted,
                Short => TypeKind::Direct,
                UShort => TypeKind::Direct,
                Int => TypeKind::Direct,
                UInt => TypeKind::Direct,
                Long => TypeKind::Direct,
                ULong => TypeKind::Direct,
                Size => TypeKind::Direct,
                SSize => TypeKind::Direct,
                Float => TypeKind::Direct,
                Double => TypeKind::Direct,
                UniChar => TypeKind::Unknown,
                Pointer => TypeKind::Pointer,
                VarArgs => TypeKind::Unknown,
                Utf8 => TypeKind::Pointer,
                Filename => TypeKind::Pointer,
                Type => TypeKind::Converted,
                None => TypeKind::Unknown,
                Unsupported => TypeKind::Unknown,
            },
            &Enumeration(_) => TypeKind::Enumeration,
            &Interface(_) => TypeKind::Interface,
            &Class(_) => TypeKind::Object,
            _ => TypeKind::Unknown,
        }
    }
}
<|endoftext|>


<commit_before>use std::io;

use tag;
use err;
use serial;
use byte::{read_byte, write_byte};

impl serial::traits::Asn1Info for u64 {
  fn asn1_type() -> tag::Type {
    tag::Type::from("INTEGER")
  }

  fn asn1_class() -> tag::Class {
    tag::Class::Universal
  }

  fn asn1_tagnum() -> tag::TagNum {
    tag::TagNum::from(2u8)
  }

  fn asn1_constructed() -> bool {
    false
  }
}

impl serial::traits::Asn1Serialize for u64 {
  fn serialize_imp<W: io::Write>(&self, writer: &mut W) -> Result<(), err::EncodeError> {
    let mut started = false;
    // Loop through bytes in int backwards, start writing when first non-zero byte is encounted.
    for offset in (0..8).rev() {
      let shifted: u64 = self >> (offset * 8);
      let byte: u8 = (shifted & 0xff) as u8;
      if !started {
        if byte == 0 {
          continue;
        }
        started = true;
      }
      try!(write_byte(writer, byte));
    }

    // If we haven't written anything, write a zero byte.
    if !started {
      try!(write_byte(writer, 0 as u8));
    }
    Ok(())
  }
}

impl serial::traits::Asn1Deserialize for u64 {
  fn deserialize_imp<I: Iterator<Item=io::Result<u8>>>(reader: &mut I, len: tag::Len) -> Result<Self, err::DecodeError> {
    let len_num = try!(match len {
      tag::Len::Def(l) => Ok(l),
      _ => Err(err::DecodeError::PrimIndef),
    });

    let mut int: u64 = 0;

    for _ in 0..len_num {
      let byte = try!(read_byte(reader));
      int = (int << 8) + (byte as u64);
    }

    Ok(int)
  }
}
<commit_msg>Move cereal implementation for ints into a macro<commit_after>use std::io;

use tag;
use err;
use serial;
use byte::{read_byte, write_byte};

use std::cmp;

macro_rules! asn1_cereal_int {
  ($rs_type:ty, $size:expr) => (
    impl serial::traits::Asn1Info for $rs_type {
      fn asn1_type() -> tag::Type {
        tag::Type::from("INTEGER")
      }

      fn asn1_class() -> tag::Class {
        tag::Class::Universal
      }

      fn asn1_tagnum() -> tag::TagNum {
        tag::TagNum::from(2u8)
      }

      fn asn1_constructed() -> bool {
        false
      }
    }

    impl serial::traits::Asn1Serialize for $rs_type {
      fn serialize_imp<W: io::Write>(&self, writer: &mut W) -> Result<(), err::EncodeError> {
        let mut started = false;
        // Loop through bytes in int backwards, start writing when first non-zero byte is encounted.
        for offset in (0..8).rev() {
          let shifted: $rs_type = self >> (offset * 8);
          let byte: u8 = (shifted & 0xff) as u8;
          if !started {
            if byte == 0 {
              continue;
            }
            started = true;
          }
          try!(write_byte(writer, byte));
        }

        // If we haven't written anything, write a zero byte.
        if !started {
          try!(write_byte(writer, 0 as u8));
        }
        Ok(())
      }
    }

    impl serial::traits::Asn1Deserialize for $rs_type {
      fn deserialize_imp<I: Iterator<Item=io::Result<u8>>>(reader: &mut I, len: tag::Len) -> Result<Self, err::DecodeError> {
        let len_num = try!(match len {
          tag::Len::Def(l) => Ok(l),
          _ => Err(err::DecodeError::PrimIndef),
        });

        let mut int: $rs_type = 0;
        let size = cmp::min($size, len_num);

        for _ in 0..len_num {
          let byte = try!(read_byte(reader));
          int = (int << 8) + (byte as $rs_type);
        }

        Ok(int)
      }
    }
  )
}

asn1_cereal_int!(u8, 1);
asn1_cereal_int!(u16, 2);
asn1_cereal_int!(u32, 4);
asn1_cereal_int!(u64, 8);
<|endoftext|>


<commit_before>extern mod r5;

use std::io;
use r5::runtime::{Runtime};
use r5::parser::Parser;

fn eval_test(src: ~str, expected_src: ~str) {
    let expr =
    do io::with_str_reader(src) |rdr| {
        let mut parser = Parser(rdr);
        match parser.parse_datum() {
            Ok(v) => @v,
            Err(e) => fail!(e),
        }
    };

    let expected =
    do io::with_str_reader(expected_src) |rdr| {
        let mut parser = Parser(rdr);
        match parser.parse_datum() {
            Ok(v) => @v,
            Err(e) => fail!(e),
        }
    };

    let mut runtime = Runtime::new_std();

    let val = runtime.eval(expr);

    match val {
        Ok(v) => if v != expected {
            fail!(fmt!("expected %s, got %s", expected.to_str(), v.to_str()))
        },
        Err(e) =>
            fail!(e.to_str()),
    }
}

#[test]
fn add_test() {
    eval_test(~"(+ 1 2)", ~"3");
}

#[test]
fn sub_test() {
    eval_test(~"(- 3 1)", ~"2");
    eval_test(~"(- 5 2 1)", ~"2");
}

#[test]
fn mul_test() {
    eval_test(~"(* 1 2 3)", ~"6");
}

#[test]
fn quote_test() {
    eval_test(~"'(a b)", ~"(a b)");
}

#[test]
fn quote_macro_test() {
    eval_test(~"(quote (a b))", ~"(a b)");
}

#[test]
fn car_test() {
    eval_test(~"(car '(a b))", ~"a");
}

#[test]
fn cdr_test() {
    eval_test(~"(cdr '(a b))", ~"(b)");
}

#[test]
fn if_true_test() {
    eval_test(~"(if #t 1 0)", ~"1");
}

#[test]
fn if_false_test() {
    eval_test(~"(if #f 1 0)", ~"0");
}

#[test]
fn lambda_test() {
    eval_test(~"((lambda (x y) (+ x y)) 1 2)", ~"3");
}

#[test]
fn quasiquote_test() {
    eval_test(~"`(list ,(+ 1 2) 4)", ~"(list 3 4)");
}

#[test]
fn nested_quasiquote_test() {
    eval_test(~"`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)", ~"(a `(b ,(+ 1 2) ,(foo 4 d) e) f)");
}

#[test]
fn lexical_scoping_test() {
    /*
    (\y f -> f(2)) dyn ((\y -> (\x -> y)) lex)
    lexical scoping returns lex
    dynamic scoping returns dyn
    */

    let src = ~"((lambda (y f) (f 2)) 'dyn ((lambda (y) (lambda (x) y)) 'lex))";
    eval_test(src, ~"lex");
}

#[test]
fn eqv_test() {
    eval_test(~"(eqv? 3 (+ 1 2))", ~"#t");
    eval_test(~"(eqv? #f #f)", ~"#t");
    eval_test(~"(eqv? #\\a #\\a)", ~"#t");
    eval_test(~"(eqv? 'ident 'ident)", ~"#t");
    eval_test(~"(eqv? 3.0 3)", ~"#f");
    eval_test(~"(eqv? '() '())", ~"#t");
    eval_test(~"(eqv? '(1 2) '(1 2))", ~"#f");
    eval_test(~"(eqv? \"abc\" \"abc\")", ~"#f");
    eval_test(~"((lambda (x) (eqv? x x)) '(1 2))", ~"#t");
}

#[test]
fn set_test() {
    eval_test(~"((lambda (x) (set! x 'mut) x) 'immut)", ~"mut");
}

#[test]
fn varargs_test() {
    eval_test(~"((lambda (a b . c) `(,(+ a b) . ,c)) 1 2 3 4)", ~"(3 3 4)");
}

#[test]
fn define_val_test() {
    eval_test(~"((lambda () (define a 2) (+ a 1)))", ~"3");
}

#[test]
fn define_fun_test() {
    eval_test(~"((lambda () (define (list . a) a) (list 1 2)))", ~"(1 2)");
}

#[test]
fn begin_test() {
    eval_test(~"(begin (+ 1 2) (+ 2 3))", ~"5");
}

#[test]
fn num_fun_test() {
    eval_test(~"(number? 3)", ~"#t");
    eval_test(~"(number? 3+4i)", ~"#t");
    eval_test(~"(real? 3)", ~"#t");
    eval_test(~"(real? -2.5+0.0i)", ~"#t");
    eval_test(~"(real? #e1e10)", ~"#t");
    eval_test(~"(integer? 3+0i)", ~"#t");
    eval_test(~"(integer? 3.0)", ~"#t");
    eval_test(~"(integer? 8/4)", ~"#t");
}

#[test]
fn num_cmp_test() {
    eval_test(~"(< 1 2 3)", ~"#t");
    eval_test(~"(< 1 2 2)", ~"#f");
    eval_test(~"(<= 1.0 2.0 3.0)", ~"#t");
    eval_test(~"(<= 1.0 2.0 2.0)", ~"#t");
    eval_test(~"(= #e2 #e4/2 #e2.0)", ~"#t");
    eval_test(~"(> 1 2 3)", ~"#f");
}

#[test]
fn null_test() {
    eval_test(~"(null? '())", ~"#t");
    eval_test(~"(null? '(a b c))", ~"#f");
    eval_test(~"(null? '(a . c))", ~"#f");
}

#[test]
fn pair_test() {
    eval_test(~"(pair? '())", ~"#f");
    eval_test(~"(pair? '(a b c))", ~"#t");
    eval_test(~"(pair? '(a . c))", ~"#t");
}
<commit_msg>fibonacci function test<commit_after>extern mod r5;

use std::io;
use r5::runtime::{Runtime};
use r5::parser::Parser;

fn eval_test(src: ~str, expected_src: ~str) {
    let expr =
    do io::with_str_reader(src) |rdr| {
        let mut parser = Parser(rdr);
        match parser.parse_datum() {
            Ok(v) => @v,
            Err(e) => fail!(e),
        }
    };

    let expected =
    do io::with_str_reader(expected_src) |rdr| {
        let mut parser = Parser(rdr);
        match parser.parse_datum() {
            Ok(v) => @v,
            Err(e) => fail!(e),
        }
    };

    let mut runtime = Runtime::new_std();

    let val = runtime.eval(expr);

    match val {
        Ok(v) => if v != expected {
            fail!(fmt!("expected %s, got %s", expected.to_str(), v.to_str()))
        },
        Err(e) =>
            fail!(e.to_str()),
    }
}

#[test]
fn add_test() {
    eval_test(~"(+ 1 2)", ~"3");
}

#[test]
fn sub_test() {
    eval_test(~"(- 3 1)", ~"2");
    eval_test(~"(- 5 2 1)", ~"2");
}

#[test]
fn mul_test() {
    eval_test(~"(* 1 2 3)", ~"6");
}

#[test]
fn quote_test() {
    eval_test(~"'(a b)", ~"(a b)");
}

#[test]
fn quote_macro_test() {
    eval_test(~"(quote (a b))", ~"(a b)");
}

#[test]
fn car_test() {
    eval_test(~"(car '(a b))", ~"a");
}

#[test]
fn cdr_test() {
    eval_test(~"(cdr '(a b))", ~"(b)");
}

#[test]
fn if_true_test() {
    eval_test(~"(if #t 1 0)", ~"1");
}

#[test]
fn if_false_test() {
    eval_test(~"(if #f 1 0)", ~"0");
}

#[test]
fn lambda_test() {
    eval_test(~"((lambda (x y) (+ x y)) 1 2)", ~"3");
}

#[test]
fn quasiquote_test() {
    eval_test(~"`(list ,(+ 1 2) 4)", ~"(list 3 4)");
}

#[test]
fn nested_quasiquote_test() {
    eval_test(~"`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)", ~"(a `(b ,(+ 1 2) ,(foo 4 d) e) f)");
}

#[test]
fn lexical_scoping_test() {
    /*
    (\y f -> f(2)) dyn ((\y -> (\x -> y)) lex)
    lexical scoping returns lex
    dynamic scoping returns dyn
    */

    let src = ~"((lambda (y f) (f 2)) 'dyn ((lambda (y) (lambda (x) y)) 'lex))";
    eval_test(src, ~"lex");
}

#[test]
fn eqv_test() {
    eval_test(~"(eqv? 3 (+ 1 2))", ~"#t");
    eval_test(~"(eqv? #f #f)", ~"#t");
    eval_test(~"(eqv? #\\a #\\a)", ~"#t");
    eval_test(~"(eqv? 'ident 'ident)", ~"#t");
    eval_test(~"(eqv? 3.0 3)", ~"#f");
    eval_test(~"(eqv? '() '())", ~"#t");
    eval_test(~"(eqv? '(1 2) '(1 2))", ~"#f");
    eval_test(~"(eqv? \"abc\" \"abc\")", ~"#f");
    eval_test(~"((lambda (x) (eqv? x x)) '(1 2))", ~"#t");
}

#[test]
fn set_test() {
    eval_test(~"((lambda (x) (set! x 'mut) x) 'immut)", ~"mut");
}

#[test]
fn varargs_test() {
    eval_test(~"((lambda (a b . c) `(,(+ a b) . ,c)) 1 2 3 4)", ~"(3 3 4)");
}

#[test]
fn define_val_test() {
    eval_test(~"((lambda () (define a 2) (+ a 1)))", ~"3");
}

#[test]
fn define_fun_test() {
    eval_test(~"((lambda () (define (list . a) a) (list 1 2)))", ~"(1 2)");
}

#[test]
fn begin_test() {
    eval_test(~"(begin (+ 1 2) (+ 2 3))", ~"5");
}

#[test]
fn num_fun_test() {
    eval_test(~"(number? 3)", ~"#t");
    eval_test(~"(number? 3+4i)", ~"#t");
    eval_test(~"(real? 3)", ~"#t");
    eval_test(~"(real? -2.5+0.0i)", ~"#t");
    eval_test(~"(real? #e1e10)", ~"#t");
    eval_test(~"(integer? 3+0i)", ~"#t");
    eval_test(~"(integer? 3.0)", ~"#t");
    eval_test(~"(integer? 8/4)", ~"#t");
}

#[test]
fn num_cmp_test() {
    eval_test(~"(< 1 2 3)", ~"#t");
    eval_test(~"(< 1 2 2)", ~"#f");
    eval_test(~"(<= 1.0 2.0 3.0)", ~"#t");
    eval_test(~"(<= 1.0 2.0 2.0)", ~"#t");
    eval_test(~"(= #e2 #e4/2 #e2.0)", ~"#t");
    eval_test(~"(> 1 2 3)", ~"#f");
}

#[test]
fn null_test() {
    eval_test(~"(null? '())", ~"#t");
    eval_test(~"(null? '(a b c))", ~"#f");
    eval_test(~"(null? '(a . c))", ~"#f");
}

#[test]
fn pair_test() {
    eval_test(~"(pair? '())", ~"#f");
    eval_test(~"(pair? '(a b c))", ~"#t");
    eval_test(~"(pair? '(a . c))", ~"#t");
}

#[test]
fn recursive_test() {
    eval_test(~"(begin (define (f n) (if (> n 0) (* n (f (- n 1))) 1)) (f 4))", ~"24");
}
<|endoftext|>


<commit_before>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use regex::Error as RegexpError;
use serde_json::error::Error as SerdeError;
use std::error::Error as StdError;
use std::io;
use std::num::ParseFloatError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{error, str};
use tipb::expression::ScalarFuncSig;
use tipb::select;

pub const ERR_UNKNOWN: i32 = 1105;
pub const ERR_REGEXP: i32 = 1139;
pub const ZLIB_LENGTH_CORRUPTED: i32 = 1258;
pub const ZLIB_DATA_CORRUPTED: i32 = 1259;
pub const WARN_DATA_TRUNCATED: i32 = 1265;
pub const ERR_TRUNCATE_WRONG_VALUE: i32 = 1292;
pub const ERR_UNKNOWN_TIMEZONE: i32 = 1298;
pub const ERR_DIVISION_BY_ZERO: i32 = 1365;
pub const ERR_DATA_TOO_LONG: i32 = 1406;
pub const ERR_DATA_OUT_OF_RANGE: i32 = 1690;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidDataType(reason: String) {
            description("invalid data type")
            display("{}", reason)
        }
        Encoding(err: Utf8Error) {
            from()
            cause(err)
            description("encoding failed")
        }
        ColumnOffset(offset: usize) {
            description("column offset not found")
            display("illegal column offset: {}", offset)
        }
        UnknownSignature(sig: ScalarFuncSig) {
            description("Unknown signature")
            display("Unknown signature: {:?}", sig)
        }
        Eval(s: String,code:i32) {
            description("evaluation failed")
            display("{}", s)
        }
        Other(err: Box<dyn error::Error + Send + Sync>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("{}", err)
        }
    }
}

impl Error {
    pub fn overflow(data: &str, expr: &str) -> Error {
        let msg = format!("{} value is out of range in '{}'", data, expr);
        Error::Eval(msg, ERR_DATA_OUT_OF_RANGE)
    }

    pub fn truncated_wrong_val(data_type: &str, val: &str) -> Error {
        let msg = format!("Truncated incorrect {} value: '{}'", data_type, val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn truncated() -> Error {
        Error::Eval("Data Truncated".into(), WARN_DATA_TRUNCATED)
    }

    pub fn cast_neg_int_as_unsigned() -> Error {
        let msg = "Cast to unsigned converted negative integer to it's positive complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn cast_as_signed_overflow() -> Error {
        let msg =
            "Cast to signed converted positive out-of-range integer to it's negative complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn invalid_timezone(given_time_zone: &str) -> Error {
        let msg = format!("unknown or incorrect time zone: {}", given_time_zone);
        Error::Eval(msg, ERR_UNKNOWN_TIMEZONE)
    }

    pub fn division_by_zero() -> Error {
        let msg = "Division by 0";
        Error::Eval(msg.into(), ERR_DIVISION_BY_ZERO)
    }

    pub fn data_too_long(msg: String) -> Error {
        if msg.is_empty() {
            Error::Eval("Data Too Long".into(), ERR_DATA_TOO_LONG)
        } else {
            Error::Eval(msg, ERR_DATA_TOO_LONG)
        }
    }

    pub fn code(&self) -> i32 {
        match *self {
            Error::Eval(_, code) => code,
            _ => ERR_UNKNOWN,
        }
    }

    pub fn is_overflow(&self) -> bool {
        self.code() == ERR_DATA_OUT_OF_RANGE
    }

    pub fn unexpected_eof() -> Error {
        tikv_util::codec::Error::unexpected_eof().into()
    }

    pub fn invalid_time_format(val: &str) -> Error {
        let msg = format!("invalid time format: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn incorrect_datetime_value(val: &str) -> Error {
        let msg = format!("Incorrect datetime value: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn zlib_length_corrupted() -> Error {
        let msg = "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)";
        Error::Eval(msg.into(), ZLIB_LENGTH_CORRUPTED)
    }

    pub fn zlib_data_corrupted() -> Error {
        Error::Eval("ZLIB: Input data corrupted".into(), ZLIB_DATA_CORRUPTED)
    }
}

impl From<Error> for select::Error {
    fn from(error: Error) -> select::Error {
        let mut err = select::Error::default();
        err.set_code(error.code());
        err.set_msg(format!("{:?}", error));
        err
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Encoding(err.utf8_error())
    }
}

impl From<SerdeError> for Error {
    fn from(err: SerdeError) -> Error {
        box_err!("serde:{:?}", err)
    }
}

impl From<ParseFloatError> for Error {
    fn from(err: ParseFloatError) -> Error {
        box_err!("parse float: {:?}", err)
    }
}

impl From<tikv_util::codec::Error> for Error {
    fn from(err: tikv_util::codec::Error) -> Error {
        box_err!("codec:{:?}", err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        let uerr: tikv_util::codec::Error = err.into();
        uerr.into()
    }
}

impl From<RegexpError> for Error {
    fn from(err: RegexpError) -> Error {
        let msg = format!("Got error '{:.64}' from regexp", err.description());
        Error::Eval(msg, ERR_REGEXP)
    }
}

pub type Result<T> = std::result::Result<T, Error>;
<commit_msg>Make `codec::Error` more ergonomic (#5216)<commit_after>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use regex::Error as RegexpError;
use serde_json::error::Error as SerdeError;
use std::error::Error as StdError;
use std::fmt::Display;
use std::io;
use std::num::ParseFloatError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{error, str};
use tipb::expression::ScalarFuncSig;
use tipb::select;

pub const ERR_UNKNOWN: i32 = 1105;
pub const ERR_REGEXP: i32 = 1139;
pub const ZLIB_LENGTH_CORRUPTED: i32 = 1258;
pub const ZLIB_DATA_CORRUPTED: i32 = 1259;
pub const WARN_DATA_TRUNCATED: i32 = 1265;
pub const ERR_TRUNCATE_WRONG_VALUE: i32 = 1292;
pub const ERR_UNKNOWN_TIMEZONE: i32 = 1298;
pub const ERR_DIVISION_BY_ZERO: i32 = 1365;
pub const ERR_DATA_TOO_LONG: i32 = 1406;
pub const ERR_DATA_OUT_OF_RANGE: i32 = 1690;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidDataType(reason: String) {
            description("invalid data type")
            display("{}", reason)
        }
        Encoding(err: Utf8Error) {
            from()
            cause(err)
            description("encoding failed")
        }
        ColumnOffset(offset: usize) {
            description("column offset not found")
            display("illegal column offset: {}", offset)
        }
        UnknownSignature(sig: ScalarFuncSig) {
            description("Unknown signature")
            display("Unknown signature: {:?}", sig)
        }
        Eval(s: String,code:i32) {
            description("evaluation failed")
            display("{}", s)
        }
        Other(err: Box<dyn error::Error + Send + Sync>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("{}", err)
        }
    }
}

impl Error {
    pub fn overflow(data: impl Display, expr: impl Display) -> Error {
        let msg = format!("{} value is out of range in '{}'", data, expr);
        Error::Eval(msg, ERR_DATA_OUT_OF_RANGE)
    }

    pub fn truncated_wrong_val(data_type: impl Display, val: impl Display) -> Error {
        let msg = format!("Truncated incorrect {} value: '{}'", data_type, val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn truncated() -> Error {
        Error::Eval("Data Truncated".into(), WARN_DATA_TRUNCATED)
    }

    pub fn cast_neg_int_as_unsigned() -> Error {
        let msg = "Cast to unsigned converted negative integer to it's positive complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn cast_as_signed_overflow() -> Error {
        let msg =
            "Cast to signed converted positive out-of-range integer to it's negative complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn invalid_timezone(given_time_zone: impl Display) -> Error {
        let msg = format!("unknown or incorrect time zone: {}", given_time_zone);
        Error::Eval(msg, ERR_UNKNOWN_TIMEZONE)
    }

    pub fn division_by_zero() -> Error {
        let msg = "Division by 0";
        Error::Eval(msg.into(), ERR_DIVISION_BY_ZERO)
    }

    pub fn data_too_long(msg: String) -> Error {
        if msg.is_empty() {
            Error::Eval("Data Too Long".into(), ERR_DATA_TOO_LONG)
        } else {
            Error::Eval(msg, ERR_DATA_TOO_LONG)
        }
    }

    pub fn code(&self) -> i32 {
        match *self {
            Error::Eval(_, code) => code,
            _ => ERR_UNKNOWN,
        }
    }

    pub fn is_overflow(&self) -> bool {
        self.code() == ERR_DATA_OUT_OF_RANGE
    }

    pub fn unexpected_eof() -> Error {
        tikv_util::codec::Error::unexpected_eof().into()
    }

    pub fn invalid_time_format(val: impl Display) -> Error {
        let msg = format!("invalid time format: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn incorrect_datetime_value(val: impl Display) -> Error {
        let msg = format!("Incorrect datetime value: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn zlib_length_corrupted() -> Error {
        let msg = "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)";
        Error::Eval(msg.into(), ZLIB_LENGTH_CORRUPTED)
    }

    pub fn zlib_data_corrupted() -> Error {
        Error::Eval("ZLIB: Input data corrupted".into(), ZLIB_DATA_CORRUPTED)
    }
}

impl From<Error> for select::Error {
    fn from(error: Error) -> select::Error {
        let mut err = select::Error::default();
        err.set_code(error.code());
        err.set_msg(format!("{:?}", error));
        err
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Encoding(err.utf8_error())
    }
}

impl From<SerdeError> for Error {
    fn from(err: SerdeError) -> Error {
        box_err!("serde:{:?}", err)
    }
}

impl From<ParseFloatError> for Error {
    fn from(err: ParseFloatError) -> Error {
        box_err!("parse float: {:?}", err)
    }
}

impl From<tikv_util::codec::Error> for Error {
    fn from(err: tikv_util::codec::Error) -> Error {
        box_err!("codec:{:?}", err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        let uerr: tikv_util::codec::Error = err.into();
        uerr.into()
    }
}

impl From<RegexpError> for Error {
    fn from(err: RegexpError) -> Error {
        let msg = format!("Got error '{:.64}' from regexp", err.description());
        Error::Eval(msg, ERR_REGEXP)
    }
}

pub type Result<T> = std::result::Result<T, Error>;
<|endoftext|>