diff --git a/src/callable.rs b/src/callable.rs index 2d3898f..1a62e5f 100644 --- a/src/callable.rs +++ b/src/callable.rs @@ -13,7 +13,7 @@ pub enum CallingError { CallInterpretationFailed(String), } -/// Implementations can be called. +/// Interface for callable objects in Lox (functions, methods, classes). pub trait Callable { fn name(&self) -> String; fn arity(&self) -> usize; diff --git a/src/class.rs b/src/class.rs index 0137772..0ca34a4 100644 --- a/src/class.rs +++ b/src/class.rs @@ -21,6 +21,7 @@ impl Display for Class { } impl Class { + /// Create a new class with the given name, optional superclass, and methods. pub fn new( name: String, superclass: Option, @@ -35,6 +36,8 @@ impl Class { } } + /// Find a method by name in this class or any of its superclasses. + /// This is method inheritance. pub fn find_method(&self, name: &str) -> Option<&Function> { self.methods.get(name).or_else(|| { if let Some(superclass) = &self.superclass { diff --git a/src/cli.rs b/src/cli.rs index b797c57..f766d41 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -13,6 +13,7 @@ pub struct Cli { pub command: Commands, } +/// Configuration for running a Lox source file #[derive(Args, Clone)] pub struct RunConfig { /// Path to Lox source file. @@ -20,6 +21,7 @@ pub struct RunConfig { pub source: PathBuf, } +/// Available commands for the Lox interpreter #[derive(Subcommand)] pub enum Commands { /// Run a Lox source file. diff --git a/src/environment.rs b/src/environment.rs index d73e75e..edfd980 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -12,8 +12,11 @@ pub enum EnvironmentError { InvalidDistance, } -/// Environment mapping variable names to their respective values. Can have an optional enclosing -/// environment. The outermost (global) environment has no enclosing one. +/// Environment mapping variable names to their respective values. +/// Can have an optional enclosing environment. The outermost (global) +/// environment has no enclosing one. +/// +/// This is for lexical scoping. #[derive(Default, Debug, Clone)] pub struct Environment { values: HashMap, @@ -52,6 +55,8 @@ impl Environment { } } + /// Assign a value to a variable at a specific lexical distance (number of scopes away). + /// Used by the resolver to handle closures correctly. pub fn assign_at( &mut self, distance: usize, @@ -79,6 +84,8 @@ impl Environment { } } + /// Get a variable's value from an environment at a specific lexical distance. + /// Used by the resolver to handle closures correctly. pub fn get_at(&self, distance: usize, token: &Token) -> Result { if let Some(v) = self.ancestor(distance)?.values.get(token.lexeme.as_str()) { Ok(v.clone()) @@ -90,6 +97,7 @@ impl Environment { } } + /// Find an environment at a specific lexical distance from the current one. fn ancestor(&self, distance: usize) -> Result { let mut environment = self.clone(); diff --git a/src/expression.rs b/src/expression.rs index 844e710..3b72c8a 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,6 +1,6 @@ use crate::token::{self, Token}; -/// Enumeration of all types of expressions. +/// Enumeration of all types of expressions in the Lox language. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Expression { Assign { diff --git a/src/function.rs b/src/function.rs index ce24846..385fd76 100644 --- a/src/function.rs +++ b/src/function.rs @@ -10,7 +10,7 @@ use crate::{ use core::fmt::Debug; use std::{cell::RefCell, fmt::Display, rc::Rc}; -/// A lox function. +/// A Lox function with name, parameters, body, and closure environment. #[derive(Debug, Clone)] pub struct Function { pub name: Token, @@ -62,6 +62,8 @@ impl Callable for Function { } impl Function { + /// Bind a method to an instance, creating a new function with "this" defined in its environment. + /// This allows methods to access the instance they belong to. pub fn bind(&self, instance: Rc>) -> Self { let mut env = Environment::with_enclosing(self.closure.clone()); env.define("this".to_string(), Value::Instance(instance)); diff --git a/src/instance.rs b/src/instance.rs index e9edd19..60f6581 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -14,6 +14,7 @@ pub enum InstanceError { NoSuchProperty(usize, String), } +/// An instance of a Lox class, containing fields and access to methods. #[derive(Debug, Clone, PartialEq)] pub struct Instance { class: Class, @@ -27,6 +28,7 @@ impl Display for Instance { } impl Instance { + /// Create a new instance of a class with empty fields. pub fn new(class: Class) -> Rc> { Rc::new(RefCell::new(Self { class, @@ -34,6 +36,8 @@ impl Instance { })) } + /// Get a property from this instance. First check for the name in fields, then methods. + /// If a method is found, bind it to this instance. pub fn get(&self, name: &Token, instance: Rc>) -> Result { if let Some(field) = self.fields.get(name.lexeme.as_str()) { Ok(field.clone()) @@ -50,6 +54,7 @@ impl Instance { } } + /// Set a field on this instance to the given value. pub fn set(&mut self, name: &Token, value: Value) { self.fields.insert(name.lexeme.clone(), value); } diff --git a/src/interpreter.rs b/src/interpreter.rs index f0b730f..7176892 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -46,7 +46,7 @@ pub enum InterpreterError { EnvironmentError(#[from] crate::environment::EnvironmentError), } -/// Interpreter for the Lox language. +/// Interpreter for the Lox language that executes statements and evaluates expressions. #[derive(Debug)] pub struct Interpreter { pub globals: Rc>, @@ -126,7 +126,7 @@ impl Interpreter { } /// Execute all statements within a block, using a new environment (with the old one as the - /// enclosing one). Immediately return the value if a Return Value is encountered after + /// enclosing one). Immediately return the value of a Return Value when it is encountered after /// execution of a statement. pub fn block( &mut self, diff --git a/src/native_functions.rs b/src/native_functions.rs index aaeb6cb..73438cf 100644 --- a/src/native_functions.rs +++ b/src/native_functions.rs @@ -11,6 +11,7 @@ use crate::{ value::{CallableType, Value}, }; +/// Native clock function that returns the current time in seconds since the Unix epoch struct Clock; impl Callable for Clock { @@ -22,6 +23,7 @@ impl Callable for Clock { 0 } + /// Return the current system time in seconds since the Unix epoch fn call( &self, _interpreter: &mut Interpreter, @@ -36,6 +38,7 @@ impl Callable for Clock { } } +/// Return all native functions available to the Lox interpreter pub fn all() -> Vec<(String, Value)> { vec![( "clock".into(), diff --git a/src/parser.rs b/src/parser.rs index 76e8d5a..04a0809 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -71,7 +71,7 @@ pub enum ParserError { SuperclassMethodNameExpected(usize), } -/// Parse the Lox language. +/// Parse the Lox language tokens into an abstract syntax tree. #[derive(Debug, Clone)] struct Parser { current: usize, @@ -655,7 +655,8 @@ impl Parser { } } -/// Try to parse the provided tokens into an AST. +/// Try to parse the provided tokens into an Abstract Syntax Tree (AST). +/// Return a list of statements that can be executed by the interpreter. pub fn ast(tokens: Vec) -> Result, ParserError> { let mut parser = Parser::new(tokens)?; parser.run() diff --git a/src/resolver.rs b/src/resolver.rs index 7e2ac1d..1bea277 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -37,6 +37,7 @@ enum ClassType { Subclass, } +/// Resolve variable references and performs static analysis before interpretation. #[derive(Debug)] pub struct Resolver<'a> { scopes: Vec>, diff --git a/src/statement.rs b/src/statement.rs index fc892af..5871e98 100644 --- a/src/statement.rs +++ b/src/statement.rs @@ -1,6 +1,6 @@ use crate::{expression::Expression, token::Token}; -/// Enumeration of all types of statements. +/// Enumeration of all types of statements in the Lox language. #[derive(Debug, Clone, PartialEq)] pub enum Statement { Block(Vec), diff --git a/src/token.rs b/src/token.rs index 7b5e7e6..8630b01 100644 --- a/src/token.rs +++ b/src/token.rs @@ -56,12 +56,13 @@ pub enum TokenType { Eof, } -/// Literal value. +/// Literal value in the Lox language. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Literal { /// String literal. String(String), - // Number literal, represented as f64 (thus it can be decimal). + /// Number literal, represented as f64 (thus it can be decimal). + /// Must be Ord, otherwise I need to rewrite the locals implementation in the interpreter. Number(OrderedFloat), /// Boolean literal. Boolean(bool), @@ -78,7 +79,7 @@ pub struct Token { pub lexeme: String, /// Literal value of the token, if any. pub literal: Option, - /// Starting line on which the token was oonsumed from the source. + /// Starting line on which the token was consumed from the source. pub line: usize, } diff --git a/src/tokenizer/comment.rs b/src/tokenizer/comment.rs index 1e01267..335e246 100644 --- a/src/tokenizer/comment.rs +++ b/src/tokenizer/comment.rs @@ -5,10 +5,10 @@ use crate::token::Token; use super::interface::Tokenizer; -/// Consume comments. +/// Consume comments in the source code. /// /// A comment starts with '//' and runs until the end of the line. -/// If only one '/' is seen, it is consumed as a Slash token. +/// If only one '/' is seen, it is consumed as a Slash token instead. pub struct Comment; impl Tokenizer for Comment { fn run( diff --git a/src/tokenizer/identifier.rs b/src/tokenizer/identifier.rs index e4aea6d..f681dd5 100644 --- a/src/tokenizer/identifier.rs +++ b/src/tokenizer/identifier.rs @@ -8,8 +8,8 @@ use super::interface::Tokenizer; /// Consume an identifier which also might be a keyword. /// -/// An identifier starts with an alphabetic character and goes on consuming alphanumeric and -/// underscore characters until the first different one. +/// An identifier starts with an alphabetic character or underscore and continues with +/// alphanumeric and underscore characters until the first different character. pub struct Identifier; impl Tokenizer for Identifier { fn run( diff --git a/src/tokenizer/interface.rs b/src/tokenizer/interface.rs index 2d851a0..80b874d 100644 --- a/src/tokenizer/interface.rs +++ b/src/tokenizer/interface.rs @@ -2,7 +2,8 @@ use std::{iter::Peekable, str::CharIndices}; use crate::token::Token; -/// Interface to implement by a tokenizer. +/// Interface to implement by a tokenizer. Each tokenizer handles a specific type of token +/// in the Lox language. pub trait Tokenizer: Send + Sync { /// Take a tuple consisting of the index of a char and the char itself, the whole source code /// iterator, the source itself and the current line. Return None if you can not handle the diff --git a/src/tokenizer/lookahead.rs b/src/tokenizer/lookahead.rs index 3277180..552a4c4 100644 --- a/src/tokenizer/lookahead.rs +++ b/src/tokenizer/lookahead.rs @@ -63,6 +63,7 @@ lazy_static! { } /// Consume lexemes that consist of exactly one or two characters. +/// Handles operators like !=, ==, <=, and >=. pub struct Lookahead; impl Tokenizer for Lookahead { fn run( diff --git a/src/tokenizer/number.rs b/src/tokenizer/number.rs index 17a8b19..9823a9a 100644 --- a/src/tokenizer/number.rs +++ b/src/tokenizer/number.rs @@ -5,7 +5,8 @@ use tracing::error; use super::interface::Tokenizer; -/// Consume a number literal. Numbers can have one decimal point. +/// Consume a number literal from the source code. +/// Numbers can have one decimal point and consist of one or more digits. pub struct Number; impl Tokenizer for Number { fn run( diff --git a/src/tokenizer/string.rs b/src/tokenizer/string.rs index 2c30e7f..6e88730 100644 --- a/src/tokenizer/string.rs +++ b/src/tokenizer/string.rs @@ -3,9 +3,10 @@ use crate::token::{Literal, Token, TokenType}; use std::{iter::Peekable, str::CharIndices}; use tracing::error; -/// Consume a string literal. +/// Consume a string literal from the source code. /// -/// A string literal consists of everything between two '"' and can stretch across multiple lines. +/// A string literal consists of everything between two double quotes (") +/// and can stretch across multiple lines. pub struct String; impl Tokenizer for String { fn run( diff --git a/src/tokenizer/whitespace.rs b/src/tokenizer/whitespace.rs index a462217..58ad5d6 100644 --- a/src/tokenizer/whitespace.rs +++ b/src/tokenizer/whitespace.rs @@ -2,7 +2,7 @@ use super::interface::Tokenizer; use crate::token::Token; use std::{iter::Peekable, str::CharIndices}; -/// Consume and ignore whitespace characters. +/// Consume and ignore whitespace characters (spaces, tabs, carriage returns). pub struct Whitespace; impl Tokenizer for Whitespace { fn run( diff --git a/src/value.rs b/src/value.rs index e96c7fd..db858a5 100644 --- a/src/value.rs +++ b/src/value.rs @@ -4,21 +4,31 @@ use ordered_float::OrderedFloat; use crate::{callable::Callable, instance, token::Literal}; +/// Represents the type of a callable value in Lox. #[derive(Clone, Debug, PartialEq)] pub enum CallableType { + /// A regular function or method Function, + /// A class (which is callable to create instances) Class(crate::class::Class), } -/// Concrete value in the interpreter. +/// Concrete runtime value in the Lox interpreter. #[derive(Clone, Debug, PartialEq)] pub enum Value { + /// Special value for function returns Return(Box), + /// Function, method, or class Callable((Rc, CallableType)), + /// String value String(String), + /// Numeric value Number(OrderedFloat), + /// Boolean value Boolean(bool), + /// Class instance Instance(Rc>), + /// Nil value (null) Nil, } @@ -37,6 +47,7 @@ impl Display for Value { } impl Value { + /// Determine if a value is "truthy" according to Lox rules. /// Return false for nil or a false boolean, true otherwise. pub fn is_truthy(&self) -> bool { match self {