<commit_before>//! Floating point traits
//!
//! This module is work-around for the lack of floating point operations under `#![no_std]`. If you
//! haven't disabled the `std` feature, it just re-exports `num_traits::Float`.
//!
//! However, without `std`, it's a custom trait with a subset of the methods from
//!`num_traits::Float`, implemented for `f32` and `f64`.
//!
//! If you are using this on `no_std`, there are two options to supply the necessary floating point
//! operations:
//!
//! * By enabling the `soft_float` feature, these functions are supplied using the `mish` and `m`
//!   crates. This comes with the caveat that as software implementations, they're likely to be
//!   slower and less precise than potential hardware versions.
//! * Without the `soft_float` feature, it is necessary to supply the required operations via
//!   `extern "C"` declarations. This might be beneficial if, for example, you're using a platform
//!   that has hard float operations and you need it to be faster. It's recommended to enable LTO in
//!   this case, to minimize any overhead. These are the functions it expects to link against:
//!   ```rust,ignore
//!   extern "C" {
//!       // Computes the square root of `x`
//!       // Should be compatible with `x.sqrt()` from the standard library
//!       fn sqrtf32(x: f32) -> f32;
//!       fn sqrtf64(x: f64) -> f64;
//!       // Computes `x` to the power of `y`
//!       // Should be compatible with `x.powf(y)` from the standard library
//!       fn powf32(x: f32, y: f32) -> f32;
//!       fn powf64(x: f64, y: f64) -> f64;
//!       // Computes the sine of `x` radians
//!       // Should be compatible with `x.sin()` from the standard library
//!       fn sinf32(x: f32) -> f32;
//!       fn sinf64(x: f64) -> f64;
//!       // Computes the cosine of `x` radians
//!       // Should be compatible with `x.cos()` from the standard library
//!       fn cosf32(x: f32) -> f32;
//!       fn cosf64(x: f64) -> f64;
//!       // Computes the inverse tangent of `y / x`, in the corresponding quadrant
//!       // Should be compatible with `y.atan2(x)` from the standard library
//!       fn atan2f32(y: f32, x: f32) -> f32;
//!       fn atan2f64(y: f64, x: f64) -> f64;
//!   }
//!   ```
//!
//! Because new floating point functions may be needed in patch releases, the specifics of which
//! operations are included in the trait (and likewise in the list of required `extern "C"` functions)
//! are semver-exempt on `no_std`.

#[cfg(feature = "std")]
pub use num_traits::Float;

#[cfg(not(feature = "std"))]
pub use self::no_std_float_trait::Float;

#[cfg(not(feature = "std"))]
mod no_std_float_trait {
    #[cfg(feature = "soft_float")]
    extern crate m;
    #[cfg(feature = "soft_float")]
    extern crate mish;

    use num_traits::float::FloatCore;

    /// This is the trait that represents a floating-point number under `no_std`. It has a subset
    /// of the operations that are in `num_traits::Float`, including all of the
    /// `num_traits::float::FloatCore` opterations. For documentation of specific functions in this
    /// trait, see the [`num_traits::Float` docs][num_traits].
    ///
    /// It's implemented for `f32` and `f64`. See the [module docs][module] for details.
    ///
    /// # Compatibility between versions
    ///
    /// Because of the possibility of needing more floating point operations in point releases, this
    /// trait is semver-exempt with respect to adding new functions. (If you really need to
    /// implement it for your own `MyFloat` type, pin a specific version in your `Cargo.toml`.)
    /// However, removing methods from this trait is still considered a breaking change.
    ///
    /// [num_traits]: https://docs.rs/num-traits/0.2.5/num_traits/float/trait.Float.html
    /// [module]: index.html
    pub trait Float: FloatCore {
        fn sqrt(self) -> Self;
        fn powf(self, other: Self) -> Self;
        fn sin(self) -> Self;
        fn cos(self) -> Self;
        fn atan2(self, other: Self) -> Self;
    }

    #[cfg(feature = "soft_float")]
    impl Float for f32 {
        fn sqrt(self) -> f32 {
            mish::sqrt(self)
        }
        fn powf(self, other: f32) -> f32 {
            mish::powf(self, other)
        }
        fn sin(self) -> f32 {
            mish::sin(self)
        }
        fn cos(self) -> f32 {
            mish::cos(self)
        }
        fn atan2(self, other: f32) -> f32 {
            m::Float::atan2(self, other)
        }
    }

    #[cfg(feature = "soft_float")]
    impl Float for f64 {
        fn sqrt(self) -> f64 {
            mish::sqrt(self)
        }
        fn powf(self, other: f64) -> f64 {
            mish::powf(self, other)
        }
        fn sin(self) -> f64 {
            mish::sin(self)
        }
        fn cos(self) -> f64 {
            mish::cos(self)
        }
        fn atan2(self, other: f64) -> f64 {
            // f64 atan2 isn't implemented in `m` yet
            m::Float::atan2(self as f32, other as f32).into()
        }
    }

    #[cfg(not(feature = "soft_float"))]
    extern "C" {
        // Computes the square root of `x`
        // Should be compatible with `x.sqrt()` from the standard library
        fn sqrtf32(x: f32) -> f32;
        fn sqrtf64(x: f64) -> f64;
        // Computes `x` to the power of `y`
        // Should be compatible with `x.powf(y)` from the standard library
        fn powf32(x: f32, y: f32) -> f32;
        fn powf64(x: f64, y: f64) -> f64;
        // Computes the sine of `x` radians
        // Should be compatible with `x.sin()` from the standard library
        fn sinf32(x: f32) -> f32;
        fn sinf64(x: f64) -> f64;
        // Computes the cosine of `x` radians
        // Should be compatible with `x.cos()` from the standard library
        fn cosf32(x: f32) -> f32;
        fn cosf64(x: f64) -> f64;
        // Computes the inverse tangent of `y / x`, in the corresponding quadrant
        // Should be compatible with `y.atan2(x)` from the standard library
        fn atan2f32(y: f32, x: f32) -> f32;
        fn atan2f64(y: f64, x: f64) -> f64;
    }

    #[cfg(not(feature = "soft_float"))]
    impl Float for f32 {
        fn sqrt(self) -> f32 {
            unsafe { sqrtf32(self) }
        }
        fn powf(self, other: f32) -> f32 {
            unsafe { powf32(self, other) }
        }
        fn sin(self) -> f32 {
            unsafe { sinf32(self) }
        }
        fn cos(self) -> f32 {
            unsafe { cosf32(self) }
        }
        fn atan2(self, other: f32) -> f32 {
            unsafe { atan2f32(self, other) }
        }
    }

