~dvko/nederlang

d5d1ead691fc73cdd015ab214336e9df1e493b69 — Danny van Kooten 1 year, 6 months ago c433dd7
rework object creation into a more uniform interface
6 files changed, 74 insertions(+), 62 deletions(-)

M src/builtins.rs
M src/compiler.rs
M src/gc.rs
M src/lib.rs
M src/object.rs
M src/vm.rs
M src/builtins.rs => src/builtins.rs +3 -3
@@ 1,6 1,6 @@
use crate::{
    gc::GC,
    object::{Error, Object, Type},
    object::{Error, FromString, Object, Type},
};

#[repr(u8)]


@@ 68,7 68,7 @@ fn call_type(args: &[Object], gc: &mut GC) -> Result<Object, Error> {
        )));
    }

    Ok(Object::string(&args[0].tag().to_string(), gc))
    Ok(Object::string(args[0].tag().to_string(), gc))
}

/// Casts the given object to a string object


@@ 93,7 93,7 @@ fn call_string(args: &[Object], gc: &mut GC) -> Result<Object, Error> {
            )))
        }
    };
    Ok(Object::string(&t, gc))
    Ok(Object::string(t.as_str(), gc))
}

/// Casts the given object to a bool object

M src/compiler.rs => src/compiler.rs +4 -4
@@ 1,12 1,12 @@
use std::fmt::Display;
use std::fmt::Write;

use crate::ast::*;
use crate::builtins;
use crate::gc::GC;
use crate::object::Error;
use crate::object::FromString;
use crate::object::Object;
use crate::symbols::*;
use std::fmt::Display;
use std::fmt::Write;

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]


