~dvko/nederlang

c050d629794d263f19ed56cee7b94eee6f6bdd5c — Danny van Kooten 1 year, 6 months ago 60a74c8 main
very minor restructuring of function order
5 files changed, 109 insertions(+), 115 deletions(-)

M Cargo.toml
M src/object.rs
M src/parser.rs
M src/symbols.rs
M src/vm.rs
M Cargo.toml => Cargo.toml +2 -1
@@ 13,9 13,10 @@ criterion =  {version = "0.3", default-features = false }

[profile.bench]
lto = true
debug = true

[profile.release]
debug = true
lto = true

# Criterion benchmarks:
[[bench]]

M src/object.rs => src/object.rs +1 -1
@@ 100,7 100,6 @@ impl Object {
    }

    /// Create a new function value
    #[inline]
    pub fn function(ip: u32, num_locals: u16) -> Self {
        let value = ((ip as isize) << 16) | num_locals as isize;
        Self::with_type((value << VALUE_SHIFT_BITS) as _, Type::Function)


@@ 564,6 563,7 @@ impl Display for Type {
}

/// Allocate a chunk of memory with the given layout
#[inline]
fn allocate(layout: Layout) -> *mut u8 {
    // Safety: we only call this function for types with a non-zero layout
    let ptr = unsafe { alloc(layout) };

M src/parser.rs => src/parser.rs +100 -101
@@ 61,11 61,110 @@ impl<'a> Parser<'a> {
        self.current_token = self.tokenizer.next().unwrap_or(Token::Illegal);
    }

    /// Assert current token is of the given type and skips it
    #[inline]
    fn skip(&mut self, t: Token) -> Result<(), ParseError> {
        if self.current_token != t {
            return Err(ParseError::SyntaxError(format!(
                "onverwachte token. verwacchte {t:?}, maar kreeg {:?}",
                self.current_token
            )));
        }
        self.advance();
        Ok(())
    }

    /// Skips the current token if it is of the given type
    #[inline]
    fn skip_optional(&mut self, t: Token) {
        if self.current_token == t {
            self.advance()
        }
    }

    /// Parses an operator token
    fn parse_operator(&mut self) -> Operator {
        Operator::from(self.current_token)
    }

    /// Parse an expression
    #[inline]
    fn parse_expr(&mut self, precedence: Precedence) -> Result<Expr, ParseError> {
        let mut left = match self.current_token {
            Token::Int(s) => self.parse_int_expression(s),
            Token::Float(s) => self.parse_float_expression(s),
            Token::True => self.parse_bool_expression(true),
            Token::False => self.parse_bool_expression(false),
            Token::String(s) => self.parse_string_expression(s),
            Token::OpenParen => {
                self.advance();
                let expr = self.parse_expr(Precedence::Lowest)?;
                self.skip(Token::CloseParen)?;
                expr
            }
            Token::If => self.parse_if_expr()?,
            Token::Bang | Token::Minus => self.parse_prefix_expr()?,
            Token::Identifier(name) => self.parse_ident(name),
            Token::Func => self.parse_function_expr()?,
            Token::While => self.parse_while_expr()?,
            Token::OpenBracket => self.parse_array_expr()?,
            _ => {
                return Err(ParseError::SyntaxError(format!(
                    "onverwachte token. verwachtte een expressie, maar kreeg {:?}",
                    self.current_token
                )))
            }
        };

        // keep going
        while self.current_token != Token::Semi && precedence < self.current_token.precedence() {
            left = match self.current_token {
                Token::Lt
                | Token::Lte
                | Token::Gt
                | Token::Gte
                | Token::Eq
                | Token::Neq
                | Token::Plus
                | Token::Minus
                | Token::Slash
                | Token::Star
                | Token::And
                | Token::Or
                | Token::Percent => self.parse_infix_expr(left)?,
                Token::Assign => self.parse_assign_expr(left)?,
                Token::OpenParen => self.parse_call_expr(left)?,
                Token::OpenBracket => self.parse_index_expr(left)?,
                _ => return Ok(left),
            };
        }

        Ok(left)
    }

    /// Parse a single statement
    #[inline]
    fn parse_statement(&mut self) -> Result<Stmt, ParseError> {
        let stmt = match self.current_token {
            Token::Declare => self.parse_decl_statement()?,
            Token::OpenBrace => Stmt::Block(self.parse_block_statement()?),
            Token::Return => self.parse_return_statement()?,
            Token::Continue => {
                self.advance();
                Stmt::Continue
            }
            Token::Break => {
                self.advance();
                Stmt::Break
            }
            _ => Stmt::Expr(self.parse_expr(Precedence::Lowest)?),
        };

        self.skip_optional(Token::Semi);

        Ok(stmt)
    }

    /// Parses OpAssign expressions, like a += 5
    /// This is just syntactic sugar, internally they are replaced by two seperate expression
    /// Perhaps this deserves its own specialized OpCode in the future to save some instructions


@@ 170,27 269,6 @@ impl<'a> Parser<'a> {
        })
    }

    /// Assert current token is of the given type and skips it
    #[inline]
    fn skip(&mut self, t: Token) -> Result<(), ParseError> {
        if self.current_token != t {
            return Err(ParseError::SyntaxError(format!(
                "onverwachte token. verwacchte {t:?}, maar kreeg {:?}",
                self.current_token
            )));
        }
        self.advance();
        Ok(())
    }

    /// Skips the current token if it is of the given type
    #[inline]
    fn skip_optional(&mut self, t: Token) {
        if self.current_token == t {
            self.advance()
        }
    }

    #[inline]
    fn parse_int_expression(&mut self, strval: &str) -> Expr {
        self.advance();


@@ 272,7 350,6 @@ impl<'a> Parser<'a> {
        })
    }

    #[inline]
    fn parse_ident(&mut self, name: &str) -> Expr {
        let expr = Expr::Identifier(name.to_owned());
        self.advance();


@@ 355,61 432,6 @@ impl<'a> Parser<'a> {
        })
    }

    /// Parse an expression
    #[inline]
    fn parse_expr(&mut self, precedence: Precedence) -> Result<Expr, ParseError> {
        let mut left = match self.current_token {
            Token::Int(s) => self.parse_int_expression(s),
            Token::Float(s) => self.parse_float_expression(s),
            Token::True => self.parse_bool_expression(true),
            Token::False => self.parse_bool_expression(false),
            Token::String(s) => self.parse_string_expression(s),
            Token::OpenParen => {
                self.advance();
                let expr = self.parse_expr(Precedence::Lowest)?;
                self.skip(Token::CloseParen)?;
                expr
            }
            Token::If => self.parse_if_expr()?,
            Token::Bang | Token::Minus => self.parse_prefix_expr()?,
            Token::Identifier(name) => self.parse_ident(name),
            Token::Func => self.parse_function_expr()?,
            Token::While => self.parse_while_expr()?,
            Token::OpenBracket => self.parse_array_expr()?,
            _ => {
                return Err(ParseError::SyntaxError(format!(
                    "onverwachte token. verwachtte een expressie, maar kreeg {:?}",
                    self.current_token
                )))
            }
        };

        // keep going
        while self.current_token != Token::Semi && precedence < self.current_token.precedence() {
            left = match self.current_token {
                Token::Lt
                | Token::Lte
                | Token::Gt
                | Token::Gte
                | Token::Eq
                | Token::Neq
                | Token::Plus
                | Token::Minus
                | Token::Slash
                | Token::Star
                | Token::And
                | Token::Or
                | Token::Percent => self.parse_infix_expr(left)?,
                Token::Assign => self.parse_assign_expr(left)?,
                Token::OpenParen => self.parse_call_expr(left)?,
                Token::OpenBracket => self.parse_index_expr(left)?,
                _ => return Ok(left),
            };
        }

        Ok(left)
    }

    fn parse_decl_statement(&mut self) -> Result<Stmt, ParseError> {
        // skip Token::Declare
        self.advance();


@@ 440,29 462,6 @@ impl<'a> Parser<'a> {
        Ok(Stmt::Return(expr))
    }

    /// Parse a single statement
    #[inline]
    fn parse_statement(&mut self) -> Result<Stmt, ParseError> {
        let stmt = match self.current_token {
            Token::Declare => self.parse_decl_statement()?,
            Token::OpenBrace => Stmt::Block(self.parse_block_statement()?),
            Token::Return => self.parse_return_statement()?,
            Token::Continue => {
                self.advance();
                Stmt::Continue
            }
            Token::Break => {
                self.advance();
                Stmt::Break
            }
            _ => Stmt::Expr(self.parse_expr(Precedence::Lowest)?),
        };

        self.skip_optional(Token::Semi);

        Ok(stmt)
    }

    /// Parse a block (surrounded by curly braces)
    /// Can be an unnamed block, function body, if consequence, etc.
    fn parse_block_statement(&mut self) -> Result<BlockStmt, ParseError> {


@@ 481,7 480,7 @@ impl<'a> Parser<'a> {
/// Parses the program string into an AST representation
pub fn parse(program: &str) -> Result<BlockStmt, ParseError> {
    let mut parser = Parser::new(program);
    let mut block = BlockStmt::with_capacity(64);
    let mut block = BlockStmt::new();

    while parser.current_token != Token::Illegal {
        block.push(parser.parse_statement()?);

M src/symbols.rs => src/symbols.rs +1 -6
@@ 58,6 58,7 @@ impl Context {
    }

    /// Resolves a symbol in this context along with its absolute index (relative to the context its top scope)
    #[inline]
    fn resolve(&self, name: &str) -> Option<Symbol> {
        let mut abs_index = self.total_len();
        for scope in self.symbols.iter().rev() {


@@ 83,40 84,34 @@ impl SymbolTable {
    }

    /// Returns a mutable reference to the current context
    #[inline(always)]
    fn current_context(&mut self) -> &mut Context {
        self.contexts.last_mut().unwrap()
    }

    /// Create a new context to define symbols in.
    /// This will always be a local context (as there is only one global context).
    #[inline]
    pub fn new_context(&mut self) {
        self.contexts.push(Context::new(Scope::Local));
    }

    /// Destroys the current context and returns the maximum number of symbols it had at some point in time.
    #[inline]
    pub fn leave_context(&mut self) -> usize {
        self.contexts.pop().unwrap().max_size()
    }

    /// Enter a new scope in the current context
    /// For example, at the start of a block statement.
    #[inline]
    pub fn enter_scope(&mut self) {
        self.current_context().symbols.push(Vec::new());
    }

    /// Leave scope in the current context.
    /// For example, at the end of a block statement.
    #[inline]
    pub fn leave_scope(&mut self) {
        self.current_context().symbols.pop().unwrap();
    }

    /// Define a symbol in the current context (and current scope within that context).
    #[inline]
    pub fn define(&mut self, name: &str) -> Symbol {
        self.current_context().define(name)
    }

M src/vm.rs => src/vm.rs +5 -6
@@ 85,7 85,7 @@ impl VM {
    }

    /// Sets the instruction pointer to the given value
    #[inline]
    #[inline(always)]
    fn jump(&mut self, ip: u16) {
        self.ip = ip as usize;
    }


@@ 286,13 286,12 @@ impl VM {
                }
                OpCode::JumpIfFalse => {
                    let condition = self.pop();
                    let evaluation = match condition.tag() {
                    Type::Bool => Ok(condition.as_bool()),
                    _ => Err(Error::TypeError(format!("kan object met type {} niet gebruiken als voorwaarde. Gebruik evt. bool() om te type casten naar boolean.", condition.tag()))),
                }?;
                    if condition.tag() != Type::Bool {
                        return Err(Error::TypeError(format!("kan object met type {} niet gebruiken als voorwaarde. Gebruik evt. bool() om te type casten naar boolean.", condition.tag())));
                    }

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