    #[cfg(not(feature = "soft_float"))]
    impl Float for f64 {
        fn sqrt(self) -> f64 {
            unsafe { sqrtf64(self) }
        }
        fn powf(self, other: f64) -> f64 {
            unsafe { powf64(self, other) }
        }
        fn sin(self) -> f64 {
            unsafe { sinf64(self) }
        }
        fn cos(self) -> f64 {
            unsafe { cosf64(self) }
        }
        fn atan2(self, other: f64) -> f64 {
            unsafe { atan2f64(self, other) }
        }
    }
}
<commit_msg>Add method docs for no_std float::Float trait<commit_after>//! Floating point traits
//!
//! This module is work-around for the lack of floating point operations under `#![no_std]`. If you
//! haven't disabled the `std` feature, it just re-exports `num_traits::Float`.
//!
//! However, without `std`, it's a custom trait with a subset of the methods from
//!`num_traits::Float`, implemented for `f32` and `f64`.
//!
//! If you are using this on `no_std`, there are two options to supply the necessary floating point
//! operations:
//!
//! * By enabling the `soft_float` feature, these functions are supplied using the `mish` and `m`
//!   crates. This comes with the caveat that as software implementations, they're likely to be
//!   slower and less precise than potential hardware versions.
//! * Without the `soft_float` feature, it is necessary to supply the required operations via
//!   `extern "C"` declarations. This might be beneficial if, for example, you're using a platform
//!   that has hard float operations and you need it to be faster. It's recommended to enable LTO in
//!   this case, to minimize any overhead. These are the functions it expects to link against:
//!   ```rust,ignore
//!   extern "C" {
//!       // Computes the square root of `x`
//!       // Should be compatible with `x.sqrt()` from the standard library
//!       fn sqrtf32(x: f32) -> f32;
//!       fn sqrtf64(x: f64) -> f64;
//!       // Computes `x` to the power of `y`
//!       // Should be compatible with `x.powf(y)` from the standard library
//!       fn powf32(x: f32, y: f32) -> f32;
//!       fn powf64(x: f64, y: f64) -> f64;
//!       // Computes the sine of `x` radians
//!       // Should be compatible with `x.sin()` from the standard library
//!       fn sinf32(x: f32) -> f32;
//!       fn sinf64(x: f64) -> f64;
//!       // Computes the cosine of `x` radians
//!       // Should be compatible with `x.cos()` from the standard library
//!       fn cosf32(x: f32) -> f32;
//!       fn cosf64(x: f64) -> f64;
//!       // Computes the inverse tangent of `y / x`, in the corresponding quadrant
//!       // Should be compatible with `y.atan2(x)` from the standard library
//!       fn atan2f32(y: f32, x: f32) -> f32;
//!       fn atan2f64(y: f64, x: f64) -> f64;
//!   }
//!   ```
//!
//! Because new floating point functions may be needed in patch releases, the specifics of which
//! operations are included in the trait (and likewise in the list of required `extern "C"` functions)
//! are semver-exempt on `no_std`.

#[cfg(feature = "std")]
pub use num_traits::Float;

#[cfg(not(feature = "std"))]
pub use self::no_std_float_trait::Float;

#[cfg(not(feature = "std"))]
mod no_std_float_trait {
    #[cfg(feature = "soft_float")]
    extern crate m;
    #[cfg(feature = "soft_float")]
    extern crate mish;

    use num_traits::float::FloatCore;

    /// This is the trait that represents a floating-point number under `no_std`. It has a subset
    /// of the operations that are in `num_traits::Float`, including all of the
    /// `num_traits::float::FloatCore` opterations. For documentation of specific functions in this
    /// trait, see the [`num_traits::Float` docs][num_traits].
    ///
    /// It's implemented for `f32` and `f64`. See the [module docs][module] for details.
    ///
    /// # Compatibility between versions
    ///
    /// Because of the possibility of needing more floating point operations in point releases, this
    /// trait is semver-exempt with respect to adding new functions. (If you really need to
    /// implement it for your own `MyFloat` type, pin a specific version in your `Cargo.toml`.)
    /// However, removing methods from this trait is still considered a breaking change.
    ///
    /// [num_traits]: https://docs.rs/num-traits/0.2.5/num_traits/float/trait.Float.html
    /// [module]: index.html
    pub trait Float: FloatCore {
        /// `x.sqrt()` computes the square root of `x`.
        fn sqrt(self) -> Self;
        /// `x.powf(y)` computes `x` to the power of `y`.
        fn powf(self, other: Self) -> Self;
        /// `x.sin()` computes the sine of `x` radians.
        fn sin(self) -> Self;
        /// `x.cos()` computes the cosine of `x` radians.
        fn cos(self) -> Self;
        /// `y.atan2(x)` computes the inverse tangent of `y / x`, in the corresponding quadrant
        fn atan2(self, other: Self) -> Self;
    }

    #[cfg(feature = "soft_float")]
    impl Float for f32 {
        fn sqrt(self) -> f32 {
            mish::sqrt(self)
        }
        fn powf(self, other: f32) -> f32 {
            mish::powf(self, other)
        }
        fn sin(self) -> f32 {
            mish::sin(self)
        }
        fn cos(self) -> f32 {
            mish::cos(self)
        }
        fn atan2(self, other: f32) -> f32 {
            m::Float::atan2(self, other)
        }
    }

    #[cfg(feature = "soft_float")]
    impl Float for f64 {
        fn sqrt(self) -> f64 {
            mish::sqrt(self)
        }
        fn powf(self, other: f64) -> f64 {
            mish::powf(self, other)
        }
        fn sin(self) -> f64 {
            mish::sin(self)
        }
        fn cos(self) -> f64 {
            mish::cos(self)
        }
        fn atan2(self, other: f64) -> f64 {
            // f64 atan2 isn't implemented in `m` yet
            m::Float::atan2(self as f32, other as f32).into()
        }
    }

    #[cfg(not(feature = "soft_float"))]
    extern "C" {
        // Computes the square root of `x`
        // Should be compatible with `x.sqrt()` from the standard library
        fn sqrtf32(x: f32) -> f32;
        fn sqrtf64(x: f64) -> f64;
        // Computes `x` to the power of `y`
        // Should be compatible with `x.powf(y)` from the standard library
        fn powf32(x: f32, y: f32) -> f32;
        fn powf64(x: f64, y: f64) -> f64;
        // Computes the sine of `x` radians
        // Should be compatible with `x.sin()` from the standard library
        fn sinf32(x: f32) -> f32;
        fn sinf64(x: f64) -> f64;
        // Computes the cosine of `x` radians
        // Should be compatible with `x.cos()` from the standard library
        fn cosf32(x: f32) -> f32;
        fn cosf64(x: f64) -> f64;
        // Computes the inverse tangent of `y / x`, in the corresponding quadrant
        // Should be compatible with `y.atan2(x)` from the standard library
        fn atan2f32(y: f32, x: f32) -> f32;
        fn atan2f64(y: f64, x: f64) -> f64;
    }

    #[cfg(not(feature = "soft_float"))]
    impl Float for f32 {
        fn sqrt(self) -> f32 {
            unsafe { sqrtf32(self) }
        }
        fn powf(self, other: f32) -> f32 {
            unsafe { powf32(self, other) }
        }
        fn sin(self) -> f32 {
            unsafe { sinf32(self) }
        }
        fn cos(self) -> f32 {
            unsafe { cosf32(self) }
        }
        fn atan2(self, other: f32) -> f32 {
            unsafe { atan2f32(self, other) }
        }
    }

    #[cfg(not(feature = "soft_float"))]
    impl Float for f64 {
        fn sqrt(self) -> f64 {
            unsafe { sqrtf64(self) }
        }
        fn powf(self, other: f64) -> f64 {
            unsafe { powf64(self, other) }
        }
        fn sin(self) -> f64 {
            unsafe { sinf64(self) }
        }
        fn cos(self) -> f64 {
            unsafe { cosf64(self) }
        }
        fn atan2(self, other: f64) -> f64 {
            unsafe { atan2f64(self, other) }
        }
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::{env, io, fs};
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    if !cfg!(feature = "static") {
        // config.h won't exist, so make a dummy file.
        // We don't need it because of the following -D defines.
        fs::create_dir_all(format!("{}{}", target_dir, "/include/wlr/"))
            .expect("Could not create <out>/include/wlr");
        fs::File::create(format!("{}{}", target_dir, "/include/wlr/config.h"))
            .expect("Could not create dummy config.h file");
        // meson automatically sets up variables, but if we are linking
        // dynamically bindgen will no longer have them.
        builder = builder.clang_args([
            format!("-DWLR_HAS_LIBCAP={}", cfg!(feature = "libcap") as u8),
            format!("-DWLR_HAS_SYSTEMD={}", cfg!(feature = "systemd") as u8),
            format!("-DWLR_HAS_ELOGIND={}", cfg!(feature = "elogind") as u8),
            format!("-DWLR_HAS_X11_BACKEND={}", cfg!(feature = "x11_backend") as u8),
            format!("-DWLR_HAS_XWAYLAND={}", cfg!(feature = "xwayland") as u8),
            format!("-DWLR_HAS_XCB_ERRORS={}", cfg!(feature = "xcb_errors") as u8),
            format!("-DWLR_HAS_XCB_ICCCM={}", cfg!(feature = "xcb_icccm") as u8)
        ].iter())
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?
        .chain(fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?);
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner").arg("server-header")
                                           .arg(path.clone())
                                           .arg(format!("{}/{}.h",
                                                        out_path.to_str().unwrap(),
                                                        filename))
                                           .status()
                                           .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration"),
                      ("./wlroots/protocol/gamma-control.xml", "gamma_control")];

