zub 0.3.14

A fast, stack-based virtual machine for dynamic languages, with an intuitive IR-builder, garbage collection and NaN-tagging.
Documentation
use super::super::gc::{ *, tag::*, trace::* };
use super::*;

use std::fmt::{Debug, Display};
use std::rc::Rc;
use std::cell::RefCell;

use im_rc::hashmap::HashMap;

// lol nice
macro_rules! impl_as (
    ($name:ident, $typ:ident) => {
        pub fn $name(&self) -> Option<&$typ> {
            if let Object::$typ(ref o) = *self {
                Some(o)
            } else {
                None
            }
        }
    }
);

pub enum Object {
    String(String),
    Function(Function),
    NativeFunction(NativeFunction),
    Closure(Closure),
    List(List),
    Dict(Dict)
}

impl Object {
    impl_as!(as_string, String);
    impl_as!(as_closure, Closure);
    impl_as!(as_function, Function);
    impl_as!(as_list, List);
    impl_as!(as_dict, Dict);

    pub fn native_fn(name: &str, arity: u8, function: fn(&mut Heap<Object>, &[Value]) -> Value) -> Self {
        Object::NativeFunction(
            NativeFunction {
                name: name.into(),
                arity,
                function,
            },
        )
    }

    pub fn as_closure_mut(&mut self) -> Option<&mut Closure> {
        if let Object::Closure(ref mut o) = *self {
            Some(o)
        } else {
            None
        }
    }
}

impl Trace<Self> for Object {
    fn trace(&self, tracer: &mut Tracer<Self>) {
        use self::Object::*;
        
        match self {
            String(_) => {},
            Function(f) => f.trace(tracer),
            NativeFunction(_) => {},
            Closure(c) => c.trace(tracer),
            List(l) => l.trace(tracer),
            Dict(d) => d.trace(tracer)
        }
    }
}

impl Debug for Object {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        use self::Object::*;

        match self {
            String(ref s) => write!(f, "{:?}", s),
            NativeFunction(ref na) => write!(f, "<native fn {:?}>", na.name),
            Function(ref fun) => write!(f, "<fn {:?}>", fun.name),
            Closure(ref cl) => write!(f, "<closure {:?}>", cl.function),
            List(ref ls) => write!(f, "<list [{:?}]>", ls.content.len()),
            Dict(ref dict) => write!(f, "<dict [{:?}]>", dict.content.len()),
        }
    }
}

impl<'h, 'a> Display for WithHeap<'h, &'a Object> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        use self::Object::*;

        match self.item {
            String(ref s) => write!(f, "{}", s),
            NativeFunction(ref na) => write!(f, "<native fn {}>", na.name),
            Function(ref fun) => write!(f, "<fn {}>", fun.name),
            Closure(ref cl) => write!(f, "<fn {}>", cl.function.name),
            List(ref ls) => write!(f, "<list [{}]>", ls.content.len()),
            Dict(ref ls) => write!(f, "<dict [{}]>", ls.content.len()),
        }
    }
}

#[derive(Debug)]
pub struct FunctionBuilder {
    name: String,
    pub chunk: Chunk,
    arity: u8,
    upvalue_count: usize,
}

