<commit_before>use libc;
use std::ptr::{self, write_bytes};
use time;

use ctxt::{Context, FctKind, get_ctxt};
use object::Obj;

const INITIAL_THRESHOLD: usize = 128;
const USED_RATIO: f64 = 0.75;

pub struct Gc {
    obj_start: *mut Obj,
    obj_end: *mut Obj,
    bytes_allocated: usize,
    threshold: usize,
    pub cur_marked: bool,

    pub duration: u64,
    pub malloc_duration: u64,
    pub collect_duration: u64,
    pub sweep_duration: u64,
    pub total_allocated: u64,
    pub collections: u64,
}

impl Gc {
    pub fn new() -> Gc {
        Gc {
            obj_start: ptr::null_mut(),
            obj_end: ptr::null_mut(),
            cur_marked: true,
            bytes_allocated: 0,
            threshold: INITIAL_THRESHOLD,
            duration: 0,
            malloc_duration: 0,
            collect_duration: 0,
            sweep_duration: 0,
            total_allocated: 0,
            collections: 0,
        }
    }

    pub fn alloc(&mut self, size: usize) -> *mut Obj {
        let alloc_start = time::precise_time_ns();
        let ctxt = get_ctxt();

        if ctxt.args.flag_gc_stress {
            // with --gc-stress collect garbage at every allocation
            // useful for testing
            self.collect();

            // do we pass threshold with this allocation?
        } else if self.bytes_allocated + size > self.threshold {
            // collect garbage
            self.collect();

            // if still more memory than USED_RATIO % of the threshold,
            // we need to increase the threshold
            if (self.bytes_allocated + size) as f64 > self.threshold as f64 * USED_RATIO {
                let saved_threshold = self.threshold;
                self.threshold = (self.threshold as f64 / USED_RATIO) as usize;

                if ctxt.args.flag_gc_dump {
                    println!("GC: increase threshold from {} to {}",
                             saved_threshold,
                             self.threshold);
                }
            }
        }

        let malloc_start = time::precise_time_ns();
        let ptr = unsafe { libc::malloc(size) as *mut Obj };
        unsafe {
            write_bytes(ptr as *mut u8, 0, size);
        }
        self.malloc_duration += time::precise_time_ns() - malloc_start;

        {
            let ptr = ptr as *mut Obj;

            if self.obj_end.is_null() {
                assert!(self.obj_start.is_null());

                self.obj_start = ptr;
                self.obj_end = ptr;

            } else {
                assert!(!self.obj_start.is_null());

                let obj_end = unsafe { &mut *self.obj_end };
                obj_end.header_mut().set_succ(ptr);

                self.obj_end = ptr;
            }
        }

        self.bytes_allocated += size;
        self.total_allocated += size as u64;

        if ctxt.args.flag_gc_dump {
            println!("GC: allocate {} bytes: {:x} (total {} bytes, threshold {})",
                     size,
                     ptr as usize,
                     self.bytes_allocated,
                     self.threshold);
        }

        self.duration += time::precise_time_ns() - alloc_start;

        ptr
    }

    pub fn collect(&mut self) {
        let collect_start = time::precise_time_ns();
        let ctxt = get_ctxt();

        let rootset = get_rootset(ctxt);

        if ctxt.args.flag_gc_dump {
            println!("GC: collect garbage");
        }

        mark_literals(self.cur_marked);
        mark_rootset(&rootset, self.cur_marked);

        let sweep_start = time::precise_time_ns();
        let cur_marked = self.cur_marked;
        sweep(self, ctxt.args.flag_gc_dump, cur_marked);
        self.sweep_duration += time::precise_time_ns() - sweep_start;

        // switch cur_marked value, so that I don't have to unmark all
        // objects in the beginning of the next collection
        self.cur_marked = !self.cur_marked;

        self.collect_duration += time::precise_time_ns() - collect_start;
        self.collections += 1;
    }
}

impl Drop for Gc {
    fn drop(&mut self) {
        let mut obj = self.obj_start;

        while !obj.is_null() {
            let curr = obj;
            obj = unsafe { &mut *obj }.header().succ();

            unsafe {
                libc::free(curr as *mut libc::c_void);
            }
        }
    }
}

fn mark_literals(cur_marked: bool) {
    let ctxt = get_ctxt();
    let literals = ctxt.literals.lock().unwrap();

    for lit in literals.iter() {
        mark_recursive(lit.raw() as *mut Obj, cur_marked);
    }
}

fn mark_rootset(rootset: &Vec<usize>, cur_marked: bool) {
    for &root in rootset {
        mark_recursive(root as *mut Obj, cur_marked);
    }
}

fn mark_recursive(obj: *mut Obj, cur_marked: bool) {
    if obj.is_null() {
        return;
    }

    let mut elements: Vec<*mut Obj> = vec![obj];

    while !elements.is_empty() {
        let ptr = elements.pop().unwrap();
        let obj = unsafe { &mut *ptr };

        if obj.header().marked() != cur_marked {
            obj.header_mut().set_mark(cur_marked);
            let class = obj.header().vtbl().class();

            for field in class.all_fields(get_ctxt()) {
                if field.ty.reference_type() {
                    let addr = ptr as isize + field.offset as isize;
                    let obj = unsafe { *(addr as *const usize) } as *mut Obj;

                    if obj.is_null() {
                        continue;
                    }

                    elements.push(obj);
                }
            }
        }
    }
}

fn sweep(gc: &mut Gc, dump: bool, cur_marked: bool) {
    let mut obj = gc.obj_start;
    let mut last: *mut Obj = ptr::null_mut();

    while !obj.is_null() {
        let curr = unsafe { &mut *obj };
        let succ = curr.header().succ();

        if curr.header().marked() != cur_marked {
            let size = curr.size();

            unsafe {
                // overwrite memory for better detection of gc bugs
                write_bytes(obj as *mut u8, 0xcc, size);

                // free unused memory
                libc::free(obj as *mut libc::c_void);
            }

            gc.bytes_allocated -= size;

            if dump {
                println!("sweep {:x} with {} bytes", obj as usize, size);
            }

        } else {
            if last.is_null() {
                gc.obj_start = obj;
            } else {
                let last = unsafe { &mut *last };
                last.header_mut().set_succ(obj);
            }

            // last survived object
            last = obj;
        }

        // set next handled object
        obj = succ;
    }

    // if no objects left, obj_start needs to be reset to null
    if last.is_null() {
        gc.obj_start = ptr::null_mut();
    }

    // last survived object is now end of list
    gc.obj_end = last;
}

pub fn get_rootset(ctxt: &Context) -> Vec<usize> {
    let mut rootset = Vec::new();

    let mut pc: usize;
    let mut fp: usize;

    assert!(!ctxt.sfi.borrow().is_null());

    {
        let sfi = unsafe { &**ctxt.sfi.borrow() };

        pc = sfi.ra;
        fp = sfi.fp;
    }

    while fp != 0 {
        if !determine_rootset(&mut rootset, ctxt, fp, pc) {
            break;
        }

        pc = unsafe { *((fp + 8) as *const usize) };
        fp = unsafe { *(fp as *const usize) };
    }

    rootset
}

fn determine_rootset(rootset: &mut Vec<usize>, ctxt: &Context, fp: usize, pc: usize) -> bool {
    let code_map = ctxt.code_map.lock().unwrap();
    let fct_id = code_map.get(pc as *const u8);

    if let Some(fct_id) = fct_id {
        let fct = ctxt.fct_by_id(fct_id);

        if let FctKind::Source(ref src) = fct.kind {
            let src = src.lock().unwrap();
            let jit_fct = src.jit_fct.as_ref().expect("no jit information");
            let offset = pc - (jit_fct.fct_ptr() as usize);
            let gcpoint = jit_fct.gcpoint_for_offset(offset as i32).expect("no gcpoint");

            for &offset in &gcpoint.offsets {
                let addr = (fp as isize + offset as isize) as usize;
                let obj = unsafe { *(addr as *const usize) };

                rootset.push(obj);
            }
        } else {
            panic!("should be FctKind::Source");
        }

        true
    } else {
        false
    }
}
<commit_msg>emit more infos for garbage collections<commit_after>use libc;
use std::ptr::{self, write_bytes};
use time;

use ctxt::{Context, FctKind, get_ctxt};
use object::Obj;

const INITIAL_THRESHOLD: usize = 128;
const USED_RATIO: f64 = 0.75;

pub struct Gc {
    obj_start: *mut Obj,
    obj_end: *mut Obj,
    bytes_allocated: usize,
    threshold: usize,
    pub cur_marked: bool,

    pub duration: u64,
    pub malloc_duration: u64,
    pub collect_duration: u64,
    pub sweep_duration: u64,
    pub total_allocated: u64,
    pub collections: u64,
}

impl Gc {
    pub fn new() -> Gc {
        Gc {
            obj_start: ptr::null_mut(),
            obj_end: ptr::null_mut(),
            cur_marked: true,
            bytes_allocated: 0,
            threshold: INITIAL_THRESHOLD,
            duration: 0,
            malloc_duration: 0,
            collect_duration: 0,
            sweep_duration: 0,
            total_allocated: 0,
            collections: 0,
        }
    }

    pub fn alloc(&mut self, size: usize) -> *mut Obj {
        let alloc_start = time::precise_time_ns();
        let ctxt = get_ctxt();

        if ctxt.args.flag_gc_stress {
            // with --gc-stress collect garbage at every allocation
            // useful for testing
            self.collect();

            // do we pass threshold with this allocation?
        } else if self.bytes_allocated + size > self.threshold {
            // collect garbage
            self.collect();

            // if still more memory than USED_RATIO % of the threshold,
            // we need to increase the threshold
            if (self.bytes_allocated + size) as f64 > self.threshold as f64 * USED_RATIO {
                let saved_threshold = self.threshold;
                self.threshold = (self.threshold as f64 / USED_RATIO) as usize;

                if ctxt.args.flag_gc_dump {
                    println!("GC: increase threshold from {} to {}",
                             saved_threshold,
                             self.threshold);
                }
            }
        }

        let malloc_start = time::precise_time_ns();
        let ptr = unsafe { libc::malloc(size) as *mut Obj };
        unsafe {
            write_bytes(ptr as *mut u8, 0, size);
        }
        self.malloc_duration += time::precise_time_ns() - malloc_start;

        {
            let ptr = ptr as *mut Obj;

            if self.obj_end.is_null() {
                assert!(self.obj_start.is_null());

                self.obj_start = ptr;
                self.obj_end = ptr;

            } else {
                assert!(!self.obj_start.is_null());

                let obj_end = unsafe { &mut *self.obj_end };
                obj_end.header_mut().set_succ(ptr);

                self.obj_end = ptr;
            }
        }

        self.bytes_allocated += size;
        self.total_allocated += size as u64;

        if ctxt.args.flag_gc_dump {
            println!("GC: allocate {} bytes: {:x} (total {} bytes, threshold {})",
                     size,
                     ptr as usize,
                     self.bytes_allocated,
                     self.threshold);
        }

        self.duration += time::precise_time_ns() - alloc_start;

        ptr
    }

