From 4e6096fd3ffb845d8b77dcd824af1ad4e67627e3 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Tue, 18 Nov 2025 18:30:56 -0700 Subject: [PATCH] Rename error variants --- libs/compiler/src/lib.rs | 10 +- libs/compiler/src/test/mod.rs | 38 ++++++- libs/compiler/src/v2.rs | 85 +++++++++----- libs/compiler/src/variable_manager.rs | 155 ++++++++++++++++++++++++-- libs/parser/src/lib.rs | 116 +++++++++---------- libs/tokenizer/src/lib.rs | 55 ++++----- src/lib.rs | 6 +- src/main.rs | 10 +- 8 files changed, 330 insertions(+), 145 deletions(-) diff --git a/libs/compiler/src/lib.rs b/libs/compiler/src/lib.rs index 98910a9..4d1d570 100644 --- a/libs/compiler/src/lib.rs +++ b/libs/compiler/src/lib.rs @@ -11,10 +11,12 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::io::{BufWriter, Write}; +pub use v2::{Compiler, Error}; + quick_error! { #[derive(Debug)] pub enum CompileError { - ParseError(err: parser::ParseError) { + ParseError(err: parser::Error) { from() display("Parse error: {}", err) } @@ -43,7 +45,7 @@ quick_error! { } } -pub struct Compiler<'a, W: std::io::Write> { +pub struct CompilerV1<'a, W: std::io::Write> { parser: ASTParser, /// Max stack size for the program is by default 512. variable_scope: Vec>, @@ -54,7 +56,7 @@ pub struct Compiler<'a, W: std::io::Write> { declared_main: bool, } -impl<'a, W: std::io::Write> Compiler<'a, W> { +impl<'a, W: std::io::Write> CompilerV1<'a, W> { pub fn new(parser: ASTParser, writer: &'a mut BufWriter) -> Self { Self { parser, @@ -212,7 +214,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { self.variable_scope.push(HashMap::new()); fn perform_operation( - compiler: &mut Compiler, + compiler: &mut CompilerV1, op: &str, left: Expression, right: Expression, diff --git a/libs/compiler/src/test/mod.rs b/libs/compiler/src/test/mod.rs index ef883df..7200928 100644 --- a/libs/compiler/src/test/mod.rs +++ b/libs/compiler/src/test/mod.rs @@ -38,6 +38,36 @@ macro_rules! compile { }}; } +#[test] +fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> { + let compiled = compile!(debug r#" + // we need more than 4 params to 'spill' into a stack var + fn doSomething(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {}; + "#); + + assert_eq!( + compiled, + indoc! {" + j main + doSomething: + pop r8 #arg9 + pop r9 #arg8 + pop r10 #arg7 + pop r11 #arg6 + pop r12 #arg5 + pop r13 #arg4 + pop r14 #arg3 + pop r15 #arg2 + push ra + pop ra + sub sp 1 + j ra + "} + ); + + Ok(()) +} + #[test] fn test_function_declaration_with_register_params() -> anyhow::Result<()> { let compiled = compile!(debug r#" @@ -51,13 +81,9 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> { indoc! {" j main doSomething: + pop r8 #arg2 + pop r9 #arg1 push ra - push r4 - move r4 r0 #arg1 - push r5 - move r5 r1 #arg2 - pop r5 - pop r4 pop ra j ra "} diff --git a/libs/compiler/src/v2.rs b/libs/compiler/src/v2.rs index 7a8d4ce..2eec79f 100644 --- a/libs/compiler/src/v2.rs +++ b/libs/compiler/src/v2.rs @@ -1,3 +1,4 @@ +use crate::variable_manager::{self, LocationRequest, VariableLocation, VariableScope}; use parser::{ Parser as ASTParser, tree_node::{BlockExpression, Expression, FunctionExpression}, @@ -8,17 +9,18 @@ use std::{ io::{BufWriter, Write}, }; -use crate::variable_manager::VariableScope; - quick_error! { #[derive(Debug)] - pub enum CompilerError { - ParseError(error: parser::ParseError) { + pub enum Error { + ParseError(error: parser::Error) { from() } IoError(error: std::io::Error) { from() } + ScopeError(error: variable_manager::Error) { + from() + } DuplicateFunction(func_name: String) { display("{func_name} has already been defined") } @@ -60,7 +62,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { } } - pub fn compile(mut self) -> Result<(), CompilerError> { + pub fn compile(mut self) -> Result<(), Error> { let expr = self.parser.parse_all()?; let Some(expr) = expr else { return Ok(()) }; @@ -69,7 +71,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { self.expression(expr, &mut VariableScope::default()) } - fn write_output(&mut self, output: impl Into) -> Result<(), CompilerError> { + fn write_output(&mut self, output: impl Into) -> Result<(), Error> { self.output.write_all(output.into().as_bytes())?; self.output.write_all(b"\n")?; self.current_line += 1; @@ -80,7 +82,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { &mut self, expr: Expression, scope: &mut VariableScope<'v>, - ) -> Result<(), CompilerError> { + ) -> Result<(), Error> { match expr { Expression::Function(expr_func) => self.expression_function(expr_func, scope)?, Expression::Block(expr_block) => { @@ -96,7 +98,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { &mut self, mut expr: BlockExpression, scope: &mut VariableScope<'v>, - ) -> Result<(), CompilerError> { + ) -> Result<(), Error> { // First, sort the expressions to ensure functions are hoisted expr.0.sort_by(|a, b| { if matches!(b, Expression::Function(_)) && matches!(a, Expression::Function(_)) { @@ -120,11 +122,13 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { Ok(()) } + /// Compile a function declaration. + /// Calees are responsible for backing up any registers they wish to use. fn expression_function<'v>( &mut self, expr: FunctionExpression, scope: &mut VariableScope<'v>, - ) -> Result<(), CompilerError> { + ) -> Result<(), Error> { let FunctionExpression { name, arguments, @@ -132,38 +136,69 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { } = expr; if self.function_locations.contains_key(&name) { - return Err(CompilerError::DuplicateFunction(name)); + return Err(Error::DuplicateFunction(name)); } self.function_locations .insert(name.clone(), self.current_line); + // Declare the function as a line identifier self.write_output(format!("{}:", name))?; - self.write_output("push ra")?; + // Create a new block scope for the function body let mut block_scope = VariableScope::scoped(&scope); - for (index, var_name) in arguments.iter().enumerate() { - self.write_output(format!("push r{}", index + 4))?; - self.write_output(format!( - "move r{} r{} {}", - index + 4, - index, - if self.config.debug { - format!("#{}", var_name) - } else { - "".into() + let mut saved_variables = 0; + + // do a reverse pass to pop variables from the stack and put them into registers + for var_name in arguments + .iter() + .rev() + .take(VariableScope::PERSIST_REGISTER_COUNT as usize) + { + let loc = block_scope.add_variable(var_name, LocationRequest::Persist)?; + // we don't need to imcrement the stack offset as it's already on the stack from the + // previous scope + + match loc { + VariableLocation::Persistant(loc) => { + self.write_output(format!( + "pop r{loc} {}", + if self.config.debug { + format!("#{}", var_name) + } else { + "".into() + } + ))?; } - ))?; + VariableLocation::Stack(_) => { + unimplemented!("Attempted to save to stack without tracking in scope") + } + + _ => { + unimplemented!( + "Attempted to return a Temporary scoped variable from a Persistant request" + ) + } + } + saved_variables += 1; } + // now do a forward pass in case we have spilled into the stack. We don't need to push + // anything as they already exist on the stack, but we DO need to let our block_scope be + // aware that the variables exist on the stack (left to right) + for var_name in arguments.iter().take(arguments.len() - saved_variables) { + block_scope.add_variable(var_name, LocationRequest::Stack)?; + } + + self.write_output("push ra")?; self.expression_block(body, &mut block_scope)?; + self.write_output("pop ra")?; - for (indx, _) in arguments.iter().enumerate().rev() { - self.write_output(format!("pop r{}", indx + 4))?; + if block_scope.stack_offset() > 0 { + self.write_output(format!("sub sp {}", block_scope.stack_offset()))?; } - self.write_output("pop ra")?; self.write_output("j ra")?; Ok(()) } diff --git a/libs/compiler/src/variable_manager.rs b/libs/compiler/src/variable_manager.rs index 56189c6..fb34802 100644 --- a/libs/compiler/src/variable_manager.rs +++ b/libs/compiler/src/variable_manager.rs @@ -1,12 +1,28 @@ -// r0 - r3 : function arguments -// r4 - r9 : temporary variables -// r10 - r15 : persistant variables +// r0 - r7 : temporary variables +// r8 - r15 : persistant variables -use std::collections::HashMap; +use quick_error::quick_error; +use std::collections::{HashMap, VecDeque}; -enum VarType { - /// Represents a parameter register (r0 - r3) - Func(u8), +const TEMP: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +const PERSIST: [u8; 8] = [8, 9, 10, 11, 12, 13, 14, 15]; + +quick_error! { + #[derive(Debug)] + pub enum Error { + DuplicateVariable(var: String) { + display("{var} already exists.") + } + UnknownVariable(var: String) { + display("{var} does not exist.") + } + Unknown(reason: String) { + display("{reason}") + } + } +} + +pub enum VarType { /// Represents a temporary register (r4 - r8) Temp(u8), /// Represents a variable register (r9 - r15) @@ -15,19 +31,136 @@ enum VarType { Stack(u16), } -#[derive(Default)] +/// A request to store a variable at a specific register type +pub enum LocationRequest { + /// Request to store a variable in a temprary register. + Temp, + /// Request to store a variable in a persistant register. + Persist, + /// Request to store a variable in the stack. + Stack, +} + +#[derive(Clone)] +pub enum VariableLocation { + Temporary(u8), + Persistant(u8), + Stack(u16), +} + pub struct VariableScope<'a> { - stack: Vec>, - temp: HashMap<&'a str, u8>, - persist: HashMap<&'a str, u8>, + temporary_vars: VecDeque, + persistant_vars: VecDeque, + var_lookup_table: HashMap, + var_stack: HashMap, + stack_offset: u16, parent: Option<&'a VariableScope<'a>>, } +impl<'a> Default for VariableScope<'a> { + fn default() -> Self { + Self { + parent: None, + stack_offset: 0, + persistant_vars: PERSIST.to_vec().into(), + temporary_vars: TEMP.to_vec().into(), + var_stack: HashMap::new(), + var_lookup_table: HashMap::new(), + } + } +} + impl<'a> VariableScope<'a> { + pub const TEMP_REGISTER_COUNT: u8 = 8; + pub const PERSIST_REGISTER_COUNT: u8 = 8; + pub fn scoped(parent: &'a VariableScope<'a>) -> Self { Self { parent: Option::Some(parent), ..Default::default() } } + + pub fn stack_offset(&self) -> u16 { + self.stack_offset + } + + pub fn stack_incr(&mut self) { + self.stack_offset += 1; + } + + /// Adds and tracks a new scoped variable. If the location you request is full, will fall back + /// to the stack. + pub fn add_variable( + &mut self, + var_name: impl Into, + location: LocationRequest, + ) -> Result { + let var_name = var_name.into(); + if self.var_lookup_table.contains_key(var_name.as_str()) { + return Err(Error::DuplicateVariable(var_name)); + } + let var_location = match location { + LocationRequest::Temp => { + if let Some(next_var) = self.temporary_vars.pop_front() { + let loc = VariableLocation::Temporary(next_var); + loc + } else { + let loc = VariableLocation::Stack(self.stack_offset); + self.stack_offset += 1; + loc + } + } + LocationRequest::Persist => { + if let Some(next_var) = self.persistant_vars.pop_front() { + let loc = VariableLocation::Persistant(next_var); + loc + } else { + let loc = VariableLocation::Stack(self.stack_offset); + self.stack_offset += 1; + loc + } + } + LocationRequest::Stack => { + let loc = VariableLocation::Stack(self.stack_offset); + self.stack_offset += 1; + loc + } + }; + self.var_lookup_table.insert(var_name, var_location.clone()); + + Ok(var_location) + } + + pub fn get_location_of( + &mut self, + var_name: impl Into, + ) -> Result { + let var_name = var_name.into(); + self.var_lookup_table + .get(var_name.as_str()) + .map(|v| v.clone()) + .ok_or(Error::UnknownVariable(var_name)) + } + + pub fn free_temp(&mut self, var_name: impl Into) -> Result<(), Error> { + let var_name = var_name.into(); + let Some(location) = self.var_lookup_table.remove(var_name.as_str()) else { + return Err(Error::UnknownVariable(var_name)); + }; + + match location { + VariableLocation::Temporary(t) => { + self.temporary_vars.push_back(t); + } + VariableLocation::Persistant(_) => { + return Err(Error::UnknownVariable(String::from( + "Attempted to free a `let` variable.", + ))); + } + VariableLocation::Stack(_) => {} + }; + + Ok(()) + } } diff --git a/libs/parser/src/lib.rs b/libs/parser/src/lib.rs index d5c476f..5e597a6 100644 --- a/libs/parser/src/lib.rs +++ b/libs/parser/src/lib.rs @@ -5,7 +5,7 @@ use quick_error::quick_error; use std::io::SeekFrom; use sys_call::SysCall; use tokenizer::{ - Tokenizer, TokenizerBuffer, TokenizerError, + self, Tokenizer, TokenizerBuffer, token::{Keyword, Symbol, Token, TokenType}, }; use tree_node::*; @@ -20,8 +20,8 @@ macro_rules! boxed { quick_error! { #[derive(Debug)] - pub enum ParseError { - TokenizerError(err: TokenizerError) { + pub enum Error { + TokenizerError(err: tokenizer::Error) { from() display("Tokenizer Error: {}", err) source(err) @@ -57,7 +57,7 @@ macro_rules! token_from_option { ($token:expr) => { match $token { Some(ref token) => token.clone(), - None => return Err(ParseError::UnexpectedEOF), + None => return Err(Error::UnexpectedEOF), } }; } @@ -66,14 +66,14 @@ macro_rules! extract_token_data { ($token:ident, $pattern:pat, $extraction:expr) => { match $token.token_type { $pattern => $extraction, - _ => return Err(ParseError::UnexpectedToken($token.clone())), + _ => return Err(Error::UnexpectedToken($token.clone())), } }; ($token:expr, $pattern:pat, $extraction:expr) => { match $token.token_type { $pattern => $extraction, _ => { - return Err(ParseError::UnexpectedToken($token.clone())); + return Err(Error::UnexpectedToken($token.clone())); } } }; @@ -118,7 +118,7 @@ impl Parser { /// Parses all the input from the tokenizer buffer and returns the resulting expression /// Expressions are returned in a root block expression node - pub fn parse_all(&mut self) -> Result, ParseError> { + pub fn parse_all(&mut self) -> Result, Error> { let mut expressions = Vec::::new(); while let Some(expression) = self.parse()? { @@ -129,7 +129,7 @@ impl Parser { } /// Parses the input from the tokenizer buffer and returns the resulting expression - pub fn parse(&mut self) -> Result, ParseError> { + pub fn parse(&mut self) -> Result, Error> { self.assign_next()?; let expr = self.expression()?; @@ -141,18 +141,18 @@ impl Parser { } /// Assigns the next token in the tokenizer buffer to the current token - fn assign_next(&mut self) -> Result<(), ParseError> { + fn assign_next(&mut self) -> Result<(), Error> { self.current_token = self.tokenizer.next_token()?; Ok(()) } /// Calls `assign_next` and returns the next token in the tokenizer buffer - fn get_next(&mut self) -> Result, ParseError> { + fn get_next(&mut self) -> Result, Error> { self.assign_next()?; Ok(self.current_token.as_ref()) } - fn expression(&mut self) -> Result, ParseError> { + fn expression(&mut self) -> Result, Error> { macro_rules! matches_keyword { ($keyword:expr, $($pattern:pat),+) => { matches!($keyword, $($pattern)|+) @@ -172,7 +172,7 @@ impl Parser { TokenType::Keyword(e) if matches_keyword!(e, Keyword::Enum, Keyword::If, Keyword::Else) => { - return Err(ParseError::UnsupportedKeyword(current_token.clone())); + return Err(Error::UnsupportedKeyword(current_token.clone())); } // match declarations with a `let` keyword @@ -215,7 +215,7 @@ impl Parser { TokenType::Symbol(Symbol::LParen) => Expression::Priority(self.priority()?), _ => { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } }); @@ -237,7 +237,7 @@ impl Parser { Ok(Some(expr)) } - fn get_binary_child_node(&mut self) -> Result { + fn get_binary_child_node(&mut self) -> Result { let current_token = token_from_option!(self.current_token); match current_token.token_type { @@ -257,16 +257,16 @@ impl Parser { { self.invocation().map(Expression::Invocation) } - _ => Err(ParseError::UnexpectedToken(current_token.clone())), + _ => Err(Error::UnexpectedToken(current_token.clone())), } } - fn device(&mut self) -> Result { + fn device(&mut self) -> Result { // sanity check, make sure current token is a `device` keyword let current_token = token_from_option!(self.current_token); if !self_matches_current!(self, TokenType::Keyword(Keyword::Device)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } let identifier = extract_token_data!( @@ -277,7 +277,7 @@ impl Parser { let current_token = token_from_option!(self.get_next()?).clone(); if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { - return Err(ParseError::UnexpectedToken(current_token)); + return Err(Error::UnexpectedToken(current_token)); } let device = extract_token_data!( @@ -292,7 +292,7 @@ impl Parser { }) } - fn assignment(&mut self) -> Result { + fn assignment(&mut self) -> Result { let identifier = extract_token_data!( token_from_option!(self.current_token), TokenType::Identifier(ref id), @@ -301,11 +301,11 @@ impl Parser { let current_token = token_from_option!(self.get_next()?).clone(); if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { - return Err(ParseError::UnexpectedToken(current_token)); + return Err(Error::UnexpectedToken(current_token)); } self.assign_next()?; - let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; + let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; Ok(AssignmentExpression { identifier, @@ -314,7 +314,7 @@ impl Parser { } /// Handles mathmatical expressions in the explicit order of PEMDAS - fn binary(&mut self, previous: Expression) -> Result { + fn binary(&mut self, previous: Expression) -> Result { // We cannot use recursion here, as we need to handle the precedence of the operators // We need to use a loop to parse the binary expressions. @@ -330,7 +330,7 @@ impl Parser { | Expression::Negation(_) // -1 + 2 => {} _ => { - return Err(ParseError::InvalidSyntax(current_token.clone(), String::from("Invalid expression for binary operation"))) + return Err(Error::InvalidSyntax(current_token.clone(), String::from("Invalid expression for binary operation"))) } } @@ -352,7 +352,7 @@ impl Parser { // validate the vectors and make sure operators.len() == expressions.len() - 1 if operators.len() != expressions.len() - 1 { - return Err(ParseError::InvalidSyntax( + return Err(Error::InvalidSyntax( current_token.clone(), String::from("Invalid number of operators"), )); @@ -433,7 +433,7 @@ impl Parser { // Ensure there is only one expression left in the expressions vector, and no operators left if expressions.len() != 1 || !operators.is_empty() { - return Err(ParseError::InvalidSyntax( + return Err(Error::InvalidSyntax( current_token.clone(), String::from("Invalid number of operators"), )); @@ -454,24 +454,24 @@ impl Parser { } } - fn priority(&mut self) -> Result, ParseError> { + fn priority(&mut self) -> Result, Error> { let current_token = token_from_option!(self.current_token); if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } self.assign_next()?; - let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; + let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; let current_token = token_from_option!(self.get_next()?); if !token_matches!(current_token, TokenType::Symbol(Symbol::RParen)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } Ok(boxed!(expression)) } - fn invocation(&mut self) -> Result { + fn invocation(&mut self) -> Result { let identifier = extract_token_data!( token_from_option!(self.current_token), TokenType::Identifier(ref id), @@ -481,7 +481,7 @@ impl Parser { // Ensure the next token is a left parenthesis let current_token = token_from_option!(self.get_next()?); if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } let mut arguments = Vec::::new(); @@ -492,10 +492,10 @@ impl Parser { TokenType::Symbol(Symbol::RParen) ) { let current_token = token_from_option!(self.current_token); - let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; + let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; if let Expression::Block(_) = expression { - return Err(ParseError::InvalidSyntax( + return Err(Error::InvalidSyntax( current_token, String::from("Block expressions are not allowed in function invocations"), )); @@ -507,7 +507,7 @@ impl Parser { if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { - return Err(ParseError::UnexpectedToken( + return Err(Error::UnexpectedToken( token_from_option!(self.get_next()?).clone(), )); } @@ -527,20 +527,20 @@ impl Parser { }) } - fn block(&mut self) -> Result { + fn block(&mut self) -> Result { let mut expressions = Vec::::new(); let current_token = token_from_option!(self.current_token); // sanity check: make sure the current token is a left brace if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } while !self_matches_peek!( self, TokenType::Symbol(Symbol::RBrace) | TokenType::Keyword(Keyword::Return) ) { - let expression = self.parse()?.ok_or(ParseError::UnexpectedEOF)?; + let expression = self.parse()?.ok_or(Error::UnexpectedEOF)?; expressions.push(expression); } @@ -549,7 +549,7 @@ impl Parser { if token_matches!(current_token, TokenType::Keyword(Keyword::Return)) { self.assign_next()?; - let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; + let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; let return_expr = Expression::Return(boxed!(expression)); expressions.push(return_expr); self.assign_next()?; @@ -560,10 +560,10 @@ impl Parser { Ok(BlockExpression(expressions)) } - fn declaration(&mut self) -> Result { + fn declaration(&mut self) -> Result { let current_token = token_from_option!(self.current_token); if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } let identifier = extract_token_data!( token_from_option!(self.get_next()?), @@ -574,16 +574,16 @@ impl Parser { let current_token = token_from_option!(self.get_next()?).clone(); if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } self.assign_next()?; - let assignment_expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?; + let assignment_expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; // make sure the next token is a semi-colon let current_token = token_from_option!(self.get_next()?); if !token_matches!(current_token, TokenType::Symbol(Symbol::Semicolon)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } Ok(Expression::Declaration( @@ -592,22 +592,22 @@ impl Parser { )) } - fn literal(&mut self) -> Result { + fn literal(&mut self) -> Result { let current_token = token_from_option!(self.current_token); let literal = match current_token.token_type { TokenType::Number(num) => Literal::Number(num), TokenType::String(string) => Literal::String(string), - _ => return Err(ParseError::UnexpectedToken(current_token.clone())), + _ => return Err(Error::UnexpectedToken(current_token.clone())), }; Ok(literal) } - fn function(&mut self) -> Result { + fn function(&mut self) -> Result { let current_token = token_from_option!(self.current_token); // Sanify check that the current token is a `fn` keyword if !self_matches_current!(self, TokenType::Keyword(Keyword::Fn)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } let fn_ident = extract_token_data!( @@ -619,7 +619,7 @@ impl Parser { // make sure next token is a left parenthesis let current_token = token_from_option!(self.get_next()?); if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); } let mut arguments = Vec::::new(); @@ -635,7 +635,7 @@ impl Parser { extract_token_data!(current_token, TokenType::Identifier(ref id), id.clone()); if arguments.contains(&argument) { - return Err(ParseError::DuplicateIdentifier(current_token.clone())); + return Err(Error::DuplicateIdentifier(current_token.clone())); } arguments.push(argument); @@ -644,7 +644,7 @@ impl Parser { if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { - return Err(ParseError::UnexpectedToken( + return Err(Error::UnexpectedToken( token_from_option!(self.get_next()?).clone(), )); } @@ -661,7 +661,7 @@ impl Parser { // make sure the next token is a left brace let current_token = token_from_option!(self.get_next()?); if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { - return Err(ParseError::UnexpectedToken(current_token.clone())); + return Err(Error::UnexpectedToken(current_token.clone())); }; Ok(FunctionExpression { @@ -671,15 +671,15 @@ impl Parser { }) } - fn syscall(&mut self) -> Result { + fn syscall(&mut self) -> Result { /// Checks the length of the arguments and returns an error if the length is not equal to the expected length fn check_length( parser: &Parser, arguments: &[Expression], length: usize, - ) -> Result<(), ParseError> { + ) -> Result<(), Error> { if arguments.len() != length { - return Err(ParseError::InvalidSyntax( + return Err(Error::InvalidSyntax( token_from_option!(parser.current_token).clone(), format!("Expected {} arguments", length), )); @@ -695,7 +695,7 @@ impl Parser { } Some(Expression::Variable(ident)) => LiteralOrVariable::Variable(ident.clone()), _ => { - return Err(ParseError::UnexpectedToken( + return Err(Error::UnexpectedToken( token_from_option!(self.current_token).clone(), )) } @@ -709,7 +709,7 @@ impl Parser { match $arg { LiteralOrVariable::$matcher(i) => i, _ => { - return Err(ParseError::InvalidSyntax( + return Err(Error::InvalidSyntax( token_from_option!(self.current_token).clone(), String::from("Expected a variable"), )) @@ -737,7 +737,7 @@ impl Parser { let device = literal_or_variable!(args.next()); let Some(Expression::Literal(Literal::String(variable))) = args.next() else { - return Err(ParseError::UnexpectedToken( + return Err(Error::UnexpectedToken( token_from_option!(self.current_token).clone(), )); }; @@ -756,7 +756,7 @@ impl Parser { let Literal::String(logic_type) = get_arg!(Literal, literal_or_variable!(args.next())) else { - return Err(ParseError::UnexpectedToken( + return Err(Error::UnexpectedToken( token_from_option!(self.current_token).clone(), )); }; diff --git a/libs/tokenizer/src/lib.rs b/libs/tokenizer/src/lib.rs index 47b2c17..215d053 100644 --- a/libs/tokenizer/src/lib.rs +++ b/libs/tokenizer/src/lib.rs @@ -12,7 +12,7 @@ use token::{Keyword, Number, Symbol, Temperature, Token, TokenType}; quick_error! { #[derive(Debug)] - pub enum TokenizerError { + pub enum Error { IOError(err: std::io::Error) { from() display("IO Error: {}", err) @@ -48,7 +48,7 @@ pub struct Tokenizer { } impl Tokenizer { - pub fn from_path(input_file: impl Into) -> Result { + pub fn from_path(input_file: impl Into) -> Result { let file = std::fs::File::open(input_file.into())?; let reader = BufReader::new(Box::new(file) as Box); @@ -83,7 +83,7 @@ impl Tokenizer { /// /// # Important /// This function will increment the line and column counters - fn next_char(&mut self) -> Result, TokenizerError> { + fn next_char(&mut self) -> Result, Error> { let bytes_read = self.reader.read(&mut self.char_buffer)?; if bytes_read == 0 { @@ -106,7 +106,7 @@ impl Tokenizer { /// /// # Important /// This does not increment the line or column counters - fn peek_next_char(&mut self) -> Result, TokenizerError> { + fn peek_next_char(&mut self) -> Result, Error> { let current_pos = self.reader.stream_position()?; let to_return = if self.reader.read(&mut self.char_buffer)? == 0 { @@ -126,7 +126,7 @@ impl Tokenizer { /// /// # Important /// This function will increment the line and column counters - fn skip_line(&mut self) -> Result<(), TokenizerError> { + fn skip_line(&mut self) -> Result<(), Error> { while let Some(next_char) = self.next_char()? { if next_char == '\n' { break; @@ -137,7 +137,7 @@ impl Tokenizer { /// Consumes the tokenizer and returns the next token in the stream /// If there are no more tokens in the stream, this function returns None - pub fn next_token(&mut self) -> Result, TokenizerError> { + pub fn next_token(&mut self) -> Result, Error> { while let Some(next_char) = self.next_char()? { // skip whitespace if next_char.is_whitespace() { @@ -165,11 +165,7 @@ impl Tokenizer { return self.tokenize_keyword_or_identifier(next_char).map(Some); } _ => { - return Err(TokenizerError::UnknownSymbolError( - next_char, - self.line, - self.column, - )); + return Err(Error::UnknownSymbolError(next_char, self.line, self.column)); } } } @@ -183,7 +179,7 @@ impl Tokenizer { /// Peeks the next token in the stream without consuming it /// If there are no more tokens in the stream, this function returns None - pub fn peek_next(&mut self) -> Result, TokenizerError> { + pub fn peek_next(&mut self) -> Result, Error> { let current_pos = self.reader.stream_position()?; let column = self.column; let line = self.line; @@ -196,7 +192,7 @@ impl Tokenizer { } /// Tokenizes a symbol - fn tokenize_symbol(&mut self, first_symbol: char) -> Result { + fn tokenize_symbol(&mut self, first_symbol: char) -> Result { /// Helper macro to create a symbol token macro_rules! symbol { ($symbol:ident) => { @@ -266,7 +262,7 @@ impl Tokenizer { symbol!(LogicalOr) } - _ => Err(TokenizerError::UnknownSymbolError( + _ => Err(Error::UnknownSymbolError( first_symbol, self.line, self.column, @@ -275,7 +271,7 @@ impl Tokenizer { } /// Tokenizes a number literal. Also handles temperatures with a suffix of `c`, `f`, or `k`. - fn tokenize_number(&mut self, first_char: char) -> Result { + fn tokenize_number(&mut self, first_char: char) -> Result { let mut primary = String::with_capacity(16); let mut decimal: Option = None; let mut reading_decimal = false; @@ -319,16 +315,16 @@ impl Tokenizer { let decimal_scale = decimal.len() as u32; let number = format!("{}{}", primary, decimal) .parse::() - .map_err(|e| TokenizerError::NumberParseError(e, self.line, self.column))?; + .map_err(|e| Error::NumberParseError(e, self.line, self.column))?; Number::Decimal( Decimal::try_from_i128_with_scale(number, decimal_scale) - .map_err(|e| TokenizerError::DecimalParseError(e, line, column))?, + .map_err(|e| Error::DecimalParseError(e, line, column))?, ) } else { Number::Integer( primary .parse() - .map_err(|e| TokenizerError::NumberParseError(e, line, column))?, + .map_err(|e| Error::NumberParseError(e, line, column))?, ) }; @@ -350,7 +346,7 @@ impl Tokenizer { } /// Tokenizes a string literal - fn tokenize_string(&mut self, beginning_quote: char) -> Result { + fn tokenize_string(&mut self, beginning_quote: char) -> Result { let mut buffer = String::with_capacity(16); let column = self.column; @@ -368,10 +364,7 @@ impl Tokenizer { } /// Tokenizes a keyword or an identifier. Also handles boolean literals - fn tokenize_keyword_or_identifier( - &mut self, - first_char: char, - ) -> Result { + fn tokenize_keyword_or_identifier(&mut self, first_char: char) -> Result { macro_rules! keyword { ($keyword:ident) => {{ return Ok(Token::new( @@ -441,9 +434,7 @@ impl Tokenizer { looped_char = self.next_char()?; } - Err(TokenizerError::UnknownKeywordOrIdentifierError( - buffer, line, column, - )) + Err(Error::UnknownKeywordOrIdentifierError(buffer, line, column)) } } @@ -464,7 +455,7 @@ impl TokenizerBuffer { /// Reads the next token from the tokenizer, pushing the value to the back of the history /// and returning the token - pub fn next_token(&mut self) -> Result, TokenizerError> { + pub fn next_token(&mut self) -> Result, Error> { if let Some(token) = self.buffer.pop_front() { self.history.push_back(token.clone()); return Ok(Some(token)); @@ -478,7 +469,7 @@ impl TokenizerBuffer { } /// Peeks the next token in the stream without adding to the history stack - pub fn peek(&mut self) -> Result, TokenizerError> { + pub fn peek(&mut self) -> Result, Error> { if let Some(token) = self.buffer.front() { return Ok(Some(token.clone())); } @@ -487,7 +478,7 @@ impl TokenizerBuffer { Ok(token) } - fn seek_from_current(&mut self, seek_to: i64) -> Result<(), TokenizerError> { + fn seek_from_current(&mut self, seek_to: i64) -> Result<(), Error> { use Ordering::*; // if seek_to > 0 then we need to check if the buffer has enough tokens to pop, otherwise we need to read from the tokenizer // if seek_to < 0 then we need to pop from the history and push to the front of the buffer. If not enough, then we throw (we reached the front of the history) @@ -500,7 +491,7 @@ impl TokenizerBuffer { if let Some(token) = self.tokenizer.next_token()? { tokens.push(token); } else { - return Err(TokenizerError::IOError(std::io::Error::new( + return Err(Error::IOError(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, "Unexpected EOF", ))); @@ -515,7 +506,7 @@ impl TokenizerBuffer { if let Some(token) = self.history.pop_back() { tokens.push(token); } else { - return Err(TokenizerError::IOError(std::io::Error::new( + return Err(Error::IOError(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, "Unexpected EOF", ))); @@ -530,7 +521,7 @@ impl TokenizerBuffer { } /// Adds to or removes from the History stack, allowing the user to move back and forth in the stream - pub fn seek(&mut self, from: SeekFrom) -> Result<(), TokenizerError> { + pub fn seek(&mut self, from: SeekFrom) -> Result<(), Error> { match from { SeekFrom::Current(seek_to) => self.seek_from_current(seek_to)?, SeekFrom::End(_) => unimplemented!("SeekFrom::End will not be implemented"), diff --git a/src/lib.rs b/src/lib.rs index c023443..68a5650 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,14 +9,12 @@ fn compile_from_string( input: &safer_ffi::string::String, output: &mut safer_ffi::string::String, ) -> bool { - let buffer = Vec::::new(); - - let mut writer = BufWriter::new(buffer); + let mut writer = BufWriter::new(Vec::new()); let tokenizer = Tokenizer::from(input.to_string()); let parser = Parser::new(tokenizer); - let compiler = Compiler::new(parser, &mut writer); + let compiler = Compiler::new(parser, &mut writer, None); let Ok(()) = compiler.compile() else { return false; diff --git a/src/main.rs b/src/main.rs index a549747..f93734a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,20 +9,20 @@ use std::{ io::{BufWriter, Read, Write}, path::PathBuf, }; -use tokenizer::{Tokenizer, TokenizerError}; +use tokenizer::{self, Tokenizer}; quick_error! { #[derive(Debug)] enum StationlangError { - TokenizerError(err: TokenizerError) { + TokenizerError(err: tokenizer::Error) { from() display("Tokenizer error: {}", err) } - ParserError(err: parser::ParseError) { + ParserError(err: parser::Error) { from() display("Parser error: {}", err) } - CompileError(err: compiler::CompileError) { + CompileError(err: compiler::Error) { from() display("Compile error: {}", err) } @@ -71,7 +71,7 @@ fn run_logic() -> Result<(), StationlangError> { None => BufWriter::new(Box::new(std::io::stdout())), }; - let compiler = Compiler::new(parser, &mut writer); + let compiler = Compiler::new(parser, &mut writer, None); compiler.compile()?; writer.flush()?;