    for protocol in protocols {
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                         wayland_scanner::Side::Server);
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                         wayland_scanner::Side::Client);
        wayland_scanner::generate_c_interfaces(protocol.0,
                                               output_dir.join(format!("{}_interfaces.rs",
                                                                       protocol.1)));
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
       println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<commit_msg>linking to wrong protocol, doh!<commit_after>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::{env, io, fs};
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    if !cfg!(feature = "static") {
        // config.h won't exist, so make a dummy file.
        // We don't need it because of the following -D defines.
        fs::create_dir_all(format!("{}{}", target_dir, "/include/wlr/"))
            .expect("Could not create <out>/include/wlr");
        fs::File::create(format!("{}{}", target_dir, "/include/wlr/config.h"))
            .expect("Could not create dummy config.h file");
        // meson automatically sets up variables, but if we are linking
        // dynamically bindgen will no longer have them.
        builder = builder.clang_args([
            format!("-DWLR_HAS_LIBCAP={}", cfg!(feature = "libcap") as u8),
            format!("-DWLR_HAS_SYSTEMD={}", cfg!(feature = "systemd") as u8),
            format!("-DWLR_HAS_ELOGIND={}", cfg!(feature = "elogind") as u8),
            format!("-DWLR_HAS_X11_BACKEND={}", cfg!(feature = "x11_backend") as u8),
            format!("-DWLR_HAS_XWAYLAND={}", cfg!(feature = "xwayland") as u8),
            format!("-DWLR_HAS_XCB_ERRORS={}", cfg!(feature = "xcb_errors") as u8),
            format!("-DWLR_HAS_XCB_ICCCM={}", cfg!(feature = "xcb_icccm") as u8)
        ].iter())
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?
        .chain(fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?);
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner").arg("server-header")
                                           .arg(path.clone())
                                           .arg(format!("{}/{}.h",
                                                        out_path.to_str().unwrap(),
                                                        filename))
                                           .status()
                                           .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration"),
                      ("./wlroots/protocol/wlr-gamma-control-unstable-v1.xml", "gamma_control")];

    for protocol in protocols {
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                         wayland_scanner::Side::Server);
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                         wayland_scanner::Side::Client);
        wayland_scanner::generate_c_interfaces(protocol.0,
                                               output_dir.join(format!("{}_interfaces.rs",
                                                                       protocol.1)));
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
       println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<|endoftext|>


<commit_before>use std;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;

use class::ClassId;
use ctxt::{SemContext, get_ctxt};
use gc::root::IndirectObj;
use mem;
use vtable::VTable;

#[repr(C)]
pub struct Header {
    // ptr to class
    vtable: *mut VTable,

    // additional information>
    // bit 0 - marked flag
    // bit 1-4 - age (4 bits)
    info: usize,
}

impl Header {
    pub fn size() -> i32 {
        std::mem::size_of::<Header>() as i32
    }

    pub fn vtblptr(&self) -> *mut VTable {
        self.vtable
    }

    pub fn vtbl(&self) -> &mut VTable {
        unsafe { &mut *self.vtable }
    }

    pub fn set_mark(&mut self, value: bool) {
        self.info = if value {
            self.info | 1
        } else {
            self.info & (!1)
        };
    }

    pub fn marked(&self) -> bool {
        if (self.info & 1) != 0 { true } else { false }
    }

    pub fn age(&self) -> u32 {
        (self.info & 0x1E) as u32 >> 1
    }

    pub fn set_age(&mut self, age: u32) {
        assert!(age <= 15);
        self.info = (self.info & !0x1E) | (age << 1) as usize;
    }
}

#[test]
fn test_age() {
    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 3 << 1,
    };
    assert_eq!(3, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 15 << 1,
    };
    assert_eq!(15, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    assert_eq!(0, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0xFFFF,
    };
    assert_eq!(15, hdr.age());
}

#[test]
fn test_set_age() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };

    hdr.set_age(15);
    assert_eq!(15, hdr.age());

    hdr.set_age(0);
    assert_eq!(0, hdr.age());

    hdr.set_age(2);
    assert_eq!(2, hdr.age());
}

#[test]
#[should_panic]
fn test_set_age_over_15() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    hdr.set_age(16);
}

// is used to reference any object
#[repr(C)]
pub struct Obj {
    header: Header,
    data: u8,
}

impl Obj {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn size(&self) -> usize {
        let cls = self.header().vtbl().class();
        let size = cls.size;

        if size > 0 {
            return size as usize;
        }

        let ty = cls.ty;

        if cls.is_array {
            let handle: Handle<ByteArray> = Handle { ptr: self as *const Obj as *const ByteArray };

            let value = Header::size() as usize + mem::ptr_width() as usize +
                        cls.element_size as usize * handle.len() as usize;

            return mem::align_usize(value, mem::ptr_width() as usize);
        }

        if ty.cls_id() == get_ctxt().primitive_classes.str_class {
            let handle: Handle<Str> = Handle { ptr: self as *const Obj as *const Str };
            mem::align_usize(handle.size(), mem::ptr_width() as usize)
        } else {
            panic!("size unknown");
        }
    }

    pub fn visit_reference_fields<F>(&mut self, mut f: F)
        where F: FnMut(IndirectObj)
    {
        let classptr = self.header().vtbl().classptr;
        let cls = unsafe { &*classptr };

        if cls.is_object_array {
            let array = unsafe { &*(self as *const _ as *const StrArray) };

            // walk through all objects in array
            let mut ptr = array.data() as *mut *mut Obj;
            let last = unsafe { ptr.offset(array.len() as isize) };

            while ptr < last {
                f((ptr as usize).into());

                unsafe { ptr = ptr.offset(1) }
            }

            return;
        }

        for &offset in &cls.ref_fields {
            let obj = (self as *mut Obj as usize) + offset as usize;
            f(obj.into());
        }
    }
}

#[repr(C)]
pub struct Handle<T> {
    ptr: *const T,
}

unsafe impl<T> Send for Handle<T> {}

impl<T> Handle<T> {
    pub fn null() -> Handle<T> {
        Handle { ptr: ptr::null() }
    }

    pub fn cast<R>(&self) -> Handle<R> {
        Handle { ptr: self.ptr as *const R }
    }

    pub fn raw(&self) -> *const T {
        self.ptr
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.ptr as *mut T) }
    }
}

impl<T> Into<Handle<T>> for usize {
    fn into(self) -> Handle<T> {
        Handle { ptr: self as *const T }
    }
}

#[repr(C)]
pub struct Testing {
    header: Header,
    failed: bool,
}

impl Testing {
    pub fn has_failed(&self) -> bool {
        self.failed
    }
}

#[repr(C)]
pub struct Str {
    header: Header,
    length: usize,
    data: u8,
}

impl Str {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn to_cstring(&self) -> CString {
        let view = unsafe { slice::from_raw_parts(self.data(), self.len()) };

        CString::new(view).unwrap()
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() + 1 // string content
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer_in_perm(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_perm(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());

            // string should end with 0 for C compatibility
            *(data.offset(buf.len() as isize)) = 0;
        }

        handle
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_heap(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());

            // string should end with 0 for C compatibility
            *(data.offset(buf.len() as isize)) = 0;
        }

        handle
    }

    pub fn concat(ctxt: &SemContext, lhs: Handle<Str>, rhs: Handle<Str>) -> Handle<Str> {
        let len = lhs.len() + rhs.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(lhs.data(), handle.data() as *mut u8, lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                                     handle.data().offset(lhs.len() as isize) as *mut u8,
                                     rhs.len());

            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }

    // duplicate string into a new object
    pub fn dup(&self, ctxt: &SemContext) -> Handle<Str> {
        let len = self.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(self.data(), handle.data() as *mut u8, len);
            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }
}