    pub fn collect(&mut self) {
        let collect_start = time::precise_time_ns();
        let ctxt = get_ctxt();

        let rootset = get_rootset(ctxt);

        if ctxt.args.flag_gc_dump {
            println!("GC: collect garbage ({} bytes)", self.bytes_allocated);
        }

        mark_literals(self.cur_marked);
        mark_rootset(&rootset, self.cur_marked);

        let sweep_start = time::precise_time_ns();
        let cur_marked = self.cur_marked;
        sweep(self, ctxt.args.flag_gc_dump, cur_marked);
        self.sweep_duration += time::precise_time_ns() - sweep_start;

        if ctxt.args.flag_gc_dump {
            println!("GC: collect finished ({} bytes)", self.bytes_allocated);
        }

        // switch cur_marked value, so that I don't have to unmark all
        // objects in the beginning of the next collection
        self.cur_marked = !self.cur_marked;

        self.collect_duration += time::precise_time_ns() - collect_start;
        self.collections += 1;
    }
}

impl Drop for Gc {
    fn drop(&mut self) {
        let mut obj = self.obj_start;
        let ctxt = get_ctxt();

        while !obj.is_null() {
            let curr = unsafe { &mut *obj };
            obj = unsafe { &mut *obj }.header().succ();

            unsafe {
                libc::free(curr as *mut _ as *mut libc::c_void);
            }
        }
    }
}

fn mark_literals(cur_marked: bool) {
    let ctxt = get_ctxt();
    let literals = ctxt.literals.lock().unwrap();

    for lit in literals.iter() {
        mark_recursive(lit.raw() as *mut Obj, cur_marked);
    }
}

fn mark_rootset(rootset: &Vec<usize>, cur_marked: bool) {
    for &root in rootset {
        mark_recursive(root as *mut Obj, cur_marked);
    }
}

fn mark_recursive(obj: *mut Obj, cur_marked: bool) {
    if obj.is_null() {
        return;
    }

    let mut elements: Vec<*mut Obj> = vec![obj];

    while !elements.is_empty() {
        let ptr = elements.pop().unwrap();
        let obj = unsafe { &mut *ptr };

        if obj.header().marked() != cur_marked {
            obj.header_mut().set_mark(cur_marked);
            let class = obj.header().vtbl().class();

            for field in class.all_fields(get_ctxt()) {
                if field.ty.reference_type() {
                    let addr = ptr as isize + field.offset as isize;
                    let obj = unsafe { *(addr as *const usize) } as *mut Obj;

                    if obj.is_null() {
                        continue;
                    }

                    elements.push(obj);
                }
            }
        }
    }
}

fn sweep(gc: &mut Gc, dump: bool, cur_marked: bool) {
    let mut obj = gc.obj_start;
    let mut last: *mut Obj = ptr::null_mut();

    while !obj.is_null() {
        let curr = unsafe { &mut *obj };
        let succ = curr.header().succ();

        if curr.header().marked() != cur_marked {
            let size = curr.size();

            unsafe {
                // overwrite memory for better detection of gc bugs
                write_bytes(obj as *mut u8, 0xcc, size);

                // free unused memory
                libc::free(obj as *mut libc::c_void);
            }

            gc.bytes_allocated -= size;

            if dump {
                println!("GC: sweep {:x} with {} bytes", obj as usize, size);
            }

        } else {
            if last.is_null() {
                gc.obj_start = obj;
            } else {
                let last = unsafe { &mut *last };
                last.header_mut().set_succ(obj);
            }

            // last survived object
            last = obj;
        }

        // set next handled object
        obj = succ;
    }

    // if no objects left, obj_start needs to be reset to null
    if last.is_null() {
        gc.obj_start = ptr::null_mut();
    }

    // last survived object is now end of list
    gc.obj_end = last;
}

pub fn get_rootset(ctxt: &Context) -> Vec<usize> {
    let mut rootset = Vec::new();

    let mut pc: usize;
    let mut fp: usize;

    assert!(!ctxt.sfi.borrow().is_null());

    {
        let sfi = unsafe { &**ctxt.sfi.borrow() };

        pc = sfi.ra;
        fp = sfi.fp;
    }

    while fp != 0 {
        if !determine_rootset(&mut rootset, ctxt, fp, pc) {
            break;
        }

        pc = unsafe { *((fp + 8) as *const usize) };
        fp = unsafe { *(fp as *const usize) };
    }

    rootset
}