@@ 385,7 385,7 @@ impl Compiler {
                self.emit_u16(idx);
            }
            Expr::String { value } => {
                let obj = Object::string(&value, &mut self.gc);
                let obj = Object::string(value.as_str(), &mut self.gc);
                let idx = self.add_constant(obj);
                self.emit_opcode(OpCode::Const);
                self.emit_u16(idx);

M src/gc.rs => src/gc.rs +9 -9
@@ 1,6 1,6 @@
use crate::object::{Header, Object, Type};

// TODO: Change visibility of GC to crate-private
// TODO: Change visibility of GC to crate-private (not directly possible because of pub Object type)
pub struct GC {
    /// Vector of all currently alive heap-allocated objects in the universe
    objects: Vec<Object>,


@@ 10,7 10,7 @@ impl GC {
    /// Create a new Garbage Collector to manage heap-allocated objects
    pub fn new() -> GC {
        Self {
            objects: Vec::with_capacity(8),
            objects: Vec::new(),
        }
    }



@@ 55,15 55,15 @@ impl GC {

    /// Runs a full mark & sweep cycle
    /// Only objects in the given roots are kept alive
    pub fn run(&mut self, roots: &[&[Object]]) {
    pub fn run(&mut self, roots: &mut [&mut [Object]]) {
        // Don't traverse roots if we have no traced objects
        if self.objects.is_empty() {
            return;
        }

        // mark all reachable objects
        for root in roots.iter() {
            for obj in root.iter() {
        for root in roots.iter_mut() {
            for obj in root.iter_mut() {
                mark(obj);
            }
        }


@@ 76,7 76,7 @@ impl GC {
    pub fn sweep(&mut self) {
        let mut i = 0;
        while i < self.objects.len() {
            let obj = self.objects[i];
            let mut obj = self.objects[i];

            // Immediate values should not end up on the traced objects list
            debug_assert!(obj.is_heap_allocated());


@@ 84,7 84,7 @@ impl GC {
            // Object is heap allocated
            // Read its header to check if its marked
            // If its marked, clear flag & continue
            let mut header = unsafe { Header::read(&obj) };
            let mut header = unsafe { Header::read(&mut obj) };
            if header.marked {
                header.marked = false;
                i += 1;


@@ 109,7 109,7 @@ impl Drop for GC {

/// Marks the given object as reachable
#[inline]
fn mark(o: &Object) {
fn mark(o: &mut Object) {
    if !o.is_heap_allocated() {
        return;
    }


@@ 118,7 118,7 @@ fn mark(o: &Object) {
    header.marked = true;

    if o.tag() == Type::Array {
        for v in o.as_vec() {
        for v in o.as_vec_mut() {
            mark(v);
        }
    }

M src/lib.rs => src/lib.rs +1 -1
@@ 1,10 1,10 @@
mod ast;
mod builtins;
mod gc;
mod lexer;
mod symbols;

pub mod compiler;
pub mod gc;
pub mod object;
pub mod parser;
pub mod vm;

M src/object.rs => src/object.rs +53 -41
@@ 69,6 69,13 @@ impl Object {
        Self((raw as usize | t as usize) as _)
    }

    /// Returns the type of this object pointer
    #[inline(always)]
    pub fn tag(self) -> Type {
        // Safety: self.0 with TAG_MASK applied will always yield a correct Type
        unsafe { std::mem::transmute((self.0 as usize & TAG_MASK) as u8) }
    }

    /// Create a new null value
    #[inline(always)]
    pub fn null() -> Self {


@@ 89,7 96,6 @@ impl Object {
    pub fn int(value: isize) -> Self {
        // assert there is no data loss because of the shift
        debug_assert_eq!(((value << VALUE_SHIFT_BITS) >> VALUE_SHIFT_BITS), value);

        Self::with_type((value << VALUE_SHIFT_BITS) as _, Type::Int)
    }



@@ 100,23 106,6 @@ impl Object {
        Self::with_type((value << VALUE_SHIFT_BITS) as _, Type::Function)
    }

    /// Create a new (garbage-collected) String value
    #[inline]
    pub fn from_string(value: RString, gc: &mut GC) -> Self {
        let ptr = String::from_string(value);
        gc.trace(ptr);
        ptr
    }

    /// Create a new (garbage-collected) String value
    #[inline]
    pub fn string(value: &str, gc: &mut GC) -> Self {
        let ptr = String::from_str(value);
        gc.trace(ptr);
        ptr
    }

    /// Create a new (garbage-collected) Float value
    #[inline]
    pub fn float(value: f64, gc: &mut GC) -> Self {
        let ptr = Float::from_f64(value);


@@ 124,21 113,6 @@ impl Object {
        ptr
    }

    /// Create a new (garbage-collected) Array value
    #[inline]
    pub fn array(value: &[Object], gc: &mut GC) -> Self {
        let ptr = Array::from_slice(value);
        gc.trace(ptr);
        ptr
    }

    /// Returns the type of this object pointer
    #[inline(always)]
    pub fn tag(self) -> Type {
        // Safety: self.0 with TAG_MASK applied will always yield a correct Type
        unsafe { std::mem::transmute((self.0 as usize & TAG_MASK) as u8) }
    }

    /// Returns the boolean value of this object pointer
    /// Note that is up to the caller to ensure this pointer is of the correct type
    #[inline(always)]


@@ 193,7 167,7 @@ impl Object {
    }

    #[inline]
    pub fn as_string_mut(&self) -> &mut RString {
    pub fn as_string_mut(&mut self) -> &mut RString {
        assert_eq!(self.tag(), Type::String);
        unsafe { &mut self.get_mut::<String>().value }
    }


@@ 223,7 197,7 @@ impl Object {
    /// Returns a mutable reference to the Vec<Pointer> value this pointer points to
    /// Panics if object does not point to an Array
    #[inline]
    pub fn as_vec_mut(&self) -> &mut Vec<Object> {
    pub fn as_vec_mut(&mut self) -> &mut Vec<Object> {
        assert_eq!(self.tag(), Type::Array);
        unsafe { self.as_vec_unchecked_mut() }
    }


@@ 231,7 205,7 @@ impl Object {
    /// Returns a mutable reference to the Vec<Pointer> value this pointer points to
    /// The caller should ensure this pointer actually points to an Array
    #[inline]
    pub unsafe fn as_vec_unchecked_mut(&self) -> &mut Vec<Object> {
    pub unsafe fn as_vec_unchecked_mut(&mut self) -> &mut Vec<Object> {
        &mut self.get_mut::<Array>().value
    }



@@ 291,6 265,48 @@ impl Object {
    }
}

pub trait FromString<T> {
    fn string(value: T, gc: &mut GC) -> Self;
}

impl FromString<RString> for Object {
    fn string(value: RString, gc: &mut GC) -> Self {
        let ptr = String::from_string(value);
        gc.trace(ptr);
        ptr
    }
}

impl FromString<&str> for Object {
    fn string(value: &str, gc: &mut GC) -> Self {
        let ptr = String::from_string(value.to_string());
        gc.trace(ptr);
        ptr
    }
}

pub trait FromVec<T> {
    fn array(value: T, gc: &mut GC) -> Self;
}

impl FromVec<Vec<Object>> for Object {
    /// Create a new (garbage-collected) Array value
    fn array(value: Vec<Object>, gc: &mut GC) -> Self {
        let ptr = Array::from_vec(value);
        gc.trace(ptr);
        ptr
    }
}

impl FromVec<&[Object]> for Object {
    /// Create a new (garbage-collected) Array value
    fn array(value: &[Object], gc: &mut GC) -> Self {
        let ptr = Array::from_slice(value);
        gc.trace(ptr);
        ptr
    }
}

impl PartialEq for Object {
    #[inline(always)]
    fn eq(&self, other: &Self) -> bool {


@@ 406,7 422,7 @@ pub(crate) struct Header {

impl Header {
    #[inline]
    pub unsafe fn read(obj: &Object) -> &mut Header {
    pub unsafe fn read(obj: &mut Object) -> &mut Header {
        obj.get_mut::<Self>()
    }
}


@@ 457,10 473,6 @@ impl String {
        init!(obj.value => value);
        ptr
    }

    fn from_str(value: &str) -> Object {
        Self::from_string(value.to_string())
    }
}

#[repr(C)]

M src/vm.rs => src/vm.rs +4 -4
@@ 1,7 1,7 @@
use crate::builtins::{self, Builtin};
use crate::compiler::{Bytecode, OpCode};
use crate::gc::GC;
use crate::object::{Error, Object, Type};
use crate::object::{Error, FromString, FromVec, Object, Type};

#[cfg(feature = "debug")]
use std::io::Write;


@@ 405,7 405,7 @@ impl VM {
                    }
                    vec.reverse();
                    // TODO: Re-use vector allocation here
                    let obj = Object::array(&vec, gc);
                    let obj = Object::array(vec, gc);
                    self.push(obj);
                }
                OpCode::IndexGet => {


@@ 480,11 480,11 @@ fn index_get_string(obj: Object, mut index: isize, gc: &mut GC) -> Result<Object
    }

    let ch = str.chars().nth(index).unwrap();
    let result = Object::from_string(ch.to_string(), gc);
    let result = Object::string(ch.to_string(), gc);
    Ok(result)
}

fn index_set(left: Object, index: Object, value: Object) -> Result<Object, Error> {
fn index_set(mut left: Object, index: Object, value: Object) -> Result<Object, Error> {
    if index.tag() != Type::Int {
        return Err(Error::TypeError(format!(
            "lijst index moet een integer zijn, geen {}",