fn str_alloc_heap(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt,
              len,
              |ctxt, size| ctxt.gc.alloc(ctxt, size) as *const u8)
}

fn str_alloc_perm(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt, len, |ctxt, size| ctxt.gc.alloc_perm(size))
}

fn str_alloc<F>(ctxt: &SemContext, len: usize, alloc: F) -> Handle<Str>
    where F: FnOnce(&SemContext, usize) -> *const u8
{
    let size = Header::size() as usize     // Object header
                + mem::ptr_width() as usize // length field
                + len + 1; // string content

    let size = mem::align_usize(size, mem::ptr_width() as usize);
    let ptr = alloc(ctxt, size) as usize;

    let clsid = ctxt.primitive_classes.str_class;
    let cls = ctxt.classes[clsid].borrow();
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Str> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

#[repr(C)]
pub struct Array<T: Copy> {
    header: Header,
    length: usize,
    data: u8,
    phantom: PhantomData<T>,
}

impl<T> Array<T>
    where T: Copy
{
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn data(&self) -> *const T {
        &self.data as *const u8 as *const T
    }

    pub fn data_mut(&mut self) -> *mut T {
        &self.data as *const u8 as *mut T
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() * std::mem::size_of::<T>() // array content
    }

    pub fn alloc(ctxt: &SemContext, len: usize, elem: T, clsid: ClassId) -> Handle<Array<T>> {
        let size = Header::size() as usize        // Object header
                   + mem::ptr_width() as usize    // length field
                   + len * std::mem::size_of::<T>(); // array content

        let ptr = ctxt.gc.alloc(ctxt, size) as usize;
        let cls = ctxt.classes[clsid].borrow();
        let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
        let mut handle: Handle<Array<T>> = ptr.into();
        handle.header_mut().vtable = vtable as *mut VTable;
        handle.length = len;

        for i in 0..handle.len() {
            unsafe {
                *handle.data_mut().offset(i as isize) = elem;
            }
        }

        handle
    }
}

pub fn offset_of_array_length() -> i32 {
    offset_of!(Array<i32>, length) as i32
}

pub fn offset_of_array_data() -> i32 {
    offset_of!(Array<i32>, data) as i32
}

pub type BoolArray = Array<bool>;
pub type ByteArray = Array<u8>;
pub type CharArray = Array<char>;
pub type IntArray = Array<i32>;
pub type LongArray = Array<i64>;
pub type FloatArray = Array<f32>;
pub type DoubleArray = Array<f64>;
pub type StrArray = Array<Handle<Str>>;

pub fn alloc(ctxt: &SemContext, clsid: ClassId) -> Handle<Obj> {
    let cls = ctxt.classes[clsid].borrow();

    let ptr = ctxt.gc.alloc(ctxt, cls.size as usize) as usize;
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Obj> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}
<commit_msg>do not null-terminate strings<commit_after>use std;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;

use class::ClassId;
use ctxt::{SemContext, get_ctxt};
use gc::root::IndirectObj;
use mem;
use vtable::VTable;

#[repr(C)]
pub struct Header {
    // ptr to class
    vtable: *mut VTable,

    // additional information>
    // bit 0 - marked flag
    // bit 1-4 - age (4 bits)
    info: usize,
}

impl Header {
    pub fn size() -> i32 {
        std::mem::size_of::<Header>() as i32
    }

    pub fn vtblptr(&self) -> *mut VTable {
        self.vtable
    }

    pub fn vtbl(&self) -> &mut VTable {
        unsafe { &mut *self.vtable }
    }

    pub fn set_mark(&mut self, value: bool) {
        self.info = if value {
            self.info | 1
        } else {
            self.info & (!1)
        };
    }

    pub fn marked(&self) -> bool {
        if (self.info & 1) != 0 { true } else { false }
    }

    pub fn age(&self) -> u32 {
        (self.info & 0x1E) as u32 >> 1
    }

    pub fn set_age(&mut self, age: u32) {
        assert!(age <= 15);
        self.info = (self.info & !0x1E) | (age << 1) as usize;
    }
}

#[test]
fn test_age() {
    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 3 << 1,
    };
    assert_eq!(3, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 15 << 1,
    };
    assert_eq!(15, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    assert_eq!(0, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0xFFFF,
    };
    assert_eq!(15, hdr.age());
}

#[test]
fn test_set_age() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };

    hdr.set_age(15);
    assert_eq!(15, hdr.age());

    hdr.set_age(0);
    assert_eq!(0, hdr.age());

    hdr.set_age(2);
    assert_eq!(2, hdr.age());
}

#[test]
#[should_panic]
fn test_set_age_over_15() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    hdr.set_age(16);
}

// is used to reference any object
#[repr(C)]
pub struct Obj {
    header: Header,
    data: u8,
}

impl Obj {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn size(&self) -> usize {
        let cls = self.header().vtbl().class();
        let size = cls.size;

        if size > 0 {
            return size as usize;
        }

        let ty = cls.ty;

        if cls.is_array {
            let handle: Handle<ByteArray> = Handle { ptr: self as *const Obj as *const ByteArray };

            let value = Header::size() as usize + mem::ptr_width() as usize +
                        cls.element_size as usize * handle.len() as usize;

            return mem::align_usize(value, mem::ptr_width() as usize);
        }

        if ty.cls_id() == get_ctxt().primitive_classes.str_class {
            let handle: Handle<Str> = Handle { ptr: self as *const Obj as *const Str };
            mem::align_usize(handle.size(), mem::ptr_width() as usize)
        } else {
            panic!("size unknown");
        }
    }

    pub fn visit_reference_fields<F>(&mut self, mut f: F)
        where F: FnMut(IndirectObj)
    {
        let classptr = self.header().vtbl().classptr;
        let cls = unsafe { &*classptr };

        if cls.is_object_array {
            let array = unsafe { &*(self as *const _ as *const StrArray) };

            // walk through all objects in array
            let mut ptr = array.data() as *mut *mut Obj;
            let last = unsafe { ptr.offset(array.len() as isize) };

            while ptr < last {
                f((ptr as usize).into());

                unsafe { ptr = ptr.offset(1) }
            }

            return;
        }

        for &offset in &cls.ref_fields {
            let obj = (self as *mut Obj as usize) + offset as usize;
            f(obj.into());
        }
    }
}

#[repr(C)]
pub struct Handle<T> {
    ptr: *const T,
}

unsafe impl<T> Send for Handle<T> {}

impl<T> Handle<T> {
    pub fn null() -> Handle<T> {
        Handle { ptr: ptr::null() }
    }

    pub fn cast<R>(&self) -> Handle<R> {
        Handle { ptr: self.ptr as *const R }
    }

    pub fn raw(&self) -> *const T {
        self.ptr
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.ptr as *mut T) }
    }
}

impl<T> Into<Handle<T>> for usize {
    fn into(self) -> Handle<T> {
        Handle { ptr: self as *const T }
    }
}

#[repr(C)]
pub struct Testing {
    header: Header,
    failed: bool,
}

impl Testing {
    pub fn has_failed(&self) -> bool {
        self.failed
    }
}

#[repr(C)]
pub struct Str {
    header: Header,
    length: usize,
    data: u8,
}

impl Str {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn to_cstring(&self) -> CString {
        let view = unsafe { slice::from_raw_parts(self.data(), self.len()) };

        CString::new(view).unwrap()
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len()                // string content
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer_in_perm(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_perm(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());
        }

        handle
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_heap(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());

            // string should end with 0 for C compatibility
            *(data.offset(buf.len() as isize)) = 0;
        }

        handle
    }

    pub fn concat(ctxt: &SemContext, lhs: Handle<Str>, rhs: Handle<Str>) -> Handle<Str> {
        let len = lhs.len() + rhs.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(lhs.data(), handle.data() as *mut u8, lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                                     handle.data().offset(lhs.len() as isize) as *mut u8,
                                     rhs.len());

            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }

    // duplicate string into a new object
    pub fn dup(&self, ctxt: &SemContext) -> Handle<Str> {
        let len = self.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(self.data(), handle.data() as *mut u8, len);
            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }
}