impl FunctionBuilder {
    pub fn new(name: &str, arity: u8) -> Self {
        let name: String = name.into();
        let chunk = Chunk::new(name.clone());
        FunctionBuilder { name, arity, chunk, upvalue_count: 0 }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn chunk_mut(&mut self) -> &mut Chunk {
        &mut self.chunk
    }

    pub fn set_upvalue_count(&mut self, count: usize) {
        self.upvalue_count = count;
    }

    pub fn build(self) -> Function {
        Function::new(self)
    }
}

#[derive(Debug, Clone)]
pub struct Function {
    name: String,
    chunk: Chunk,
    arity: u8,
    upvalue_count: usize,
}

impl Function {
    fn new(builder: FunctionBuilder) -> Self {
        Function {
            name: builder.name,
            arity: builder.arity,
            chunk: builder.chunk,
            upvalue_count: builder.upvalue_count,
        }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn chunk(&self) -> &Chunk {
        &self.chunk
    }

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

impl Trace<Object> for Function {
    fn trace(&self, tracer: &mut Tracer<Object>) {
        self.chunk.trace(tracer);
    }
}

#[derive(Clone)]
pub struct NativeFunction {
    pub name: String,
    pub arity: u8,
    pub function: fn(&mut Heap<Object>, &[Value]) -> Value,
}

#[derive(Debug, Clone)]
pub struct UpValue {
    inner: Rc<RefCell<Result<Value, usize>>>,
}

impl UpValue {
    pub fn new(local: usize) -> Self {
        UpValue {
            inner: Rc::new(RefCell::new(Err(local))),
        }
    }

    pub fn close<F: FnOnce(usize) -> Value>(&mut self, f: F) {
        let mut inner = self.inner.borrow_mut();
        if let Err(e) = *inner {
            *inner = Ok(f(e))
        }
    }

    pub fn as_local(&self) -> Option<usize> {
        self.inner.borrow().err()
    }

    pub fn get(&self) -> Result<Value, usize> {
        self.inner.borrow().clone()
    }

    pub fn set(&mut self, value: Value) -> Result<(), usize> {
        let mut inner = self.inner.borrow_mut();
        (*inner)?;

        *inner = Ok(value);

        Ok(())
    }
}

pub struct Dict {
    pub content: HashMap<HashValue, Value>,
}

impl Dict {
    #[inline]
    pub fn new(content: HashMap<HashValue, Value>) -> Self {
        Dict {
            content,
        }
    }

    #[inline]
    pub fn empty() -> Self {
        Dict {
            content: HashMap::new()
        }
    }

    pub fn insert(&mut self, key: HashValue, value: Value) {
        self.content.insert(key, value);
    }

    pub fn get(&self, key: &HashValue) -> Option<&Value> {
        self.content.get(key)
    }
}

impl Trace<Object> for Dict {
    fn trace(&self, tracer: &mut Tracer<Object>) {
        self.content.values().for_each(|v| v.trace(tracer));
    }
}

#[derive(Debug)]
pub struct List {
    pub content: Vec<Value>,
}

// Inline everything >:()
impl List {
    #[inline]
    pub fn new(content: Vec<Value>) -> Self {
        List {
            content
        }
    }

    #[inline]
    pub fn set(&mut self, idx: usize, value: Value) {
        self.content[idx] = value
    }

    #[inline]
    pub fn push(&mut self, value: Value) {
        self.content.push(value)
    }

    #[inline]
    pub fn pop(&mut self) -> Value {
        self.content.pop().unwrap()
    }

    #[inline]
    pub fn get(&self, idx: usize) -> Value {
        self.content[idx].clone() // Might not have to use a clone here
    }
}

impl Trace<Object> for List {
    fn trace(&self, tracer: &mut Tracer<Object>) {
        self.content.iter()
            .for_each(|v| v.trace(tracer));
    }
}

#[derive(Debug, Clone)]
pub struct Closure {
    function: Function,
    upvalues: Vec<UpValue>,
}

impl Closure {
    pub fn new(function: Function, upvalues: Vec<UpValue>) -> Self {
        Closure {
            function,
            upvalues
        }
    }

    pub fn name(&self) -> &str {
        self.function.name()
    }

    pub fn arity(&self) -> u8 {
        self.function.arity
    }

    pub fn chunk(&self) -> &Chunk {
        self.function.chunk()
    }

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

    #[inline]
    pub fn get(&self, idx: usize) -> UpValue {
        self.upvalues[idx].clone()
    }
}

impl Trace<Object> for Closure {
    fn trace(&self, tracer: &mut Tracer<Object>) {
        self.function.trace(tracer);
        self.upvalues.iter()
            .flat_map(|u| u.get())
            .for_each(|v| v.trace(tracer));
    }
}