diff --git a/clippy.toml b/clippy.toml index e2a9559..77fc7e2 100644 --- a/clippy.toml +++ b/clippy.toml @@ -2,5 +2,4 @@ disallowed-types = [ { path = "std::collections::HashMap", reason = "may be fxhash or siphash, depending on the feature, stay flexible" }, { path = "std::collections::HashSet", reason = "may be fxhash or siphash, depending on the feature, stay flexible" }, { path = "std::collections::Vec", reason = "we generally want to use bumpalos collections" }, - { path = "std::boxed::Box", reason = "we generally want to use bumpalos allocation" }, ] diff --git a/src/ast.rs b/src/ast.rs index 02e7a2e..752640c 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,5 +1,7 @@ //! //! The AST module contains all structs and enums for the abstract syntax tree generated by the parser +//! +//! All AST nodes are bump allocated into the lifetime `'ast` use crate::errors::Span; use crate::value::Symbol; diff --git a/src/bytecode.rs b/src/bytecode.rs index 5a36efa..f795a31 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -1,3 +1,5 @@ +//! The bytecode that is executed in the vm + use crate::errors::Span; use crate::value::{HashMap, Symbol}; use bumpalo::boxed::Box; diff --git a/src/compile.rs b/src/compile.rs index 5ecbcd8..741b17e 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,3 +1,5 @@ +//! The compiler that compiles the AST down to bytecode + use crate::ast::{ Assignment, BinaryOp, BinaryOpKind, Block, Call, Declaration, Expr, FnDecl, Ident, IfStmt, Literal, Program, Stmt, UnaryOp, WhileStmt, diff --git a/src/errors.rs b/src/errors.rs index 003755e..d8e4ae0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,10 @@ //! //! This modules handles error reporting in the interpreter +//! +//! The `span` submodule handles Spans, which are used for tracking locations in the source code. +//! +//! There is a single type `CompilerError` that can be created from anywhere, and reported using +//! functions from here. use std::fmt::Debug; diff --git a/src/lex.rs b/src/lex.rs index 72d2c54..4bc29f4 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -1,5 +1,8 @@ //! //! The lex module lexes the source code into Tokens +//! +//! For error handling, there is a single `Error` token, which contains the error. The lexer +//! is an iterator, and can therefore be used without any allocations use crate::errors::{CompilerError, Span}; use std::iter::Peekable; @@ -96,8 +99,8 @@ pub enum TokenKind<'code> { /// <= LessEqual, - /// An error occurred - Error(CompilerError), + /// An error occurred. It's boxed to save space, since `CompilerError` is > 6 `usize` big + Error(Box), } #[derive(Debug, Clone)] @@ -199,11 +202,11 @@ impl<'code> Iterator for Lexer<'code> { } else { Token::new( Span::single(start), - TokenKind::Error(CompilerError::with_note( + TokenKind::Error(Box::new(CompilerError::with_note( Span::single(start), "Expected '=' after '!'".to_string(), "If you meant to use it for negation, use `not`".to_string(), - )), + ))), ) }; } @@ -232,11 +235,11 @@ impl<'code> Iterator for Lexer<'code> { None => { return Some(Token::new( Span::single(start), - TokenKind::Error(CompilerError::with_note( + TokenKind::Error(Box::new(CompilerError::with_note( Span::single(start), // no not show the whole literal, this does not make sense "String literal not closed".to_string(), "Close the literal using '\"'".to_string(), - )), + ))), )); } } @@ -265,19 +268,19 @@ impl<'code> Iterator for Lexer<'code> { let number = number_str.parse::(); break match number { Ok(number) if number.is_infinite() => { - Token::new(span, TokenKind::Error(CompilerError::with_note( + Token::new(span, TokenKind::Error(Box::new(CompilerError::with_note( span, "Number literal too long".to_string(), "A number literal cannot be larger than a 64 bit float can represent" .to_string(), - ))) + )))) } Ok(number) => Token::new(span, TokenKind::Number(number)), - Err(err) => Token::new(span, TokenKind::Error(CompilerError::with_note( + Err(err) => Token::new(span, TokenKind::Error(Box::new(CompilerError::with_note( span, "Invalid number".to_string(), err.to_string(), - ))), + )))), }; } else if is_valid_ident_start(char) { // it must be an identifier @@ -297,12 +300,12 @@ impl<'code> Iterator for Lexer<'code> { } else { break Token::new( Span::single(start), - TokenKind::Error(CompilerError::with_note( + TokenKind::Error(Box::new(CompilerError::with_note( Span::single(start), format!("Unexpected character: '{}'", char), "Character is not allowed outside of string literals and comments" .to_string(), - )), + ))), ); } } diff --git a/src/parse.rs b/src/parse.rs index 2596468..c082fbd 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,3 +1,8 @@ +//! The parser implementation. +//! +//! It's a handwritten recursive descent parser. It has an internal peekable iterator from where +//! it gets its next tokens. Only a lookahead of one is required. + #[cfg(test)] mod test;