fn determine_rootset(rootset: &mut Vec<usize>, ctxt: &Context, fp: usize, pc: usize) -> bool {
    let code_map = ctxt.code_map.lock().unwrap();
    let fct_id = code_map.get(pc as *const u8);

    if let Some(fct_id) = fct_id {
        let fct = ctxt.fct_by_id(fct_id);

        if let FctKind::Source(ref src) = fct.kind {
            let src = src.lock().unwrap();
            let jit_fct = src.jit_fct.as_ref().expect("no jit information");
            let offset = pc - (jit_fct.fct_ptr() as usize);
            let gcpoint = jit_fct.gcpoint_for_offset(offset as i32).expect("no gcpoint");

            for &offset in &gcpoint.offsets {
                let addr = (fp as isize + offset as isize) as usize;
                let obj = unsafe { *(addr as *const usize) };

                rootset.push(obj);
            }
        } else {
            panic!("should be FctKind::Source");
        }

        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use super::*;

use common::word;
use generics::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
use nom::{digit, multispace};

use std::str;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Ty {
    /// A variable-length array (`[T]`)
    Vec(Box<Ty>),
    /// A fixed length array (`[T; n]`)
    FixedLengthVec(Box<Ty>, usize),
    /// A raw pointer (`*const T` or `*mut T`)
    Ptr(Box<MutTy>),
    /// A reference (`&'a T` or `&'a mut T`)
    Rptr(Option<Lifetime>, Box<MutTy>),
    /// A bare function (e.g. `fn(usize) -> bool`)
    BareFn(Box<BareFnTy>),
    /// The never type (`!`)
    Never,
    /// A tuple (`(A, B, C, D, ...)`)
    Tup(Vec<Ty>),
    /// A path (`module::module::...::Type`), optionally
    /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
    ///
    /// Type parameters are stored in the Path itself
    Path(Option<QSelf>, Path),
    /// Something like `A+B`. Note that `B` must always be a path.
    ObjectSum(Box<Ty>, Vec<TyParamBound>),
    /// A type like `for<'a> Foo<&'a Bar>`
    PolyTraitRef(Vec<TyParamBound>),
    /// An `impl TraitA+TraitB` type.
    ImplTrait(Vec<TyParamBound>),
    /// No-op; kept solely so that we can pretty-print faithfully
    Paren(Box<Ty>),
    /// TyKind::Infer means the type should be inferred instead of it having been
    /// specified. This can appear anywhere in a type.
    Infer,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MutTy {
    pub ty: Ty,
    pub mutability: Mutability,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Mutability {
    Mutable,
    Immutable,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>,
}

/// A segment of a path: an identifier, an optional lifetime, and a set of types.
///
/// E.g. `std`, `String` or `Box<T>`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PathSegment {
    pub ident: Ident,
    pub parameters: PathParameters,
}

impl PathSegment {
    pub fn ident(ident: Ident) -> Self {
        PathSegment {
            ident: ident,
            parameters: PathParameters::none(),
        }
    }
}

/// Parameters of a path segment.
///
/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PathParameters {
    /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
    AngleBracketed(AngleBracketedParameterData),
    /// The `(A, B)` and `C` in `Foo(A, B) -> C`
    Parenthesized(ParenthesizedParameterData),
}

impl PathParameters {
    pub fn none() -> Self {
        PathParameters::AngleBracketed(AngleBracketedParameterData::default())
    }
}

/// A path like `Foo<'a, T>`
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct AngleBracketedParameterData {
    /// The lifetime parameters for this path segment.
    pub lifetimes: Vec<Lifetime>,
    /// The type parameters for this path segment, if present.
    pub types: Vec<Ty>,
    /// Bindings (equality constraints) on associated types, if present.
    ///
    /// E.g., `Foo<A=Bar>`.
    pub bindings: Vec<TypeBinding>,
}

/// Bind a type to an associated type: `A=Foo`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TypeBinding {
    pub ident: Ident,
    pub ty: Ty,
}

/// A path like `Foo(A,B) -> C`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParenthesizedParameterData {
    /// `(A, B)`
    pub inputs: Vec<Ty>,
    /// `C`
    pub output: Option<Ty>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PolyTraitRef {
    /// The `'a` in `<'a> Foo<&'a T>`
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
    pub trait_ref: Path,
}

/// The explicit Self type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
/// item qualified with this Self type.
///
/// ```rust,ignore
/// <Vec<T> as a::b::Trait>::AssociatedItem
///  ^~~~~     ~~~~~~~~~~~~~~^
///  ty        position = 3
///
/// <Vec<T>>::AssociatedItem
///  ^~~~~    ^
///  ty       position = 0
/// ```
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct QSelf {
    pub ty: Box<Ty>,
    pub position: usize
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct BareFnTy {
    pub lifetimes: Vec<LifetimeDef>,
    pub decl: FnDecl
}

/// Header (not the body) of a function declaration.
///
/// E.g. `fn foo(bar: baz)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FnDecl {
    pub inputs: Vec<Arg>,
    pub output: FunctionRetTy,
}

/// An argument in a function header.
///
/// E.g. `bar: usize` as in `fn foo(bar: usize)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Arg {
    pub pat: Option<Ident>,
    pub ty: Ty,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FunctionRetTy {
    /// Return type is not specified.
    ///
    /// Functions default to `()` and
    /// closures default to inference. Span points to where return
    /// type would be inserted.
    Default,
    /// Everything else
    Ty(Ty),
}

named!(pub ty<&str, Ty>, alt!(
    delimited!(
        punct!("["),
        ty,
        punct!("]")
    ) => { |elem| Ty::Vec(Box::new(elem)) }
    |
    do_parse!(
        punct!("[") >>
        elem: ty >>
        punct!(";") >>
        opt!(multispace) >>
        size: map_res!(digit, str::parse) >>
        (Ty::FixedLengthVec(Box::new(elem), size))
    )
    |
    do_parse!(
        punct!("*") >>
        mutability: alt!(
            punct!("const") => { |_| Mutability::Immutable }
            |
            punct!("mut") => { |_| Mutability::Mutable }
        ) >>
        target: ty >>
        (Ty::Ptr(Box::new(MutTy {
            ty: target,
            mutability: mutability,
        })))
    )
    |
    do_parse!(
        punct!("&") >>
        life: opt!(lifetime) >>
        mutability: mutability >>
        target: ty >>
        (Ty::Rptr(life, Box::new(MutTy {
            ty: target,
            mutability: mutability,
        })))
    )
    |
    do_parse!(
        punct!("fn") >>
        multispace >>
        lifetimes: opt_vec!(delimited!(
            punct!("<"),
            separated_list!(punct!(","), lifetime_def),
            punct!(">")
        )) >>
        punct!("(") >>
        inputs: separated_list!(punct!(","), fn_arg) >>
        punct!(")") >>
        output: opt!(preceded!(
            punct!("->"),
            ty
        )) >>
        (Ty::BareFn(Box::new(BareFnTy {
            lifetimes: lifetimes,
            decl: FnDecl {
                inputs: inputs,
                output: match output {
                    Some(ty) => FunctionRetTy::Ty(ty),
                    None => FunctionRetTy::Default,
                },
            },
        })))
    )
    |
    punct!("!") => { |_| Ty::Never }
    |
    delimited!(
        punct!("("),
        separated_list!(punct!(","), ty),
        punct!(")")
    ) => { Ty::Tup }
    |
    path => { |p| Ty::Path(None, p) }
    |
    do_parse!(
        punct!("<") >>
        this: map!(ty, Box::new) >>
        path: opt!(preceded!(
            tuple!(punct!("as"), multispace),
            path
        )) >>
        punct!(">") >>
        punct!("::") >>
        rest: separated_nonempty_list!(punct!("::"), path_segment) >>
        ({
            match path {
                Some(mut path) => {
                    let pos = path.segments.len();
                    path.segments.extend(rest);
                    Ty::Path(Some(QSelf { ty: this, position: pos }), path)
                }
                None => {
                    Ty::Path(Some(QSelf { ty: this, position: 0 }), Path {
                        global: false,
                        segments: rest,
                    })
                }
            }
        })
    )
    |
    preceded!(
        tuple!(punct!("impl"), multispace),
        separated_nonempty_list!(punct!("+"), ty_param_bound)
    ) => { Ty::ImplTrait }
    |
    delimited!(
        punct!("("),
        ty,
        punct!(")")
    ) => { |inner| Ty::Paren(Box::new(inner)) }
));

named!(mutability<&str, Mutability>, preceded!(
    opt!(multispace),
    alt!(
        terminated!(tag_s!("mut"), multispace) => { |_| Mutability::Mutable }
        |
        epsilon!() => { |_| Mutability::Immutable }
    )
));

named!(path<&str, Path>, do_parse!(
    global: opt!(punct!("::")) >>
    segments: separated_nonempty_list!(punct!("::"), path_segment) >>
    (Path {
        global: global.is_some(),
        segments: segments,
    })
));

named!(path_segment<&str, PathSegment>, alt!(
    do_parse!(
        ident: word >>
        punct!("<") >>
        lifetimes: separated_list!(punct!(","), lifetime) >>
        types: opt_vec!(preceded!(
            cond!(!lifetimes.is_empty(), punct!(",")),
            separated_nonempty_list!(
                punct!(","),
                terminated!(ty, not!(peek!(punct!("="))))
            )
        )) >>
        bindings: opt_vec!(preceded!(
            cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
            separated_nonempty_list!(punct!(","), type_binding)
        )) >>
        punct!(">") >>
        (PathSegment {
            ident: ident,
            parameters: PathParameters::AngleBracketed(
                AngleBracketedParameterData {
                    lifetimes: lifetimes,
                    types: types,
                    bindings: bindings,
                }
            ),
        })
    )
    |
    map!(word, PathSegment::ident)
));

named!(type_binding<&str, TypeBinding>, do_parse!(
    ident: word >>
    punct!("=") >>
    ty: ty >>
    (TypeBinding {
        ident: ident,
        ty: ty,
    })
));

named!(pub poly_trait_ref<&str, PolyTraitRef>, do_parse!(
    bound_lifetimes: bound_lifetimes >>
    trait_ref: path >>
    (PolyTraitRef {
        bound_lifetimes: bound_lifetimes,
        trait_ref: trait_ref,
    })
));

named!(fn_arg<&str, Arg>, do_parse!(
    pat: opt!(terminated!(word, punct!(":"))) >>
    ty: ty >>
    (Arg {
        pat: pat,
        ty: ty,
    })
));
<commit_msg>Split up type-parsing function<commit_after>use super::*;

use common::word;
use generics::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
use nom::{digit, multispace};

use std::str;

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Ty {
    /// A variable-length array (`[T]`)
    Vec(Box<Ty>),
    /// A fixed length array (`[T; n]`)
    FixedLengthVec(Box<Ty>, usize),
    /// A raw pointer (`*const T` or `*mut T`)
    Ptr(Box<MutTy>),
    /// A reference (`&'a T` or `&'a mut T`)
    Rptr(Option<Lifetime>, Box<MutTy>),
    /// A bare function (e.g. `fn(usize) -> bool`)
    BareFn(Box<BareFnTy>),
    /// The never type (`!`)
    Never,
    /// A tuple (`(A, B, C, D, ...)`)
    Tup(Vec<Ty>),
    /// A path (`module::module::...::Type`), optionally
    /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
    ///
    /// Type parameters are stored in the Path itself
    Path(Option<QSelf>, Path),
    /// Something like `A+B`. Note that `B` must always be a path.
    ObjectSum(Box<Ty>, Vec<TyParamBound>),
    /// A type like `for<'a> Foo<&'a Bar>`
    PolyTraitRef(Vec<TyParamBound>),
    /// An `impl TraitA+TraitB` type.
    ImplTrait(Vec<TyParamBound>),
    /// No-op; kept solely so that we can pretty-print faithfully
    Paren(Box<Ty>),
    /// TyKind::Infer means the type should be inferred instead of it having been
    /// specified. This can appear anywhere in a type.
    Infer,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MutTy {
    pub ty: Ty,
    pub mutability: Mutability,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Mutability {
    Mutable,
    Immutable,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>,
}

/// A segment of a path: an identifier, an optional lifetime, and a set of types.
///
/// E.g. `std`, `String` or `Box<T>`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PathSegment {
    pub ident: Ident,
    pub parameters: PathParameters,
}

impl PathSegment {
    pub fn ident(ident: Ident) -> Self {
        PathSegment {
            ident: ident,
            parameters: PathParameters::none(),
        }
    }
}

/// Parameters of a path segment.
///
/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PathParameters {
    /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
    AngleBracketed(AngleBracketedParameterData),
    /// The `(A, B)` and `C` in `Foo(A, B) -> C`
    Parenthesized(ParenthesizedParameterData),
}

impl PathParameters {
    pub fn none() -> Self {
        PathParameters::AngleBracketed(AngleBracketedParameterData::default())
    }
}

/// A path like `Foo<'a, T>`
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct AngleBracketedParameterData {
    /// The lifetime parameters for this path segment.
    pub lifetimes: Vec<Lifetime>,
    /// The type parameters for this path segment, if present.
    pub types: Vec<Ty>,
    /// Bindings (equality constraints) on associated types, if present.
    ///
    /// E.g., `Foo<A=Bar>`.
    pub bindings: Vec<TypeBinding>,
}

/// Bind a type to an associated type: `A=Foo`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TypeBinding {
    pub ident: Ident,
    pub ty: Ty,
}

/// A path like `Foo(A,B) -> C`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParenthesizedParameterData {
    /// `(A, B)`
    pub inputs: Vec<Ty>,
    /// `C`
    pub output: Option<Ty>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PolyTraitRef {
    /// The `'a` in `<'a> Foo<&'a T>`
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
    pub trait_ref: Path,
}

/// The explicit Self type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
/// item qualified with this Self type.
///
/// ```rust,ignore
/// <Vec<T> as a::b::Trait>::AssociatedItem
///  ^~~~~     ~~~~~~~~~~~~~~^
///  ty        position = 3
///
/// <Vec<T>>::AssociatedItem
///  ^~~~~    ^
///  ty       position = 0
/// ```
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct QSelf {
    pub ty: Box<Ty>,
    pub position: usize
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct BareFnTy {
    pub lifetimes: Vec<LifetimeDef>,
    pub decl: FnDecl
}

/// Header (not the body) of a function declaration.
///
/// E.g. `fn foo(bar: baz)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FnDecl {
    pub inputs: Vec<Arg>,
    pub output: FunctionRetTy,
}

/// An argument in a function header.
///
/// E.g. `bar: usize` as in `fn foo(bar: usize)`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Arg {
    pub pat: Option<Ident>,
    pub ty: Ty,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FunctionRetTy {
    /// Return type is not specified.
    ///
    /// Functions default to `()` and
    /// closures default to inference. Span points to where return
    /// type would be inserted.
    Default,
    /// Everything else
    Ty(Ty),
}

named!(pub ty<&str, Ty>, alt!(
    ty_vec
    |
    ty_fixed_length_vec
    |
    ty_ptr
    |
    ty_rptr
    |
    ty_bare_fn
    |
    ty_never
    |
    ty_tup
    |
    ty_path
    |
    ty_qpath
    |
    ty_impl_trait
    |
    ty_paren
));

named!(ty_vec<&str, Ty>, do_parse!(
    punct!("[") >>
    elem: ty >>
    punct!("]") >>
    (Ty::Vec(Box::new(elem)))
));

named!(ty_fixed_length_vec<&str, Ty>, do_parse!(
    punct!("[") >>
    elem: ty >>
    punct!(";") >>
    opt!(multispace) >>
    size: map_res!(digit, str::parse) >>
    (Ty::FixedLengthVec(Box::new(elem), size))
));

named!(ty_ptr<&str, Ty>, do_parse!(
    punct!("*") >>
    mutability: alt!(
        punct!("const") => { |_| Mutability::Immutable }
        |
        punct!("mut") => { |_| Mutability::Mutable }
    ) >>
    target: ty >>
    (Ty::Ptr(Box::new(MutTy {
        ty: target,
        mutability: mutability,
    })))
));

named!(ty_rptr<&str, Ty>, do_parse!(
    punct!("&") >>
    life: opt!(lifetime) >>
    mutability: mutability >>
    target: ty >>
    (Ty::Rptr(life, Box::new(MutTy {
        ty: target,
        mutability: mutability,
    })))
));

named!(ty_bare_fn<&str, Ty>, do_parse!(
    punct!("fn") >>
    multispace >>
    lifetimes: opt_vec!(delimited!(
        punct!("<"),
        separated_list!(punct!(","), lifetime_def),
        punct!(">")
    )) >>
    punct!("(") >>
    inputs: separated_list!(punct!(","), fn_arg) >>
    punct!(")") >>
    output: opt!(preceded!(
        punct!("->"),
        ty
    )) >>
    (Ty::BareFn(Box::new(BareFnTy {
        lifetimes: lifetimes,
        decl: FnDecl {
            inputs: inputs,
            output: match output {
                Some(ty) => FunctionRetTy::Ty(ty),
                None => FunctionRetTy::Default,
            },
        },
    })))
));

named!(ty_never<&str, Ty>, map!(punct!("!"), |_| Ty::Never));

named!(ty_tup<&str, Ty>, do_parse!(
    punct!("(") >>
    elems: separated_list!(punct!(","), ty) >>
    punct!(")") >>
    (Ty::Tup(elems))
));

named!(ty_path<&str, Ty>, map!(path, |p| Ty::Path(None, p)));

named!(ty_qpath<&str, Ty>, do_parse!(
    punct!("<") >>
    this: map!(ty, Box::new) >>
    path: opt!(preceded!(
        tuple!(punct!("as"), multispace),
        path
    )) >>
    punct!(">") >>
    punct!("::") >>
    rest: separated_nonempty_list!(punct!("::"), path_segment) >>
    ({
        match path {
            Some(mut path) => {
                let pos = path.segments.len();
                path.segments.extend(rest);
                Ty::Path(Some(QSelf { ty: this, position: pos }), path)
            }
            None => {
                Ty::Path(Some(QSelf { ty: this, position: 0 }), Path {
                    global: false,
                    segments: rest,
                })
            }
        }
    })
));

named!(ty_impl_trait<&str, Ty>, do_parse!(
    punct!("impl") >>
    multispace >>
    elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
    (Ty::ImplTrait(elem))
));

named!(ty_paren<&str, Ty>, do_parse!(
    punct!("(") >>
    elem: ty >>
    punct!(")") >>
    (Ty::Paren(Box::new(elem)))
));

named!(mutability<&str, Mutability>, preceded!(
    opt!(multispace),
    alt!(
        terminated!(tag_s!("mut"), multispace) => { |_| Mutability::Mutable }
        |
        epsilon!() => { |_| Mutability::Immutable }
    )
));

named!(path<&str, Path>, do_parse!(
    global: opt!(punct!("::")) >>
    segments: separated_nonempty_list!(punct!("::"), path_segment) >>
    (Path {
        global: global.is_some(),
        segments: segments,
    })
));

named!(path_segment<&str, PathSegment>, alt!(
    do_parse!(
        ident: word >>
        punct!("<") >>
        lifetimes: separated_list!(punct!(","), lifetime) >>
        types: opt_vec!(preceded!(
            cond!(!lifetimes.is_empty(), punct!(",")),
            separated_nonempty_list!(
                punct!(","),
                terminated!(ty, not!(peek!(punct!("="))))
            )
        )) >>
        bindings: opt_vec!(preceded!(
            cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
            separated_nonempty_list!(punct!(","), type_binding)
        )) >>
        punct!(">") >>
        (PathSegment {
            ident: ident,
            parameters: PathParameters::AngleBracketed(
                AngleBracketedParameterData {
                    lifetimes: lifetimes,
                    types: types,
                    bindings: bindings,
                }
            ),
        })
    )
    |
    map!(word, PathSegment::ident)
));

named!(type_binding<&str, TypeBinding>, do_parse!(
    ident: word >>
    punct!("=") >>
    ty: ty >>
    (TypeBinding {
        ident: ident,
        ty: ty,
    })
));

named!(pub poly_trait_ref<&str, PolyTraitRef>, do_parse!(
    bound_lifetimes: bound_lifetimes >>
    trait_ref: path >>
    (PolyTraitRef {
        bound_lifetimes: bound_lifetimes,
        trait_ref: trait_ref,
    })
));

named!(fn_arg<&str, Arg>, do_parse!(
    pat: opt!(terminated!(word, punct!(":"))) >>
    ty: ty >>
    (Arg {
        pat: pat,
        ty: ty,
    })
));
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use error::*;
use bytecode;
use ieee754::Ieee754;

pub type Word = u64;
pub type Number = f64;
pub type Address = usize;

pub struct VM {
    instruction_ptr: Address,
    stack_ptr: Address,
    stack: Vec<Word>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            instruction_ptr: 0,
            stack_ptr: 0,
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        let mut image_bytes: Vec<u8> = Vec::new();
        image_file.read_to_end(&mut image_bytes).chain_err(|| "unable to read image")?;

        while self.instruction_ptr < image_bytes.len() {
            let byte = self.current_byte(&image_bytes)
                .chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PRINT => {
                    self.print().chain_err(|| "unable to execute 'print' instruction")?
                }
                bytecode::PUSH => {
                    let res = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    self.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                    continue;
                }
                bytecode::JZ => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                _ => {
                    bail!("unexpected opcode {:02x} at address {:?}",
                          byte,
                          self.instruction_ptr)
                }
            }

            self.advance_instruction_ptr().chain_err(|| "unable to advance instruction pointer")?;
        }

        Ok(())
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.stack_ptr += 1;
        }

        self.stack.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.stack.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.stack.remove(self.stack_ptr);
        if !self.stack.is_empty() {
            self.stack_ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn jmp(&mut self, addr: Address) -> VMResult<()> {
        self.instruction_ptr = addr;
        Ok(())
    }

    fn read_word(&mut self, bytes: &Vec<u8>) -> VMResult<Word> {
        // Build a Word from single bytes
        let mut res: Word = 0;
        for _ in 0..8 {
            res <<= 8;
            self.advance_instruction_ptr().chain_err(|| "unable to advance instruction pointer")?;
            let current_byte = self.current_byte(&bytes)
                .chain_err(|| "unable to read current byte")?;
            res |= current_byte as Word;
        }

        Ok(res)
    }

    fn advance_instruction_ptr(&mut self) -> VMResult<()> {
        self.instruction_ptr += 1;
        Ok(())
    }

    fn current_byte(&mut self, bytes: &Vec<u8>) -> VMResult<u8> {
        if self.instruction_ptr < bytes.len() {
            Ok(bytes[self.instruction_ptr])
        } else {
            bail!("instruction pointer out of bounds");
        }
    }

    fn peek_word(&mut self) -> VMResult<Word> {
        if self.stack_ptr < self.stack.len() {
            Ok(self.stack[self.stack_ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }

    fn print(&mut self) -> VMResult<()> {
        let top = self.peek_number().chain_err(|| "unable to get current top of stack")?;
        println!("{:?}", top);
        Ok(())
    }
}
<commit_msg>Added registers and moved out typedefs<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use error::*;
use bytecode;
use ieee754::Ieee754;

struct DisplayRegister {
    width: TinyWord,
    height: TinyWord,
    color_mode: ColorMode,
}

enum ColorMode {
    _1Bit,
    _8Bit,
    _16Bit,
    _32Bit,
}

pub const BUF_REG_COUNT: usize = 8;

pub struct VM {
    instruction_ptr: Address,
    stack_ptr: Address,
    buf_regs: [Word; BUF_REG_COUNT],
    display_reg: DisplayRegister,
    stack: Vec<Word>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            instruction_ptr: 0,
            stack_ptr: 0,
            buf_regs: [0; BUF_REG_COUNT],
            display_reg: DisplayRegister {
                width: 0,
                height: 0,
                color_mode: ColorMode::_8Bit,
            },
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        let mut image_bytes: Vec<Byte> = Vec::new();
        image_file.read_to_end(&mut image_bytes).chain_err(|| "unable to read image")?;

        while self.instruction_ptr < image_bytes.len() {
            let byte = self.current_byte(&image_bytes)
                .chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PRINT => {
                    self.print().chain_err(|| "unable to execute 'print' instruction")?
                }
                bytecode::PUSH => {
                    let res = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    self.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                    continue;
                }
                bytecode::JZ => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr = self.read_word(&image_bytes).chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                _ => {
                    bail!("unexpected opcode {:02x} at address {:?}",
                          byte,
                          self.instruction_ptr)
                }
            }

            self.advance_instruction_ptr().chain_err(|| "unable to advance instruction pointer")?;
        }

        Ok(())
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.stack_ptr += 1;
        }

        self.stack.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.stack.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.stack.remove(self.stack_ptr);
        if !self.stack.is_empty() {
            self.stack_ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn jmp(&mut self, addr: Address) -> VMResult<()> {
        self.instruction_ptr = addr;
        Ok(())
    }

    fn read_word(&mut self, bytes: &Vec<Byte>) -> VMResult<Word> {
        // Build a Word from single bytes
        let mut res: Word = 0;
        for _ in 0..8 {
            res <<= 8;
            self.advance_instruction_ptr().chain_err(|| "unable to advance instruction pointer")?;
            let current_byte = self.current_byte(&bytes)
                .chain_err(|| "unable to read current byte")?;
            res |= current_byte as Word;
        }

        Ok(res)
    }

    fn advance_instruction_ptr(&mut self) -> VMResult<()> {
        self.instruction_ptr += 1;
        Ok(())
    }

    fn current_byte(&mut self, bytes: &Vec<Byte>) -> VMResult<Byte> {
        if self.instruction_ptr < bytes.len() {
            Ok(bytes[self.instruction_ptr])
        } else {
            bail!("instruction pointer out of bounds");
        }
    }

    fn peek_word(&mut self) -> VMResult<Word> {
        if self.stack_ptr < self.stack.len() {
            Ok(self.stack[self.stack_ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }

    fn print(&mut self) -> VMResult<()> {
        let top = self.peek_number().chain_err(|| "unable to get current top of stack")?;
        println!("{:?}", top);
        Ok(())
    }
}
<|endoftext|>


<commit_before>/*!
 * A task-based interface to the uv loop
 *
 * The I/O task runs in its own single-threaded scheduler.  By using the
 * `interact` function you can execute code in a uv callback.
 */

export IoTask;
export spawn_iotask;
export interact;
export exit;

use libc::c_void;
use ptr::addr_of;
use comm = core::comm;
use comm::{Port, Chan, listen};
use task::TaskBuilder;
use ll = uv_ll;

/// Used to abstract-away direct interaction with a libuv loop.
enum IoTask {
    IoTask_({
        async_handle: *ll::uv_async_t,
        op_chan: Chan<IoTaskMsg>
    })
}

fn spawn_iotask(-task: task::TaskBuilder) -> IoTask {

    do listen |iotask_ch| {

        do task.sched_mode(task::SingleThreaded).spawn {
            debug!("entering libuv task");
            run_loop(iotask_ch);
            debug!("libuv task exiting");
        };

        iotask_ch.recv()
    }
}

/**
 * Provide a callback to be processed by `iotask`
 *
 * The primary way to do operations again a running `iotask` that
 * doesn't involve creating a uv handle via `safe_handle`
 *
 * # Warning
 *
 * This function is the only safe way to interact with _any_ `iotask`.
 * Using functions in the `uv::ll` module outside of the `cb` passed into
 * this function is _very dangerous_.
 *
 * # Arguments
 *
 * * iotask - a uv I/O task that you want to do operations against
 * * cb - a function callback to be processed on the running loop's
 * thread. The only parameter passed in is an opaque pointer representing the
 * running `uv_loop_t*`. In the context of this callback, it is safe to use
 * this pointer to do various uv_* API calls contained within the `uv::ll`
 * module. It is not safe to send the `loop_ptr` param to this callback out
 * via ports/chans.
 */
unsafe fn interact(iotask: IoTask,
                   -cb: fn~(*c_void)) {
    send_msg(iotask, Interaction(move cb));
}

/**
 * Shut down the I/O task
 *
 * Is used to signal to the loop that it should close the internally-held
 * async handle and do a sanity check to make sure that all other handles are
 * closed, causing a failure otherwise.
 */
fn exit(iotask: IoTask) unsafe {
    send_msg(iotask, TeardownLoop);
}

// INTERNAL API

enum IoTaskMsg {
    Interaction (fn~(*libc::c_void)),
    TeardownLoop
}

/// Run the loop and begin handling messages
fn run_loop(iotask_ch: Chan<IoTask>) unsafe {

    let loop_ptr = ll::loop_new();

    // set up the special async handle we'll use to allow multi-task
    // communication with this loop
    let async = ll::async_t();
    let async_handle = addr_of(async);

    // associate the async handle with the loop
    ll::async_init(loop_ptr, async_handle, wake_up_cb);

    // initialize our loop data and store it in the loop
    let data: IoTaskLoopData = {
        async_handle: async_handle,
        msg_po: Port()
    };
    ll::set_data_for_uv_handle(async_handle, addr_of(data));

    // Send out a handle through which folks can talk to us
    // while we dwell in the I/O loop
    let iotask = IoTask_({
        async_handle: async_handle,
        op_chan: data.msg_po.chan()
    });
    iotask_ch.send(iotask);

    log(debug, ~"about to run uv loop");
    // enter the loop... this blocks until the loop is done..
    ll::run(loop_ptr);
    log(debug, ~"uv loop ended");
    ll::loop_delete(loop_ptr);
}

// data that lives for the lifetime of the high-evel oo
type IoTaskLoopData = {
    async_handle: *ll::uv_async_t,
    msg_po: Port<IoTaskMsg>
};

fn send_msg(iotask: IoTask,
            -msg: IoTaskMsg) unsafe {
    iotask.op_chan.send(move msg);
    ll::async_send(iotask.async_handle);
}

/// Dispatch all pending messages
extern fn wake_up_cb(async_handle: *ll::uv_async_t,
                    status: int) unsafe {

    log(debug, fmt!("wake_up_cb extern.. handle: %? status: %?",
                     async_handle, status));

    let loop_ptr = ll::get_loop_for_uv_handle(async_handle);
    let data = ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData;
    let msg_po = (*data).msg_po;

    while msg_po.peek() {
        match msg_po.recv() {
          Interaction(cb) => cb(loop_ptr),
          TeardownLoop => begin_teardown(data)
        }
    }
}

fn begin_teardown(data: *IoTaskLoopData) unsafe {
    log(debug, ~"iotask begin_teardown() called, close async_handle");
    let async_handle = (*data).async_handle;
    ll::close(async_handle as *c_void, tear_down_close_cb);
}

extern fn tear_down_close_cb(handle: *ll::uv_async_t) unsafe {
    let loop_ptr = ll::get_loop_for_uv_handle(handle);
    let loop_refs = ll::loop_refcount(loop_ptr);
    log(debug, fmt!("tear_down_close_cb called, closing handle at %? refs %?",
                    handle, loop_refs));
    assert loop_refs == 1i32;
}

#[cfg(test)]
mod test {
    extern fn async_close_cb(handle: *ll::uv_async_t) unsafe {
        log(debug, fmt!("async_close_cb handle %?", handle));
        let exit_ch = (*(ll::get_data_for_uv_handle(handle)
                        as *AhData)).exit_ch;
        core::comm::send(exit_ch, ());
    }
    extern fn async_handle_cb(handle: *ll::uv_async_t, status: libc::c_int)
        unsafe {
        log(debug, fmt!("async_handle_cb handle %? status %?",handle,status));
        ll::close(handle, async_close_cb);
    }
    type AhData = {
        iotask: IoTask,
        exit_ch: comm::Chan<()>
    };
    fn impl_uv_iotask_async(iotask: IoTask) unsafe {
        let async_handle = ll::async_t();
        let ah_ptr = ptr::addr_of(async_handle);
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let ah_data = {
            iotask: iotask,
            exit_ch: exit_ch
        };
        let ah_data_ptr = ptr::addr_of(ah_data);
        do interact(iotask) |loop_ptr| unsafe {
            ll::async_init(loop_ptr, ah_ptr, async_handle_cb);
            ll::set_data_for_uv_handle(ah_ptr, ah_data_ptr as *libc::c_void);
            ll::async_send(ah_ptr);
        };
        core::comm::recv(exit_po);
    }

    // this fn documents the bear minimum neccesary to roll your own
    // high_level_loop
    unsafe fn spawn_test_loop(exit_ch: comm::Chan<()>) -> IoTask {
        let iotask_port = comm::Port::<IoTask>();
        let iotask_ch = comm::Chan(iotask_port);
        do task::spawn_sched(task::ManualThreads(1u)) {
            run_loop(iotask_ch);
            exit_ch.send(());
        };
        return core::comm::recv(iotask_port);
    }

    extern fn lifetime_handle_close(handle: *libc::c_void) unsafe {
        log(debug, fmt!("lifetime_handle_close ptr %?", handle));
    }

    extern fn lifetime_async_callback(handle: *libc::c_void,
                                     status: libc::c_int) {
        log(debug, fmt!("lifetime_handle_close ptr %? status %?",
                        handle, status));
    }

    #[test]
    fn test_uv_iotask_async() unsafe {
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let iotask = spawn_test_loop(exit_ch);

        // using this handle to manage the lifetime of the high_level_loop,
        // as it will exit the first time one of the impl_uv_hl_async() is
        // cleaned up with no one ref'd handles on the loop (Which can happen
        // under race-condition type situations.. this ensures that the loop
        // lives until, at least, all of the impl_uv_hl_async() runs have been
        // called, at least.
        let work_exit_po = core::comm::Port::<()>();
        let work_exit_ch = core::comm::Chan(work_exit_po);
        for iter::repeat(7u) {
            do task::spawn_sched(task::ManualThreads(1u)) {
                impl_uv_iotask_async(iotask);
                core::comm::send(work_exit_ch, ());
            };
        };
        for iter::repeat(7u) {
            core::comm::recv(work_exit_po);
        };
        log(debug, ~"sending teardown_loop msg..");
        exit(iotask);
        core::comm::recv(exit_po);
        log(debug, ~"after recv on exit_po.. exiting..");
    }
}
<commit_msg>std: Demode uv::iotask<commit_after>/*!
 * A task-based interface to the uv loop
 *
 * The I/O task runs in its own single-threaded scheduler.  By using the
 * `interact` function you can execute code in a uv callback.
 */

#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

export IoTask;
export spawn_iotask;
export interact;
export exit;

use libc::c_void;
use ptr::addr_of;
use comm = core::comm;
use comm::{Port, Chan, listen};
use task::TaskBuilder;
use ll = uv_ll;

/// Used to abstract-away direct interaction with a libuv loop.
enum IoTask {
    IoTask_({
        async_handle: *ll::uv_async_t,
        op_chan: Chan<IoTaskMsg>
    })
}

fn spawn_iotask(+task: task::TaskBuilder) -> IoTask {

    do listen |iotask_ch| {

        do task.sched_mode(task::SingleThreaded).spawn {
            debug!("entering libuv task");
            run_loop(iotask_ch);
            debug!("libuv task exiting");
        };

        iotask_ch.recv()
    }
}

/**
 * Provide a callback to be processed by `iotask`
 *
 * The primary way to do operations again a running `iotask` that
 * doesn't involve creating a uv handle via `safe_handle`
 *
 * # Warning
 *
 * This function is the only safe way to interact with _any_ `iotask`.
 * Using functions in the `uv::ll` module outside of the `cb` passed into
 * this function is _very dangerous_.
 *
 * # Arguments
 *
 * * iotask - a uv I/O task that you want to do operations against
 * * cb - a function callback to be processed on the running loop's
 * thread. The only parameter passed in is an opaque pointer representing the
 * running `uv_loop_t*`. In the context of this callback, it is safe to use
 * this pointer to do various uv_* API calls contained within the `uv::ll`
 * module. It is not safe to send the `loop_ptr` param to this callback out
 * via ports/chans.
 */
unsafe fn interact(iotask: IoTask,
                   +cb: fn~(*c_void)) {
    send_msg(iotask, Interaction(move cb));
}

/**
 * Shut down the I/O task
 *
 * Is used to signal to the loop that it should close the internally-held
 * async handle and do a sanity check to make sure that all other handles are
 * closed, causing a failure otherwise.
 */
fn exit(iotask: IoTask) unsafe {
    send_msg(iotask, TeardownLoop);
}

// INTERNAL API

enum IoTaskMsg {
    Interaction (fn~(*libc::c_void)),
    TeardownLoop
}

/// Run the loop and begin handling messages
fn run_loop(iotask_ch: Chan<IoTask>) unsafe {

    let loop_ptr = ll::loop_new();

    // set up the special async handle we'll use to allow multi-task
    // communication with this loop
    let async = ll::async_t();
    let async_handle = addr_of(async);

    // associate the async handle with the loop
    ll::async_init(loop_ptr, async_handle, wake_up_cb);

    // initialize our loop data and store it in the loop
    let data: IoTaskLoopData = {
        async_handle: async_handle,
        msg_po: Port()
    };
    ll::set_data_for_uv_handle(async_handle, addr_of(data));

    // Send out a handle through which folks can talk to us
    // while we dwell in the I/O loop
    let iotask = IoTask_({
        async_handle: async_handle,
        op_chan: data.msg_po.chan()
    });
    iotask_ch.send(iotask);

    log(debug, ~"about to run uv loop");
    // enter the loop... this blocks until the loop is done..
    ll::run(loop_ptr);
    log(debug, ~"uv loop ended");
    ll::loop_delete(loop_ptr);
}

// data that lives for the lifetime of the high-evel oo
type IoTaskLoopData = {
    async_handle: *ll::uv_async_t,
    msg_po: Port<IoTaskMsg>
};

fn send_msg(iotask: IoTask,
            +msg: IoTaskMsg) unsafe {
    iotask.op_chan.send(move msg);
    ll::async_send(iotask.async_handle);
}

/// Dispatch all pending messages
extern fn wake_up_cb(async_handle: *ll::uv_async_t,
                    status: int) unsafe {

    log(debug, fmt!("wake_up_cb extern.. handle: %? status: %?",
                     async_handle, status));

    let loop_ptr = ll::get_loop_for_uv_handle(async_handle);
    let data = ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData;
    let msg_po = (*data).msg_po;

    while msg_po.peek() {
        match msg_po.recv() {
          Interaction(cb) => cb(loop_ptr),
          TeardownLoop => begin_teardown(data)
        }
    }
}

fn begin_teardown(data: *IoTaskLoopData) unsafe {
    log(debug, ~"iotask begin_teardown() called, close async_handle");
    let async_handle = (*data).async_handle;
    ll::close(async_handle as *c_void, tear_down_close_cb);
}

extern fn tear_down_close_cb(handle: *ll::uv_async_t) unsafe {
    let loop_ptr = ll::get_loop_for_uv_handle(handle);
    let loop_refs = ll::loop_refcount(loop_ptr);
    log(debug, fmt!("tear_down_close_cb called, closing handle at %? refs %?",
                    handle, loop_refs));
    assert loop_refs == 1i32;
}

#[cfg(test)]
mod test {
    extern fn async_close_cb(handle: *ll::uv_async_t) unsafe {
        log(debug, fmt!("async_close_cb handle %?", handle));
        let exit_ch = (*(ll::get_data_for_uv_handle(handle)
                        as *AhData)).exit_ch;
        core::comm::send(exit_ch, ());
    }
    extern fn async_handle_cb(handle: *ll::uv_async_t, status: libc::c_int)
        unsafe {
        log(debug, fmt!("async_handle_cb handle %? status %?",handle,status));
        ll::close(handle, async_close_cb);
    }
    type AhData = {
        iotask: IoTask,
        exit_ch: comm::Chan<()>
    };
    fn impl_uv_iotask_async(iotask: IoTask) unsafe {
        let async_handle = ll::async_t();
        let ah_ptr = ptr::addr_of(async_handle);
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let ah_data = {
            iotask: iotask,
            exit_ch: exit_ch
        };
        let ah_data_ptr = ptr::addr_of(ah_data);
        do interact(iotask) |loop_ptr| unsafe {
            ll::async_init(loop_ptr, ah_ptr, async_handle_cb);
            ll::set_data_for_uv_handle(ah_ptr, ah_data_ptr as *libc::c_void);
            ll::async_send(ah_ptr);
        };
        core::comm::recv(exit_po);
    }

    // this fn documents the bear minimum neccesary to roll your own
    // high_level_loop
    unsafe fn spawn_test_loop(exit_ch: comm::Chan<()>) -> IoTask {
        let iotask_port = comm::Port::<IoTask>();
        let iotask_ch = comm::Chan(iotask_port);
        do task::spawn_sched(task::ManualThreads(1u)) {
            run_loop(iotask_ch);
            exit_ch.send(());
        };
        return core::comm::recv(iotask_port);
    }

    extern fn lifetime_handle_close(handle: *libc::c_void) unsafe {
        log(debug, fmt!("lifetime_handle_close ptr %?", handle));
    }

    extern fn lifetime_async_callback(handle: *libc::c_void,
                                     status: libc::c_int) {
        log(debug, fmt!("lifetime_handle_close ptr %? status %?",
                        handle, status));
    }

    #[test]
    fn test_uv_iotask_async() unsafe {
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let iotask = spawn_test_loop(exit_ch);

        // using this handle to manage the lifetime of the high_level_loop,
        // as it will exit the first time one of the impl_uv_hl_async() is
        // cleaned up with no one ref'd handles on the loop (Which can happen
        // under race-condition type situations.. this ensures that the loop
        // lives until, at least, all of the impl_uv_hl_async() runs have been
        // called, at least.
        let work_exit_po = core::comm::Port::<()>();
        let work_exit_ch = core::comm::Chan(work_exit_po);
        for iter::repeat(7u) {
            do task::spawn_sched(task::ManualThreads(1u)) {
                impl_uv_iotask_async(iotask);
                core::comm::send(work_exit_ch, ());
            };
        };
        for iter::repeat(7u) {
            core::comm::recv(work_exit_po);
        };
        log(debug, ~"sending teardown_loop msg..");
        exit(iotask);
        core::comm::recv(exit_po);
        log(debug, ~"after recv on exit_po.. exiting..");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use collections::HashMap;
pub use std::default::Default;
pub use lexer::{Location, Located};

pub struct Module {
    pub name : ~str,
    pub bindings : ~[Binding],
    pub typeDeclarations : ~[TypeDeclaration],
    pub classes : ~[Class],
    pub instances : ~[Instance],
    pub dataDefinitions : ~[DataDefinition]
}
#[deriving(Clone)]
pub struct Class {
    pub name : ~str,
    pub variable : TypeVariable,
    pub declarations : ~[TypeDeclaration]
}

pub struct Instance {
    pub bindings : ~[Binding],
    pub constraints : ~[Constraint],
    pub typ : Type,
    pub classname : ~str
}

#[deriving(Eq)]
pub struct Binding {
    pub name : ~str,
    pub expression : TypedExpr,
    pub typeDecl : TypeDeclaration,
    pub arity : uint
}

#[deriving(Eq, TotalEq, Clone, Show)]
pub struct Constructor {
    pub name : ~str,
    pub typ : Type,
    pub tag : int,
    pub arity : int
}

#[deriving(Eq, Clone)]
pub struct DataDefinition {
    pub constructors : ~[Constructor],
    pub typ : Type,
    pub parameters : HashMap<~str, int>
}

#[deriving(Clone, Eq, TotalEq, Default)]
pub struct TypeDeclaration {
    pub context : ~[Constraint],
    pub typ : Type,
    pub name : ~str
}

#[deriving(Clone, Default, Eq, TotalEq, Hash)]
pub struct TypeOperator {
    pub name : ~str,
    pub kind : Kind
}
#[deriving(Clone, Eq, TotalEq, Default, Hash)]
pub struct TypeVariable {
    pub id : int,
    pub kind : Kind
}
#[deriving(Clone, TotalEq, Hash)]
pub enum Type {
    TypeVariable(TypeVariable),
    TypeOperator(TypeOperator),
    TypeApplication(~Type, ~Type)
}

impl Type {

    pub fn new_var(id : int) -> Type {
        TypeVariable(TypeVariable { id : id, kind: unknown_kind.clone() })
    }
    pub fn new_var_kind(id : int, kind: Kind) -> Type {
        TypeVariable(TypeVariable { id : id, kind: kind })
    }
    pub fn new_op(name : ~str, types : ~[Type]) -> Type {
        let mut result = TypeOperator(TypeOperator { name : name, kind: Kind::new(types.len() as int + 1) });
        for typ in types.move_iter() {
            result = TypeApplication(~result, ~typ);
        }
        result
    }
    pub fn new_op_kind(name : ~str, types : ~[Type], kind: Kind) -> Type {
        let mut result = TypeOperator(TypeOperator { name : name, kind: kind });
        for typ in types.move_iter() {
            result = TypeApplication(~result, ~typ);
        }
        result
    }

    pub fn var<'a>(&'a self) -> &'a TypeVariable {
        match self {
            &TypeVariable(ref var) => var,
            _ => fail!("Tried to unwrap {} as a TypeVariable", self)
        }
    }
    #[allow(dead_code)]
    pub fn op<'a>(&'a self) -> &'a TypeOperator {
        match self {
            &TypeOperator(ref op) => op,
            _ => fail!("Tried to unwrap {} as a TypeOperator", self)
        }
    }
    #[allow(dead_code)]
    pub fn appl<'a>(&'a self) -> &'a Type {
        match self {
            &TypeApplication(ref lhs, _) => { let l: &Type = *lhs; l }
            _ => fail!("Error: Tried to unwrap {} as TypeApplication", self)
        }
    }
    #[allow(dead_code)]
    pub fn appr<'a>(&'a self) -> &'a Type {
        match self {
            &TypeApplication(_, ref rhs) => { let r: &Type = *rhs; r }
            _ => fail!("Error: Tried to unwrap TypeApplication")
        }
    }

    pub fn kind<'a>(&'a self) -> &'a Kind {
        match self {
            &TypeVariable(ref v) => &v.kind,
            &TypeOperator(ref v) => &v.kind,
            &TypeApplication(ref lhs, _) =>
                match lhs.kind() {
                    &KindFunction(_, ref k) => {
                        let kind: &Kind = *k;
                        kind
                    }
                    _ => fail!("Type application must have a kind of KindFunction, {}", self)
                }
        }
    }
    pub fn mut_kind<'a>(&'a mut self) -> &'a mut Kind {
        match self {
            &TypeVariable(ref mut v) => &mut v.kind,
            &TypeOperator(ref mut v) => &mut v.kind,
            _ => fail!("Typeapplication has no kind")
        }
    }
}

