~dvko/nederlang

60a74c8b85b30dfb6c82bdeaa52cf7f4c426b0cc — Danny van Kooten 1 year, 6 months ago d5d1ead
address clippy warnings
7 files changed, 88 insertions(+), 75 deletions(-)

M src/builtins.rs
M src/compiler.rs
M src/object.rs
M src/parser.rs
M src/symbols.rs
M src/vm.rs
M tests/vm_test.rs
M src/builtins.rs => src/builtins.rs +4 -4
@@ 44,11 44,11 @@ pub(crate) fn call(builtin: Builtin, args: &[Object], gc: &mut GC) -> Result<Obj
/// Example:
///     print("Hallo {}!", "wereld") => prints "Hallo wereld" to stdout
fn call_print(args: &[Object]) -> Result<Object, Error> {
    if args.len() > 0 {
    if !args.is_empty() {
        let mut args = args.iter();
        let mut format_str = args.next().unwrap().to_string();

        while let Some(replacement) = args.next() {
        for replacement in args {
            format_str = format_str.replacen("{}", &replacement.to_string(), 1);
        }



@@ 110,8 110,8 @@ fn call_bool(args: &[Object]) -> Result<Object, Error> {
        Type::Bool => return Ok(args[0]),
        Type::Float => unsafe { args[0].as_f64_unchecked() > 0.00 },
        Type::Int => args[0].as_int() > 0,
        Type::String => unsafe { args[0].as_str_unchecked().len() > 0 },
        Type::Array => unsafe { args[0].as_vec_unchecked().len() > 0 },
        Type::String => unsafe { !args[0].as_str_unchecked().is_empty() },
        Type::Array => unsafe { !args[0].as_vec_unchecked().is_empty() },
        Type::Function => {
            return Err(Error::ArgumentError(format!(
                "kan geen bool maken van een {}",

M src/compiler.rs => src/compiler.rs +33 -33
@@ 237,7 237,7 @@ impl Compiler {
    fn compile_block_statement(&mut self, stmts: &[Stmt]) -> Result<(), Error> {
        // if block statement does not contain any other statements or expressions
        // simply push a NULL onto the stack
        if stmts.len() == 0 {
        if stmts.is_empty() {
            self.emit_opcode(OpCode::Null);
            return Ok(());
        }


@@ 253,13 253,13 @@ impl Compiler {
    fn compile_statement(&mut self, stmt: &Stmt) -> Result<(), Error> {
        match stmt {
            Stmt::Expr(expr) => {
                self.compile_expression(&expr)?;
                self.compile_expression(expr)?;
                self.emit_opcode(OpCode::Pop);
            }
            Stmt::Block(stmts) => self.compile_block_statement(stmts)?,
            Stmt::Let(name, value) => {
                let symbol = self.symbols.define(&name);
                self.compile_expression(&value)?;
                let symbol = self.symbols.define(name);
                self.compile_expression(value)?;
                let op = if symbol.scope == Scope::Global {
                    OpCode::SetGlobal
                } else {


@@ 270,7 270,7 @@ impl Compiler {
            }
            Stmt::Return(expr) => {
                // TODO: Allow expression to be omitted (needs work in parser first)
                self.compile_expression(&expr)?;
                self.compile_expression(expr)?;
                self.emit_opcode(OpCode::ReturnValue);
            }
            Stmt::Break => {


@@ 280,7 280,9 @@ impl Compiler {
                self.emit_u16(JUMP_PLACEHOLDER);
                let ctx = match self.loop_contexts.last_mut() {
                    Some(ctx) => ctx,
                    None => return Err(Error::SyntaxError(format!("foutief gebruik van 'stop'"))),
                    None => {
                        return Err(Error::SyntaxError("foutief gebruik van 'stop'".to_string()))
                    }
                };
                ctx.break_instructions.push(pos);
            }


@@ 289,9 291,9 @@ impl Compiler {

                let pos = match self.loop_contexts.iter().last() {
                    Some(ctx) => Ok(ctx.start),
                    None => Err(Error::SyntaxError(format!(
                        "foutief gebruik van 'volgende'"
                    ))),
                    None => Err(Error::SyntaxError(
                        "foutief gebruik van 'volgende'".to_string(),
                    )),
                }?;
                self.emit_opcode(OpCode::Jump);
                self.emit_u16(pos.try_into().unwrap());


@@ 347,9 349,7 @@ impl Compiler {
                    (Operator::Modulo, Scope::Local) => OpCode::ModuloLocalConst,
                    _ => {
                        // This is just for other part of compiler to signal it should emit a normal instruction sequence
                        return Err(Error::ReferenceError(format!(
                        "Optimized variant of this operator & scope type is not yet implemented."
                    )));
                        return Err(Error::ReferenceError("Optimized variant of this operator & scope type is not yet implemented.".to_string()));
                    }
                };



@@ 391,7 391,7 @@ impl Compiler {
                self.emit_u16(idx);
            }
            Expr::Identifier(name) => {
                let symbol = self.symbols.resolve(&name);
                let symbol = self.symbols.resolve(name);
                match symbol {
                    Some(symbol) => {
                        let opcode = if symbol.scope == Scope::Global {


@@ 410,7 410,7 @@ impl Compiler {
                }
            }
            Expr::Prefix { operator, right } => {
                self.compile_expression(&*right)?;
                self.compile_expression(right)?;

                match operator {
                    Operator::Negate | Operator::Subtract => {


@@ 432,9 432,9 @@ impl Compiler {
                let name = match &**left {
                    Expr::Identifier(name) => name,
                    Expr::Index { left, index } => {
                        self.compile_expression(&*left)?;
                        self.compile_expression(&*index)?;
                        self.compile_expression(&*right)?;
                        self.compile_expression(left)?;
                        self.compile_expression(index)?;
                        self.compile_expression(right)?;
                        self.emit_opcode(OpCode::IndexSet);
                        return Ok(());
                    }


@@ 446,10 446,10 @@ impl Compiler {
                    }
                };

                let symbol = self.symbols.resolve(&name);
                let symbol = self.symbols.resolve(name);
                match symbol {
                    Some(symbol) => {
                        self.compile_expression(&*right)?;
                        self.compile_expression(right)?;

                        match symbol.scope {
                            Scope::Global => {


@@ 483,7 483,7 @@ impl Compiler {
                match (&**left, &**right) {
                    (Expr::Identifier(name), Expr::Int { value })
                    | (Expr::Int { value }, Expr::Identifier(name)) => {
                        let res = self.compile_const_var_infix_expression(&name, *value, &operator);
                        let res = self.compile_const_var_infix_expression(name, *value, operator);
                        if res.is_ok() {
                            return res;
                        }


@@ 492,16 492,16 @@ impl Compiler {
                }

                // If that failed because we haven't implemented a specialized instruction yet, compile it as a sequence of normal instructions
                self.compile_expression(&*left)?;
                self.compile_expression(&*right)?;
                self.compile_operator(&operator);
                self.compile_expression(left)?;
                self.compile_expression(right)?;
                self.compile_operator(operator);
            }
            Expr::If {
                condition,
                consequence,
                alternative,
            } => {
                self.compile_expression(&*condition)?;
                self.compile_expression(condition)?;
                let pos_jump_if_false = self.instructions.len();
                self.emit_opcode(OpCode::JumpIfFalse);
                self.emit_u16(JUMP_PLACEHOLDER);


@@ 539,7 539,7 @@ impl Compiler {
                self.loop_contexts
                    .push(LoopContext::new(self.instructions.len()));
                let pos_before_condition = self.instructions.len();
                self.compile_expression(&*condition)?;
                self.compile_expression(condition)?;

                let pos_jump_if_false = self.instructions.len();
                self.emit_opcode(OpCode::JumpIfFalse);


@@ 574,8 574,8 @@ impl Compiler {
                parameters,
                body,
            } => {
                let symbol = if name != "" {
                    Some(self.symbols.define(&name))
                let symbol = if !name.is_empty() {
                    Some(self.symbols.define(name))
                } else {
                    None
                };


@@ 587,7 587,7 @@ impl Compiler {
                // Compile function in a new scope
                self.symbols.new_context();
                for p in parameters {
                    self.symbols.define(&p);
                    self.symbols.define(p);
                }

                let pos_start_function = self.instructions.len();


@@ 642,7 642,7 @@ impl Compiler {
                        break 'compile_call;
                    }
                }
                self.compile_expression(&*left)?;
                self.compile_expression(left)?;
                self.emit_opcode(OpCode::Call);
                self.emit_u8(arguments.len().try_into().unwrap());
            }


@@ 656,8 656,8 @@ impl Compiler {
            }

            Expr::Index { left, index } => {
                self.compile_expression(&*left)?;
                self.compile_expression(&*index)?;
                self.compile_expression(left)?;
                self.compile_expression(index)?;
                self.emit_opcode(OpCode::IndexGet);
            }
        }


@@ 753,7 753,7 @@ pub(crate) fn bytecode_to_human(code: &[u8], positions: bool) -> String {
        }
        str.push_str(&op.to_string());

        if op.operands().len() > 0 {
        if !op.operands().is_empty() {
            str.push('(');
        }
        for (i, width) in op.operands().iter().enumerate() {


@@ 773,7 773,7 @@ pub(crate) fn bytecode_to_human(code: &[u8], positions: bool) -> String {
            };
            ip += width;
        }
        if op.operands().len() > 0 {
        if !op.operands().is_empty() {
            str.push(')');
        }


M src/object.rs => src/object.rs +23 -11
@@ 117,7 117,7 @@ impl Object {
    /// Note that is up to the caller to ensure this pointer is of the correct type
    #[inline(always)]
    pub fn as_bool(self) -> bool {
        ((self.0 as u8 >> VALUE_SHIFT_BITS) as u8) != 0
        (self.0 as u8 >> VALUE_SHIFT_BITS) != 0
    }

    /// Returns the integer value of this object pointer


@@ 152,6 152,9 @@ impl Object {
    }

    /// Returns the f64 value of this object pointer
    ///
    /// # Safety
    ///
    /// The caller should ensure this pointer points to an actual Float type
    #[inline]
    pub unsafe fn as_f64_unchecked(self) -> f64 {


@@ 173,13 176,16 @@ impl Object {
    }

    /// Returns the &str value of this object pointer
    ///
    /// # Safety
    ///
    /// The caller should ensure this pointer points to an actual String type
    #[inline]
    pub unsafe fn as_str_unchecked(&self) -> &str {
        self.get::<String>().value.as_str()
    }

    /// Returns a reference to the Vec<Pointer> value this pointer points to
    /// Returns a reference to the Vec<Object> value this pointer points to
    /// Panics if object does not point to an Array
    #[inline]
    pub fn as_vec(&self) -> &Vec<Object> {


@@ 187,14 193,17 @@ impl Object {
        unsafe { self.as_vec_unchecked() }
    }

    /// Returns a reference to the Vec<Pointer> value this pointer points to
    /// Returns a reference to the Vec<Object> value this pointer points to
    ///
    /// # Safety
    ///
    /// The caller should ensure this pointer actually points to an Array
    #[inline]
    pub unsafe fn as_vec_unchecked(&self) -> &Vec<Object> {
        Array::read(&self)
        Array::read(self)
    }

    /// Returns a mutable reference to the Vec<Pointer> value this pointer points to
    /// Returns a mutable reference to the Vec<Object> value this pointer points to
    /// Panics if object does not point to an Array
    #[inline]
    pub fn as_vec_mut(&mut self) -> &mut Vec<Object> {


@@ 202,7 211,10 @@ impl Object {
        unsafe { self.as_vec_unchecked_mut() }
    }

    /// Returns a mutable reference to the Vec<Pointer> value this pointer points to
    /// Returns a mutable reference to the Vec<Object> value this pointer points to
    ///
    /// # Safety
    ///
    /// The caller should ensure this pointer actually points to an Array
    #[inline]
    pub unsafe fn as_vec_unchecked_mut(&mut self) -> &mut Vec<Object> {


@@ 572,8 584,8 @@ mod tests {
        assert_eq!(Object::function(1, 1).tag(), Type::Function);
        assert_eq!(Object::function(1, 1).as_function(), [1, 1]);
        assert_eq!(
            Object::function(1, 0xFFFF as u16).as_function(),
            [1, 0xFFFF as u32]
            Object::function(1, 0xFFFF_u16).as_function(),
            [1, 0xFFFF_u32]
        );
        assert_eq!(
            Object::function(0xFFFFFFFF, 1).as_function(),


@@ 584,7 596,7 @@ mod tests {
    #[test]
    fn test_object_null() {
        assert_eq!(Object::null().tag(), Type::Null);
        assert!(Object::null().is_heap_allocated() == false);
        assert!(!Object::null().is_heap_allocated());
    }

    #[test]


@@ 598,8 610,8 @@ mod tests {
        assert_eq!(t.as_bool(), true);
        assert_eq!(f.as_bool(), false);

        assert!(t.is_heap_allocated() == false);
        assert!(f.is_heap_allocated() == false);
        assert!(!t.is_heap_allocated());
        assert!(!f.is_heap_allocated());
    }

    #[test]

M src/parser.rs => src/parser.rs +1 -1
@@ 108,7 108,7 @@ impl<'a> Parser<'a> {
        let right = self.parse_expr(precedence)?;
        Ok(Expr::Infix {
            left: Box::new(left),
            operator: operator,
            operator,
            right: Box::new(right),
        })
    }

M src/symbols.rs => src/symbols.rs +1 -1
@@ 27,7 27,7 @@ pub(crate) struct Context {
impl Context {
    fn new(scope: Scope) -> Self {
        Context {
            scope: scope,
            scope,
            max_size: 0,
            symbols: vec![Vec::new()],
        }

M src/vm.rs => src/vm.rs +23 -23
@@ 106,7 106,7 @@ impl VM {
    /// Performance: -25% over a regular call to `Vec::pop()`
    #[inline(always)]
    fn pop(&mut self) -> Object {
        debug_assert!(self.stack.is_empty() == false);
        debug_assert!(!self.stack.is_empty());

        // Safety: if the compiler and VM are implemented correctly, the stack will never be empty
        unsafe {


@@ 292,7 292,7 @@ impl VM {
                }?;

                    let pos = self.read_u16();
                    if evaluation == false {
                    if !evaluation {
                        self.jump(pos);
                    }
                }


@@ 359,14 359,14 @@ impl VM {
                    let [ip, num_locals] = obj.as_function();

                    // Make room on the stack for any local variables defined inside this function
                    for _ in 0..num_locals as u32 - num_args as u32 {
                    for _ in 0..num_locals - num_args as u32 {
                        self.push(Object::null());
                    }

                    self.pushframe(ip, base_pointer);
                }
                OpCode::CallBuiltin => {
                    let builtin = self.read_u8() as u8;
                    let builtin = self.read_u8();
                    let num_args = self.read_u8() as usize;
                    let mut args = Vec::with_capacity(num_args);
                    for _ in 0..num_args {


@@ 455,13 455,13 @@ fn index_get(left: Object, index: Object, gc: &mut GC) -> Result<Object, Error> 
fn index_get_array(obj: Object, mut index: isize) -> Result<Object, Error> {
    let array = obj.as_vec();
    if index < 0 {
        index = array.len() as isize + index;
        index += array.len() as isize;
    }
    let index = index as usize;
    if index >= array.len() {
        return Err(Error::IndexError(format!(
            "lijst index valt buiten de lijst"
        )));
        return Err(Error::IndexError(
            "lijst index valt buiten de lijst".to_string(),
        ));
    }

    Ok(array[index])


@@ 470,13 470,13 @@ fn index_get_array(obj: Object, mut index: isize) -> Result<Object, Error> {
fn index_get_string(obj: Object, mut index: isize, gc: &mut GC) -> Result<Object, Error> {
    let str = obj.as_str();
    if index < 0 {
        index = str.chars().count() as isize + index;
        index += str.chars().count() as isize;
    }
    let index = index as usize;
    if index >= str.len() {
        return Err(Error::IndexError(format!(
            "lijst index valt buiten de lijst"
        )));
        return Err(Error::IndexError(
            "lijst index valt buiten de lijst".to_string(),
        ));
    }

    let ch = str.chars().nth(index).unwrap();


@@ 507,13 507,13 @@ fn index_set(mut left: Object, index: Object, value: Object) -> Result<Object, E

fn index_set_array(array: &mut Vec<Object>, mut index: isize, value: Object) -> Result<(), Error> {
    if index < 0 {
        index = array.len() as isize + index;
        index += array.len() as isize;
    }
    let index = index as usize;
    if index >= array.len() {
        return Err(Error::IndexError(format!(
            "lijst index valt buiten de lijst"
        )));
        return Err(Error::IndexError(
            "lijst index valt buiten de lijst".to_string(),
        ));
    }
    array[index] = value;
    Ok(())


@@ 522,19 522,19 @@ fn index_set_array(array: &mut Vec<Object>, mut index: isize, value: Object) -> 
fn index_set_string(string: &mut String, mut index: isize, value: Object) -> Result<(), Error> {
    let strlen = string.chars().count();
    if index < 0 {
        index = strlen as isize + index;
        index += strlen as isize;
    }
    let index = index as usize;
    if index >= strlen {
        return Err(Error::IndexError(format!(
            "lijst index valt buiten de lijst"
        )));
        return Err(Error::IndexError(
            "lijst index valt buiten de lijst".to_string(),
        ));
    }

    if value.tag() != Type::String {
        return Err(Error::TypeError(format!(
            "kan geen niet-string invoegen op string object"
        )));
        return Err(Error::TypeError(
            "kan geen niet-string invoegen op string object".to_string(),
        ));
    }

    string.replace_range(

M tests/vm_test.rs => tests/vm_test.rs +3 -2
@@ 251,7 251,7 @@ fn test_function_vars() {

#[test]
fn test_named_functions() {
    assert!(10 as u32 as i64 as u32 == 10);
    assert!(10_u32 as i64 as u32 == 10);
    assert!(eval("stel a = 100; a();").is_err());
    assert!(eval("stel a = functie() { 1 }; a();").is_ok());



@@ 370,7 370,8 @@ fn test_gc_negate_float() {

#[test]
fn test_gc_float() {
    for (test, expected) in [("3.14 + 3.15", 3.14 + 3.15)] {
    {
        let (test, expected) = ("3.14 + 3.15", 3.14 + 3.15);
        let result = eval(test);
        assert!(result.is_ok());