<commit_before>extern crate bindgen;

fn osx_version() -> Result<String, std::io::Error> {
    use std::process::Command;

    let output = Command::new("defaults")
        .arg("read")
        .arg("loginwindow")
        .arg("SystemVersionStampAsString")
        .output()?
        .stdout;
    let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
    let version = version_str.trim_right();

    Ok(version.to_owned())
}

fn parse_version(version: &str) -> Option<i32> {
    version
        .split(".")
        .skip(1)
        .next()
        .and_then(|m| m.parse::<i32>().ok())
}

fn frameworks_path() -> Result<String, std::io::Error> {
    // For 10.13 and higher:
    //
    // While macOS has its system frameworks located at "/System/Library/Frameworks"
    // for actually linking against them (especially for cross-compilation) once
    // has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…".

    // Use environment variable if set
    if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") {
        return Ok(path)
    }

    if osx_version()
        .and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
        .unwrap_or(false)
    {
        use std::process::Command;

        let output = Command::new("xcode-select").arg("-p").output()?.stdout;
        let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
        let prefix = prefix_str.trim_right();

        let target = std::env::var("TARGET").unwrap();
        let platform = if target.contains("apple-darwin") {
            "MacOSX"
        } else if target.contains("apple-ios") {
            "iPhoneOS"
        } else {
            unreachable!();
        };

        let infix = if prefix == "/Library/Developer/CommandLineTools" {
            format!("SDKs/{}.sdk", platform)
        } else {
            format!(
                "Platforms/{}.platform/Developer/SDKs/{}.sdk",
                platform, platform
            )
        };

        let suffix = "System/Library/Frameworks";
        let directory = format!("{}/{}/{}", prefix, infix, suffix);

        Ok(directory)
    } else {
        Ok("/System/Library/Frameworks".to_string())
    }
}

fn build(frameworks_path: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut frameworks = vec![];
    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        frameworks.push("AudioToolbox");
        headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        frameworks.push("AudioUnit");
        headers.push("AudioUnit.framework/Headers/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        frameworks.push("CoreAudio");
        headers.push("CoreAudio.framework/Headers/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        frameworks.push("OpenAL");
        headers.push("OpenAL.framework/Headers/al.h");
        headers.push("OpenAL.framework/Headers/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if std::env::var("TARGET").unwrap().contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            frameworks.push("CoreMIDI");
            headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
        }
    }

    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_arg(format!("-F/{}", frameworks_path));

    // Add all headers.
    for relative_path in headers {
        let absolute_path = format!("{}/{}", frameworks_path, relative_path);
        builder = builder.header(absolute_path);
    }

    // Link to all frameworks.
    for relative_path in frameworks {
        let link_instruction = format!("#[link = \"{}/{}\"]", frameworks_path, relative_path);
        builder = builder.raw_line(link_instruction);
    }

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true)
        .rustfmt_bindings(false);

    if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") {
        builder = builder.clang_args(cflags.split(" "));
    }

    let bindings = builder
        .generate()
        .expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if ! (target.contains("apple-darwin") || target.contains("apple-ios")) {
        eprintln!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = frameworks_path() {
        build(&directory);
    } else {
        eprintln!("coreaudio-sys could not find frameworks path");
    }
}

<commit_msg>Remove #[link] attributes<commit_after>extern crate bindgen;

fn osx_version() -> Result<String, std::io::Error> {
    use std::process::Command;

    let output = Command::new("defaults")
        .arg("read")
        .arg("loginwindow")
        .arg("SystemVersionStampAsString")
        .output()?
        .stdout;
    let version_str = std::str::from_utf8(&output).expect("invalid output from `defaults`");
    let version = version_str.trim_right();

    Ok(version.to_owned())
}

fn parse_version(version: &str) -> Option<i32> {
    version
        .split(".")
        .skip(1)
        .next()
        .and_then(|m| m.parse::<i32>().ok())
}