#[deriving(Clone, Eq, TotalEq, Hash)]
pub struct Constraint {
    pub class : ~str,
    pub variables : ~[TypeVariable]
}

#[deriving(Clone, Eq, TotalEq, Hash)]
pub enum Kind {
    KindFunction(~Kind, ~Kind),
    StarKind
}
impl fmt::Show for Kind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &StarKind => write!(f.buf, "*"),
            &KindFunction(ref lhs, ref rhs) => write!(f.buf, "({} -> {})", *lhs, *rhs)
        }
    }
}

impl Kind {
    pub fn new(v: int) -> Kind {
        let mut kind = star_kind.clone();
        for _ in range(1, v) {
            kind = KindFunction(~StarKind, ~kind);
        }
        kind
    }
}

impl Default for Kind {
    fn default() -> Kind {
        StarKind
    }
}
pub static unknown_kind : Kind = StarKind;
pub static star_kind : Kind = StarKind;

impl Default for Type {
    fn default() -> Type {
        Type::new_var(-1)
    }
}
impl fmt::Show for TypeVariable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.id)
    }
}
impl fmt::Show for TypeOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.name)
    }
}

impl fmt::Show for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TypeVariable(ref var) => write!(f.buf, "{}", *var),
            &TypeOperator(ref op) => write!(f.buf, "{}", *op),
            &TypeApplication(ref lhs, ref rhs) => {
                let l: &Type = *lhs;
                let is_list = match l {
                    &TypeOperator(ref op) => "[]" == op.name,
                    _ => false
                };
                let is_func = match l {
                    &TypeApplication(ref xx, _) => {
                        let x: &Type = *xx;
                        match x {
                            &TypeOperator(ref op) => "->" == op.name,
                            _ => false
                        }
                    }
                    _ => false
                };
                if is_func {
                    let is_lhs_func = match l {
                        &TypeApplication(ref x, _) => {
                            let xx: &Type = *x;
                            match xx {
                                &TypeApplication(ref y, _) => {
                                    let yy: &Type = *y;
                                    match yy {
                                        &TypeOperator(ref op) => "->" == op.name,
                                        _ => false
                                    }
                                }
                                _ => false
                            }
                        }
                        _ => false
                    };
                    if is_lhs_func {
                        write!(f.buf, "({}) -> {}", lhs, rhs)
                    }
                    else {
                        write!(f.buf, "{} -> {}", lhs, rhs)
                    }
                }
                else {
                    if is_list {
                        try!(write!(f.buf, "["));
                    }
                    else {
                        try!(write!(f.buf, "({} ", lhs));
                    }
                    try!(write!(f.buf, "{}", rhs));
                    if is_list {
                        write!(f.buf, "]")
                    }
                    else {
                        write!(f.buf, ")")
                    }
                }
            }
        }
    }
}
impl fmt::Show for Constraint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f.buf, "{}", self.class));
        for var in self.variables.iter() {
            try!(write!(f.buf, " {}", *var));
        }
        Ok(())
    }
}
impl fmt::Show for TypeDeclaration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f.buf, "{} :: ", self.name));
        for constraint in self.context.iter() {
            try!(write!(f.buf, "{} ", *constraint));
        }
        if self.context.len() > 0 {
            try!(write!(f.buf, "=> "));
        }
        write!(f.buf, "{}", self.typ)
    }
}