fn str_alloc_heap(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt,
              len,
              |ctxt, size| ctxt.gc.alloc(ctxt, size) as *const u8)
}

fn str_alloc_perm(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt, len, |ctxt, size| ctxt.gc.alloc_perm(size))
}

fn str_alloc<F>(ctxt: &SemContext, len: usize, alloc: F) -> Handle<Str>
    where F: FnOnce(&SemContext, usize) -> *const u8
{
    let size = Header::size() as usize      // Object header
                + mem::ptr_width() as usize // length field
                + len;                      // string content

    let size = mem::align_usize(size, mem::ptr_width() as usize);
    let ptr = alloc(ctxt, size) as usize;

    let clsid = ctxt.primitive_classes.str_class;
    let cls = ctxt.classes[clsid].borrow();
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Str> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

#[repr(C)]
pub struct Array<T: Copy> {
    header: Header,
    length: usize,
    data: u8,
    phantom: PhantomData<T>,
}

impl<T> Array<T>
    where T: Copy
{
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn data(&self) -> *const T {
        &self.data as *const u8 as *const T
    }

    pub fn data_mut(&mut self) -> *mut T {
        &self.data as *const u8 as *mut T
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() * std::mem::size_of::<T>() // array content
    }

    pub fn alloc(ctxt: &SemContext, len: usize, elem: T, clsid: ClassId) -> Handle<Array<T>> {
        let size = Header::size() as usize        // Object header
                   + mem::ptr_width() as usize    // length field
                   + len * std::mem::size_of::<T>(); // array content

        let ptr = ctxt.gc.alloc(ctxt, size) as usize;
        let cls = ctxt.classes[clsid].borrow();
        let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
        let mut handle: Handle<Array<T>> = ptr.into();
        handle.header_mut().vtable = vtable as *mut VTable;
        handle.length = len;

        for i in 0..handle.len() {
            unsafe {
                *handle.data_mut().offset(i as isize) = elem;
            }
        }

        handle
    }
}

pub fn offset_of_array_length() -> i32 {
    offset_of!(Array<i32>, length) as i32
}

pub fn offset_of_array_data() -> i32 {
    offset_of!(Array<i32>, data) as i32
}

pub type BoolArray = Array<bool>;
pub type ByteArray = Array<u8>;
pub type CharArray = Array<char>;
pub type IntArray = Array<i32>;
pub type LongArray = Array<i64>;
pub type FloatArray = Array<f32>;
pub type DoubleArray = Array<f64>;
pub type StrArray = Array<Handle<Str>>;

pub fn alloc(ctxt: &SemContext, clsid: ClassId) -> Handle<Obj> {
    let cls = ctxt.classes[clsid].borrow();

    let ptr = ctxt.gc.alloc(ctxt, cls.size as usize) as usize;
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Obj> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}
<|endoftext|>


<commit_before>use lexicon::Token;
use lexicon::Token::*;
use lexicon::KeywordKind::*;
use lexicon::ReservedKind::*;
use lexicon::CompareKind::*;
use lexicon::OperatorKind::*;
use tokenizer::Tokenizer;
use std::iter::Peekable;
use grammar::*;

/// If the next token matches `$p`, consume that token and return
/// true, else do nothing and return false
macro_rules! allow {
    ($parser:ident, $p:pat) => {
        match $parser.lookahead() {
            Some(&$p) => {
                $parser.consume();
                true
            },
            _ => false
        }
    }
}

/// Allow multiple occurences of `$p` in a row, consuming them all,
/// returns true if at least one was found
macro_rules! allow_many {
    ($parser: ident, $p: pat) => {
        if allow!($parser, $p) {
            while allow!($parser, $p) {}
            true
        } else {
            false
        }
    };
}

/// Just a shorthand for allow_many!(self, LineTermination)
macro_rules! ignore_nl {
    ($parser:ident) => {
        allow_many!($parser, LineTermination)
    }
}

/// Expects next token to match `$p`, otherwise panics.
macro_rules! expect {
    ($parser:ident, $p:pat => $value:ident) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($p) => $value,
            None     => panic!("Unexpected end of program"),
            token    => panic!("Unexpected token {:?}", token),
        }
    });
    ($parser:ident, $p:pat) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($p) => {},
            None     => panic!("Unexpected end of program"),
            token    => panic!("Unexpected token {:?}", token),
        }
    })
}

macro_rules! predict {
    ($parser:ident, { $( $p:pat => $then:expr ),* }) => ({
        ignore_nl!($parser);
        match $parser.lookahead() {
            $(
                Some(&$p) => $then,
            )*
            _ => {}
        }
    })
}

/// More robust version of the regular `match`, will peek at the next
/// token, if the token matches `$p` then consume that token, any line
/// breaks after and call the `$then` expression.
macro_rules! on {
    ($parser:ident, { $( $p:pat => $then:expr ),* }) => ({
        ignore_nl!($parser);
        match $parser.lookahead() {
            $(
                Some(&$p) => {
                    $parser.consume();
                    ignore_nl!($parser);
                    $then;
                }
            )*
            _ => {}
        }
    })
}

/// Expects a semicolon to end the statement and return `true`. If no
/// semicolon is found, we try to follow the ECMA 262 Automatic
/// Semicolon Insertion (ASI) Rules.
macro_rules! expect_statement_end {
    ($parser:ident, $cont:pat) => ({
        ignore_nl!($parser);

        let asi = $parser.allow_asi;
        let end = match $parser.lookahead() {
            None | Some(&Semicolon) => true,
            Some(&$cont)            => false,
            token                   =>
                asi || panic!("Unexpected token {:?}", token)
        };

        if !asi {
            $parser.consume();
        }

        end
    });

    ($parser:ident) => ({
        ignore_nl!($parser);

        let asi = $parser.allow_asi;
        match $parser.lookahead() {
            None | Some(&Semicolon) => true,
            token                   =>
                asi || panic!("Unexpected token {:?}", token)
        };

        if !asi {
            $parser.consume();
        }

        true
    })
}

/// Read a list of items with predefined `$start`, `$end` and
/// `$separator` tokens and an `$item` expression that is then
/// pushed onto a vector.
macro_rules! expect_list {
    [$parser:ident, $item:expr, $start:pat, $separator:pat, $end:pat] => ({
        ignore_nl!($parser);
        expect!($parser, $start);

        let mut list = Vec::new();
        loop {
            ignore_nl!($parser);
            if allow!($parser, $end) {
                break;
            }
            list.push($item);
            if expect_list_end!($parser, $separator, $end) {
                break;
            } else {
                continue;
            }
        }

        list
    });
    [$parser:ident, $item:expr, $separator:pat, $end:pat] => ({
        let mut list = Vec::new();
        loop {
            ignore_nl!($parser);
            if allow!($parser, $end) {
                break;
            }
            list.push($item);
            if expect_list_end!($parser, $separator, $end) {
                break;
            } else {
                continue;
            }
        }

        list
    })
}

/// Shorthand for reading a key expression, separator token and
/// value expression in that order.
macro_rules! expect_key_value_pair {
    ($parser:ident, $key:expr, $separator:pat, $value:expr) => ({
        ignore_nl!($parser);
        let key = $key;
        ignore_nl!($parser);
        expect!($parser, $separator);
        ignore_nl!($parser);
        (key, $value)
    })
}

/// Returns true if met with a list closing token `$p`, allows
/// a tailing comma to appear before `$p`.
macro_rules! expect_list_end {
    ($parser:ident, $separator:pat, $end:pat) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($separator) => {
                ignore_nl!($parser);
                allow!($parser, $end)
            }
            Some($end)       => true,
            _                => false,
        }
    })
}