fn frameworks_path() -> Result<String, std::io::Error> {
    // For 10.13 and higher:
    //
    // While macOS has its system frameworks located at "/System/Library/Frameworks"
    // for actually linking against them (especially for cross-compilation) once
    // has to refer to the frameworks as found within "Xcode.app/Contents/Developer/…".

    // Use environment variable if set
    if let Ok(path) = std::env::var("COREAUDIO_FRAMEWORKS_PATH") {
        return Ok(path)
    }

    if osx_version()
        .and_then(|version| Ok(parse_version(&version).map(|v| v >= 13).unwrap_or(false)))
        .unwrap_or(false)
    {
        use std::process::Command;

        let output = Command::new("xcode-select").arg("-p").output()?.stdout;
        let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcode-select`");
        let prefix = prefix_str.trim_right();

        let target = std::env::var("TARGET").unwrap();
        let platform = if target.contains("apple-darwin") {
            "MacOSX"
        } else if target.contains("apple-ios") {
            "iPhoneOS"
        } else {
            unreachable!();
        };

        let infix = if prefix == "/Library/Developer/CommandLineTools" {
            format!("SDKs/{}.sdk", platform)
        } else {
            format!(
                "Platforms/{}.platform/Developer/SDKs/{}.sdk",
                platform, platform
            )
        };

        let suffix = "System/Library/Frameworks";
        let directory = format!("{}/{}/{}", prefix, infix, suffix);

        Ok(directory)
    } else {
        Ok("/System/Library/Frameworks".to_string())
    }
}

fn build(frameworks_path: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit.framework/Headers/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        headers.push("CoreAudio.framework/Headers/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL.framework/Headers/al.h");
        headers.push("OpenAL.framework/Headers/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if std::env::var("TARGET").unwrap().contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
        }
    }

    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_arg(format!("-F/{}", frameworks_path));

    // Add all headers.
    for relative_path in headers {
        let absolute_path = format!("{}/{}", frameworks_path, relative_path);
        builder = builder.header(absolute_path);
    }

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true)
        .rustfmt_bindings(false);

    if let Ok(cflags) = std::env::var("COREAUDIO_CFLAGS") {
        builder = builder.clang_args(cflags.split(" "));
    }

    let bindings = builder
        .generate()
        .expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if ! (target.contains("apple-darwin") || target.contains("apple-ios")) {
        eprintln!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = frameworks_path() {
        build(&directory);
    } else {
        eprintln!("coreaudio-sys could not find frameworks path");
    }
}

<|endoftext|>


<commit_before>#![feature(core)]
#![feature(io)]
#![feature(env)]
#![feature(path)]

use std::old_io::{Command, File, Truncate, Write};
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let dir = path::Path::new(&dir_var);
    let out_file = dir.join("codegen");
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file.to_str().unwrap())
                       .status()
                       .unwrap();
    let code = Command::new(out_file.to_str().unwrap()).output().unwrap();
    if !code.status.success() {
        panic!("{}", String::from_utf8_lossy(code.error.as_slice()));
    }
    let mut f = File::open_mode(&Path::new("src/type_size.rs"), Truncate, Write);
    f.write_all(code.output.as_slice()).unwrap();
}
<commit_msg>Update build.rs to the new io<commit_after>#![feature(fs)]
#![feature(io)]
#![feature(process)]
#![feature(env)]
#![feature(path)]

use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let dir = path::Path::new(&dir_var).join("codegen");
    let out_file = dir.to_str().unwrap();
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file)
                       .status()
                       .unwrap();
    let output = Command::new(out_file).output().unwrap();
    if !output.status.success() {
        panic!("{}", String::from_utf8_lossy(output.stderr.as_slice()));
    }
    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("{:?}", e)
    };
    f.write_all(output.stdout.as_slice()).unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 38 {
        println!("cargo:rustc-cfg=anyhow_no_macro_reexport");
    }

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;

    // Make sure to pick up Cargo rustc configuration.
    let mut cmd = if let Some(wrapper) = env::var_os("CARGO_RUSTC_WRAPPER") {
        let mut cmd = Command::new(wrapper);
        // The wrapper's first argument is supposed to be the path to rustc.
        cmd.arg(rustc);
        cmd
    } else {
        Command::new(rustc)
    };

    cmd.stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile);

    // If Cargo wants to set RUSTFLAGS, use that.
    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
        if !rustflags.is_empty() {
            for arg in rustflags.split('\x1f') {
                cmd.arg(arg);
            }
        }
    }

    cmd.status().ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<commit_msg>Ignore unhelpful Clippy lint in build script<commit_after>#![allow(clippy::option_if_let_else)]

use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str;

#[cfg(all(feature = "backtrace", not(feature = "std")))]
compile_error! {
    "`backtrace` feature without `std` feature is not supported"
}

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if cfg!(feature = "std") {
        match compile_probe() {
            Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
            _ => {}
        }
    }

    let rustc = match rustc_minor_version() {
        Some(rustc) => rustc,
        None => return,
    };

    if rustc < 38 {
        println!("cargo:rustc-cfg=anyhow_no_macro_reexport");
    }

    if rustc < 51 {
        println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;

    // Make sure to pick up Cargo rustc configuration.
    let mut cmd = if let Some(wrapper) = env::var_os("CARGO_RUSTC_WRAPPER") {
        let mut cmd = Command::new(wrapper);
        // The wrapper's first argument is supposed to be the path to rustc.
        cmd.arg(rustc);
        cmd
    } else {
        Command::new(rustc)
    };

    cmd.stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile);

    // If Cargo wants to set RUSTFLAGS, use that.
    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
        if !rustflags.is_empty() {
            for arg in rustflags.split('\x1f') {
                cmd.arg(arg);
            }
        }
    }

    cmd.status().ok()
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<|endoftext|>


<commit_before>fn main() {
    let libstdcxx = cfg!(feature = "libstdcxx");
    let libcxx = cfg!(feature = "libcxx");
    let nothing = cfg!(feature = "nothing");

    if nothing {
        return;
    }

    if libstdcxx && libcxx {
        println!(
            "cargo:warning=-lstdc++ and -lc++ are both requested, \
             using the platform's default"
        );
    }

    match (libstdcxx, libcxx) {
        (true, false) => println!("cargo:rustc-link-lib=stdc++"),
        (false, true) => println!("cargo:rustc-link-lib=c++"),
        (false, false) | (true, true) => {
            // The platform's default.
            cc::Build::new().cpp(true).compile("link-cplusplus");
        }
    }
}
<commit_msg>Make mac's `ar` happy<commit_after>use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
    let libstdcxx = cfg!(feature = "libstdcxx");
    let libcxx = cfg!(feature = "libcxx");
    let nothing = cfg!(feature = "nothing");

    if nothing {
        return;
    }

    if libstdcxx && libcxx {
        println!(
            "cargo:warning=-lstdc++ and -lc++ are both requested, \
             using the platform's default"
        );
    }

    match (libstdcxx, libcxx) {
        (true, false) => println!("cargo:rustc-link-lib=stdc++"),
        (false, true) => println!("cargo:rustc-link-lib=c++"),
        (false, false) | (true, true) => {
            // The platform's default.
            let out_dir = env::var_os("OUT_DIR").expect("missing OUT_DIR");
            let path = PathBuf::from(out_dir).join("dummy.cc");
            fs::write(&path, "int rust_link_cplusplus;\n").unwrap();
            cc::Build::new().cpp(true).file(&path).compile("link-cplusplus");
        }
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::vec::Vec;
use error::IndentexError;

const LINESEP: &'static str = "\n";
const LATEX_TO_INDENTEX_FACTOR: f64 = 1.5;

pub struct TranspileOptions {
    pub flatten_output: bool,
    pub prepend_do_not_edit_notice: bool,
}

// Indentation processing
#[inline]
fn count_left_indent<T: AsRef<str>>(line: T) -> Option<usize> {
    if line.as_ref().is_empty() {
        None
    } else {
        Some(line.as_ref().chars().count() - line.as_ref().trim_left().chars().count())
    }
}

fn scan_indents<T: AsRef<str>>(lines: &[T]) -> Vec<usize> {
    let raw_indents = lines.iter().map(count_left_indent).collect::<Vec<_>>();

    let mut adjusted_indents: Vec<usize> = Vec::with_capacity(raw_indents.len() + 1);
    let mut last_indent: usize = 0;

    for current_indent in raw_indents.iter().rev() {
        adjusted_indents.push(match *current_indent {
            None => last_indent,
            Some(ind) => {
                last_indent = ind;
                ind
            }
        });
    }

    adjusted_indents.reverse();
    adjusted_indents.push(0);

    adjusted_indents
}

// Transpilation
fn transpile<T: AsRef<str>>(lines: &[T], options: &TranspileOptions) -> String {
    use parsers::Environment;
    use parsers::Hashline::{PlainLine, OpenEnv};
    use parsers::process_line;

    // The number of environments is not known beforehand
    let mut env_stack: Vec<Environment> = Vec::new();

    // Input size is the sum of all line lengths plus the number of lines (for lineseps)
    let input_size = lines.iter().fold(0, |sum, l| sum + l.as_ref().len()) + lines.len();
    // We do not know how much larger the transpiled LaTeX file will be, but we can guess...
    let indentex_size = (LATEX_TO_INDENTEX_FACTOR * (input_size as f64)).round() as usize;
    let mut transpiled = String::with_capacity(indentex_size);

    let adjusted_indents = scan_indents(lines);

    if options.prepend_do_not_edit_notice {
        transpiled.push_str("% ============================================================== %\n");
        transpiled.push_str("%                                                                %\n");
        transpiled.push_str("% THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. %\n");
        transpiled.push_str("%                                                                %\n");
        transpiled.push_str("% ============================================================== %\n");
    }

    for (line_num, line) in lines.iter().enumerate() {
        let list_like_active = match env_stack.last() {
            None => false, // No environment is active at all
            Some(d) => d.is_list_like(),
        };

        let tl = match process_line(line.as_ref(), list_like_active) {
            PlainLine(l) => l,
            OpenEnv(e) => {
                let tag_begin = e.latex_begin();
                env_stack.push(e);
                tag_begin
            }
        };
        if options.flatten_output {
            transpiled.push_str(tl.trim_left());
        } else {
            transpiled.push_str(&tl);
        }
        transpiled.push_str(LINESEP);

        // Check if we are in an environment and close as many as needed
        while match env_stack.last() {
            None => false,
            Some(d) => d.indent_depth() >= adjusted_indents[line_num + 1],
        } {
            // `unwrap()` is safe here since we have already checked if the stack is empty
            let tag_end = env_stack.pop().unwrap().latex_end();
            if options.flatten_output {
                transpiled.push_str(tag_end.trim_left());
            } else {
                transpiled.push_str(&tag_end);
            }
            transpiled.push_str(LINESEP);
        }
    }

    transpiled
}

pub fn transpile_file<T: AsRef<Path>>(path: T, options: &TranspileOptions) -> Result<(), IndentexError> {
    use file_utils::{read_and_trim_lines, rename_indentex_file, write_to_file};

    let lines = read_and_trim_lines(path.as_ref())?;
    let transpiled_text = transpile(&lines, options);
    let path_out = rename_indentex_file(path)?;
    write_to_file(path_out, &transpiled_text)?;

    Ok(())
}

#[cfg(test)]
mod tests {
    #[test]
    fn count_left_indent() {
        use super::count_left_indent;

        assert_eq!(count_left_indent(""), None);
        assert_eq!(count_left_indent("foo"), Some(0));
        assert_eq!(count_left_indent("  bar"), Some(2));
        // We assume that the input has no trailing whitespaces
        // This is not a bug (but not a nice behaviour either)
        assert_eq!(count_left_indent("   "), Some(3));
    }

    #[test]
    fn scan_indents() {
        use super::scan_indents;

        // Always add a zero at the end
        let a = [" a"];
        assert_eq!(scan_indents(&a), [1, 0]);
        assert_eq!(scan_indents(&a).capacity(), 2);
        // Indents are propagated backwards
        let b = ["  b", "b", "", "  b"];
        assert_eq!(scan_indents(&b), [2, 0, 2, 2, 0]);
        assert_eq!(scan_indents(&b).capacity(), 5);
        // We assume that the input has no trailing whitespaces
        // This is not a bug (but not a nice behaviour either)
        let c = ["", "   "];
        assert_eq!(scan_indents(&c), [3, 3, 0]);
        assert_eq!(scan_indents(&c).capacity(), 3);

        let d = ["d", " d", "", " d", "", "   d", "  d", "     d"];
        assert_eq!(scan_indents(&d), [0, 1, 1, 1, 3, 3, 2, 5, 0]);
        assert_eq!(scan_indents(&d).capacity(), 9);
    }
}
<commit_msg>Make the do not edit notice a const str<commit_after>use std::path::Path;
use std::vec::Vec;
use error::IndentexError;

const LINESEP: &'static str = "\n";
const LATEX_TO_INDENTEX_FACTOR: f64 = 1.5;
const DO_NOT_EDIT_NOTICE: &'static str = "\
    % ============================================================== %\n\
    %                                                                %\n\
    % THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. %\n\
    %                                                                %\n\
    % ============================================================== %\n";

pub struct TranspileOptions {
    pub flatten_output: bool,
    pub prepend_do_not_edit_notice: bool,
}

// Indentation processing
#[inline]
fn count_left_indent<T: AsRef<str>>(line: T) -> Option<usize> {
    if line.as_ref().is_empty() {
        None
    } else {
        Some(line.as_ref().chars().count() - line.as_ref().trim_left().chars().count())
    }
}

fn scan_indents<T: AsRef<str>>(lines: &[T]) -> Vec<usize> {
    let raw_indents = lines.iter().map(count_left_indent).collect::<Vec<_>>();

    let mut adjusted_indents: Vec<usize> = Vec::with_capacity(raw_indents.len() + 1);
    let mut last_indent: usize = 0;

    for current_indent in raw_indents.iter().rev() {
        adjusted_indents.push(match *current_indent {
            None => last_indent,
            Some(ind) => {
                last_indent = ind;
                ind
            }
        });
    }

    adjusted_indents.reverse();
    adjusted_indents.push(0);

    adjusted_indents
}

// Transpilation
fn transpile<T: AsRef<str>>(lines: &[T], options: &TranspileOptions) -> String {
    use parsers::Environment;
    use parsers::Hashline::{PlainLine, OpenEnv};
    use parsers::process_line;

    // The number of environments is not known beforehand
    let mut env_stack: Vec<Environment> = Vec::new();

    // Input size is the sum of all line lengths plus the number of lines (for lineseps)
    let input_size = lines.iter().fold(0, |sum, l| sum + l.as_ref().len()) + lines.len();
    // We do not know how much larger the transpiled LaTeX file will be, but we can guess...
    let indentex_size = (LATEX_TO_INDENTEX_FACTOR * (input_size as f64)).round() as usize;
    let mut transpiled = String::with_capacity(indentex_size);

    let adjusted_indents = scan_indents(lines);

    if options.prepend_do_not_edit_notice {
        transpiled.push_str(DO_NOT_EDIT_NOTICE);
    }

    for (line_num, line) in lines.iter().enumerate() {
        let list_like_active = match env_stack.last() {
            None => false, // No environment is active at all
            Some(d) => d.is_list_like(),
        };

        let tl = match process_line(line.as_ref(), list_like_active) {
            PlainLine(l) => l,
            OpenEnv(e) => {
                let tag_begin = e.latex_begin();
                env_stack.push(e);
                tag_begin
            }
        };
        if options.flatten_output {
            transpiled.push_str(tl.trim_left());
        } else {
            transpiled.push_str(&tl);
        }
        transpiled.push_str(LINESEP);

        // Check if we are in an environment and close as many as needed
        while match env_stack.last() {
            None => false,
            Some(d) => d.indent_depth() >= adjusted_indents[line_num + 1],
        } {
            // `unwrap()` is safe here since we have already checked if the stack is empty
            let tag_end = env_stack.pop().unwrap().latex_end();
            if options.flatten_output {
                transpiled.push_str(tag_end.trim_left());
            } else {
                transpiled.push_str(&tag_end);
            }
            transpiled.push_str(LINESEP);
        }
    }

    transpiled
}

pub fn transpile_file<T: AsRef<Path>>(path: T, options: &TranspileOptions) -> Result<(), IndentexError> {
    use file_utils::{read_and_trim_lines, rename_indentex_file, write_to_file};

    let lines = read_and_trim_lines(path.as_ref())?;
    let transpiled_text = transpile(&lines, options);
    let path_out = rename_indentex_file(path)?;
    write_to_file(path_out, &transpiled_text)?;

    Ok(())
}

#[cfg(test)]
mod tests {
    #[test]
    fn count_left_indent() {
        use super::count_left_indent;

        assert_eq!(count_left_indent(""), None);
        assert_eq!(count_left_indent("foo"), Some(0));
        assert_eq!(count_left_indent("  bar"), Some(2));
        // We assume that the input has no trailing whitespaces
        // This is not a bug (but not a nice behaviour either)
        assert_eq!(count_left_indent("   "), Some(3));
    }

    #[test]
    fn scan_indents() {
        use super::scan_indents;

        // Always add a zero at the end
        let a = [" a"];
        assert_eq!(scan_indents(&a), [1, 0]);
        assert_eq!(scan_indents(&a).capacity(), 2);
        // Indents are propagated backwards
        let b = ["  b", "b", "", "  b"];
        assert_eq!(scan_indents(&b), [2, 0, 2, 2, 0]);
        assert_eq!(scan_indents(&b).capacity(), 5);
        // We assume that the input has no trailing whitespaces
        // This is not a bug (but not a nice behaviour either)
        let c = ["", "   "];
        assert_eq!(scan_indents(&c), [3, 3, 0]);
        assert_eq!(scan_indents(&c).capacity(), 3);

        let d = ["d", " d", "", " d", "", "   d", "  d", "     d"];
        assert_eq!(scan_indents(&d), [0, 1, 1, 1, 3, 3, 2, 5, 0]);
        assert_eq!(scan_indents(&d).capacity(), 9);
    }
}
<|endoftext|>


<commit_before>extern crate syn;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use syn::visit::Visitor;

fn main() {
    // Parse all .rs files to collect everything which implements Command.
    // This code won't work properly with lib.rs or mod.rs.
    let mut data = Data::new();

    for entry in walkdir::WalkDir::new("src")
            .into_iter()
            .filter_map(|e| e.ok())
            .filter(|e| !e.file_type().is_dir()) {
        let mut path = String::new();

        for name in entry.path().with_extension("").iter().skip(1) {
            path.push_str(&format!("::{}", name.to_str().unwrap()));
        }

        let entry_data = get_data(entry.path());

        data.commands.extend(entry_data.commands.into_iter()
                                 .map(|c| format!("{}::{}", &path, c)));
        data.cvars.extend(entry_data.cvars.into_iter()
                              .map(|c| format!("{}::{}", &path, c)));
    }

    let command_array = make_command_array(data.commands);
    let cvar_array = make_cvar_array(data.cvars);

    let out_dir = env::var("OUT_DIR").unwrap();

    let dest_path = Path::new(&out_dir).join("command_array.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", command_array).unwrap();

    let dest_path = Path::new(&out_dir).join("cvar_array.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", cvar_array).unwrap();

    // Output OUT_DIR for rustdoc in Travis
    let mut f = File::create("out_dir").unwrap();
    write!(f, "{}", out_dir).unwrap();
}

struct Data {
    commands: Vec<String>,
    cvars: Vec<String>,
}

impl Data {
    fn new() -> Self {
        Self {
            commands: Vec::new(),
            cvars: Vec::new(),
        }
    }
}

fn get_data(path: &Path) -> Data {
    let mut source = String::new();
    File::open(path)
        .unwrap()
        .read_to_string(&mut source)
        .unwrap();

    if let Ok(_crate) = syn::parse_crate(&source) {
        let mut visitor = MyVisitor::new();
        visitor.visit_crate(&_crate);

        Data { commands: visitor.commands, cvars: visitor.cvars }
    } else {
        Data::new()
    }
}

fn make_command_array(commands: Vec<String>) -> String {
    let mut buf = format!("pub const COMMANDS: [&Command; {}] = [", commands.len());

    let mut iter = commands.into_iter();

    if let Some(first) = iter.next() {
        buf.push_str(&format!("&{}", first));
    }

    for command in iter {
        buf.push_str(&format!(", &{}", command));
    }

    buf.push_str("];");

    buf
}

fn make_cvar_array(cvars: Vec<String>) -> String {
    let mut buf = format!("pub static CVARS: [&::engine::CVarGuard; {}] = [",
                          cvars.len());

    let mut iter = cvars.into_iter();

    if let Some(first) = iter.next() {
        buf.push_str(&format!("&{}", first));
    }

    for cvar in iter {
        buf.push_str(&format!(", &{}", cvar));
    }

    buf.push_str("];");

    buf
}

struct MyVisitor {
    commands: Vec<String>,
    cvars: Vec<String>,
}

impl MyVisitor {
    fn new() -> Self {
        Self { commands: Vec::new(), cvars: Vec::new() }
    }
}

impl Visitor for MyVisitor {
    fn visit_mac(&mut self, mac: &syn::Mac) {
        if mac.path == "command".into() {
            if let Some(&syn::TokenTree::Delimited(ref delimited)) = mac.tts.iter().next() {
                if let Some(&syn::TokenTree::Token(ref token)) = delimited.tts.iter().next() {
                    if let &syn::Token::Ident(ref ident) = token {
                        self.commands.push(ident.as_ref().to_owned());
                    }
                }
            }
        }

        if mac.path == "cvar".into() {
            if let Some(&syn::TokenTree::Delimited(ref delimited)) = mac.tts.iter().next() {
                if let Some(&syn::TokenTree::Token(ref token)) = delimited.tts.iter().next() {
                    if let &syn::Token::Ident(ref ident) = token {
                        self.cvars.push(ident.as_ref().to_owned());
                    }
                }
            }
        }

        syn::visit::walk_mac(self, mac);
    }
}
<commit_msg>Parse only .rs files in build.rs<commit_after>extern crate syn;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use syn::visit::Visitor;

fn main() {
    // Parse all .rs files to collect everything which implements Command.
    // This code won't work properly with lib.rs or mod.rs.
    let mut data = Data::new();

    for entry in walkdir::WalkDir::new("src")
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|e| !e.file_type().is_dir())
        .filter(|e| e.path().extension() == Some(OsStr::new(".rs")))
    {
        let mut path = String::new();

        for name in entry.path().with_extension("").iter().skip(1) {
            path.push_str(&format!("::{}", name.to_str().unwrap()));
        }

        let entry_data = get_data(entry.path());

        data.commands.extend(
            entry_data.commands.into_iter().map(|c| {
                format!("{}::{}", &path, c)
            }),
        );
        data.cvars.extend(entry_data.cvars.into_iter().map(
            |c| format!("{}::{}", &path, c),
        ));
    }

    let command_array = make_command_array(data.commands);
    let cvar_array = make_cvar_array(data.cvars);

    let out_dir = env::var("OUT_DIR").unwrap();

    let dest_path = Path::new(&out_dir).join("command_array.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", command_array).unwrap();

    let dest_path = Path::new(&out_dir).join("cvar_array.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", cvar_array).unwrap();

    // Output OUT_DIR for rustdoc in Travis
    let mut f = File::create("out_dir").unwrap();
    write!(f, "{}", out_dir).unwrap();
}

struct Data {
    commands: Vec<String>,
    cvars: Vec<String>,
}

impl Data {
    fn new() -> Self {
        Self {
            commands: Vec::new(),
            cvars: Vec::new(),
        }
    }
}

fn get_data(path: &Path) -> Data {
    let mut source = String::new();
    File::open(path)
        .unwrap()
        .read_to_string(&mut source)
        .unwrap();

    if let Ok(_crate) = syn::parse_crate(&source) {
        let mut visitor = MyVisitor::new();
        visitor.visit_crate(&_crate);

        Data {
            commands: visitor.commands,
            cvars: visitor.cvars,
        }
    } else {
        Data::new()
    }
}

fn make_command_array(commands: Vec<String>) -> String {
    let mut buf = format!("pub const COMMANDS: [&Command; {}] = [", commands.len());

    let mut iter = commands.into_iter();

    if let Some(first) = iter.next() {
        buf.push_str(&format!("&{}", first));
    }

    for command in iter {
        buf.push_str(&format!(", &{}", command));
    }

    buf.push_str("];");

    buf
}

fn make_cvar_array(cvars: Vec<String>) -> String {
    let mut buf = format!(
        "pub static CVARS: [&::engine::CVarGuard; {}] = [",
        cvars.len()
    );

    let mut iter = cvars.into_iter();

    if let Some(first) = iter.next() {
        buf.push_str(&format!("&{}", first));
    }

    for cvar in iter {
        buf.push_str(&format!(", &{}", cvar));
    }

    buf.push_str("];");

    buf
}

struct MyVisitor {
    commands: Vec<String>,
    cvars: Vec<String>,
}

impl MyVisitor {
    fn new() -> Self {
        Self {
            commands: Vec::new(),
            cvars: Vec::new(),
        }
    }
}

impl Visitor for MyVisitor {
    fn visit_mac(&mut self, mac: &syn::Mac) {
        if mac.path == "command".into() {
            if let Some(&syn::TokenTree::Delimited(ref delimited)) = mac.tts.iter().next() {
                if let Some(&syn::TokenTree::Token(ref token)) = delimited.tts.iter().next() {
                    if let &syn::Token::Ident(ref ident) = token {
                        self.commands.push(ident.as_ref().to_owned());
                    }
                }
            }
        }

        if mac.path == "cvar".into() {
            if let Some(&syn::TokenTree::Delimited(ref delimited)) = mac.tts.iter().next() {
                if let Some(&syn::TokenTree::Token(ref token)) = delimited.tts.iter().next() {
                    if let &syn::Token::Ident(ref ident) = token {
                        self.cvars.push(ident.as_ref().to_owned());
                    }
                }
            }
        }

        syn::visit::walk_mac(self, mac);
    }
}
<|endoftext|>


<commit_before>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

pub struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy) -> Path {
		Path{path:vec![GraphIterable::Vertex(vertex)]}
    }
	fn new_empty() -> Path {
		Path{path:vec![]}
	}

}

impl Clone for Path {
	fn clone(&self) -> Path {
		Path::new_empty()
	}

	fn clone_from(&mut self, source: &Self ) {

	}
}

pub struct GraphQuery {
	// many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

	pub fn get_paths(&self) -> &Vec<Path> {
		&self.paths
	}

	/*
	generic mapper for our queries
	future this may use worker threads to perform
	traversals
	 */
    fn map<F: Fn(&Path) -> Vec<Path>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
		for x in self.paths.iter() {
			let mut tmp = closure(x);
			result.paths.append(&mut tmp)
		}
		result
    }

    pub fn outV(&self) -> GraphQuery {
		let f = |path: &Path| {
			println!("applying outV");
			let mut result : Vec<Path> = Vec::new();
			//take the final element in the path
			let element = path.path.last().unwrap();

			match element {
				&GraphIterable::Vertex(ref v) => {
					println!("matched vertex");
					let mut tmp = v.outV();
					for vertex in tmp {
						println!("adding path based on vertex match");
						let new_path = path.clone();
						result.push(new_path);
					}
				},
				&GraphIterable::Edge(ref e) => {

				}
			}
			// apply outV

			result
		};
		self.map(f)
    }

	pub fn inV(&self) -> GraphQuery {
		let g = GraphQuery::empty();
		g
	}
}

<commit_msg>setting up map, renamed old map to full_map<commit_after>
use vertex::{Vertex, VertexProxy};
use edge::{Edge, EdgeProxy};
// define a traversal as a series of stages

struct VertexVisit {
    vertex: VertexProxy
}

struct EdgeVisit {
    edge: EdgeProxy
}

enum TraversalStage {

}

pub enum GraphIterable {
    Vertex(VertexProxy),
    Edge(EdgeProxy)
}

// used to track a single graph traversal
// will be used in conjunction with a GraphQuery

pub struct Path {
    path: Vec<GraphIterable>
}

impl Path {
    fn new(vertex: VertexProxy) -> Path {
		Path{path:vec![GraphIterable::Vertex(vertex)]}
    }
	fn new_empty() -> Path {
		Path{path:vec![]}
	}

}

impl Clone for Path {
	fn clone(&self) -> Path {
		Path::new_empty()
	}

	fn clone_from(&mut self, source: &Self ) {

	}
}

pub struct GraphQuery {
	// many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<VertexProxy>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
			let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

	pub fn get_paths(&self) -> &Vec<Path> {
		&self.paths
	}

	/*
	generic mapper for our queries
	future this may use worker threads to perform
	traversals
	 */
    fn full_map<F: Fn(&Path) -> Vec<Path>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
		for x in self.paths.iter() {
			let mut tmp = closure(x);
			result.paths.append(&mut tmp)
		}
		result
    }

	/*
	accepts a proxy and a closure, per
	 */
	fn map<F: Fn(&VertexProxy) -> Vec<GraphIterable>>(&self, closure: F)
		-> GraphQuery {
		GraphQuery::empty()
	}

    pub fn outV(&self) -> GraphQuery {
		let f = |path: &Path| {
			println!("applying outV");
			let mut result : Vec<Path> = Vec::new();
			//take the final element in the path
			let element = path.path.last().unwrap();

			match element {
				&GraphIterable::Vertex(ref v) => {
					println!("matched vertex");
					let mut tmp = v.outV();
					for vertex in tmp {
						println!("adding path based on vertex match");
						let new_path = path.clone();
						result.push(new_path);
					}
				},
				&GraphIterable::Edge(ref e) => {

				}
			}
			// apply outV

			result
		};
		self.full_map(f)
    }

	pub fn inV(&self) -> GraphQuery {
		let g = GraphQuery::empty();
		g
	}
}

<|endoftext|>


<commit_before>extern crate cmake;

fn main() {
    // Builds the project in the directory located in `chipmunk`, installing it
    // into $OUT_DIR
    let dst = cmake::build("chipmunk");

    println!("cargo:rustc-link-search=native={}", dst.display());
    println!("cargo:rustc-link-lib=static=chipmunk");
}
<commit_msg>Disable building chipmunk demo and shared library.<commit_after>extern crate cmake;

fn main() {
    // Builds the project in the directory located in `chipmunk`, installing it
    // into $OUT_DIR
    let dst = cmake::Config::new("chipmunk")
            .define("BUILD_DEMOS", "OFF")
            .define("INSTALL_DEMOS", "OFF")
            .define("BUILD_SHARED", "OFF")
            .build();

    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
    println!("cargo:rustc-link-lib=static=chipmunk");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::result;

use ::front::Position;
use ::front::FrontendError;
use ::diagnostics as diag;
use super::ast;

pub type Result<T> = result::Result<T, SymbolError>;

type SymbolTable = HashMap<String, Rc<ast::Variable>>;

#[derive(Debug)]
pub struct Context {
    pub id_counter: u32,
    pub filename: String,
    pub function_name: String,
    pub scopes: Vec<SymbolTable>,
    pub log: Option<diag::symbols::Log>,
}

impl Context {
    pub fn new(function: &ast::Node<ast::Function>, config: &Option<diag::Config>) -> Context {
        Context {
            id_counter: 1,
            filename: function.node.filename.clone(),
            function_name: function.node.name.clone(),
            scopes: vec![SymbolTable::new()],
            log: if config.as_ref().map_or(false, |c| c.dump_symbol_table) {
                Some(diag::symbols::Log::new(function, config))
            } else {
                None
            },
        }
    }

    pub fn lookup(&self, var: &str) -> Result<Rc<ast::Variable>> {
        for scope in self.scopes.iter().rev() {
            if let Some(v) = scope.get(var) {
                return Ok(v.clone());
            }
        }
        Err(SymbolError::UnknownVariable {
            pos: Position::default(),
            var: var.to_owned(),
            filename: self.filename.clone(),
        })
    }

    pub fn insert(&mut self, var: &mut Rc<ast::Variable>) -> Result<Rc<ast::Variable>> {
        // check for duplicate
        if self.scopes.last().unwrap().contains_key(&var.name) {
            return Err(SymbolError::AlreadyDeclared {
                pos: Position::default(),
                var: var.name.clone(),
                filename: self.filename.clone(),
            });
        }

        // insert new one
        let new = Rc::new(ast::Variable {
            id: self.id_counter,
            type_: var.type_,
            name: var.name.clone(),
        });
        self.scopes.last_mut().unwrap().insert(var.name.clone(), new.clone());
        self.id_counter += 1;

        if let Some(ref mut log) = self.log {
            log.insert(&new);
        }

        // return reference to final variable
        Ok(new)
    }
}

pub fn symbolize(function: &mut ast::Node<ast::Function>) -> Result<()> {
    symbolize_with_diag(function, &None)
}

pub fn symbolize_with_diag(function: &mut ast::Node<ast::Function>,
                           config: &Option<diag::Config>)
                           -> Result<()> {
    let mut ctx = Context::new(function, config);

    if let Some(ref mut log) = ctx.log {
        log.function(function);
    }

    // add arugments to root scope
    let pos = function.pos;
    for arg in &mut function.node.args {
        *arg = try!(ctx.insert(arg).map_err(|err| err.pos(pos)));
    }

    try!(symbolize_statement(&mut ctx, &mut function.node.body));

    if let Some(ref mut log) = ctx.log {
        log.scope_close();
    }

    Ok(())
}

fn symbolize_statement(ctx: &mut Context, stmt: &mut ast::Node<ast::Statement>) -> Result<()> {

    // log creation of new scope, must be done before destructuring `stmt`
    if let Some(ref mut log) = ctx.log {
        if let ast::Statement::Compound { .. } = stmt.node {
            log.scope_open(stmt);
        }
    }

    let pos = stmt.pos;
    match stmt.node {
        ast::Statement::Expression { ref mut expr } => symbolize_expression(ctx, expr),
        ast::Statement::Declaration { ref mut var } => {
            *var = try!(ctx.insert(var).map_err(|err| err.pos(pos)));
            Ok(())
        }
        ast::Statement::Assignment { ref mut var, ref mut expr } => {
            *var = try!(ctx.lookup(&var.name).map_err(|err| err.pos(expr.pos)));
            symbolize_expression(ctx, expr)
        }
        ast::Statement::If { ref mut cond, ref mut on_true, ref mut on_false } => {
            try!(symbolize_expression(ctx, cond));
            try!(symbolize_statement(ctx, on_true));
            if let Some(ref mut stmt) = *on_false {
                symbolize_statement(ctx, stmt)
            } else {
                Ok(())
            }
        }
        ast::Statement::While { ref mut cond, ref mut body } => {
            try!(symbolize_expression(ctx, cond));
            symbolize_statement(ctx, body)
        }
        ast::Statement::Return { expr: Some(ref mut e) } => symbolize_expression(ctx, e),
        ast::Statement::Compound { ref mut stmts } => {
            // open up new scope
            ctx.scopes.push(SymbolTable::new());

            for stmt in stmts.iter_mut() {
                try!(symbolize_statement(ctx, stmt));
            }

            // scope done
            ctx.scopes.pop();
            if let Some(ref mut log) = ctx.log {
                log.scope_close();
            }

            Ok(())
        }
        _ => Ok(()),
    }
}

fn symbolize_expression(ctx: &mut Context, expr: &mut ast::Node<ast::Expression>) -> Result<()> {
    let pos = expr.pos;
    match expr.node {
        ast::Expression::Variable { ref mut var } => {
            *var = try!(ctx.lookup(&var.name).map_err(|err| err.pos(pos)));
            Ok(())
        }
        ast::Expression::Call { ref mut args, .. } => {
            for arg in args.iter_mut() {
                try!(symbolize_expression(ctx, arg));
            }
            Ok(())
        }
        ast::Expression::Binary { ref mut left, ref mut right, .. } => {
            try!(symbolize_expression(ctx, left));
            symbolize_expression(ctx, right)
        }
        ast::Expression::Unary { ref mut expr, .. } |
        ast::Expression::Parenthesis { ref mut expr } => symbolize_expression(ctx, expr),
        _ => Ok(()),
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum SymbolError {
    UnknownVariable {
        pos: Position,
        var: String,
        filename: String,
    },
    AlreadyDeclared {
        pos: Position,
        var: String,
        filename: String,
    },
}

impl SymbolError {
    fn pos(mut self, position: Position) -> SymbolError {
        match self {
            SymbolError::UnknownVariable { ref mut pos, .. } |
            SymbolError::AlreadyDeclared { ref mut pos, .. } => *pos = position,
        };
        self
    }
}

impl fmt::Display for SymbolError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SymbolError::UnknownVariable { ref var, .. } => write!(f, "UnknownVariable: `{}`", var),
            SymbolError::AlreadyDeclared { ref var, .. } => write!(f, "AlreadyDeclared: `{}`", var),
        }
    }
}

impl Error for SymbolError {
    fn description(&self) -> &str {
        match *self {
            SymbolError::UnknownVariable { .. } => "unknown variable used",
            SymbolError::AlreadyDeclared { .. } => "variable already declared in this scope",
        }
    }
}

impl From<SymbolError> for FrontendError {
    fn from(err: SymbolError) -> FrontendError {
        let (pos, filename) = match err {
            SymbolError::UnknownVariable { pos, ref filename, .. } |
            SymbolError::AlreadyDeclared { pos, ref filename, .. } => (pos, filename.clone()),
        };
        FrontendError {
            pos: pos,
            filename: filename,
            msg: err.to_string(),
            cause: Some(Box::new(err)),
        }
    }
}
<commit_msg>Front: Export SymbolTable for rust stable<commit_after>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use std::result;

use ::front::Position;
use ::front::FrontendError;
use ::diagnostics as diag;
use super::ast;

pub type Result<T> = result::Result<T, SymbolError>;
pub type SymbolTable = HashMap<String, Rc<ast::Variable>>;

#[derive(Debug)]
pub struct Context {
    pub id_counter: u32,
    pub filename: String,
    pub function_name: String,
    pub scopes: Vec<SymbolTable>,
    pub log: Option<diag::symbols::Log>,
}

impl Context {
    pub fn new(function: &ast::Node<ast::Function>, config: &Option<diag::Config>) -> Context {
        Context {
            id_counter: 1,
            filename: function.node.filename.clone(),
            function_name: function.node.name.clone(),
            scopes: vec![SymbolTable::new()],
            log: if config.as_ref().map_or(false, |c| c.dump_symbol_table) {
                Some(diag::symbols::Log::new(function, config))
            } else {
                None
            },
        }
    }

    pub fn lookup(&self, var: &str) -> Result<Rc<ast::Variable>> {
        for scope in self.scopes.iter().rev() {
            if let Some(v) = scope.get(var) {
                return Ok(v.clone());
            }
        }
        Err(SymbolError::UnknownVariable {
            pos: Position::default(),
            var: var.to_owned(),
            filename: self.filename.clone(),
        })
    }

    pub fn insert(&mut self, var: &mut Rc<ast::Variable>) -> Result<Rc<ast::Variable>> {
        // check for duplicate
        if self.scopes.last().unwrap().contains_key(&var.name) {
            return Err(SymbolError::AlreadyDeclared {
                pos: Position::default(),
                var: var.name.clone(),
                filename: self.filename.clone(),
            });
        }

        // insert new one
        let new = Rc::new(ast::Variable {
            id: self.id_counter,
            type_: var.type_,
            name: var.name.clone(),
        });
        self.scopes.last_mut().unwrap().insert(var.name.clone(), new.clone());
        self.id_counter += 1;

        if let Some(ref mut log) = self.log {
            log.insert(&new);
        }

        // return reference to final variable
        Ok(new)
    }
}

pub fn symbolize(function: &mut ast::Node<ast::Function>) -> Result<()> {
    symbolize_with_diag(function, &None)
}

pub fn symbolize_with_diag(function: &mut ast::Node<ast::Function>,
                           config: &Option<diag::Config>)
                           -> Result<()> {
    let mut ctx = Context::new(function, config);

    if let Some(ref mut log) = ctx.log {
        log.function(function);
    }

    // add arugments to root scope
    let pos = function.pos;
    for arg in &mut function.node.args {
        *arg = try!(ctx.insert(arg).map_err(|err| err.pos(pos)));
    }

    try!(symbolize_statement(&mut ctx, &mut function.node.body));

    if let Some(ref mut log) = ctx.log {
        log.scope_close();
    }

    Ok(())
}

fn symbolize_statement(ctx: &mut Context, stmt: &mut ast::Node<ast::Statement>) -> Result<()> {

    // log creation of new scope, must be done before destructuring `stmt`
    if let Some(ref mut log) = ctx.log {
        if let ast::Statement::Compound { .. } = stmt.node {
            log.scope_open(stmt);
        }
    }

    let pos = stmt.pos;
    match stmt.node {
        ast::Statement::Expression { ref mut expr } => symbolize_expression(ctx, expr),
        ast::Statement::Declaration { ref mut var } => {
            *var = try!(ctx.insert(var).map_err(|err| err.pos(pos)));
            Ok(())
        }
        ast::Statement::Assignment { ref mut var, ref mut expr } => {
            *var = try!(ctx.lookup(&var.name).map_err(|err| err.pos(expr.pos)));
            symbolize_expression(ctx, expr)
        }
        ast::Statement::If { ref mut cond, ref mut on_true, ref mut on_false } => {
            try!(symbolize_expression(ctx, cond));
            try!(symbolize_statement(ctx, on_true));
            if let Some(ref mut stmt) = *on_false {
                symbolize_statement(ctx, stmt)
            } else {
                Ok(())
            }
        }
        ast::Statement::While { ref mut cond, ref mut body } => {
            try!(symbolize_expression(ctx, cond));
            symbolize_statement(ctx, body)
        }
        ast::Statement::Return { expr: Some(ref mut e) } => symbolize_expression(ctx, e),
        ast::Statement::Compound { ref mut stmts } => {
            // open up new scope
            ctx.scopes.push(SymbolTable::new());

            for stmt in stmts.iter_mut() {
                try!(symbolize_statement(ctx, stmt));
            }

            // scope done
            ctx.scopes.pop();
            if let Some(ref mut log) = ctx.log {
                log.scope_close();
            }

            Ok(())
        }
        _ => Ok(()),
    }
}

fn symbolize_expression(ctx: &mut Context, expr: &mut ast::Node<ast::Expression>) -> Result<()> {
    let pos = expr.pos;
    match expr.node {
        ast::Expression::Variable { ref mut var } => {
            *var = try!(ctx.lookup(&var.name).map_err(|err| err.pos(pos)));
            Ok(())
        }
        ast::Expression::Call { ref mut args, .. } => {
            for arg in args.iter_mut() {
                try!(symbolize_expression(ctx, arg));
            }
            Ok(())
        }
        ast::Expression::Binary { ref mut left, ref mut right, .. } => {
            try!(symbolize_expression(ctx, left));
            symbolize_expression(ctx, right)
        }
        ast::Expression::Unary { ref mut expr, .. } |
        ast::Expression::Parenthesis { ref mut expr } => symbolize_expression(ctx, expr),
        _ => Ok(()),
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum SymbolError {
    UnknownVariable {
        pos: Position,
        var: String,
        filename: String,
    },
    AlreadyDeclared {
        pos: Position,
        var: String,
        filename: String,
    },
}

impl SymbolError {
    fn pos(mut self, position: Position) -> SymbolError {
        match self {
            SymbolError::UnknownVariable { ref mut pos, .. } |
            SymbolError::AlreadyDeclared { ref mut pos, .. } => *pos = position,
        };
        self
    }
}

impl fmt::Display for SymbolError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SymbolError::UnknownVariable { ref var, .. } => write!(f, "UnknownVariable: `{}`", var),
            SymbolError::AlreadyDeclared { ref var, .. } => write!(f, "AlreadyDeclared: `{}`", var),
        }
    }
}

impl Error for SymbolError {
    fn description(&self) -> &str {
        match *self {
            SymbolError::UnknownVariable { .. } => "unknown variable used",
            SymbolError::AlreadyDeclared { .. } => "variable already declared in this scope",
        }
    }
}

impl From<SymbolError> for FrontendError {
    fn from(err: SymbolError) -> FrontendError {
        let (pos, filename) = match err {
            SymbolError::UnknownVariable { pos, ref filename, .. } |
            SymbolError::AlreadyDeclared { pos, ref filename, .. } => (pos, filename.clone()),
        };
        FrontendError {
            pos: pos,
            filename: filename,
            msg: err.to_string(),
            cause: Some(Box::new(err)),
        }
    }
}
<|endoftext|>


<commit_before>//! An implementation of disjoint set forests for union find.

/// Data structure for efficient union find.
pub struct DisjointSetForest {
    /// Number of forest elements.
    count: usize,
    /// parent[i] is the index of the parent
    /// of the element with index i. If parent[i] == i
    /// then i is a root.
    parent: Vec<usize>,
    /// tree_size[i] is the size of the tree rooted at i.
    tree_size: Vec<usize>,
}

impl DisjointSetForest {

    /// Constructs forest of singletons with count elements.
    pub fn new(count: usize) -> DisjointSetForest {
        let mut parent = vec![0 as usize; count];
        for i in 0..count {
            parent[i] = i;
        }
        let tree_size = vec![1 as usize; count];
        DisjointSetForest {
            count: count,
            parent: parent,
            tree_size: tree_size}
    }

    /// Returns the number of trees in the forest.
    pub fn num_trees(&self) -> usize {
        self.parent
            .iter()
            .enumerate()
            .fold(0, |acc, (i, p)| acc + if i == *p { 1 } else { 0 })
    }

    /// Returns index of the root of the tree containing i.
    /// Needs mutable reference to self for path compression.
    pub fn root(&mut self, i: usize) -> usize {
        let mut j = i;
        loop {
            unsafe {
                let p = *self.parent.get_unchecked(j);
                *self.parent.get_unchecked_mut(j) = *self.parent.get_unchecked(p);
                if j == p {
                    break;
                }
                j = p;
            }
        }
        j
    }

    /// Returns true if i and j are in the same tree.
    /// Need mutable reference to self for path compression.
    pub fn find(&mut self, i: usize, j: usize) -> bool {
        self.root(i) == self.root(j)
    }

    /// Unions the trees containing i and j.
    pub fn union(&mut self, i: usize, j: usize) {
        let p = self.root(i);
        let q = self.root(j);
        if p == q {
            return;
        }
        unsafe {
            let p_size = *self.tree_size.get_unchecked(p);
            let q_size = *self.tree_size.get_unchecked(q);
            if p_size < q_size {
                *self.parent.get_unchecked_mut(p) = q;
                *self.tree_size.get_unchecked_mut(q) = p_size + q_size;
            }
            else {
                *self.parent.get_unchecked_mut(q) = p;
                *self.tree_size.get_unchecked_mut(p) = p_size + q_size;
            }
        }
    }

    /// Returns the elements of each tree.
    pub fn trees(&mut self) -> Vec<Vec<usize>> {
        use std::collections::HashMap;

        // Maps a tree root to the index of the set
        // containing its children
        let mut root_sets: HashMap<usize, usize> = HashMap::new();

        let mut sets: Vec<Vec<usize>> = vec![];
        for i in 0..self.count {
            let root = self.root(i);
            match root_sets.get(&root).cloned() {
                Some(set_idx) => {
                    sets[set_idx].push(i);
                },
                None => {
                    let idx = sets.len();
                    let set = vec![i];
                    sets.push(set);
                    root_sets.insert(root, idx);
                }
            }
        }
        sets
    }
}

#[cfg(test)]
mod test {

    use super::{
        DisjointSetForest
    };

    #[test]
    fn test_trees() {
        //    3         4
        //    |        /  \
        //    1       5    7
        //   /  \     |
        //  0    2    6
        let mut forest = DisjointSetForest {
            count: 8,
            // element:     0, 1, 2, 3, 4, 5, 6, 7
            parent:    vec![1, 3, 1, 3, 4, 4, 5, 4],
            tree_size: vec![1, 3, 1, 4, 4, 2, 1, 1]
        };

        assert_eq!(forest.trees(),
            vec![vec![0, 1, 2, 3], vec![4, 5, 6, 7]]);
    }

    #[test]
    fn test_union_find_sequence() {

        let mut forest = DisjointSetForest::new(6);
        // 0  1  2  3  4  5

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 3, 4, 5]);
        assert_eq!(forest.num_trees(), 6);

        forest.union(0, 4);
        // 0  1  2  3  5
        // |
        // 4

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 3, 0, 5]);
        assert_eq!(forest.num_trees(), 5);

        forest.union(1, 3);
        // 0  1  2  5
        // |  |
        // 4  3

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 4);

        forest.union(3, 2);
        // 0    1     5
        // |   / \
        // 4  3   2

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 1, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 3);

        forest.union(2, 4);
        //    1     5
        //  / | \
        // 0  3  2
        // |
        // 4

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![1, 1, 1, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 2);
    }

    // TODO: write a benchmark
}
<commit_msg>Add unionfind benchmark<commit_after>//! An implementation of disjoint set forests for union find.

/// Data structure for efficient union find.
pub struct DisjointSetForest {
    /// Number of forest elements.
    count: usize,
    /// parent[i] is the index of the parent
    /// of the element with index i. If parent[i] == i
    /// then i is a root.
    parent: Vec<usize>,
    /// tree_size[i] is the size of the tree rooted at i.
    tree_size: Vec<usize>,
}

impl DisjointSetForest {

    /// Constructs forest of singletons with count elements.
    pub fn new(count: usize) -> DisjointSetForest {
        let mut parent = vec![0 as usize; count];
        for i in 0..count {
            parent[i] = i;
        }
        let tree_size = vec![1 as usize; count];
        DisjointSetForest {
            count: count,
            parent: parent,
            tree_size: tree_size}
    }

    /// Returns the number of trees in the forest.
    pub fn num_trees(&self) -> usize {
        self.parent
            .iter()
            .enumerate()
            .fold(0, |acc, (i, p)| acc + if i == *p { 1 } else { 0 })
    }

    /// Returns index of the root of the tree containing i.
    /// Needs mutable reference to self for path compression.
    pub fn root(&mut self, i: usize) -> usize {
        let mut j = i;
        loop {
            unsafe {
                let p = *self.parent.get_unchecked(j);
                *self.parent.get_unchecked_mut(j) = *self.parent.get_unchecked(p);
                if j == p {
                    break;
                }
                j = p;
            }
        }
        j
    }

    /// Returns true if i and j are in the same tree.
    /// Need mutable reference to self for path compression.
    pub fn find(&mut self, i: usize, j: usize) -> bool {
        self.root(i) == self.root(j)
    }

    /// Unions the trees containing i and j.
    pub fn union(&mut self, i: usize, j: usize) {
        let p = self.root(i);
        let q = self.root(j);
        if p == q {
            return;
        }
        unsafe {
            let p_size = *self.tree_size.get_unchecked(p);
            let q_size = *self.tree_size.get_unchecked(q);
            if p_size < q_size {
                *self.parent.get_unchecked_mut(p) = q;
                *self.tree_size.get_unchecked_mut(q) = p_size + q_size;
            }
            else {
                *self.parent.get_unchecked_mut(q) = p;
                *self.tree_size.get_unchecked_mut(p) = p_size + q_size;
            }
        }
    }

    /// Returns the elements of each tree.
    pub fn trees(&mut self) -> Vec<Vec<usize>> {
        use std::collections::HashMap;

        // Maps a tree root to the index of the set
        // containing its children
        let mut root_sets: HashMap<usize, usize> = HashMap::new();

        let mut sets: Vec<Vec<usize>> = vec![];
        for i in 0..self.count {
            let root = self.root(i);
            match root_sets.get(&root).cloned() {
                Some(set_idx) => {
                    sets[set_idx].push(i);
                },
                None => {
                    let idx = sets.len();
                    let set = vec![i];
                    sets.push(set);
                    root_sets.insert(root, idx);
                }
            }
        }
        sets
    }
}

#[cfg(test)]
mod test {

    use super::DisjointSetForest;
    use test;
    use rand::{SeedableRng, StdRng};
    use rand::distributions::{IndependentSample, Range};

    #[test]
    fn test_trees() {
        //    3         4
        //    |        /  \
        //    1       5    7
        //   /  \     |
        //  0    2    6
        let mut forest = DisjointSetForest {
            count: 8,
            // element:     0, 1, 2, 3, 4, 5, 6, 7
            parent:    vec![1, 3, 1, 3, 4, 4, 5, 4],
            tree_size: vec![1, 3, 1, 4, 4, 2, 1, 1]
        };

        assert_eq!(forest.trees(),
            vec![vec![0, 1, 2, 3], vec![4, 5, 6, 7]]);
    }

    #[test]
    fn test_union_find_sequence() {

        let mut forest = DisjointSetForest::new(6);
        // 0  1  2  3  4  5

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 3, 4, 5]);
        assert_eq!(forest.num_trees(), 6);

        forest.union(0, 4);
        // 0  1  2  3  5
        // |
        // 4

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 3, 0, 5]);
        assert_eq!(forest.num_trees(), 5);

        forest.union(1, 3);
        // 0  1  2  5
        // |  |
        // 4  3

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 2, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 4);

        forest.union(3, 2);
        // 0    1     5
        // |   / \
        // 4  3   2

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![0, 1, 1, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 3);

        forest.union(2, 4);
        //    1     5
        //  / | \
        // 0  3  2
        // |
        // 4

        //                             0, 1, 2, 3, 4, 5
        assert_eq!(forest.parent, vec![1, 1, 1, 1, 0, 5]);
        assert_eq!(forest.num_trees(), 2);
    }

    #[bench]
    fn bench_disjoint_set_forest(b: &mut test::Bencher) {
        let num_nodes = 500;
        let num_edges = 20 * num_nodes;

        let seed_array: &[_] = &[1usize];
        let mut rng: StdRng = SeedableRng::from_seed(seed_array);
        let uniform = Range::new(0, num_nodes + 1);

        let mut forest = DisjointSetForest::new(num_nodes);
        b.iter(|| {
            let mut count = 0;
            while count < num_edges {
                let u = uniform.ind_sample(&mut rng);
                let v = uniform.ind_sample(&mut rng);
                forest.union(u, v);
                count += 1;
            }
            test::black_box(forest.num_trees());
        });
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uniq"]
/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

#![feature(macro_rules)]

extern crate getopts;

use std::ascii::OwnedStrAsciiExt;
use std::cmp::min;
use std::from_str::FromStr;
use std::io;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "uniq";
static VERSION: &'static str = "1.0.0";

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: String,
    show_counts: bool,
    slice_start: Option<uint>,
    slice_stop: Option<uint>,
    ignore_case: bool,
}

impl Uniq {
    pub fn print_uniq<R: Reader, W: Writer>(&self, reader: &mut io::BufferedReader<R>, writer: &mut io::BufferedWriter<W>) {
        let mut lines: Vec<String> = vec!();
        let mut first_line_printed = false;
        let delimiters = self.delimiters.as_slice();

        for io_line in reader.lines() {
            let line = crash_if_err!(1, io_line);
            if !lines.is_empty() && self.cmp_key(&lines[0]) != self.cmp_key(&line) {
                let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn cmp_key(&self, line: &String) -> String {
        let len = line.len();
        if len > 0 {
            let slice_start = match self.slice_start {
                Some(i) => min(i, len - 1),
                None => 0
            };
            let slice_stop = match self.slice_stop {
                Some(i) => min(slice_start + i, len),
                None => len
            };
            let sliced = line.as_slice().slice(slice_start, slice_stop).into_string();
            if self.ignore_case {
                sliced.into_ascii_upper()
            } else {
                sliced
            }
        } else {
            line.clone()
        }
    }

    fn print_lines<W: Writer>(&self, writer: &mut io::BufferedWriter<W>, lines: &Vec<String>, print_delimiter: bool) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only
                || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines.tail().iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Writer>(&self, writer: &mut io::BufferedWriter<W>, line: &String, count: uint, print_delimiter: bool) {
        let output_line = if self.show_counts {
            format!("{:7} {}", count, line)
        } else {
            line.clone()
        };
        if print_delimiter {
            crash_if_err!(1, writer.write_line(""));
        }
        crash_if_err!(1, writer.write_str(output_line.as_slice()));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &getopts::Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = from_str(arg_str.as_slice());
        opt_val.unwrap_or_else(||
            crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> int {
    let program_path = Path::new(args[0].clone());
    let program = program_path.filename_str().unwrap_or(NAME);

    let opts = [
        getopts::optflag("c", "count", "prefix lines by the number of occurrences"),
        getopts::optflag("d", "repeated", "only print duplicate lines"),
        getopts::optflagopt(
            "D",
            "all-repeated",
            "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
            "delimit-method"
        ),
        getopts::optopt("s", "skip-chars", "avoid comparing the first N characters", "N"),
        getopts::optopt("w", "check-chars", "compare no more than N characters in lines", "N"),
        getopts::optflag("i", "ignore-case", "ignore differences in case when comparing"),
        getopts::optflag("u", "unique", "only print unique lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print!("{}", getopts::usage("Filter adjacent matching lines from INPUT (or standard input),\n\
                                    writing to OUTPUT (or standard output).", opts));
        println!("");
        println!("Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
                  You may want to sort the input first, or use 'sort -u' without '{0}'.\n", program);
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".into_string(), "-".into_string()),
            1 => (matches.free[0].clone(), "-".into_string()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg.as_slice() != "none" => {
                    let rep_args = ["prepend".to_string(), "separate".to_string()];
                    if !rep_args.contains(opt_arg) {
                        crash!(1, "Incorrect argument for all-repeated: {}", opt_arg.clone());
                    }
                    opt_arg.clone()
                },
                _ => "".to_string()
            },
            show_counts: matches.opt_present("count"),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
        };
        uniq.print_uniq(&mut open_input_file(in_file_name),
                        &mut open_output_file(out_file_name));
    }
    0
}

fn open_input_file(in_file_name: String) -> io::BufferedReader<Box<Reader+'static>> {
    let in_file = if in_file_name.as_slice() == "-" {
        box io::stdio::stdin_raw() as Box<Reader>
    } else {
        let path = Path::new(in_file_name);
        let in_file = io::File::open(&path);
        box crash_if_err!(1, in_file) as Box<Reader>
    };
    io::BufferedReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> io::BufferedWriter<Box<Writer+'static>> {
    let out_file = if out_file_name.as_slice() == "-" {
        box io::stdio::stdout_raw() as Box<Writer>
    } else {
        let path = Path::new(out_file_name);
        let in_file = io::File::create(&path);
        box crash_if_err!(1, in_file) as Box<Writer>
    };
    io::BufferedWriter::new(out_file)
}
<commit_msg>uniq: fix build<commit_after>#![crate_name = "uniq"]
/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

#![feature(macro_rules)]

extern crate getopts;

use std::ascii::OwnedAsciiExt;
use std::cmp::min;
use std::from_str::FromStr;
use std::io;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "uniq";
static VERSION: &'static str = "1.0.0";

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: String,
    show_counts: bool,
    slice_start: Option<uint>,
    slice_stop: Option<uint>,
    ignore_case: bool,
}

impl Uniq {
    pub fn print_uniq<R: Reader, W: Writer>(&self, reader: &mut io::BufferedReader<R>, writer: &mut io::BufferedWriter<W>) {
        let mut lines: Vec<String> = vec!();
        let mut first_line_printed = false;
        let delimiters = self.delimiters.as_slice();

        for io_line in reader.lines() {
            let line = crash_if_err!(1, io_line);
            if !lines.is_empty() && self.cmp_key(&lines[0]) != self.cmp_key(&line) {
                let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
                first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
                lines.truncate(0);
            }
            lines.push(line);
        }
        if !lines.is_empty() {
            let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
            self.print_lines(writer, &lines, print_delimiter);
        }
    }

    fn cmp_key(&self, line: &String) -> String {
        let len = line.len();
        if len > 0 {
            let slice_start = match self.slice_start {
                Some(i) => min(i, len - 1),
                None => 0
            };
            let slice_stop = match self.slice_stop {
                Some(i) => min(slice_start + i, len),
                None => len
            };
            let sliced = line.as_slice().slice(slice_start, slice_stop).into_string();
            if self.ignore_case {
                sliced.into_ascii_upper()
            } else {
                sliced
            }
        } else {
            line.clone()
        }
    }

    fn print_lines<W: Writer>(&self, writer: &mut io::BufferedWriter<W>, lines: &Vec<String>, print_delimiter: bool) -> bool {
        let mut first_line_printed = false;
        let mut count = if self.all_repeated { 1 } else { lines.len() };
        if lines.len() == 1 && !self.repeats_only
                || lines.len() > 1 && !self.uniques_only {
            self.print_line(writer, &lines[0], count, print_delimiter);
            first_line_printed = true;
            count += 1;
        }
        if self.all_repeated {
            for line in lines.tail().iter() {
                self.print_line(writer, line, count, print_delimiter && !first_line_printed);
                first_line_printed = true;
                count += 1;
            }
        }
        first_line_printed
    }

    fn print_line<W: Writer>(&self, writer: &mut io::BufferedWriter<W>, line: &String, count: uint, print_delimiter: bool) {
        let output_line = if self.show_counts {
            format!("{:7} {}", count, line)
        } else {
            line.clone()
        };
        if print_delimiter {
            crash_if_err!(1, writer.write_line(""));
        }
        crash_if_err!(1, writer.write_str(output_line.as_slice()));
    }
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &getopts::Matches) -> Option<T> {
    matches.opt_str(opt_name).map(|arg_str| {
        let opt_val: Option<T> = from_str(arg_str.as_slice());
        opt_val.unwrap_or_else(||
            crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
    })
}

pub fn uumain(args: Vec<String>) -> int {
    let program_path = Path::new(args[0].clone());
    let program = program_path.filename_str().unwrap_or(NAME);

    let opts = [
        getopts::optflag("c", "count", "prefix lines by the number of occurrences"),
        getopts::optflag("d", "repeated", "only print duplicate lines"),
        getopts::optflagopt(
            "D",
            "all-repeated",
            "print all duplicate lines delimit-method={none(default),prepend,separate} Delimiting is done with blank lines",
            "delimit-method"
        ),
        getopts::optopt("s", "skip-chars", "avoid comparing the first N characters", "N"),
        getopts::optopt("w", "check-chars", "compare no more than N characters in lines", "N"),
        getopts::optflag("i", "ignore-case", "ignore differences in case when comparing"),
        getopts::optflag("u", "unique", "only print unique lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print!("{}", getopts::usage("Filter adjacent matching lines from INPUT (or standard input),\n\
                                    writing to OUTPUT (or standard output).", opts));
        println!("");
        println!("Note: '{0}' does not detect repeated lines unless they are adjacent.\n\
                  You may want to sort the input first, or use 'sort -u' without '{0}'.\n", program);
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else {
        let (in_file_name, out_file_name) = match matches.free.len() {
            0 => ("-".into_string(), "-".into_string()),
            1 => (matches.free[0].clone(), "-".into_string()),
            2 => (matches.free[0].clone(), matches.free[1].clone()),
            _ => {
                crash!(1, "Extra operand: {}", matches.free[2]);
            }
        };
        let uniq = Uniq {
            repeats_only: matches.opt_present("repeated") || matches.opt_present("all-repeated"),
            uniques_only: matches.opt_present("unique"),
            all_repeated: matches.opt_present("all-repeated"),
            delimiters: match matches.opt_default("all-repeated", "none") {
                Some(ref opt_arg) if opt_arg.as_slice() != "none" => {
                    let rep_args = ["prepend".to_string(), "separate".to_string()];
                    if !rep_args.contains(opt_arg) {
                        crash!(1, "Incorrect argument for all-repeated: {}", opt_arg.clone());
                    }
                    opt_arg.clone()
                },
                _ => "".to_string()
            },
            show_counts: matches.opt_present("count"),
            slice_start: opt_parsed("skip-chars", &matches),
            slice_stop: opt_parsed("check-chars", &matches),
            ignore_case: matches.opt_present("ignore-case"),
        };
        uniq.print_uniq(&mut open_input_file(in_file_name),
                        &mut open_output_file(out_file_name));
    }
    0
}

fn open_input_file(in_file_name: String) -> io::BufferedReader<Box<Reader+'static>> {
    let in_file = if in_file_name.as_slice() == "-" {
        box io::stdio::stdin_raw() as Box<Reader>
    } else {
        let path = Path::new(in_file_name);
        let in_file = io::File::open(&path);
        box crash_if_err!(1, in_file) as Box<Reader>
    };
    io::BufferedReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> io::BufferedWriter<Box<Writer+'static>> {
    let out_file = if out_file_name.as_slice() == "-" {
        box io::stdio::stdout_raw() as Box<Writer>
    } else {
        let path = Path::new(out_file_name);
        let in_file = io::File::create(&path);
        box crash_if_err!(1, in_file) as Box<Writer>
    };
    io::BufferedWriter::new(out_file)
}
<|endoftext|>