fn type_eq<'a>(mapping: &mut HashMap<&'a TypeVariable, &'a TypeVariable>, lhs: &'a Type, rhs: &'a Type) -> bool {
    match (lhs, rhs) {
        (&TypeOperator(ref l), &TypeOperator(ref r)) => l.name == r.name,
        (&TypeVariable(ref r), &TypeVariable(ref l)) => {
            match mapping.find(&l) {
                Some(x) => return x.id == r.id,
                None => ()
            }
            mapping.insert(l, r);
            true
        }
        (&TypeApplication(ref lhs1, ref rhs1), &TypeApplication(ref lhs2, ref rhs2)) => {
            type_eq(mapping, *lhs1, *lhs2) && type_eq(mapping, *rhs1, *rhs2)
        }
        _ => false
    }
}

impl Eq for Type {
    fn eq(&self, other: &Type) -> bool {
        let mut mapping = HashMap::new();
        type_eq(&mut mapping, self, other)
    }
}

pub struct TypedExpr {
    pub expr : Expr,
    pub typ : Type,
    pub location : Location
}

impl Eq for TypedExpr {
    fn eq(&self, other : &TypedExpr) -> bool {
        self.expr == other.expr
    }
}

impl fmt::Show for TypedExpr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.expr)
    }
}

impl TypedExpr {
    pub fn new(expr : Expr) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : Location { column : -1, row : -1, absolute : -1 } }
    }
    pub fn with_location(expr : Expr, loc : Location) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : loc }
    }
}