pub struct Parser<'a> {
    tokenizer: Peekable<Tokenizer<'a>>,
    allow_asi: bool,
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a String) -> Self {
        Parser {
            tokenizer: Tokenizer::new(source).peekable(),
            allow_asi: false,
        }
    }

    #[inline(always)]
    fn consume(&mut self) -> Option<Token> {
        let token = self.tokenizer.next();

        match token {
            Some(LineTermination) => self.allow_asi = true,
            _                     => self.allow_asi = false,
        }

        // println!("Consume {:?}", token);

        return token;
    }

    #[inline(always)]
    fn lookahead(&mut self) -> Option<&Token> {
        self.tokenizer.peek()
    }

    fn array_expression(&mut self) -> Expression {
        Expression::ArrayExpression(expect_list![self,
            self.expression(),
            BracketOn,
            Comma,
            BracketOff
        ])
    }

    fn object_expression(&mut self) -> Expression {
        Expression::ObjectExpression(expect_list![self,
            expect_key_value_pair!(self,
                self.object_key(),
                Colon,
                self.expression()
            ),
            BlockOn,
            Comma,
            BlockOff
        ])
    }

    fn object_key(&mut self) -> ObjectKey {
        match self.consume() {
            Some(Identifier(key)) | Some(Literal(LiteralString(key))) => {
                ObjectKey::Static(key)
            },
            Some(BracketOn) => {
                ignore_nl!(self);
                let key = self.expression();
                expect!(self, BracketOff);
                ObjectKey::Computed(key)
            },
            token => {
                panic!("Expected object key, got {:?}", token)
            }
        }
    }

    fn optional_block(&mut self) -> OptionalBlock {
        ignore_nl!(self);
        if let Some(&BlockOn) = self.lookahead() {
            self.consume();
            OptionalBlock::Block(self.block())
        } else {
            OptionalBlock::Expression(Box::new(self.expression()))
        }
    }

    fn block(&mut self) -> Vec<Statement> {
        let mut body = Vec::new();
        loop {
            on!(self, {
                BlockOff => break
            });
            match self.statement() {
                Some(statement) => body.push(statement),
                None            => panic!("Unexpected end of function block")
            }
        }

        body
    }

    fn arrow_function_expression(&mut self, p: Expression) -> Expression {
        let params: Vec<Parameter> = match p {
            Expression::Identifier(name) => {
                vec![Parameter { name: name }]
            },
            _ =>
                panic!("Can cast {:?} to parameters", p),
        };

        Expression::ArrowFunctionExpression {
            params: params,
            body: self.optional_block()
        }
    }

    fn expression(&mut self) -> Expression {
        let mut left = match self.lookahead() {
            Some(&Literal(_)) => {
                Expression::Literal(expect!(self, Literal(v) => v))
            }
            Some(&Identifier(_)) => {
                Expression::Identifier(
                    expect!(self, Identifier(v) => v)
                )
            }
            Some(&BracketOn) => self.array_expression(),
            Some(&BlockOn)   => self.object_expression(),
            Some(_)          => panic!("Unexpected token"),
            _                => panic!("Unexpected end of program")
        };

        'nest: loop {
            left = match self.lookahead() {
                Some(&ParenOn) => {
                    Expression::CallExpression {
                        callee: Box::new(left),
                        arguments: expect_list![self,
                            self.expression(),
                            ParenOn,
                            Comma,
                            ParenOff
                        ]
                    }
                },
                Some(&Accessor) => {
                    self.consume();
                    ignore_nl!(self);

                    Expression::MemberExpression {
                        object: Box::new(left),
                        property: Box::new(ObjectKey::Static(
                            expect!(self, Identifier(key) => key)
                        )),
                    }
                },
                Some(&BracketOn) => Expression::MemberExpression {
                    object: Box::new(left),
                    property: Box::new({
                        expect!(self, BracketOn);
                        ignore_nl!(self);
                        let key = self.expression();
                        expect!(self, BracketOff);
                        ObjectKey::Computed(key)
                    }),
                },
                Some(&Operator(_)) => {
                    match expect!(self, Operator(op) => op) {
                        Increment => {
                            Expression::UpdateExpression {
                                operator: UpdateOperator::Increment,
                                prefix: false,
                                argument: Box::new(left),
                            }
                        },
                        Decrement => {
                            Expression::UpdateExpression {
                                operator: UpdateOperator::Decrement,
                                prefix: false,
                                argument: Box::new(left),
                            }
                        },
                        Add => {
                            ignore_nl!(self);
                            Expression::BinaryExpression {
                                operator: BinaryOperator::Add,
                                left: Box::new(left),
                                right: Box::new(self.expression()),
                            }
                        },
                        Multiply => {
                            ignore_nl!(self);
                            Expression::BinaryExpression {
                                operator: BinaryOperator::Multiply,
                                left: Box::new(left),
                                right: Box::new(self.expression()),
                            }
                        },
                        op => panic!("Unimplemented operator {:?}", op)
                    }
                },
                Some(&FatArrow) => {
                    self.consume();
                    ignore_nl!(self);
                    return self.arrow_function_expression(left);
                }
                _ => break 'nest,
            }
        }

        left
    }

    fn variable_declaration_statement(&mut self, kind: VariableDeclarationKind)
    -> Statement {
        let mut declarations = Vec::new();

        loop {
            declarations.push(expect_key_value_pair!(self,
                expect!(self, Identifier(name) => name),
                Assign,
                self.expression()
            ));

            if expect_statement_end!(self, Comma) {
                break
            }
        }

        Statement::VariableDeclarationStatement {
            kind: kind,
            declarations: declarations,
        }
    }

    fn expression_statement(&mut self) -> Statement {
        let expression = self.expression();
        expect_statement_end!(self);
        Statement::ExpressionStatement(expression)
    }

    fn return_statement(&mut self) -> Statement {
        let expression = self.expression();
        expect_statement_end!(self);
        Statement::ReturnStatement(expression)
    }

    fn while_statement(&mut self) -> Statement {
        expect!(self, ParenOn);
        ignore_nl!(self);
        let condition = self.expression();
        expect!(self, ParenOff);

        Statement::WhileStatement {
            condition: condition,
            body: self.optional_block()
        }
    }

    fn function_statement(&mut self) -> Statement {
        let name = expect!(self, Identifier(name) => name);
        let params = expect_list![self,
            Parameter { name: expect!(self, Identifier(name) => name) },
            ParenOn,
            Comma,
            ParenOff
        ];
        expect!(self, BlockOn);
        Statement::FunctionStatement {
            name: name,
            params: params,
            body: self.block(),
        }
    }

    fn statement(&mut self) -> Option<Statement> {
        on!(self, {
            Keyword(Var)      => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Var
            )),
            Keyword(Let)      => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Let
            )),
            Keyword(Const)    => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Const
            )),
            Keyword(Return)   => return Some(self.return_statement()),
            Keyword(Function) => return Some(self.function_statement()),
            Keyword(While)    => return Some(self.while_statement()),
            Semicolon         => return self.statement()
        });

        if self.lookahead().is_some() {
            Some(self.expression_statement())
        } else {
            None
        }
    }
}

pub fn parse(source: String) -> Program {
    let mut parser = Parser::new(&source);
    let mut program = Program { body: Vec::new() };

    while let Some(statement) = parser.statement() {
        program.body.push(statement);
    }

    return program;
}
<commit_msg>Macro all the things<commit_after>use lexicon::Token;
use lexicon::Token::*;
use lexicon::KeywordKind::*;
use lexicon::ReservedKind::*;
use lexicon::CompareKind::*;
use lexicon::OperatorKind::*;
use tokenizer::Tokenizer;
use std::iter::Peekable;
use grammar::*;

/// If the next token matches `$p`, consume that token and return
/// true, else do nothing and return false
macro_rules! allow {
    ($parser:ident, $p:pat) => {
        match $parser.lookahead() {
            Some(&$p) => {
                $parser.consume();
                true
            },
            _ => false
        }
    }
}

/// Allow multiple occurences of `$p` in a row, consuming them all,
/// returns true if at least one was found
macro_rules! allow_many {
    ($parser: ident, $p: pat) => {
        if allow!($parser, $p) {
            while allow!($parser, $p) {}
            true
        } else {
            false
        }
    };
}

