diff --git a/LICENSE b/LICENSE index 789d263..23f03a2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Devin Bidwell +Copyright (c) 2024-2025 Devin Bidwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/libs/compiler/src/v2.rs b/libs/compiler/src/v2.rs index 6ccc637..2f41ccd 100644 --- a/libs/compiler/src/v2.rs +++ b/libs/compiler/src/v2.rs @@ -34,7 +34,7 @@ quick_error! { ScopeError(error: variable_manager::Error) { from() } - DuplicateFunction(func_name: String) { + DuplicateIdentifier(func_name: String) { display("`{func_name}` has already been defined") } UnknownIdentifier(ident: String) { @@ -111,7 +111,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { match expr { Expression::Function(expr_func) => self.expression_function(expr_func, scope)?, Expression::Block(expr_block) => self.expression_block(expr_block, scope)?, - Expression::DeviceDeclaration(expr_dev) => self.expression_device(expr_dev), + Expression::DeviceDeclaration(expr_dev) => self.expression_device(expr_dev)?, Expression::Declaration(var_name, expr) => { self.expression_declaration(var_name, *expr, scope)? } @@ -258,8 +258,13 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { Ok(()) } - fn expression_device(&mut self, expr: DeviceDeclarationExpression) { + fn expression_device(&mut self, expr: DeviceDeclarationExpression) -> Result<(), Error> { + if self.devices.contains_key(&expr.name) { + return Err(Error::DuplicateIdentifier(expr.name)); + } self.devices.insert(expr.name, expr.device); + + Ok(()) } fn expression_block<'v>( @@ -293,6 +298,42 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { Ok(()) } + /// Takes the result of the expression and stores it in VariableScope::RETURN_REGISTER + fn expression_return<'v>( + &mut self, + expr: Expression, + scope: &mut VariableScope<'v>, + ) -> Result<(), Error> { + match expr { + Expression::Variable(var_name) => match scope.get_location_of(var_name)? { + VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => { + self.write_output(format!( + "move r{} r{reg} {}", + VariableScope::RETURN_REGISTER, + debug!(self, "returnValue") + ))?; + } + VariableLocation::Stack(offset) => { + self.write_output(format!( + "sub r{} sp {offset}", + VariableScope::TEMP_STACK_REGISTER + ))?; + self.write_output(format!( + "get r{} db r{}", + VariableScope::RETURN_REGISTER, + VariableScope::TEMP_STACK_REGISTER + ))?; + } + }, + Expression::Literal(Literal::Number(num)) => { + self.write_output(format!("move r{} {}", VariableScope::RETURN_REGISTER, num))?; + } + _ => return Err(Error::Unknown("Unsupported `return` statement.".into())), + } + + Ok(()) + } + /// Compile a function declaration. /// Calees are responsible for backing up any registers they wish to use. fn expression_function<'v>( @@ -307,7 +348,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { } = expr; if self.function_locations.contains_key(&name) { - return Err(Error::DuplicateFunction(name)); + return Err(Error::DuplicateIdentifier(name)); } self.function_metadata @@ -364,7 +405,15 @@ impl<'a, W: std::io::Write> Compiler<'a, W> { self.write_output("push ra")?; block_scope.add_variable(format!("{name}_ra"), LocationRequest::Stack)?; - self.expression_block(body, &mut block_scope)?; + for expr in body.0 { + match expr { + Expression::Return(ret_expr) => { + self.expression_return(*ret_expr, &mut block_scope)? + } + _ => self.expression(expr, &mut block_scope)?, + } + } + // Get the saved return address and save it back into `ra` let VariableLocation::Stack(ra_stack_offset) = block_scope.get_location_of(format!("{name}_ra"))? diff --git a/libs/compiler/src/variable_manager.rs b/libs/compiler/src/variable_manager.rs index 6892f03..ecf29ca 100644 --- a/libs/compiler/src/variable_manager.rs +++ b/libs/compiler/src/variable_manager.rs @@ -26,6 +26,7 @@ quick_error! { /// A request to store a variable at a specific register type pub enum LocationRequest { + #[allow(dead_code)] /// Request to store a variable in a temprary register. Temp, /// Request to store a variable in a persistant register. @@ -62,6 +63,7 @@ impl<'a> Default for VariableScope<'a> { } impl<'a> VariableScope<'a> { + #[allow(dead_code)] pub const TEMP_REGISTER_COUNT: u8 = 7; pub const PERSIST_REGISTER_COUNT: u8 = 7; @@ -94,10 +96,6 @@ impl<'a> VariableScope<'a> { 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( @@ -112,8 +110,7 @@ impl<'a> VariableScope<'a> { let var_location = match location { LocationRequest::Temp => { if let Some(next_var) = self.temporary_vars.pop_front() { - let loc = VariableLocation::Temporary(next_var); - loc + VariableLocation::Temporary(next_var) } else { let loc = VariableLocation::Stack(self.stack_offset); self.stack_offset += 1; @@ -122,8 +119,7 @@ impl<'a> VariableScope<'a> { } LocationRequest::Persist => { if let Some(next_var) = self.persistant_vars.pop_front() { - let loc = VariableLocation::Persistant(next_var); - loc + VariableLocation::Persistant(next_var) } else { let loc = VariableLocation::Stack(self.stack_offset); self.stack_offset += 1; @@ -149,7 +145,7 @@ impl<'a> VariableScope<'a> { let var = self .var_lookup_table .get(var_name.as_str()) - .map(|v| v.clone()) + .cloned() .ok_or(Error::UnknownVariable(var_name))?; if let VariableLocation::Stack(inserted_at_offset) = var { @@ -165,6 +161,7 @@ impl<'a> VariableScope<'a> { self.parent.is_some() } + #[allow(dead_code)] 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 {