#[deriving(Eq)]
pub struct Alternative {
    pub pattern : Located<Pattern>,
    pub expression : TypedExpr
}

#[deriving(Eq, TotalEq)]
pub enum Pattern {
    NumberPattern(int),
    IdentifierPattern(~str),
    ConstructorPattern(~str, ~[Pattern])
}

#[deriving(Eq)]
pub enum Expr {
    Identifier(~str),
    Apply(~TypedExpr, ~TypedExpr),
    Number(int),
    Rational(f64),
    String(~str),
    Char(char),
    Lambda(~str, ~TypedExpr),
    Let(~[Binding], ~TypedExpr),
    Case(~TypedExpr, ~[Alternative])
}

impl fmt::Show for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Identifier(ref s) => write!(f.buf, "{}", *s),
            &Apply(ref func, ref arg) => write!(f.buf, "({} {})", *func, *arg),
            &Number(num) => write!(f.buf, "{}", num),
            &Rational(num) => write!(f.buf, "{}", num),
            &String(ref s) => write!(f.buf, "\"{}\"", *s),
            &Char(c) => write!(f.buf, "'{}'", c),
            &Lambda(ref arg, ref body) => write!(f.buf, "({} -> {})", *arg, *body),
            &Let(ref bindings, ref body) => {
                try!(write!(f.buf, "let \\{\n"));
                for bind in bindings.iter() {
                    try!(write!(f.buf, "; {} = {}\n", bind.name, bind.expression));
                }
                write!(f.buf, "\\} in {}\n", *body)
            }
            &Case(ref expr, ref alts) => {
                try!(write!(f.buf, "case {} of \\{\n", *expr));
                for alt in alts.iter() {
                    try!(write!(f.buf, "; {} -> {}\n", alt.pattern.node, alt.expression));
                }
                write!(f.buf, "\\}\n")
            }
        }
    }
}
impl fmt::Show for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IdentifierPattern(ref s) => write!(f.buf, "{}", s),
            &NumberPattern(ref i) => write!(f.buf, "{}", i),
            &ConstructorPattern(ref name, ref patterns) => {
                try!(write!(f.buf, "({}", name));
                for p in patterns.iter() {
                    try!(write!(f.buf, "{} ", p));
                }
                write!(f.buf, ")")
            }
        }
    }
}
<commit_msg>Parametrized Module, Expr, etc. with an Identifier type<commit_after>use std::fmt;
use collections::HashMap;
pub use std::default::Default;
pub use lexer::{Location, Located};