/// Just a shorthand for allow_many!(self, LineTermination)
macro_rules! ignore_nl {
    ($parser:ident) => {
        allow_many!($parser, LineTermination)
    }
}

/// Expects next token to match `$p`, otherwise panics.
macro_rules! expect {
    ($parser:ident, $p:pat => $value:ident) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($p) => $value,
            None     => panic!("Unexpected end of program"),
            token    => panic!("Unexpected token {:?}", token),
        }
    });
    ($parser:ident, $p:pat) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($p) => {},
            None     => panic!("Unexpected end of program"),
            token    => panic!("Unexpected token {:?}", token),
        }
    })
}

macro_rules! predict {
    ($parser:ident, { $( $p:pat => $then:expr ),* }) => ({
        ignore_nl!($parser);
        match $parser.lookahead() {
            $(
                Some(&$p) => $then,
            )*
            _ => {}
        }
    })
}

/// More robust version of the regular `match`, will peek at the next
/// token, if the token matches `$p` then consume that token, any line
/// breaks after and call the `$then` expression.
macro_rules! on {
    ($parser:ident, { $( $p:pat => $then:expr ),* }) => ({
        ignore_nl!($parser);
        match $parser.lookahead() {
            $(
                Some(&$p) => {
                    $parser.consume();
                    ignore_nl!($parser);
                    $then;
                }
            )*
            _ => {}
        }
    })
}

/// Expects a semicolon to end the statement and return `true`. If no
/// semicolon is found, we try to follow the ECMA 262 Automatic
/// Semicolon Insertion (ASI) Rules.
macro_rules! expect_statement_end {
    ($parser:ident, $cont:pat) => ({
        ignore_nl!($parser);

        let asi = $parser.allow_asi;
        let end = match $parser.lookahead() {
            None | Some(&Semicolon) => true,
            Some(&$cont)            => false,
            token                   =>
                asi || panic!("Unexpected token {:?}", token)
        };

        if !asi {
            $parser.consume();
        }

        end
    });

    ($parser:ident) => ({
        ignore_nl!($parser);

        let asi = $parser.allow_asi;
        match $parser.lookahead() {
            None | Some(&Semicolon) => true,
            token                   =>
                asi || panic!("Unexpected token {:?}", token)
        };

        if !asi {
            $parser.consume();
        }

        true
    })
}

/// Read a list of items with predefined `$start`, `$end` and
/// `$separator` tokens and an `$item` expression that is then
/// pushed onto a vector.
macro_rules! expect_list {
    [$parser:ident, $item:expr, $start:pat, $separator:pat, $end:pat] => ({
        ignore_nl!($parser);
        expect!($parser, $start);

        let mut list = Vec::new();
        loop {
            ignore_nl!($parser);
            if allow!($parser, $end) {
                break;
            }
            list.push($item);
            if expect_list_end!($parser, $separator, $end) {
                break;
            } else {
                continue;
            }
        }

        list
    });
    [$parser:ident, $item:expr, $separator:pat, $end:pat] => ({
        let mut list = Vec::new();
        loop {
            ignore_nl!($parser);
            if allow!($parser, $end) {
                break;
            }
            list.push($item);
            if expect_list_end!($parser, $separator, $end) {
                break;
            } else {
                continue;
            }
        }

        list
    })
}

macro_rules! expect_wrapped {
    ($parser:ident, $item:expr, $start:pat, $end:pat) => ({
        expect!($parser, $start);
        expect_wrapped!($parser, $item, $end)
    });
    ($parser:ident, $item:expr, $end:pat) => ({
        ignore_nl!($parser);
        let item = $item;
        expect!($parser, $end);
        item
    })
}

/// Shorthand for reading a key expression, separator token and
/// value expression in that order.
macro_rules! expect_key_value_pair {
    ($parser:ident, $key:expr, $separator:pat, $value:expr) => ({
        ignore_nl!($parser);
        let key = $key;
        ignore_nl!($parser);
        expect!($parser, $separator);
        ignore_nl!($parser);
        (key, $value)
    })
}

/// Returns true if met with a list closing token `$p`, allows
/// a tailing comma to appear before `$p`.
macro_rules! expect_list_end {
    ($parser:ident, $separator:pat, $end:pat) => ({
        ignore_nl!($parser);
        match $parser.consume() {
            Some($separator) => {
                ignore_nl!($parser);
                allow!($parser, $end)
            }
            Some($end)       => true,
            _                => false,
        }
    })
}

pub struct Parser<'a> {
    tokenizer: Peekable<Tokenizer<'a>>,
    allow_asi: bool,
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a String) -> Self {
        Parser {
            tokenizer: Tokenizer::new(source).peekable(),
            allow_asi: false,
        }
    }

    #[inline(always)]
    fn consume(&mut self) -> Option<Token> {
        let token = self.tokenizer.next();

        match token {
            Some(LineTermination) => self.allow_asi = true,
            _                     => self.allow_asi = false,
        }

        // println!("Consume {:?}", token);

        return token;
    }

    #[inline(always)]
    fn lookahead(&mut self) -> Option<&Token> {
        self.tokenizer.peek()
    }

    fn array_expression(&mut self) -> Expression {
        Expression::ArrayExpression(expect_list![self,
            self.expression(),
            BracketOn,
            Comma,
            BracketOff
        ])
    }

    fn object_expression(&mut self) -> Expression {
        Expression::ObjectExpression(expect_list![self,
            expect_key_value_pair!(self,
                self.object_key(),
                Colon,
                self.expression()
            ),
            BlockOn,
            Comma,
            BlockOff
        ])
    }

    fn object_key(&mut self) -> ObjectKey {
        match self.consume() {
            Some(Identifier(key)) | Some(Literal(LiteralString(key))) => {
                ObjectKey::Static(key)
            },
            Some(BracketOn) => ObjectKey::Computed(
                expect_wrapped!(self, self.expression(), BracketOff)
            ),
            token => {
                panic!("Expected object key, got {:?}", token)
            }
        }
    }

    fn optional_block(&mut self) -> OptionalBlock {
        ignore_nl!(self);
        if let Some(&BlockOn) = self.lookahead() {
            self.consume();
            OptionalBlock::Block(self.block())
        } else {
            OptionalBlock::Expression(Box::new(self.expression()))
        }
    }

    fn block(&mut self) -> Vec<Statement> {
        let mut body = Vec::new();
        loop {
            on!(self, {
                BlockOff => break
            });
            match self.statement() {
                Some(statement) => body.push(statement),
                None            => panic!("Unexpected end of function block")
            }
        }

        body
    }

    fn arrow_function_expression(&mut self, p: Expression) -> Expression {
        let params: Vec<Parameter> = match p {
            Expression::Identifier(name) => {
                vec![Parameter { name: name }]
            },
            _ =>
                panic!("Can cast {:?} to parameters", p),
        };

        Expression::ArrowFunctionExpression {
            params: params,
            body: self.optional_block()
        }
    }

    fn expression(&mut self) -> Expression {
        let mut left = match self.lookahead() {
            Some(&Identifier(_)) => {
                Expression::Identifier(expect!(self, Identifier(v) => v))
            },
            Some(&Literal(_))    => {
                Expression::Literal(expect!(self, Literal(v) => v))
            },
            Some(&ParenOn)       => {
                expect_wrapped!(self, self.expression(), ParenOn, ParenOff)
            },
            Some(&BracketOn) => self.array_expression(),
            Some(&BlockOn)   => self.object_expression(),
            Some(_)          => panic!("Unexpected token"),
            _                => panic!("Unexpected end of program")
        };

        'nest: loop {
            left = match self.lookahead() {
                Some(&ParenOn) => {
                    Expression::CallExpression {
                        callee: Box::new(left),
                        arguments: expect_list![self,
                            self.expression(),
                            ParenOn,
                            Comma,
                            ParenOff
                        ]
                    }
                },
                Some(&Accessor) => {
                    self.consume();
                    ignore_nl!(self);

                    Expression::MemberExpression {
                        object: Box::new(left),
                        property: Box::new(ObjectKey::Static(
                            expect!(self, Identifier(key) => key)
                        )),
                    }
                },
                Some(&BracketOn) => Expression::MemberExpression {
                    object: Box::new(left),
                    property: Box::new(ObjectKey::Computed(
                        expect_wrapped!(self,
                            self.expression(),
                            BracketOn,
                            BracketOff
                        )
                    )),
                },
                Some(&Operator(_)) => {
                    match expect!(self, Operator(op) => op) {
                        Increment => {
                            Expression::UpdateExpression {
                                operator: UpdateOperator::Increment,
                                prefix: false,
                                argument: Box::new(left),
                            }
                        },
                        Decrement => {
                            Expression::UpdateExpression {
                                operator: UpdateOperator::Decrement,
                                prefix: false,
                                argument: Box::new(left),
                            }
                        },
                        Add => {
                            ignore_nl!(self);
                            Expression::BinaryExpression {
                                operator: BinaryOperator::Add,
                                left: Box::new(left),
                                right: Box::new(self.expression()),
                            }
                        },
                        Multiply => {
                            ignore_nl!(self);
                            Expression::BinaryExpression {
                                operator: BinaryOperator::Multiply,
                                left: Box::new(left),
                                right: Box::new(self.expression()),
                            }
                        },
                        op => panic!("Unimplemented operator {:?}", op)
                    }
                },
                Some(&FatArrow) => {
                    self.consume();
                    ignore_nl!(self);
                    return self.arrow_function_expression(left);
                }
                _ => break 'nest,
            }
        }

        left
    }

    fn variable_declaration_statement(&mut self, kind: VariableDeclarationKind)
    -> Statement {
        let mut declarations = Vec::new();

        loop {
            declarations.push(expect_key_value_pair!(self,
                expect!(self, Identifier(name) => name),
                Assign,
                self.expression()
            ));

            if expect_statement_end!(self, Comma) {
                break
            }
        }

        Statement::VariableDeclarationStatement {
            kind: kind,
            declarations: declarations,
        }
    }

    fn expression_statement(&mut self) -> Statement {
        let expression = self.expression();
        expect_statement_end!(self);
        Statement::ExpressionStatement(expression)
    }

    fn return_statement(&mut self) -> Statement {
        let expression = self.expression();
        expect_statement_end!(self);
        Statement::ReturnStatement(expression)
    }

    fn while_statement(&mut self) -> Statement {
        expect!(self, ParenOn);
        ignore_nl!(self);
        let condition = self.expression();
        expect!(self, ParenOff);

        Statement::WhileStatement {
            condition: condition,
            body: self.optional_block()
        }
    }

    fn function_statement(&mut self) -> Statement {
        let name = expect!(self, Identifier(name) => name);
        let params = expect_list![self,
            Parameter { name: expect!(self, Identifier(name) => name) },
            ParenOn,
            Comma,
            ParenOff
        ];
        expect!(self, BlockOn);
        Statement::FunctionStatement {
            name: name,
            params: params,
            body: self.block(),
        }
    }

    fn statement(&mut self) -> Option<Statement> {
        on!(self, {
            Keyword(Var)      => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Var
            )),
            Keyword(Let)      => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Let
            )),
            Keyword(Const)    => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Const
            )),
            Keyword(Return)   => return Some(self.return_statement()),
            Keyword(Function) => return Some(self.function_statement()),
            Keyword(While)    => return Some(self.while_statement()),
            Semicolon         => return self.statement()
        });

        if self.lookahead().is_some() {
            Some(self.expression_statement())
        } else {
            None
        }
    }
}

