<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
//
// TODO: Implement custom subtyping here for things like GParamSpecInt to get
// default/min/max values and similar
#[cfg(any(feature = "v2_38", feature = "dox"))]
use Value;
use gobject_ffi as ffi;
use ffi as glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;
use libc;
use translate::*;
use ParamFlags;

glib_wrapper! {
    pub struct ParamSpec(Shared<ffi::GParamSpec>);

    match fn {
        ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr),
        unref => |ptr| gobject_ffi::g_param_spec_unref(ptr),
        get_type => || gobject_ffi::G_TYPE_PARAM,
    }
}

impl ParamSpec {
    pub fn get_value_type(&self) -> ::Type {
        unsafe {
            from_glib((*self.to_glib_none().0).value_type)
        }
    }

    pub fn get_owner_type(&self) -> ::Type {
        unsafe {
            from_glib((*self.to_glib_none().0).owner_type)
        }
    }

    pub fn get_flags(&self) -> ParamFlags {
        unsafe {
            from_glib((*self.to_glib_none().0).flags)
        }
    }

    pub fn get_blurb(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_blurb(self.to_glib_none().0))
        }
    }

    #[cfg(any(feature = "v2_38", feature = "dox"))]
    pub fn get_default_value(&self) -> Option<Value> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_default_value(self.to_glib_none().0))
        }
    }

    pub fn get_name(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_name(self.to_glib_none().0))
        }
    }

    #[cfg(any(feature = "v2_46", feature = "dox"))]
    pub fn get_name_quark(&self) -> ::Quark {
        unsafe { from_glib(ffi::g_param_spec_get_name_quark(self.to_glib_none().0)) }
    }

    pub fn get_nick(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_nick(self.to_glib_none().0))
        }
    }

    //pub fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_get_qdata() }
    //}

    pub fn get_redirect_target(&self) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_redirect_target(self.to_glib_none().0))
        }
    }

    //pub fn set_qdata<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata() }
    //}

    //pub fn set_qdata_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata_full() }
    //}

    //pub fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_steal_qdata() }
    //}

    pub fn boolean(name: &str, nick: &str, blurb: &str, default_value: bool, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_boolean(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib()))
        }
    }

    pub fn boxed(name: &str, nick: &str, blurb: &str, boxed_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_boxed(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, boxed_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn char(name: &str, nick: &str, blurb: &str, minimum: i8, maximum: i8, default_value: i8, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_char(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn double(name: &str, nick: &str, blurb: &str, minimum: f64, maximum: f64, default_value: f64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_double(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn enum_(name: &str, nick: &str, blurb: &str, enum_type: ::Type, default_value: i32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_enum(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, enum_type.to_glib(), default_value, flags.to_glib()))
        }
    }

    pub fn flags(name: &str, nick: &str, blurb: &str, flags_type: ::Type, default_value: u32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_flags(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags_type.to_glib(), default_value, flags.to_glib()))
        }
    }

    pub fn float(name: &str, nick: &str, blurb: &str, minimum: f32, maximum: f32, default_value: f32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_float(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn gtype(name: &str, nick: &str, blurb: &str, is_a_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_gtype(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, is_a_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn int(name: &str, nick: &str, blurb: &str, minimum: i32, maximum: i32, default_value: i32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_int(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn int64(name: &str, nick: &str, blurb: &str, minimum: i64, maximum: i64, default_value: i64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_int64(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn long(name: &str, nick: &str, blurb: &str, minimum: libc::c_long, maximum: libc::c_long, default_value: libc::c_long, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_long(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn object(name: &str, nick: &str, blurb: &str, object_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_object(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, object_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn override_(name: &str, overridden: &ParamSpec) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_override(name.to_glib_none().0, overridden.to_glib_none().0))
        }
    }

    pub fn param(name: &str, nick: &str, blurb: &str, param_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_param(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, param_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn pointer(name: &str, nick: &str, blurb: &str, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_pointer(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags.to_glib()))
        }
    }

    pub fn string<'a, P: Into<Option<&'a str>>>(name: &str, nick: &str, blurb: &str, default_value: P, flags: ParamFlags) -> Option<ParamSpec> {
        let default_value = default_value.into();
        let default_value = default_value.to_glib_none();
        unsafe {
            from_glib_full(ffi::g_param_spec_string(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.0, flags.to_glib()))
        }
    }

    pub fn uchar(name: &str, nick: &str, blurb: &str, minimum: u8, maximum: u8, default_value: u8, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uchar(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn uint(name: &str, nick: &str, blurb: &str, minimum: u32, maximum: u32, default_value: u32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uint(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn uint64(name: &str, nick: &str, blurb: &str, minimum: u64, maximum: u64, default_value: u64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uint64(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn ulong(name: &str, nick: &str, blurb: &str, minimum: libc::c_ulong, maximum: libc::c_ulong, default_value: libc::c_ulong, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_ulong(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn unichar(name: &str, nick: &str, blurb: &str, default_value: char, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_unichar(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib()))
        }
    }

    pub fn value_array(name: &str, nick: &str, blurb: &str, element_spec: &ParamSpec, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_value_array(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, element_spec.to_glib_none().0, flags.to_glib()))
        }
    }

    pub fn variant<'a, P: Into<Option<&'a ::Variant>>>(name: &str, nick: &str, blurb: &str, type_: &::VariantTy, default_value: P, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            let default_value = default_value.into();
            from_glib_none(ffi::g_param_spec_variant(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, type_.to_glib_none().0, default_value.to_glib_none().0, flags.to_glib()))
        }
    }
}
<commit_msg>Derive Debug, PartialEq, Eq and Hash for ParamSpec<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
//
// TODO: Implement custom subtyping here for things like GParamSpecInt to get
// default/min/max values and similar
#[cfg(any(feature = "v2_38", feature = "dox"))]
use Value;
use gobject_ffi as ffi;
use ffi as glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;
use libc;
use translate::*;
use ParamFlags;

glib_wrapper! {
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct ParamSpec(Shared<ffi::GParamSpec>);

    match fn {
        ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr),
        unref => |ptr| gobject_ffi::g_param_spec_unref(ptr),
        get_type => || gobject_ffi::G_TYPE_PARAM,
    }
}

impl ParamSpec {
    pub fn get_value_type(&self) -> ::Type {
        unsafe {
            from_glib((*self.to_glib_none().0).value_type)
        }
    }

    pub fn get_owner_type(&self) -> ::Type {
        unsafe {
            from_glib((*self.to_glib_none().0).owner_type)
        }
    }

    pub fn get_flags(&self) -> ParamFlags {
        unsafe {
            from_glib((*self.to_glib_none().0).flags)
        }
    }

    pub fn get_blurb(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_blurb(self.to_glib_none().0))
        }
    }

    #[cfg(any(feature = "v2_38", feature = "dox"))]
    pub fn get_default_value(&self) -> Option<Value> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_default_value(self.to_glib_none().0))
        }
    }

    pub fn get_name(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_name(self.to_glib_none().0))
        }
    }

    #[cfg(any(feature = "v2_46", feature = "dox"))]
    pub fn get_name_quark(&self) -> ::Quark {
        unsafe { from_glib(ffi::g_param_spec_get_name_quark(self.to_glib_none().0)) }
    }

    pub fn get_nick(&self) -> String {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_nick(self.to_glib_none().0))
        }
    }

    //pub fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_get_qdata() }
    //}

    pub fn get_redirect_target(&self) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_redirect_target(self.to_glib_none().0))
        }
    }

    //pub fn set_qdata<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata() }
    //}

    //pub fn set_qdata_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata_full() }
    //}

    //pub fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_steal_qdata() }
    //}

    pub fn boolean(name: &str, nick: &str, blurb: &str, default_value: bool, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_boolean(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib()))
        }
    }

    pub fn boxed(name: &str, nick: &str, blurb: &str, boxed_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_boxed(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, boxed_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn char(name: &str, nick: &str, blurb: &str, minimum: i8, maximum: i8, default_value: i8, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_char(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn double(name: &str, nick: &str, blurb: &str, minimum: f64, maximum: f64, default_value: f64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_double(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn enum_(name: &str, nick: &str, blurb: &str, enum_type: ::Type, default_value: i32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_enum(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, enum_type.to_glib(), default_value, flags.to_glib()))
        }
    }

    pub fn flags(name: &str, nick: &str, blurb: &str, flags_type: ::Type, default_value: u32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_flags(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags_type.to_glib(), default_value, flags.to_glib()))
        }
    }

    pub fn float(name: &str, nick: &str, blurb: &str, minimum: f32, maximum: f32, default_value: f32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_float(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn gtype(name: &str, nick: &str, blurb: &str, is_a_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_gtype(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, is_a_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn int(name: &str, nick: &str, blurb: &str, minimum: i32, maximum: i32, default_value: i32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_int(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn int64(name: &str, nick: &str, blurb: &str, minimum: i64, maximum: i64, default_value: i64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_int64(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn long(name: &str, nick: &str, blurb: &str, minimum: libc::c_long, maximum: libc::c_long, default_value: libc::c_long, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_long(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn object(name: &str, nick: &str, blurb: &str, object_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_object(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, object_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn override_(name: &str, overridden: &ParamSpec) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_override(name.to_glib_none().0, overridden.to_glib_none().0))
        }
    }

    pub fn param(name: &str, nick: &str, blurb: &str, param_type: ::Type, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_param(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, param_type.to_glib(), flags.to_glib()))
        }
    }

    pub fn pointer(name: &str, nick: &str, blurb: &str, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_pointer(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags.to_glib()))
        }
    }

    pub fn string<'a, P: Into<Option<&'a str>>>(name: &str, nick: &str, blurb: &str, default_value: P, flags: ParamFlags) -> Option<ParamSpec> {
        let default_value = default_value.into();
        let default_value = default_value.to_glib_none();
        unsafe {
            from_glib_full(ffi::g_param_spec_string(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.0, flags.to_glib()))
        }
    }

    pub fn uchar(name: &str, nick: &str, blurb: &str, minimum: u8, maximum: u8, default_value: u8, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uchar(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn uint(name: &str, nick: &str, blurb: &str, minimum: u32, maximum: u32, default_value: u32, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uint(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn uint64(name: &str, nick: &str, blurb: &str, minimum: u64, maximum: u64, default_value: u64, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_uint64(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn ulong(name: &str, nick: &str, blurb: &str, minimum: libc::c_ulong, maximum: libc::c_ulong, default_value: libc::c_ulong, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_ulong(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib()))
        }
    }

    pub fn unichar(name: &str, nick: &str, blurb: &str, default_value: char, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_full(ffi::g_param_spec_unichar(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib()))
        }
    }

    pub fn value_array(name: &str, nick: &str, blurb: &str, element_spec: &ParamSpec, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_value_array(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, element_spec.to_glib_none().0, flags.to_glib()))
        }
    }

    pub fn variant<'a, P: Into<Option<&'a ::Variant>>>(name: &str, nick: &str, blurb: &str, type_: &::VariantTy, default_value: P, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            let default_value = default_value.into();
            from_glib_none(ffi::g_param_spec_variant(name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, type_.to_glib_none().0, default_value.to_glib_none().0, flags.to_glib()))
        }
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl Program {
    pub fn new(statements: Vec<Statement>) -> Program {
        Program(statements)
    }
}

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.program() {
            Ok(parser.ast())
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        //TODO: This probably isn't the right type since this should accept anything and then get
        // statically checked to ensure the correct number was put here
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    ConditionGroup {
        // Condition expression and body block
        branches: Vec<(Expression, Block)>,
        // "default" or "else" branch body
        default: Option<Block>,
    },
}

pub type Identifier = String;
pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;
<commit_msg>Implementation of Identifier as a path of any number of segments<commit_after>use std::convert::From;
use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl Program {
    pub fn new(statements: Vec<Statement>) -> Program {
        Program(statements)
    }
}

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.program() {
            Ok(parser.ast())
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        //TODO: This probably isn't the right type since this should accept anything and then get
        // statically checked to ensure the correct number was put here
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    ConditionGroup {
        // Condition expression and body block
        branches: Vec<(Expression, Block)>,
        // "default" or "else" branch body
        default: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub struct Identifier(Vec<String>);

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;
<|endoftext|>


<commit_before>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;
use self::TokenState::*;

const UNIT_INDX: usize = 0;
const K: usize = 3;

#[derive(Eq, PartialEq, Clone, Debug)]
pub enum TokenState {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl Default for TokenState {
    fn default() -> Self { SOT }
}

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    // current_token: RefCell<TokenState>,
    // aexp_tokens: Vec<Vec<Tokn>>,

    lookahead: [TokenState; K],
    p: usize,
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        let mut parser = Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            // current_token: RefCell::new(SOT),
            // aexp_tokens: vec![vec![]],
            lookahead: Default::default(),
            p: 0,
        };

        for _ in 0..K {
            parser.consume_token();
        }

        parser
    }

    pub fn parse(&mut self) {
        self.add_unit();

        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.add_prim("print");
        self.add_prim("concat");

        match self.parse_aexp() {
            Ok(_) => {},
            Err(e) => {
                println!("parse error: {:?}", e);
            },
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        self.log("parse_aexp");
        match self.current_token() {
            Has(Tokn::Sgqt) => self.parse_tpiq_single(),
            Has(Tokn::Pipe) => self.parse_tpiq(),
            Has(Tokn::Crrt) => self.parse_mpiq(),
            _ => {
                let l = (self.parse_expression())?;
                match self.current_token() {
                    Has(Tokn::Coln) => self.parse_cons(l),
                    _ => Ok(l),
                }
            },
        }
    }

    fn parse_tpiq_single(&mut self) -> Result<usize, Error> {
        self.log("parse_tpiq_single");
        self.consume_token(); // dispatcher Sgqtのはず
        match self.current_token() {
            Has(Tokn::Otag(ref otag)) => {
                self.consume_token();
                // 引数は一つ、それをqとみなす
                let qidx = (self.parse_aexp())?;
                self.match_otag(UNIT_INDX, qidx, otag)
            },
            t @ _ => Err(Error::TpiqSingle(t)),
        }
    }

    fn parse_tpiq(&mut self) -> Result<usize, Error> {
        self.log("parse_tpiq");
        self.consume_token(); // dispatcher Pipeのはず
        if let Has(Tokn::Otag(ref otag)) = self.current_token() {
            self.consume_token();
            let pidx = (self.parse_aexp())?;
            let qidx = (self.parse_aexp())?;
            self.match_otag(pidx, qidx, otag)
        } else {
            Err(Error::Unimplemented)
        }
    }

    fn parse_mpiq(&mut self) -> Result<usize, Error> {
        self.consume_token(); // dispatcher Crrtのはず
        match self.current_token() {
            Has(Tokn::Otag(ref otag)) => {
                self.consume_token();
                match otag.as_ref() {
                    // ^Tと^Fは特別扱い
                    "T" => push!(self, Epiq::Tval),
                    "F" => push!(self, Epiq::Fval),
                    _ => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                    },
                }
            },
            Has(Tokn::Lbkt) => {
                let pidx = self.vm.borrow_mut().alloc(Epiq::Uit8(-1));
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Mpiq{o:">".to_string(), p: pidx, q: qidx })
            },
            _ => Err(Error::Unimplemented),
        }
    }

    fn match_otag(&mut self, pidx: NodeId, qidx: NodeId, otag: &str) -> Result<usize, Error> {
        match otag {
            ">" => push!(self, Epiq::Eval(pidx, qidx)),
            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
            "!" => push!(self, Epiq::Appl(pidx, qidx)),
            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
            "?" => push!(self, Epiq::Cond(pidx, qidx)),
            "%" => push!(self, Epiq::Envn(pidx, qidx)),
            "#" => push!(self, Epiq::Bind(pidx, qidx)),
            "." => push!(self, Epiq::Accs(pidx, qidx)),
            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

            _ => {
                push!(self, Epiq::Tpiq{o: otag.to_string(), p: pidx, q: qidx})
            },
        }
    }

    fn parse_cons(&mut self, pidx: usize) -> Result<usize, Error> {
        self.log("parse_cons");
        self.consume_token(); // Coln
        // aexpではない、あえてexpressionしか入れられないように
        // 中置記法の使い方を限定する
        let qidx = (self.parse_expression())?;
        match self.current_token() {
            Has(Tokn::Coln) => {
                let new_cons = (self.parse_cons(qidx))?;
                push!(self, Epiq::Lpiq(pidx, new_cons))
            },
            _ => push!(self, Epiq::Lpiq(pidx, qidx)),
        }
    }

    // expressionとは、ここでは中置記法の中の値になれるものを指している
    fn parse_expression(&mut self) -> Result<usize, Error> {
        self.log("parse_expression");
        // ここはcomsume_tokenしない
        match self.current_token() {
            Has(Tokn::Lbkt) => self.parse_list(),
            _ => {
                let l = (self.parse_accessing_term())?;
                match self.current_token() {
                    Has(Tokn::Bang) => self.parse_apply(l),
                    _ => Ok(l),
                }
            }
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        self.log("parse_list");
        self.consume_token();
        self.parse_list_internal()
    }

    fn parse_list_internal(&mut self) -> Result<usize, Error> {
        self.log("parse_list_internal");
        // 閉じbracketが出るまで再帰呼出
        match self.current_token() {
            Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list_internal())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_accessing_term(&mut self) -> Result<usize, Error> {
        self.log("parse_accessing_term");
        let l = (self.parse_term())?;
        match self.current_token() {
            Has(Tokn::Stop) => self.parse_accessor(l),
            _ => Ok(l),
        }
    }

    fn parse_accessor(&mut self, left: usize) -> Result<usize, Error> {
        self.log("parse_accessor");
        self.consume_token();
        let qidx = (self.parse_term())?; // TODO: 左側はexpressionにしたいが一旦保留
        match self.current_token() {
            Has(Tokn::Stop) => {
                let id = self.vm.borrow_mut().alloc(Epiq::Accs(left, qidx));
                let new_left = self.vm.borrow_mut().alloc(Epiq::Eval(UNIT_INDX, id));
                let new_cons = (self.parse_accessor(new_left))?;
                push!(self, Epiq::Eval(UNIT_INDX, new_cons))
            },
            _ => {
                let id = self.vm.borrow_mut().alloc(Epiq::Accs(left, qidx));
                push!(self, Epiq::Eval(UNIT_INDX, id))
            },
        }
    }

    /// "term" means resolve or literal in this context
    fn parse_term(&mut self) -> Result<usize, Error> {
        self.log("parse_term");
        match self.current_token() {
            Has(Tokn::Atsm) => self.parse_resolve(),
            _ => self.parse_literal(),
        }
    }

    fn parse_apply(&mut self, left: usize) -> Result<usize, Error> {
        self.consume_token();
        let qidx = (self.parse_expression())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Appl(left, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    fn parse_resolve(&mut self) -> Result<usize, Error> {
        self.consume_token(); // Atsm
        let qidx = (self.parse_literal())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Rslv(UNIT_INDX, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        self.log("parse_literal");
        match self.current_token() {
            Has(Tokn::Smcl) => self.parse_unit(),
            Has(Tokn::Dbqt) => self.parse_text(),
            Has(Tokn::Chvc(ref s)) => self.parse_name(s),
            Has(Tokn::Nmbr(ref s)) => self.parse_number(s),
            _ => Err(Error::Unimplemented),
        }
    }

    fn parse_unit(&mut self) -> Result<usize, Error> {
        self.log("parse_unit");
        self.consume_token(); // Smclのはず
        self.vm.borrow_mut().set_entry(UNIT_INDX); // これをしないと;だけの時にentrypointがダメになる
        Ok(UNIT_INDX)
    }

    fn parse_text(&mut self) -> Result<usize, Error> {
        self.consume_token(); // Dbqt
        if let Has(Tokn::Chvc(ref s)) = self.current_token() {
            self.consume_token();
            if let Has(Tokn::Dbqt) = self.current_token() {
                self.consume_token();
                push!(self, Epiq::Text(s.clone()))
            } else {
                Err(Error::Unimplemented)
            }
        } else {
            Err(Error::Unimplemented)
        }
    }

    fn parse_name(&mut self, s: &str) -> Result<usize, Error> {
        self.log("parse_name");
        self.consume_token();
        push!(self, Epiq::Name(s.to_string()))
    }

    fn parse_number(&mut self, s: &str) -> Result<usize, Error> {
        self.consume_token();
        push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
    }

    // Unitは常に1つにする(index固定)
    fn add_unit(&mut self) {
        let _unit = self.vm.borrow_mut().alloc(Epiq::Unit);
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        log(format!("add_prim: {:?} {:?}", name, prim));
        self.vm.borrow_mut().define(name, prim);
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => self.set_current_token(Has(t)),
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => self.set_current_token(EOT),
        }
    }

    fn set_current_token(&mut self, t: TokenState) {
        self.lookahead[self.p] = t;
        self.p = (self.p + 1) % K;
    }

    fn token(&self, i: usize) -> TokenState {
        self.lookahead[(self.p + i) % K].clone()
    }

    fn current_token(&self) -> TokenState {
        self.token(0)
    }

    fn log(&self, func_name: &str) {
        if false {
            println!("{}: {:?}", func_name, self.current_token());
        }
    }
}
<commit_msg>change error handling for parser<commit_after>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;
use self::TokenState::*;

const UNIT_INDX: usize = 0;
const K: usize = 3;

#[derive(Eq, PartialEq, Clone, Debug)]
pub enum TokenState {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl Default for TokenState {
    fn default() -> Self { SOT }
}

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    // current_token: RefCell<TokenState>,
    // aexp_tokens: Vec<Vec<Tokn>>,

    lookahead: [TokenState; K],
    p: usize,
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        let mut parser = Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            // current_token: RefCell::new(SOT),
            // aexp_tokens: vec![vec![]],
            lookahead: Default::default(),
            p: 0,
        };

        for _ in 0..K {
            parser.consume_token();
        }

        parser
    }

    pub fn parse(&mut self) {
        self.add_unit();

        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.add_prim("print");
        self.add_prim("concat");

        match self.parse_aexp() {
            Ok(_) => {},
            Err(e) => {
                println!("parse error: {:?}", e);
            },
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        self.log("parse_aexp");
        match self.current_token() {
            Has(Tokn::Sgqt) => self.parse_tpiq_single(),
            Has(Tokn::Pipe) => self.parse_tpiq(),
            Has(Tokn::Crrt) => self.parse_mpiq(),
            _ => {
                let l = (self.parse_expression())?;
                match self.current_token() {
                    Has(Tokn::Coln) => self.parse_cons(l),
                    _ => Ok(l),
                }
            },
        }
    }

    fn parse_tpiq_single(&mut self) -> Result<usize, Error> {
        self.log("parse_tpiq_single");
        self.consume_token(); // dispatcher Sgqtのはず
        match self.current_token() {
            Has(Tokn::Otag(ref otag)) => {
                self.consume_token();
                // 引数は一つ、それをqとみなす
                let qidx = (self.parse_aexp())?;
                self.match_otag(UNIT_INDX, qidx, otag)
            },
            t @ _ => Err(Error::TpiqSingle(t)),
        }
    }

    fn parse_tpiq(&mut self) -> Result<usize, Error> {
        self.log("parse_tpiq");
        self.consume_token(); // dispatcher Pipeのはず
        if let Has(Tokn::Otag(ref otag)) = self.current_token() {
            self.consume_token();
            let pidx = (self.parse_aexp())?;
            let qidx = (self.parse_aexp())?;
            self.match_otag(pidx, qidx, otag)
        } else {
            // Err(Error::Unimplemented)
            panic!("parse_tpiq {:?}はOtagではありません", self.current_token());
        }
    }

    fn parse_mpiq(&mut self) -> Result<usize, Error> {
        self.consume_token(); // dispatcher Crrtのはず
        match self.current_token() {
            Has(Tokn::Otag(ref otag)) => {
                self.consume_token();
                match otag.as_ref() {
                    // ^Tと^Fは特別扱い
                    "T" => push!(self, Epiq::Tval),
                    "F" => push!(self, Epiq::Fval),
                    _ => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                    },
                }
            },
            Has(Tokn::Lbkt) => {
                let pidx = self.vm.borrow_mut().alloc(Epiq::Uit8(-1));
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Mpiq{o:">".to_string(), p: pidx, q: qidx })
            },
            _ => panic!("parse_mpiq {:?}がOtag/Lbktではありません", self.current_token()) /*Err(Error::Unimplemented)*/,
        }
    }

    fn match_otag(&mut self, pidx: NodeId, qidx: NodeId, otag: &str) -> Result<usize, Error> {
        match otag {
            ">" => push!(self, Epiq::Eval(pidx, qidx)),
            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
            "!" => push!(self, Epiq::Appl(pidx, qidx)),
            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
            "?" => push!(self, Epiq::Cond(pidx, qidx)),
            "%" => push!(self, Epiq::Envn(pidx, qidx)),
            "#" => push!(self, Epiq::Bind(pidx, qidx)),
            "." => push!(self, Epiq::Accs(pidx, qidx)),
            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

            _ => {
                push!(self, Epiq::Tpiq{o: otag.to_string(), p: pidx, q: qidx})
            },
        }
    }

    fn parse_cons(&mut self, pidx: usize) -> Result<usize, Error> {
        self.log("parse_cons");
        self.consume_token(); // Coln
        // aexpではない、あえてexpressionしか入れられないように
        // 中置記法の使い方を限定する
        let qidx = (self.parse_expression())?;
        match self.current_token() {
            Has(Tokn::Coln) => {
                let new_cons = (self.parse_cons(qidx))?;
                push!(self, Epiq::Lpiq(pidx, new_cons))
            },
            _ => push!(self, Epiq::Lpiq(pidx, qidx)),
        }
    }

    // expressionとは、ここでは中置記法の中の値になれるものを指している
    fn parse_expression(&mut self) -> Result<usize, Error> {
        self.log("parse_expression");
        // ここはcomsume_tokenしない
        match self.current_token() {
            Has(Tokn::Lbkt) => self.parse_list(),
            _ => {
                let l = (self.parse_accessing_term())?;
                match self.current_token() {
                    Has(Tokn::Bang) => self.parse_apply(l),
                    _ => Ok(l),
                }
            }
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        self.log("parse_list");
        self.consume_token();
        self.parse_list_internal()
    }

    fn parse_list_internal(&mut self) -> Result<usize, Error> {
        self.log("parse_list_internal");
        // 閉じbracketが出るまで再帰呼出
        match self.current_token() {
            Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list_internal())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_accessing_term(&mut self) -> Result<usize, Error> {
        self.log("parse_accessing_term");
        let l = (self.parse_term())?;
        match self.current_token() {
            Has(Tokn::Stop) => self.parse_accessor(l),
            _ => Ok(l),
        }
    }

    fn parse_accessor(&mut self, left: usize) -> Result<usize, Error> {
        self.log("parse_accessor");
        self.consume_token();
        let qidx = (self.parse_term())?; // TODO: 左側はexpressionにしたいが一旦保留
        match self.current_token() {
            Has(Tokn::Stop) => {
                let id = self.vm.borrow_mut().alloc(Epiq::Accs(left, qidx));
                let new_left = self.vm.borrow_mut().alloc(Epiq::Eval(UNIT_INDX, id));
                let new_cons = (self.parse_accessor(new_left))?;
                push!(self, Epiq::Eval(UNIT_INDX, new_cons))
            },
            _ => {
                let id = self.vm.borrow_mut().alloc(Epiq::Accs(left, qidx));
                push!(self, Epiq::Eval(UNIT_INDX, id))
            },
        }
    }

    /// "term" means resolve or literal in this context
    fn parse_term(&mut self) -> Result<usize, Error> {
        self.log("parse_term");
        match self.current_token() {
            Has(Tokn::Atsm) => self.parse_resolve(),
            _ => self.parse_literal(),
        }
    }

    fn parse_apply(&mut self, left: usize) -> Result<usize, Error> {
        self.consume_token();
        let qidx = (self.parse_expression())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Appl(left, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    fn parse_resolve(&mut self) -> Result<usize, Error> {
        self.consume_token(); // Atsm
        let qidx = (self.parse_literal())?;
        let id = self.vm.borrow_mut().alloc(Epiq::Rslv(UNIT_INDX, qidx));
        push!(self, Epiq::Eval(UNIT_INDX, id))
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        self.log("parse_literal");
        match self.current_token() {
            Has(Tokn::Smcl) => self.parse_unit(),
            Has(Tokn::Dbqt) => self.parse_text(),
            Has(Tokn::Chvc(ref s)) => self.parse_name(s),
            Has(Tokn::Nmbr(ref s)) => self.parse_number(s),
            _ => panic!("parse_literal {:?}がSmcl/Dbqt/Chvc/Nmbrではありません", self.current_token())/*Err(Error::Unimplemented)*/,
        }
    }

    fn parse_unit(&mut self) -> Result<usize, Error> {
        self.log("parse_unit");
        self.consume_token(); // Smclのはず
        self.vm.borrow_mut().set_entry(UNIT_INDX); // これをしないと;だけの時にentrypointがダメになる
        Ok(UNIT_INDX)
    }

    fn parse_text(&mut self) -> Result<usize, Error> {
        self.consume_token(); // Dbqt
        if let Has(Tokn::Chvc(ref s)) = self.current_token() {
            self.consume_token();
            if let Has(Tokn::Dbqt) = self.current_token() {
                self.consume_token();
                push!(self, Epiq::Text(s.clone()))
            } else {
                Err(Error::Unimplemented)
            }
        } else {
            Err(Error::Unimplemented)
        }
    }

    fn parse_name(&mut self, s: &str) -> Result<usize, Error> {
        self.log("parse_name");
        self.consume_token();
        push!(self, Epiq::Name(s.to_string()))
    }

    fn parse_number(&mut self, s: &str) -> Result<usize, Error> {
        self.consume_token();
        push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
    }

    // Unitは常に1つにする(index固定)
    fn add_unit(&mut self) {
        let _unit = self.vm.borrow_mut().alloc(Epiq::Unit);
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        log(format!("add_prim: {:?} {:?}", name, prim));
        self.vm.borrow_mut().define(name, prim);
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => self.set_current_token(Has(t)),
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => self.set_current_token(EOT),
        }
    }

    fn set_current_token(&mut self, t: TokenState) {
        self.lookahead[self.p] = t;
        self.p = (self.p + 1) % K;
    }

    fn token(&self, i: usize) -> TokenState {
        self.lookahead[(self.p + i) % K].clone()
    }

    fn current_token(&self) -> TokenState {
        self.token(0)
    }

    fn log(&self, func_name: &str) {
        if false {
            println!("{}: {:?}", func_name, self.current_token());
        }
    }
}
<|endoftext|>


<commit_before>use node::NodeKind;
use node;
use typing::Type;
use node::{BinOps, CompBinOps};
use closure::{Closure, Prog, FuncDef};

use std::collections::{HashMap, HashSet};

extern crate ordered_float;
use self::ordered_float::OrderedFloat;

use parser::EXTENV;

type ArgsTypes = Vec<Type>;

fn retrieve_var_name(e: &Closure) -> Option<String> {
    if let &Closure::Var(ref name) = e {
        Some(name.clone())
    } else {
        None
    }
}

// TODO: MUST FIX THIS DIRTY CODE!!

pub fn h(f: FuncDef, p: &mut HashMap<String, Vec<ArgsTypes>>) -> Vec<FuncDef> {
    let (name, ty) = f.name;
    let args_tys_list = if let Some(args_tys_list) = p.get(&name).cloned() {
        args_tys_list
    } else {
        // the function named 'name' is not a polymorphic function.
        return vec![];
    };

    let mut fundefs = Vec::new();
    for args_tys in args_tys_list {
        let mut env = HashMap::new();
        // TODO: should make a func for mangling.
        let mut name_mangled = name.clone() + "#";
        let mut actual_params = vec![];
        for (actual_ty, &(ref param_name, _)) in args_tys.iter().zip(&f.params.clone()) {
            env.insert(param_name.clone(), actual_ty.clone());
            actual_params.push((param_name.clone(), actual_ty.clone()));
            name_mangled += actual_ty.clone().to_string().as_str();
        }
        let (body, ret_ty) = g(*f.body.clone(), &env, p);
        fundefs.push(FuncDef {
            name: (
                name_mangled,
                Type::Func(
                    actual_params.iter().map(|x| x.1.clone()).collect(),
                    Box::new(ret_ty),
                ),
            ),
            params: actual_params,
            formal_fv: f.formal_fv.clone(),
            body: Box::new(body),
        });
    }
    fundefs
}

pub fn g(
    e: Closure,
    env: &HashMap<String, Type>,
    p: &mut HashMap<String, Vec<ArgsTypes>>,
) -> (Closure, Type) {
    macro_rules! g_seq {
        ($es:expr) => ({
            let mut tys = Vec::new();
            for e in $es { tys.push(g(e, env, p)); }
            tys
        });
    }
    match e {
        Closure::Unit => (e, Type::Unit),
        Closure::Bool(_) => (e, Type::Bool),
        Closure::Int(_) => (e, Type::Int),
        Closure::Float(_) => (e, Type::Float),
        Closure::Var(ref name) => {
            if let Some(ty) = env.get(name.as_str()).cloned() {
                (e.clone(), ty)
            } else {
                panic!()
            }
        }
        Closure::IntBinaryOp(op, lhs, rhs) => {
            (
                Closure::IntBinaryOp(op, Box::new(g(*lhs, env, p).0), Box::new(g(*rhs, env, p).0)),
                Type::Int,
            )
        }
        Closure::LetExpr((name, ty), expr, body) => {
            let mut new_env = env.clone();
            let (expr, expr_ty) = g(*expr, &env, p);
            let ty = if ty.contained_var() { expr_ty } else { ty };
            new_env.insert(name.clone(), ty.clone());
            let (body, body_ty) = g(*body, &new_env, p);
            (
                Closure::LetExpr((name, ty), Box::new(expr), Box::new(body)),
                body_ty,
            )
        }
        Closure::AppCls(callee, args) |
        Closure::AppDir(callee, args) => {
            let name = retrieve_var_name(&*callee).unwrap();
            if EXTENV.lock().unwrap().contains_key(name.as_str()) {
                let args2 = g_seq!(args.clone());
                let mut args = vec![];
                for (e, a) in args2.clone() {
                    args.push(e);
                }
                return (Closure::AppCls(callee, args), Type::Unit);
            }
            let args = g_seq!(args.clone());
            let mut name_mangled = name.clone() + "#";
            let mut args_expr = vec![];
            let mut args_ty = vec![];
            for (e, t) in args.clone() {
                name_mangled += t.to_string().as_str();
                args_expr.push(e);
                args_ty.push(t);
            }
            (*p.entry(name).or_insert(vec![])).push(args_ty);
            (
                Closure::AppCls(Box::new(Closure::Var(name_mangled)), args_expr),
                Type::Unit,
            )
        }
        _ => panic!(),
    }
}

pub fn f(e: Prog) -> Prog {
    let Prog(fundef, expr) = e.clone();
    let mut new_fundef = Vec::new();
    let mut poly_map = HashMap::new();
    let expr = g(expr, &HashMap::new(), &mut poly_map).0;

    for f in fundef {
        new_fundef.extend(h(f, &mut poly_map).iter().cloned());
    }
    Prog(new_fundef, expr)
}

impl Type {
    fn contained_var(&self) -> bool {
        macro_rules! seq {
            ($es:expr) => ({
                for e in $es { if e.contained_var() { return true } }
            });
        }
        match self {
            &Type::Unit | &Type::Char | &Type::Int | &Type::Float => false,
            &Type::Func(ref params_ty, ref ret_ty) => {
                seq!(params_ty);
                ret_ty.contained_var()
            }
            &Type::Var(_) => true,
            _ => panic!(format!("{:?}", self)),
        }
    }
}
<commit_msg>polymorphic support is later<commit_after><|endoftext|>


<commit_before>extern mod redis;

use std::io::process;
use std::io::io_error;
use std::libc::SIGTERM;

pub static SERVER_PORT: int = 38991;

struct RedisServer {
    priv process: process::Process,
}

impl RedisServer {

    fn new() -> RedisServer {
        let mut process = process::Process::new(process::ProcessConfig {
            program: "redis-server",
            args: [~"-"],
            env: None,
            cwd: None,
            io: [process::CreatePipe(true, false),
                 process::Ignored,
                 process::Ignored],
        }).unwrap();
        let input = format!("
            port {port}
        ", port=SERVER_PORT);
        process.io[0].get_mut_ref().write(input.as_bytes());
        process.io[0] = None;
        RedisServer { process: process }
    }
}

impl Drop for RedisServer {

    fn drop(&mut self) {
        io_error::cond.trap(|_e| {}).inside(|| {
            self.process.signal(SIGTERM as int);
        });
        self.process.wait();
    }
}

struct TestContext {
    server: RedisServer,
    client: redis::Client,
}

impl TestContext {

    fn new() -> TestContext {
        let url = format!("redis://127.0.0.1:{port}/0", port=SERVER_PORT);
        let server = RedisServer::new();

        let mut client;
        loop {
            match redis::Client::open(url) {
                Ok(x) => { client = x; break; }
                Err(redis::ConnectionRefused) => { std::io::timer::sleep(10); }
                _ => { fail!("Error on connect"); }
            }
        }

        client.get_connection().unwrap().flushdb();
        TestContext {
            server: server,
            client: client,
        }
    }

    fn connection(&self) -> redis::Connection {
        self.client.get_connection().unwrap()
    }
}

#[test]
fn test_ping() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    assert!(con.ping() == true);
}

#[test]
fn test_info() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    let info = con.info();
    assert!(*info.find(&~"tcp_port").unwrap() == SERVER_PORT.to_str());
}

#[test]
fn test_basics() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    con.set("foo", "bar");
    assert!(con.get("foo") == Some(~"bar"));
    con.del("foo");
    assert!(con.get("foo") == None);
}

#[test]
fn test_types() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    con.set("foo", 42);
    con.set("bar", "test");
    assert!(con.get_type("foo") == redis::StringType);
    assert!(con.get_type("bar") == redis::StringType);
    assert!(con.get("foo") == Some(~"42"));
    assert!(con.get_as::<int>("foo") == Some(42));
    assert!(con.get("bar") == Some(~"test"));
    assert!(con.exists("foo") == true);
    assert!(con.exists("invalid") == false);
}

#[test]
fn test_script() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    let script = redis::Script::new("
        return tonumber(ARGV[1]) + 1;
    ");
    assert!(con.call_script(&script, [], [redis::StrArg("42")]) == redis::Int(43));
}

#[test]
fn test_blpop() {
    let ctx = TestContext::new();
    let client = ctx.client;
    let (port, chan) = Chan::new();

    do spawn {
        let mut con = client.get_connection().unwrap();
        let rv = con.blpop(["q"], 5.0);
        assert!(rv == Some((~"q", ~"awesome")));
        chan.send(());
    }

    do spawn {
        let mut con = client.get_connection().unwrap();
        con.rpush("q", "awesome");
    }

    port.recv();
}

#[test]
fn test_scan() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();

    for x in range(0, 100) {
        con.set(format!("key:{}", x), x);
    }

    let mut found = [false, .. 100];
    for item in con.scan("key:*") {
        let mut iter = item.split(':');
        if iter.next().is_none() {
            continue;
        }
        match iter.next() {
            Some(value) => {
                found[from_str::<uint>(value).unwrap()] = true;
            }
            None => {},
        }
    }

    for x in range(0, 100) {
        assert!(found[x] == true);
    }
}
<commit_msg>Ensure redis starts up properly in tests<commit_after>extern mod redis;

use std::io::process;
use std::io::io_error;
use std::libc::SIGTERM;

pub static SERVER_PORT: int = 38991;

struct RedisServer {
    priv process: process::Process,
}

impl RedisServer {

    fn new() -> RedisServer {
        let mut process = process::Process::new(process::ProcessConfig {
            program: "redis-server",
            args: [~"-"],
            env: None,
            cwd: None,
            io: [process::CreatePipe(true, false),
                 process::Ignored,
                 process::Ignored],
        }).unwrap();
        let input = format!("
            port {port}
        ", port=SERVER_PORT);
        process.io[0].get_mut_ref().write(input.as_bytes());
        process.io[0] = None;
        RedisServer { process: process }
    }
}

impl Drop for RedisServer {

    fn drop(&mut self) {
        io_error::cond.trap(|_e| {}).inside(|| {
            self.process.signal(SIGTERM as int);
        });
        let rv = self.process.wait();
        assert!(rv.success());
    }
}

struct TestContext {
    server: RedisServer,
    client: redis::Client,
}

impl TestContext {

    fn new() -> TestContext {
        let url = format!("redis://127.0.0.1:{port}/0", port=SERVER_PORT);
        let server = RedisServer::new();

        let mut client;
        loop {
            match redis::Client::open(url) {
                Ok(x) => { client = x; break; }
                Err(redis::ConnectionRefused) => { std::io::timer::sleep(10); }
                _ => { fail!("Error on connect"); }
            }
        }

        client.get_connection().unwrap().flushdb();
        TestContext {
            server: server,
            client: client,
        }
    }

    fn connection(&self) -> redis::Connection {
        self.client.get_connection().unwrap()
    }
}

#[test]
fn test_ping() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    assert!(con.ping() == true);
}

#[test]
fn test_info() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    let info = con.info();
    assert!(*info.find(&~"tcp_port").unwrap() == SERVER_PORT.to_str());
}

#[test]
fn test_basics() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    con.set("foo", "bar");
    assert!(con.get("foo") == Some(~"bar"));
    con.del("foo");
    assert!(con.get("foo") == None);
}

#[test]
fn test_types() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    con.set("foo", 42);
    con.set("bar", "test");
    assert!(con.get_type("foo") == redis::StringType);
    assert!(con.get_type("bar") == redis::StringType);
    assert!(con.get("foo") == Some(~"42"));
    assert!(con.get_as::<int>("foo") == Some(42));
    assert!(con.get("bar") == Some(~"test"));
    assert!(con.exists("foo") == true);
    assert!(con.exists("invalid") == false);
}

#[test]
fn test_script() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();
    let script = redis::Script::new("
        return tonumber(ARGV[1]) + 1;
    ");
    assert!(con.call_script(&script, [], [redis::StrArg("42")]) == redis::Int(43));
}

#[test]
fn test_blpop() {
    let ctx = TestContext::new();
    let client = ctx.client;
    let (port, chan) = Chan::new();

    do spawn {
        let mut con = client.get_connection().unwrap();
        let rv = con.blpop(["q"], 5.0);
        assert!(rv == Some((~"q", ~"awesome")));
        chan.send(());
    }

    do spawn {
        let mut con = client.get_connection().unwrap();
        con.rpush("q", "awesome");
    }

    port.recv();
}

#[test]
fn test_scan() {
    let ctx = TestContext::new();
    let mut con = ctx.connection();

    for x in range(0, 100) {
        con.set(format!("key:{}", x), x);
    }

    let mut found = [false, .. 100];
    for item in con.scan("key:*") {
        let mut iter = item.split(':');
        if iter.next().is_none() {
            continue;
        }
        match iter.next() {
            Some(value) => {
                found[from_str::<uint>(value).unwrap()] = true;
            }
            None => {},
        }
    }

    for x in range(0, 100) {
        assert!(found[x] == true);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Gomez Guillaume
//
// 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.

use std::fs::{OpenOptions, remove_file};
use std::io::{BufRead, BufReader, Write};
use std::collections::HashMap;
use strip;
use utils::{join, loop_over_files};

use stripper_interface::{
    TypeStruct,
    EventType,
    Type,
    MOD_COMMENT,
    FILE_COMMENT,
    FILE,
};
use types::OUTPUT_COMMENT_FILE;

fn get_corresponding_type(elements: &[(Option<TypeStruct>, Vec<String>)],
                          to_find: &Option<TypeStruct>,
                          mut line: usize,
                          decal: &mut usize,
                          original_content: &mut Vec<String>) -> Option<usize> {
    let mut pos = 0;

    while pos < elements.len() {
        if match (&elements[pos].0, to_find) {
            (&Some(ref a), &Some(ref b)) => {
                let ret = a == b;

                // to detect variants
                if !ret && b.ty == Type::Unknown && b.parent.is_some() && a.parent.is_some() && a.parent == b.parent {
                    if match b.parent {
                        Some(ref p) => p.ty == Type::Struct || p.ty == Type::Enum || p.ty == Type::Use,
                        None => false,
                    } {
                        let mut tmp = b.clone();

                        tmp.ty = Type::Variant;
                        a == &tmp
                    } else {
                        false
                    }
                } else {
                    ret
                }
            },
            _ => false,
        } {
            let mut file_comment = false;

            if elements[pos].1.len() > 0 && elements[pos].1[0].starts_with(FILE_COMMENT) {
                line += 1;
                file_comment = true;
            } else {
                while line > 0 && (line + *decal) > 0 &&
                      original_content[line + *decal - 1].trim().starts_with("#") {
                    line -= 1;
                }
            }
            for comment in &elements[pos].1 {
                if file_comment {
                    original_content.insert(line + *decal, comment[FILE_COMMENT.len()..].to_owned());
                } else {
                    original_content.insert(line + *decal, comment.clone());
                }
                *decal += 1;
            }
            return Some(pos);
        }
        pos += 1;
    }
    None
}

fn regenerate_comments(path: &str, infos: &mut HashMap<String, Vec<(Option<TypeStruct>, Vec<String>)>>) {
    if !infos.contains_key(path) {
        return;
    }
    match strip::build_event_list(path) {
        Ok(mut parse_result) => {
            let mut elements = infos.get_mut(path).unwrap();
            let mut position = 0;
            let mut decal = 0;

            // first, we need to put back file comment
            for entry in elements.iter() {
                if entry.0.is_none() {
                    let mut it = 0;

                    while it < parse_result.original_content.len() {
                        if parse_result.original_content[it].starts_with("/") &&
                           it + 1 < parse_result.original_content.len() &&
                           parse_result.original_content[it + 1].len() < 1 {
                            it += 2;
                            break;
                        }
                        it += 1;
                    }
                    if it < parse_result.original_content.len() {
                        for line in &entry.1 {
                            parse_result.original_content.insert(it, line.clone());
                            decal += 1;
                            it += 1;
                        }
                    }
                    break;
                }
                position += 1;
            }
            if position < elements.len() {
                elements.remove(position);
            }
            let mut waiting_type = None;
            let mut current = None;
            let mut it = 0;

            while it < parse_result.event_list.len() {
                match parse_result.event_list[it].event {
                    EventType::Type(ref t) => {
                        if t.ty != Type::Unknown {
                            waiting_type = Some(t.clone());
                            let tmp = strip::add_to_type_scope(&current, &waiting_type);

                            match get_corresponding_type(&elements, &tmp,
                                                         parse_result.event_list[it].line,
                                                         &mut decal,
                                                         &mut parse_result.original_content) {
                                Some(l) => { elements.remove(l); },
                                None => {}
                            };
                        } else {
                            match current {
                                Some(ref c) => {
                                    if c.ty == Type::Struct || c.ty == Type::Enum ||
                                       c.ty == Type::Mod {
                                        let tmp = Some(t.clone());
                                        let cc = strip::add_to_type_scope(&current, &tmp);

                                        match get_corresponding_type(&elements, &cc,
                                                                     parse_result.event_list[it].line,
                                                                     &mut decal,
                                                                     &mut parse_result.original_content) {
                                            Some(l) => { elements.remove(l); },
                                            None => {}
                                        }
                                    }
                                }
                                None => {}
                            }
                        }
                    }
                    EventType::InScope => {
                        current = strip::add_to_type_scope(&current, &waiting_type);
                        waiting_type = None;
                        match get_corresponding_type(&elements, &current,
                                                     parse_result.event_list[it].line,
                                                     &mut decal,
                                                     &mut parse_result.original_content) {
                            Some(l) => { elements.remove(l); },
                            None => {}
                        };
                    }
                    EventType::OutScope => {
                        current = strip::type_out_scope(&current);
                        waiting_type = None;
                    }
                    _ => {}
                }
                it += 1;
            }
            rewrite_file(path, &parse_result.original_content);
        }
        Err(e) => {
            println!("Error on file '{}': {}", path, e);
        }
    }
}

fn rewrite_file(path: &str, o_content: &[String]) {
    match OpenOptions::new().write(true).create(true).truncate(true).open(path) {
        Ok(mut f) => {
            write!(f, "{}", o_content.join("\n")).unwrap();
        }
        Err(e) => {
            println!("Cannot open '{}': {}", path, e);
        }
    }
}

fn parse_mod_line(line: &str) -> Option<TypeStruct> {
    let line = line.replace(MOD_COMMENT, "");
    let parts : Vec<&str> = line.split("§").collect();
    let mut current = None;

    for part in parts {
        let elems : Vec<&str> = part.split(" ").filter(|x| x.len() > 0).collect();

        current = strip::add_to_type_scope(&current.clone(),
                                           &Some(TypeStruct::new(Type::from(elems[0]),
                                                                 elems[elems.len() - 1])));
    }
    current
}

fn save_remainings(infos: &HashMap<String, Vec<(Option<TypeStruct>, Vec<String>)>>) {
    let mut remainings = 0;

    for (_, content) in infos {
        if content.len() > 0 {
            remainings += 1;
        }
    }
    if remainings < 1 {
        remove_file(OUTPUT_COMMENT_FILE);
        return;
    }
    match OpenOptions::new().write(true).create(true).truncate(true).open(OUTPUT_COMMENT_FILE) {
        Ok(mut out_file) => {
            println!("Some comments couldn't have been regenerated to the files. Saving them back to '{}'.",
                     OUTPUT_COMMENT_FILE);
            for (key, content) in infos {
                if content.len() < 1 {
                    continue;
                }
                writeln!(out_file, "{}{}", FILE_COMMENT, key);
                for line in content {
                    match line.0 {
                        Some(ref d) => {
                            writeln!(out_file, "{}{}\n{}", MOD_COMMENT, d, join(&line.1, "\n"));
                        }
                        None => {}
                    }
                }
            }
            println!("Not implemented yet.");
        }
        Err(e) => {
            println!("An error occured while trying to open '{}': {}", OUTPUT_COMMENT_FILE, e);
            return;
        }
    }
}

pub fn regenerate_doc_comments(directory: &str, verbose: bool) {
    // we start by storing files info
    let f = match OpenOptions::new().read(true).open(OUTPUT_COMMENT_FILE) {
        Ok(f) => f,
        Err(e) => {
            println!("An error occured while trying to open '{}': {}", OUTPUT_COMMENT_FILE, e);
            return;
        }
    };
    let reader = BufReader::new(f);
    let mut current_file = String::new();
    let mut infos = HashMap::new();
    let mut current_infos = vec!();
    let mut lines = vec!();
    let mut it = 0;

    for tmp_line in reader.lines() {
        lines.push(tmp_line.unwrap());
    }
    while it < lines.len() {
        if lines[it].starts_with(FILE) {
            if current_file.len() > 0 && current_infos.len() > 0 {
                infos.insert(current_file, current_infos.clone());
                current_infos = vec!();
            }
            current_file = lines[it].replace(FILE, "").to_owned();
            it += 1;
        } else if lines[it].starts_with(MOD_COMMENT) {
            let ty = parse_mod_line(&lines[it]);
            let mut comments = vec!();

            it += 1;
            if ty.is_none() {
                continue;
            }
            while it < lines.len() {
                if lines[it].starts_with(MOD_COMMENT) ||
                   lines[it].starts_with(FILE) {
                    break;
                }
                comments.push(lines[it].to_owned());
                it += 1;
            }
            if comments.len() > 0 {
                current_infos.push((ty, comments));
            }
        } else if lines[it].starts_with(FILE_COMMENT) {
            let mut comment_lines = vec!();

            while it < lines.len() && lines[it].starts_with(FILE_COMMENT) {
                comment_lines.push(lines[it][FILE_COMMENT.len()..].to_owned());
                it += 1;
            }
            current_infos.push((None, comment_lines));
        }
    }
    if current_file.len() > 0 && current_infos.len() > 0 {
        infos.insert(current_file, current_infos.clone());
    }
    loop_over_files(directory, &mut infos, &regenerate_comments, &vec!(), verbose);
    save_remainings(&infos);
    // TODO: rewrite comments.cmts with remaining infos in regenerate_comments
}<commit_msg>Support reading the set of comments from any slice of string-like types<commit_after>// Copyright 2015 Gomez Guillaume
//
// 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.

use std::fs::{OpenOptions, remove_file};
use std::io::{BufRead, BufReader, Write};
use std::collections::HashMap;
use std::ops::Deref;
use strip;
use utils::{join, loop_over_files};

use stripper_interface::{
    TypeStruct,
    EventType,
    Type,
    MOD_COMMENT,
    FILE_COMMENT,
    FILE,
};
use types::OUTPUT_COMMENT_FILE;

fn get_corresponding_type(elements: &[(Option<TypeStruct>, Vec<String>)],
                          to_find: &Option<TypeStruct>,
                          mut line: usize,
                          decal: &mut usize,
                          original_content: &mut Vec<String>) -> Option<usize> {
    let mut pos = 0;

    while pos < elements.len() {
        if match (&elements[pos].0, to_find) {
            (&Some(ref a), &Some(ref b)) => {
                let ret = a == b;

                // to detect variants
                if !ret && b.ty == Type::Unknown && b.parent.is_some() && a.parent.is_some() && a.parent == b.parent {
                    if match b.parent {
                        Some(ref p) => p.ty == Type::Struct || p.ty == Type::Enum || p.ty == Type::Use,
                        None => false,
                    } {
                        let mut tmp = b.clone();

                        tmp.ty = Type::Variant;
                        a == &tmp
                    } else {
                        false
                    }
                } else {
                    ret
                }
            },
            _ => false,
        } {
            let mut file_comment = false;

            if elements[pos].1.len() > 0 && elements[pos].1[0].starts_with(FILE_COMMENT) {
                line += 1;
                file_comment = true;
            } else {
                while line > 0 && (line + *decal) > 0 &&
                      original_content[line + *decal - 1].trim().starts_with("#") {
                    line -= 1;
                }
            }
            for comment in &elements[pos].1 {
                if file_comment {
                    original_content.insert(line + *decal, comment[FILE_COMMENT.len()..].to_owned());
                } else {
                    original_content.insert(line + *decal, comment.clone());
                }
                *decal += 1;
            }
            return Some(pos);
        }
        pos += 1;
    }
    None
}

fn regenerate_comments(path: &str, infos: &mut HashMap<String, Vec<(Option<TypeStruct>, Vec<String>)>>) {
    if !infos.contains_key(path) {
        return;
    }
    match strip::build_event_list(path) {
        Ok(mut parse_result) => {
            let mut elements = infos.get_mut(path).unwrap();
            let mut position = 0;
            let mut decal = 0;

            // first, we need to put back file comment
            for entry in elements.iter() {
                if entry.0.is_none() {
                    let mut it = 0;

                    while it < parse_result.original_content.len() {
                        if parse_result.original_content[it].starts_with("/") &&
                           it + 1 < parse_result.original_content.len() &&
                           parse_result.original_content[it + 1].len() < 1 {
                            it += 2;
                            break;
                        }
                        it += 1;
                    }
                    if it < parse_result.original_content.len() {
                        for line in &entry.1 {
                            parse_result.original_content.insert(it, line.clone());
                            decal += 1;
                            it += 1;
                        }
                    }
                    break;
                }
                position += 1;
            }
            if position < elements.len() {
                elements.remove(position);
            }
            let mut waiting_type = None;
            let mut current = None;
            let mut it = 0;

            while it < parse_result.event_list.len() {
                match parse_result.event_list[it].event {
                    EventType::Type(ref t) => {
                        if t.ty != Type::Unknown {
                            waiting_type = Some(t.clone());
                            let tmp = strip::add_to_type_scope(&current, &waiting_type);

                            match get_corresponding_type(&elements, &tmp,
                                                         parse_result.event_list[it].line,
                                                         &mut decal,
                                                         &mut parse_result.original_content) {
                                Some(l) => { elements.remove(l); },
                                None => {}
                            };
                        } else {
                            match current {
                                Some(ref c) => {
                                    if c.ty == Type::Struct || c.ty == Type::Enum ||
                                       c.ty == Type::Mod {
                                        let tmp = Some(t.clone());
                                        let cc = strip::add_to_type_scope(&current, &tmp);

                                        match get_corresponding_type(&elements, &cc,
                                                                     parse_result.event_list[it].line,
                                                                     &mut decal,
                                                                     &mut parse_result.original_content) {
                                            Some(l) => { elements.remove(l); },
                                            None => {}
                                        }
                                    }
                                }
                                None => {}
                            }
                        }
                    }
                    EventType::InScope => {
                        current = strip::add_to_type_scope(&current, &waiting_type);
                        waiting_type = None;
                        match get_corresponding_type(&elements, &current,
                                                     parse_result.event_list[it].line,
                                                     &mut decal,
                                                     &mut parse_result.original_content) {
                            Some(l) => { elements.remove(l); },
                            None => {}
                        };
                    }
                    EventType::OutScope => {
                        current = strip::type_out_scope(&current);
                        waiting_type = None;
                    }
                    _ => {}
                }
                it += 1;
            }
            rewrite_file(path, &parse_result.original_content);
        }
        Err(e) => {
            println!("Error on file '{}': {}", path, e);
        }
    }
}

fn rewrite_file(path: &str, o_content: &[String]) {
    match OpenOptions::new().write(true).create(true).truncate(true).open(path) {
        Ok(mut f) => {
            write!(f, "{}", o_content.join("\n")).unwrap();
        }
        Err(e) => {
            println!("Cannot open '{}': {}", path, e);
        }
    }
}

fn parse_mod_line(line: &str) -> Option<TypeStruct> {
    let line = line.replace(MOD_COMMENT, "");
    let parts : Vec<&str> = line.split("§").collect();
    let mut current = None;

    for part in parts {
        let elems : Vec<&str> = part.split(" ").filter(|x| x.len() > 0).collect();

        current = strip::add_to_type_scope(&current.clone(),
                                           &Some(TypeStruct::new(Type::from(elems[0]),
                                                                 elems[elems.len() - 1])));
    }
    current
}

fn save_remainings(infos: &HashMap<String, Vec<(Option<TypeStruct>, Vec<String>)>>) {
    let mut remainings = 0;

    for (_, content) in infos {
        if content.len() > 0 {
            remainings += 1;
        }
    }
    if remainings < 1 {
        remove_file(OUTPUT_COMMENT_FILE);
        return;
    }
    match OpenOptions::new().write(true).create(true).truncate(true).open(OUTPUT_COMMENT_FILE) {
        Ok(mut out_file) => {
            println!("Some comments couldn't have been regenerated to the files. Saving them back to '{}'.",
                     OUTPUT_COMMENT_FILE);
            for (key, content) in infos {
                if content.len() < 1 {
                    continue;
                }
                writeln!(out_file, "{}{}", FILE_COMMENT, key);
                for line in content {
                    match line.0 {
                        Some(ref d) => {
                            writeln!(out_file, "{}{}\n{}", MOD_COMMENT, d, join(&line.1, "\n"));
                        }
                        None => {}
                    }
                }
            }
            println!("Not implemented yet.");
        }
        Err(e) => {
            println!("An error occured while trying to open '{}': {}", OUTPUT_COMMENT_FILE, e);
            return;
        }
    }
}

pub fn regenerate_doc_comments(directory: &str, verbose: bool) {
    // we start by storing files info
    let f = match OpenOptions::new().read(true).open(OUTPUT_COMMENT_FILE) {
        Ok(f) => f,
        Err(e) => {
            println!("An error occured while trying to open '{}': {}", OUTPUT_COMMENT_FILE, e);
            return;
        }
    };
    let reader = BufReader::new(f);
    let lines: Vec<String> = reader.lines().collect::<Result<_, _>>().unwrap();
    regenerate_doc_comments_real(directory, verbose, &lines);
}

pub fn regenerate_doc_comments_real<S>(directory: &str, verbose: bool, lines: &[S])
where S: Deref<Target = str> {
    let mut current_file = String::new();
    let mut infos = HashMap::new();
    let mut current_infos = vec!();
    let mut it = 0;

    while it < lines.len() {
        if lines[it].starts_with(FILE) {
            if current_file.len() > 0 && current_infos.len() > 0 {
                infos.insert(current_file, current_infos.clone());
                current_infos = vec!();
            }
            current_file = lines[it].replace(FILE, "").to_owned();
            it += 1;
        } else if lines[it].starts_with(MOD_COMMENT) {
            let ty = parse_mod_line(&lines[it]);
            let mut comments = vec!();

            it += 1;
            if ty.is_none() {
                continue;
            }
            while it < lines.len() {
                if lines[it].starts_with(MOD_COMMENT) ||
                   lines[it].starts_with(FILE) {
                    break;
                }
                comments.push(lines[it].to_owned());
                it += 1;
            }
            if comments.len() > 0 {
                current_infos.push((ty, comments));
            }
        } else if lines[it].starts_with(FILE_COMMENT) {
            let mut comment_lines = vec!();

            while it < lines.len() && lines[it].starts_with(FILE_COMMENT) {
                comment_lines.push(lines[it][FILE_COMMENT.len()..].to_owned());
                it += 1;
            }
            current_infos.push((None, comment_lines));
        }
    }
    if current_file.len() > 0 && current_infos.len() > 0 {
        infos.insert(current_file, current_infos.clone());
    }
    loop_over_files(directory, &mut infos, &regenerate_comments, &vec!(), verbose);
    save_remainings(&infos);
    // TODO: rewrite comments.cmts with remaining infos in regenerate_comments
}<|endoftext|>