pub struct Module<Ident = ~str> {
    pub name : Ident,
    pub bindings : ~[Binding<Ident>],
    pub typeDeclarations : ~[TypeDeclaration],
    pub classes : ~[Class],
    pub instances : ~[Instance<Ident>],
    pub dataDefinitions : ~[DataDefinition]
}
#[deriving(Clone)]
pub struct Class<Ident = ~str> {
    pub name : Ident,
    pub variable : TypeVariable,
    pub declarations : ~[TypeDeclaration]
}

pub struct Instance<Ident = ~str> {
    pub bindings : ~[Binding<Ident>],
    pub constraints : ~[Constraint],
    pub typ : Type,
    pub classname : ~str
}

#[deriving(Eq)]
pub struct Binding<Ident = ~str> {
    pub name : Ident,
    pub expression : TypedExpr<Ident>,
    pub typeDecl : TypeDeclaration,
    pub arity : uint
}

#[deriving(Eq, TotalEq, Clone, Show)]
pub struct Constructor {
    pub name : ~str,
    pub typ : Type,
    pub tag : int,
    pub arity : int
}

#[deriving(Eq, Clone)]
pub struct DataDefinition {
    pub constructors : ~[Constructor],
    pub typ : Type,
    pub parameters : HashMap<~str, int>
}

#[deriving(Clone, Eq, TotalEq, Default)]
pub struct TypeDeclaration {
    pub context : ~[Constraint],
    pub typ : Type,
    pub name : ~str
}

#[deriving(Clone, Default, Eq, TotalEq, Hash)]
pub struct TypeOperator {
    pub name : ~str,
    pub kind : Kind
}
#[deriving(Clone, Eq, TotalEq, Default, Hash)]
pub struct TypeVariable {
    pub id : int,
    pub kind : Kind
}
#[deriving(Clone, TotalEq, Hash)]
pub enum Type {
    TypeVariable(TypeVariable),
    TypeOperator(TypeOperator),
    TypeApplication(~Type, ~Type)
}

impl Type {

    pub fn new_var(id : int) -> Type {
        TypeVariable(TypeVariable { id : id, kind: unknown_kind.clone() })
    }
    pub fn new_var_kind(id : int, kind: Kind) -> Type {
        TypeVariable(TypeVariable { id : id, kind: kind })
    }
    pub fn new_op(name : ~str, types : ~[Type]) -> Type {
        let mut result = TypeOperator(TypeOperator { name : name, kind: Kind::new(types.len() as int + 1) });
        for typ in types.move_iter() {
            result = TypeApplication(~result, ~typ);
        }
        result
    }
    pub fn new_op_kind(name : ~str, types : ~[Type], kind: Kind) -> Type {
        let mut result = TypeOperator(TypeOperator { name : name, kind: kind });
        for typ in types.move_iter() {
            result = TypeApplication(~result, ~typ);
        }
        result
    }

    pub fn var<'a>(&'a self) -> &'a TypeVariable {
        match self {
            &TypeVariable(ref var) => var,
            _ => fail!("Tried to unwrap {} as a TypeVariable", self)
        }
    }
    #[allow(dead_code)]
    pub fn op<'a>(&'a self) -> &'a TypeOperator {
        match self {
            &TypeOperator(ref op) => op,
            _ => fail!("Tried to unwrap {} as a TypeOperator", self)
        }
    }
    #[allow(dead_code)]
    pub fn appl<'a>(&'a self) -> &'a Type {
        match self {
            &TypeApplication(ref lhs, _) => { let l: &Type = *lhs; l }
            _ => fail!("Error: Tried to unwrap {} as TypeApplication", self)
        }
    }
    #[allow(dead_code)]
    pub fn appr<'a>(&'a self) -> &'a Type {
        match self {
            &TypeApplication(_, ref rhs) => { let r: &Type = *rhs; r }
            _ => fail!("Error: Tried to unwrap TypeApplication")
        }
    }

    pub fn kind<'a>(&'a self) -> &'a Kind {
        match self {
            &TypeVariable(ref v) => &v.kind,
            &TypeOperator(ref v) => &v.kind,
            &TypeApplication(ref lhs, _) =>
                match lhs.kind() {
                    &KindFunction(_, ref k) => {
                        let kind: &Kind = *k;
                        kind
                    }
                    _ => fail!("Type application must have a kind of KindFunction, {}", self)
                }
        }
    }
    pub fn mut_kind<'a>(&'a mut self) -> &'a mut Kind {
        match self {
            &TypeVariable(ref mut v) => &mut v.kind,
            &TypeOperator(ref mut v) => &mut v.kind,
            _ => fail!("Typeapplication has no kind")
        }
    }
}