pub fn parse(source: String) -> Program {
    let mut parser = Parser::new(&source);
    let mut program = Program { body: Vec::new() };

    while let Some(statement) = parser.statement() {
        program.body.push(statement);
    }

    return program;
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Main public pull parse interface, running two passes over input.

use parse::{RawParser, Event, Tag, Options};
use std::collections::HashSet;

pub struct Parser<'a> {
    inner: RawParser<'a>,
    loose_lists: HashSet<usize>,
    loose_stack: Vec<bool>,
}

impl<'a> Parser<'a> {
    pub fn new(text: &'a str) -> Parser<'a> {
        // first pass, collecting info
        let mut opts = Options::new();
        opts.set_first_pass();
        let mut first = RawParser::new(text, opts);
        while first.next().is_some() { }
        let info = first.get_info();

        // second pass
        let loose_lists = info.loose_lists;
        let opts = Options::new();
        let second = RawParser::new_with_links(text, opts, info.links);

        //println!("loose lists: {:?}", info.loose_lists);
        Parser {
            inner: second,
            loose_lists: loose_lists,
            loose_stack: Vec::new(),
        }
    }

    pub fn get_offset(&self) -> usize {
        self.inner.get_offset()
    }
}

impl<'a> Iterator for Parser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        loop {
            match self.inner.next() {
                Some(event) => {
                    match event {
                        Event::Start(Tag::List(_)) => {
                            let offset = self.inner.get_offset();
                            let is_loose = self.loose_lists.contains(&offset);
                            self.loose_stack.push(is_loose);
                        }
                        Event::Start(Tag::BlockQuote) => {
                            self.loose_stack.push(true);
                        }
                        Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph) => {
                            if let Some(&false) = self.loose_stack.last() {
                                continue;
                            }
                        }
                        Event::End(Tag::List(_)) | Event::End(Tag::BlockQuote) => {
                            let _ = self.loose_stack.pop();
                        }
                        _ => ()
                    }
                    return Some(event)
                }
                None => return None
            }
        }
    }
}

# Note: there are currently no tests here, because so far there's been adequate coverage
# using the test cases from the CommonMark spec. Those can be run using:
#
#     cargo run -- -s spec.text
#
# where spec.txt is from <https://github.com/jgm/cmark/blob/master/test/spec.txt>.
#
# There are more cases that should be tested beyond that spec, and those should be added here.
<commit_msg>Fix comment syntax<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Main public pull parse interface, running two passes over input.

use parse::{RawParser, Event, Tag, Options};
use std::collections::HashSet;

pub struct Parser<'a> {
    inner: RawParser<'a>,
    loose_lists: HashSet<usize>,
    loose_stack: Vec<bool>,
}

impl<'a> Parser<'a> {
    pub fn new(text: &'a str) -> Parser<'a> {
        // first pass, collecting info
        let mut opts = Options::new();
        opts.set_first_pass();
        let mut first = RawParser::new(text, opts);
        while first.next().is_some() { }
        let info = first.get_info();

        // second pass
        let loose_lists = info.loose_lists;
        let opts = Options::new();
        let second = RawParser::new_with_links(text, opts, info.links);

        //println!("loose lists: {:?}", info.loose_lists);
        Parser {
            inner: second,
            loose_lists: loose_lists,
            loose_stack: Vec::new(),
        }
    }

    pub fn get_offset(&self) -> usize {
        self.inner.get_offset()
    }
}

impl<'a> Iterator for Parser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        loop {
            match self.inner.next() {
                Some(event) => {
                    match event {
                        Event::Start(Tag::List(_)) => {
                            let offset = self.inner.get_offset();
                            let is_loose = self.loose_lists.contains(&offset);
                            self.loose_stack.push(is_loose);
                        }
                        Event::Start(Tag::BlockQuote) => {
                            self.loose_stack.push(true);
                        }
                        Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph) => {
                            if let Some(&false) = self.loose_stack.last() {
                                continue;
                            }
                        }
                        Event::End(Tag::List(_)) | Event::End(Tag::BlockQuote) => {
                            let _ = self.loose_stack.pop();
                        }
                        _ => ()
                    }
                    return Some(event)
                }
                None => return None
            }
        }
    }
}

// Note: there are currently no tests here, because so far there's been adequate coverage
// using the test cases from the CommonMark spec. Those can be run using:
//
//     cargo run -- -s spec.text
//
// where spec.txt is from <https://github.com/jgm/cmark/blob/master/test/spec.txt>.
//
// There are more cases that should be tested beyond that spec, and those should be added here.
<|endoftext|>