#[deriving(Clone, Eq, TotalEq, Hash)]
pub struct Constraint {
    pub class : ~str,
    pub variables : ~[TypeVariable]
}

#[deriving(Clone, Eq, TotalEq, Hash)]
pub enum Kind {
    KindFunction(~Kind, ~Kind),
    StarKind
}
impl fmt::Show for Kind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &StarKind => write!(f.buf, "*"),
            &KindFunction(ref lhs, ref rhs) => write!(f.buf, "({} -> {})", *lhs, *rhs)
        }
    }
}

impl Kind {
    pub fn new(v: int) -> Kind {
        let mut kind = star_kind.clone();
        for _ in range(1, v) {
            kind = KindFunction(~StarKind, ~kind);
        }
        kind
    }
}

impl Default for Kind {
    fn default() -> Kind {
        StarKind
    }
}
pub static unknown_kind : Kind = StarKind;
pub static star_kind : Kind = StarKind;

impl Default for Type {
    fn default() -> Type {
        Type::new_var(-1)
    }
}
impl fmt::Show for TypeVariable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.id)
    }
}
impl fmt::Show for TypeOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.name)
    }
}

impl fmt::Show for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TypeVariable(ref var) => write!(f.buf, "{}", *var),
            &TypeOperator(ref op) => write!(f.buf, "{}", *op),
            &TypeApplication(ref lhs, ref rhs) => {
                let l: &Type = *lhs;
                let is_list = match l {
                    &TypeOperator(ref op) => "[]" == op.name,
                    _ => false
                };
                let is_func = match l {
                    &TypeApplication(ref xx, _) => {
                        let x: &Type = *xx;
                        match x {
                            &TypeOperator(ref op) => "->" == op.name,
                            _ => false
                        }
                    }
                    _ => false
                };
                if is_func {
                    let is_lhs_func = match l {
                        &TypeApplication(ref x, _) => {
                            let xx: &Type = *x;
                            match xx {
                                &TypeApplication(ref y, _) => {
                                    let yy: &Type = *y;
                                    match yy {
                                        &TypeOperator(ref op) => "->" == op.name,
                                        _ => false
                                    }
                                }
                                _ => false
                            }
                        }
                        _ => false
                    };
                    if is_lhs_func {
                        write!(f.buf, "({}) -> {}", lhs, rhs)
                    }
                    else {
                        write!(f.buf, "{} -> {}", lhs, rhs)
                    }
                }
                else {
                    if is_list {
                        try!(write!(f.buf, "["));
                    }
                    else {
                        try!(write!(f.buf, "({} ", lhs));
                    }
                    try!(write!(f.buf, "{}", rhs));
                    if is_list {
                        write!(f.buf, "]")
                    }
                    else {
                        write!(f.buf, ")")
                    }
                }
            }
        }
    }
}
impl fmt::Show for Constraint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f.buf, "{}", self.class));
        for var in self.variables.iter() {
            try!(write!(f.buf, " {}", *var));
        }
        Ok(())
    }
}
impl fmt::Show for TypeDeclaration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f.buf, "{} :: ", self.name));
        for constraint in self.context.iter() {
            try!(write!(f.buf, "{} ", *constraint));
        }
        if self.context.len() > 0 {
            try!(write!(f.buf, "=> "));
        }
        write!(f.buf, "{}", self.typ)
    }
}

fn type_eq<'a>(mapping: &mut HashMap<&'a TypeVariable, &'a TypeVariable>, lhs: &'a Type, rhs: &'a Type) -> bool {
    match (lhs, rhs) {
        (&TypeOperator(ref l), &TypeOperator(ref r)) => l.name == r.name,
        (&TypeVariable(ref r), &TypeVariable(ref l)) => {
            match mapping.find(&l) {
                Some(x) => return x.id == r.id,
                None => ()
            }
            mapping.insert(l, r);
            true
        }
        (&TypeApplication(ref lhs1, ref rhs1), &TypeApplication(ref lhs2, ref rhs2)) => {
            type_eq(mapping, *lhs1, *lhs2) && type_eq(mapping, *rhs1, *rhs2)
        }
        _ => false
    }
}

impl Eq for Type {
    fn eq(&self, other: &Type) -> bool {
        let mut mapping = HashMap::new();
        type_eq(&mut mapping, self, other)
    }
}

pub struct TypedExpr<Ident = ~str> {
    pub expr : Expr<Ident>,
    pub typ : Type,
    pub location : Location
}

impl <T: Eq> Eq for TypedExpr<T> {
    fn eq(&self, other : &TypedExpr<T>) -> bool {
        self.expr == other.expr
    }
}

impl fmt::Show for TypedExpr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}", self.expr)
    }
}

impl TypedExpr {
    pub fn new(expr : Expr) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : Location { column : -1, row : -1, absolute : -1 } }
    }
    pub fn with_location(expr : Expr, loc : Location) -> TypedExpr {
        TypedExpr { expr : expr, typ : Type::new_var(0), location : loc }
    }
}

#[deriving(Eq)]
pub struct Alternative<Ident = ~str> {
    pub pattern : Located<Pattern<Ident>>,
    pub expression : TypedExpr<Ident>
}

#[deriving(Eq, TotalEq)]
pub enum Pattern<Ident = ~str> {
    NumberPattern(int),
    IdentifierPattern(Ident),
    ConstructorPattern(~str, ~[Pattern<Ident>])
}

#[deriving(Eq)]
pub enum Expr<Ident = ~str> {
    Identifier(Ident),
    Apply(~TypedExpr<Ident>, ~TypedExpr<Ident>),
    Number(int),
    Rational(f64),
    String(~str),
    Char(char),
    Lambda(Ident, ~TypedExpr<Ident>),
    Let(~[Binding<Ident>], ~TypedExpr<Ident>),
    Case(~TypedExpr<Ident>, ~[Alternative<Ident>])
}

impl fmt::Show for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Identifier(ref s) => write!(f.buf, "{}", *s),
            &Apply(ref func, ref arg) => write!(f.buf, "({} {})", *func, *arg),
            &Number(num) => write!(f.buf, "{}", num),
            &Rational(num) => write!(f.buf, "{}", num),
            &String(ref s) => write!(f.buf, "\"{}\"", *s),
            &Char(c) => write!(f.buf, "'{}'", c),
            &Lambda(ref arg, ref body) => write!(f.buf, "({} -> {})", *arg, *body),
            &Let(ref bindings, ref body) => {
                try!(write!(f.buf, "let \\{\n"));
                for bind in bindings.iter() {
                    try!(write!(f.buf, "; {} = {}\n", bind.name, bind.expression));
                }
                write!(f.buf, "\\} in {}\n", *body)
            }
            &Case(ref expr, ref alts) => {
                try!(write!(f.buf, "case {} of \\{\n", *expr));
                for alt in alts.iter() {
                    try!(write!(f.buf, "; {} -> {}\n", alt.pattern.node, alt.expression));
                }
                write!(f.buf, "\\}\n")
            }
        }
    }
}
impl fmt::Show for Pattern {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IdentifierPattern(ref s) => write!(f.buf, "{}", s),
            &NumberPattern(ref i) => write!(f.buf, "{}", i),
            &ConstructorPattern(ref name, ref patterns) => {
                try!(write!(f.buf, "({}", name));
                for p in patterns.iter() {
                    try!(write!(f.buf, "{} ", p));
                }
                write!(f.buf, ")")
            }
        }
    }
}

pub trait Visitor<Ident> {
    fn visit_expr(&mut self, expr: &TypedExpr<Ident>) {
        walk_expr(self, expr)
    }
    fn visit_alternative(&mut self, alt: &Alternative<Ident>) {
        walk_alternative(self, alt)
    }
    fn visit_pattern(&mut self, pattern: &Pattern<Ident>) {
        walk_pattern(self, pattern)
    }
    fn visit_binding(&mut self, binding: &Binding<Ident>) {
        walk_binding(self, binding);
    }
    fn visit_module(&mut self, module: &Module<Ident>) {
        walk_module(self, module);
    }
}

pub fn walk_module<Ident>(visitor: &mut Visitor<Ident>, module: &Module<Ident>) {
    for bind in module.instances.iter().flat_map(|i| i.bindings.iter()) {
        visitor.visit_binding(bind);
    }
    for bind in module.bindings.iter() {
        visitor.visit_binding(bind);
    }
}

pub fn walk_binding<Ident>(visitor: &mut Visitor<Ident>, binding: &Binding<Ident>) {
    visitor.visit_expr(&binding.expression);
}

pub fn walk_expr<Ident>(visitor: &mut Visitor<Ident>, expr: &TypedExpr<Ident>) {
    match &expr.expr {
        &Apply(ref func, ref arg) => {
            visitor.visit_expr(*func);
            visitor.visit_expr(*arg);
        }
        &Lambda(_, ref body) => visitor.visit_expr(*body),
        &Let(ref binds, ref e) => {
            for b in binds.iter() {
                visitor.visit_binding(b);
            }
            visitor.visit_expr(*e);
        }
        &Case(ref e, ref alts) => {
            visitor.visit_expr(*e);
            for alt in alts.iter() {
                visitor.visit_alternative(alt);
            }
        }
        _ => ()
    }
}

pub fn walk_alternative<Ident>(visitor: &mut Visitor<Ident>, alt: &Alternative<Ident>) {
    visitor.visit_expr(&alt.expression);
}

pub fn walk_pattern<Ident>(visitor: &mut Visitor<Ident>, pattern: &Pattern<Ident>) {
    match pattern {
        &ConstructorPattern(_, ref ps) => {
            for p in ps.iter() {
                visitor.visit_pattern(p);
            }
        }
        _ => ()
    }
}
<|endoftext|>