VariableManager lifetime errors

This commit is contained in:
2025-12-09 16:05:40 -07:00
parent f54214acb9
commit c3986ab4d9
3 changed files with 281 additions and 232 deletions

View File

@@ -12,6 +12,7 @@ use parser::{
}, },
}; };
use std::{ use std::{
borrow::Cow,
collections::HashMap, collections::HashMap,
io::{BufWriter, Write}, io::{BufWriter, Write},
}; };
@@ -36,7 +37,10 @@ macro_rules! debug {
}; };
} }
fn extract_literal(literal: Literal, allow_strings: bool) -> Result<String, Error> { fn extract_literal<'a>(
literal: Literal<'a>,
allow_strings: bool,
) -> Result<Cow<'a, str>, Error<'a>> {
if !allow_strings && matches!(literal, Literal::String(_)) { if !allow_strings && matches!(literal, Literal::String(_)) {
return Err(Error::Unknown( return Err(Error::Unknown(
"Literal strings are not allowed in this context".to_string(), "Literal strings are not allowed in this context".to_string(),
@@ -45,45 +49,45 @@ fn extract_literal(literal: Literal, allow_strings: bool) -> Result<String, Erro
} }
Ok(match literal { Ok(match literal {
Literal::String(s) => s, Literal::String(s) => s,
Literal::Number(n) => n.to_string(), Literal::Number(n) => Cow::from(n.to_string()),
Literal::Boolean(b) => if b { "1" } else { "0" }.into(), Literal::Boolean(b) => Cow::from(if b { "1" } else { "0" }),
}) })
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum Error<'a> {
#[error(transparent)] #[error("{0}")]
Parse(#[from] parser::Error), Parse(parser::Error<'a>),
#[error(transparent)] #[error("{0}")]
Scope(#[from] variable_manager::Error), Scope(variable_manager::Error<'a>),
#[error("IO Error: {0}")] #[error("IO Error: {0}")]
IO(String), IO(String),
#[error("`{0}` has already been defined.")] #[error("`{0}` has already been defined.")]
DuplicateIdentifier(String, Span), DuplicateIdentifier(Cow<'a, str>, Span),
#[error("`{0}` is not found in the current scope.")] #[error("`{0}` is not found in the current scope.")]
UnknownIdentifier(String, Span), UnknownIdentifier(Cow<'a, str>, Span),
#[error("`{0}` is not valid.")] #[error("`{0}` is not valid.")]
InvalidDevice(String, Span), InvalidDevice(Cow<'a, str>, Span),
#[error("Incorrent number of arguments passed into `{0}`")] #[error("Incorrent number of arguments passed into `{0}`")]
AgrumentMismatch(String, Span), AgrumentMismatch(Cow<'a, str>, Span),
#[error("Attempted to re-assign a value to const variable `{0}`")] #[error("Attempted to re-assign a value to const variable `{0}`")]
ConstAssignment(String, Span), ConstAssignment(Cow<'a, str>, Span),
#[error("Attempted to re-assign a value to a device const `{0}`")] #[error("Attempted to re-assign a value to a device const `{0}`")]
DeviceAssignment(String, Span), DeviceAssignment(Cow<'a, str>, Span),
#[error("{0}")] #[error("{0}")]
Unknown(String, Option<Span>), Unknown(String, Option<Span>),
} }
impl From<Error> for lsp_types::Diagnostic { impl<'a> From<Error<'a>> for lsp_types::Diagnostic {
fn from(value: Error) -> Self { fn from(value: Error) -> Self {
use Error::*; use Error::*;
use lsp_types::*; use lsp_types::*;
@@ -116,8 +120,20 @@ impl From<Error> for lsp_types::Diagnostic {
} }
} }
impl<'a> From<parser::Error<'a>> for Error<'a> {
fn from(value: parser::Error<'a>) -> Self {
Self::Parse(value)
}
}
impl<'a> From<variable_manager::Error<'a>> for Error<'a> {
fn from(value: variable_manager::Error<'a>) -> Self {
Self::Scope(value)
}
}
// Map io::Error to Error manually since we can't clone io::Error // Map io::Error to Error manually since we can't clone io::Error
impl From<std::io::Error> for Error { impl<'a> From<std::io::Error> for Error<'a> {
fn from(err: std::io::Error) -> Self { fn from(err: std::io::Error) -> Self {
Error::IO(err.to_string()) Error::IO(err.to_string())
} }
@@ -129,26 +145,26 @@ pub struct CompilerConfig {
pub debug: bool, pub debug: bool,
} }
struct CompilationResult { struct CompilationResult<'a> {
location: VariableLocation, location: VariableLocation<'a>,
/// If Some, this is the name of the temporary variable that holds the result. /// If Some, this is the name of the temporary variable that holds the result.
/// It must be freed by the caller when done. /// It must be freed by the caller when done.
temp_name: Option<String>, temp_name: Option<Cow<'a, str>>,
} }
pub struct Compiler<'a, W: std::io::Write> { pub struct Compiler<'a, W: std::io::Write> {
pub parser: ASTParser<'a>, pub parser: ASTParser<'a>,
function_locations: HashMap<String, usize>, function_locations: HashMap<Cow<'a, str>, usize>,
function_metadata: HashMap<String, Vec<String>>, function_metadata: HashMap<Cow<'a, str>, Vec<Cow<'a, str>>>,
devices: HashMap<String, String>, devices: HashMap<Cow<'a, str>, Cow<'a, str>>,
output: &'a mut BufWriter<W>, output: &'a mut BufWriter<W>,
current_line: usize, current_line: usize,
declared_main: bool, declared_main: bool,
config: CompilerConfig, config: CompilerConfig,
temp_counter: usize, temp_counter: usize,
label_counter: usize, label_counter: usize,
loop_stack: Vec<(String, String)>, // Stores (start_label, end_label) loop_stack: Vec<(Cow<'a, str>, Cow<'a, str>)>, // Stores (start_label, end_label)
pub errors: Vec<Error>, pub errors: Vec<Error<'a>>,
} }
impl<'a, W: std::io::Write> Compiler<'a, W> { impl<'a, W: std::io::Write> Compiler<'a, W> {
@@ -173,7 +189,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
pub fn compile(mut self) -> Vec<Error> { pub fn compile(mut self) -> Vec<Error<'a>> {
let expr = self.parser.parse_all(); let expr = self.parser.parse_all();
// Copy errors from parser // Copy errors from parser
@@ -211,15 +227,17 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
return self.errors; return self.errors;
} }
let mut scope = VariableScope::default();
// We ignore the result of the root expression (usually a block) // We ignore the result of the root expression (usually a block)
if let Err(e) = self.expression(spanned_root, &mut VariableScope::default()) { if let Err(e) = self.expression(spanned_root, &mut scope) {
self.errors.push(e); self.errors.push(e);
} }
self.errors self.errors
} }
fn write_output(&mut self, output: impl Into<String>) -> Result<(), Error> { fn write_output(&mut self, output: impl Into<String>) -> Result<(), Error<'a>> {
self.output.write_all(output.into().as_bytes())?; self.output.write_all(output.into().as_bytes())?;
self.output.write_all(b"\n")?; self.output.write_all(b"\n")?;
self.current_line += 1; self.current_line += 1;
@@ -227,21 +245,21 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn next_temp_name(&mut self) -> String { fn next_temp_name(&mut self) -> Cow<'a, str> {
self.temp_counter += 1; self.temp_counter += 1;
format!("__binary_temp_{}", self.temp_counter) Cow::from(format!("__binary_temp_{}", self.temp_counter))
} }
fn next_label_name(&mut self) -> String { fn next_label_name(&mut self) -> Cow<'a, str> {
self.label_counter += 1; self.label_counter += 1;
format!("L{}", self.label_counter) Cow::from(format!("L{}", self.label_counter))
} }
fn expression<'v>( fn expression(
&mut self, &mut self,
expr: Spanned<Expression>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<Option<CompilationResult>, Error> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
match expr.node { match expr.node {
Expression::Function(expr_func) => { Expression::Function(expr_func) => {
self.expression_function(expr_func, scope)?; self.expression_function(expr_func, scope)?;
@@ -300,11 +318,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// Invocation returns result in r15 (RETURN_REGISTER). // Invocation returns result in r15 (RETURN_REGISTER).
// If used as an expression, we must move it to a temp to avoid overwrite. // If used as an expression, we must move it to a temp to avoid overwrite.
let temp_name = self.next_temp_name(); let temp_name = self.next_temp_name();
let temp_loc = scope.add_variable(&temp_name, LocationRequest::Temp, None)?; let temp_loc =
scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?;
self.emit_variable_assignment( self.emit_variable_assignment(
&temp_name, temp_name.clone(),
&temp_loc, &temp_loc,
format!("r{}", VariableScope::RETURN_REGISTER), Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)),
)?; )?;
Ok(Some(CompilationResult { Ok(Some(CompilationResult {
location: temp_loc, location: temp_loc,
@@ -322,8 +341,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Expression::Literal(spanned_lit) => match spanned_lit.node { Expression::Literal(spanned_lit) => match spanned_lit.node {
Literal::Number(num) => { Literal::Number(num) => {
let temp_name = self.next_temp_name(); let temp_name = self.next_temp_name();
let loc = scope.add_variable(&temp_name, LocationRequest::Temp, None)?; let loc = scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?;
self.emit_variable_assignment(&temp_name, &loc, num.to_string())?; self.emit_variable_assignment(
temp_name.clone(),
&loc,
Cow::from(num.to_string()),
)?;
Ok(Some(CompilationResult { Ok(Some(CompilationResult {
location: loc, location: loc,
temp_name: Some(temp_name), temp_name: Some(temp_name),
@@ -332,8 +355,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Literal::Boolean(b) => { Literal::Boolean(b) => {
let val = if b { "1" } else { "0" }; let val = if b { "1" } else { "0" };
let temp_name = self.next_temp_name(); let temp_name = self.next_temp_name();
let loc = scope.add_variable(&temp_name, LocationRequest::Temp, None)?; let loc = scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?;
self.emit_variable_assignment(&temp_name, &loc, val)?; self.emit_variable_assignment(temp_name.clone(), &loc, Cow::from(val))?;
Ok(Some(CompilationResult { Ok(Some(CompilationResult {
location: loc, location: loc,
temp_name: Some(temp_name), temp_name: Some(temp_name),
@@ -374,7 +397,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// 2. Allocate a temp register for the result // 2. Allocate a temp register for the result
let result_name = self.next_temp_name(); let result_name = self.next_temp_name();
let loc = scope.add_variable(&result_name, LocationRequest::Temp, None)?; let loc = scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?;
let reg = self.resolve_register(&loc)?; let reg = self.resolve_register(&loc)?;
// 3. Emit load instruction: l rX device member // 3. Emit load instruction: l rX device member
@@ -406,7 +429,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// Compile negation as 0 - inner // Compile negation as 0 - inner
let (inner_str, cleanup) = self.compile_operand(*inner_expr, scope)?; let (inner_str, cleanup) = self.compile_operand(*inner_expr, scope)?;
let result_name = self.next_temp_name(); let result_name = self.next_temp_name();
let result_loc = scope.add_variable(&result_name, LocationRequest::Temp, None)?; let result_loc =
scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?;
let result_reg = self.resolve_register(&result_loc)?; let result_reg = self.resolve_register(&result_loc)?;
self.write_output(format!("sub {result_reg} 0 {inner_str}"))?; self.write_output(format!("sub {result_reg} 0 {inner_str}"))?;
@@ -432,11 +456,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
/// Resolves an expression to a device identifier string for use in instructions like `s` or `l`. /// Resolves an expression to a device identifier string for use in instructions like `s` or `l`.
/// Returns (device_string, optional_cleanup_temp_name). /// Returns (device_string, optional_cleanup_temp_name).
fn resolve_device<'v>( fn resolve_device(
&mut self, &mut self,
expr: Spanned<Expression>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(String, Option<String>), Error> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
// If it's a direct variable reference, check if it's a known device alias first // If it's a direct variable reference, check if it's a known device alias first
if let Expression::Variable(ref name) = expr.node if let Expression::Variable(ref name) = expr.node
&& let Some(device_id) = self.devices.get(&name.node) && let Some(device_id) = self.devices.get(&name.node)
@@ -450,10 +474,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn emit_variable_assignment( fn emit_variable_assignment(
&mut self, &mut self,
var_name: &str, var_name: Cow<'a, str>,
location: &VariableLocation, location: &VariableLocation<'a>,
source_value: impl Into<String>, source_value: Cow<'a, str>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let debug_tag = if self.config.debug { let debug_tag = if self.config.debug {
format!(" #{var_name}") format!(" #{var_name}")
} else { } else {
@@ -462,10 +486,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
match location { match location {
VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => { VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => {
self.write_output(format!("move r{reg} {}{debug_tag}", source_value.into()))?; self.write_output(format!("move r{reg} {}{debug_tag}", source_value))?;
} }
VariableLocation::Stack(_) => { VariableLocation::Stack(_) => {
self.write_output(format!("push {}{debug_tag}", source_value.into()))?; self.write_output(format!("push {}{debug_tag}", source_value))?;
} }
VariableLocation::Constant(_) => { VariableLocation::Constant(_) => {
return Err(Error::Unknown( return Err(Error::Unknown(
@@ -488,12 +512,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_declaration<'v>( fn expression_declaration(
&mut self, &mut self,
var_name: Spanned<String>, var_name: Spanned<Cow<'a, str>>,
expr: Spanned<Expression>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<Option<CompilationResult>, Error> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
let name_str = var_name.node; let name_str = var_name.node;
let name_span = var_name.span; let name_span = var_name.span;
@@ -502,8 +526,13 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
&& let Expression::Literal(spanned_lit) = &box_expr.node && let Expression::Literal(spanned_lit) = &box_expr.node
&& let Literal::Number(neg_num) = &spanned_lit.node && let Literal::Number(neg_num) = &spanned_lit.node
{ {
let loc = scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; let loc =
self.emit_variable_assignment(&name_str, &loc, format!("-{neg_num}"))?; scope.add_variable(name_str.clone(), LocationRequest::Persist, Some(name_span))?;
self.emit_variable_assignment(
name_str.clone(),
&loc,
Cow::from(format!("-{neg_num}")),
)?;
return Ok(Some(CompilationResult { return Ok(Some(CompilationResult {
location: loc, location: loc,
temp_name: None, temp_name: None,
@@ -519,7 +548,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Some(name_span), Some(name_span),
)?; )?;
self.emit_variable_assignment(&name_str, &var_location, num)?; self.emit_variable_assignment(
name_str.clone(),
&var_location,
Cow::from(num.to_string()),
)?;
(var_location, None) (var_location, None)
} }
Literal::Boolean(b) => { Literal::Boolean(b) => {
@@ -530,7 +563,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Some(name_span), Some(name_span),
)?; )?;
self.emit_variable_assignment(&name_str, &var_location, val)?; self.emit_variable_assignment(name_str, &var_location, Cow::from(val))?;
(var_location, None) (var_location, None)
} }
_ => return Ok(None), _ => return Ok(None),
@@ -538,12 +571,15 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Expression::Invocation(invoke_expr) => { Expression::Invocation(invoke_expr) => {
self.expression_function_invocation(invoke_expr, scope)?; self.expression_function_invocation(invoke_expr, scope)?;
let loc = let loc = scope.add_variable(
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
self.emit_variable_assignment( self.emit_variable_assignment(
&name_str, name_str,
&loc, &loc,
format!("r{}", VariableScope::RETURN_REGISTER), Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)),
)?; )?;
(loc, None) (loc, None)
} }
@@ -564,11 +600,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}; };
let loc = let loc =
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?;
self.emit_variable_assignment( self.emit_variable_assignment(
&name_str, name_str,
&loc, &loc,
format!("r{}", VariableScope::RETURN_REGISTER), Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)),
)?; )?;
(loc, None) (loc, None)
@@ -577,19 +613,19 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Expression::Binary(bin_expr) => { Expression::Binary(bin_expr) => {
let result = self.expression_binary(bin_expr, scope)?; let result = self.expression_binary(bin_expr, scope)?;
let var_loc = let var_loc =
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?;
if let CompilationResult { if let CompilationResult {
location: VariableLocation::Constant(Literal::Number(num)), location: VariableLocation::Constant(Literal::Number(num)),
.. ..
} = result } = result
{ {
self.emit_variable_assignment(&name_str, &var_loc, num)?; self.emit_variable_assignment(name_str, &var_loc, Cow::from(num.to_string()))?;
(var_loc, None) (var_loc, None)
} else { } else {
// Move result from temp to new persistent variable // Move result from temp to new persistent variable
let result_reg = self.resolve_register(&result.location)?; let result_reg = self.resolve_register(&result.location)?;
self.emit_variable_assignment(&name_str, &var_loc, result_reg)?; self.emit_variable_assignment(name_str, &var_loc, result_reg)?;
// Free the temp result // Free the temp result
if let Some(name) = result.temp_name { if let Some(name) = result.temp_name {
@@ -601,11 +637,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Expression::Logical(log_expr) => { Expression::Logical(log_expr) => {
let result = self.expression_logical(log_expr, scope)?; let result = self.expression_logical(log_expr, scope)?;
let var_loc = let var_loc =
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?;
// Move result from temp to new persistent variable // Move result from temp to new persistent variable
let result_reg = self.resolve_register(&result.location)?; let result_reg = self.resolve_register(&result.location)?;
self.emit_variable_assignment(&name_str, &var_loc, result_reg)?; self.emit_variable_assignment(name_str, &var_loc, result_reg)?;
// Free the temp result // Free the temp result
if let Some(name) = result.temp_name { if let Some(name) = result.temp_name {
@@ -626,7 +662,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}; };
let var_loc = let var_loc =
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?;
// Handle loading from stack if necessary // Handle loading from stack if necessary
let src_str = match src_loc { let src_str = match src_loc {
@@ -646,7 +682,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
VariableLocation::Constant(_) | VariableLocation::Device(_) => unreachable!(), VariableLocation::Constant(_) | VariableLocation::Device(_) => unreachable!(),
}; };
self.emit_variable_assignment(&name_str, &var_loc, src_str)?; self.emit_variable_assignment(name_str, &var_loc, Cow::from(src_str))?;
(var_loc, None) (var_loc, None)
} }
Expression::Priority(inner) => { Expression::Priority(inner) => {
@@ -678,10 +714,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}; };
let var_loc = let var_loc =
scope.add_variable(&name_str, LocationRequest::Persist, Some(name_span))?; scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?;
let result_reg = self.resolve_register(&comp_res.location)?; let result_reg = self.resolve_register(&comp_res.location)?;
self.emit_variable_assignment(&name_str, &var_loc, result_reg)?; self.emit_variable_assignment(name_str, &var_loc, result_reg)?;
if let Some(temp) = comp_res.temp_name { if let Some(temp) = comp_res.temp_name {
scope.free_temp(temp, None)?; scope.free_temp(temp, None)?;
@@ -703,11 +739,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
})) }))
} }
fn expression_const_declaration<'v>( fn expression_const_declaration(
&mut self, &mut self,
expr: ConstDeclarationExpression, expr: ConstDeclarationExpression<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<CompilationResult, Error> { ) -> Result<CompilationResult<'a>, Error<'a>> {
let ConstDeclarationExpression { let ConstDeclarationExpression {
name: const_name, name: const_name,
value: const_value, value: const_value,
@@ -738,11 +774,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}) })
} }
fn expression_assignment<'v>( fn expression_assignment(
&mut self, &mut self,
expr: AssignmentExpression, expr: AssignmentExpression<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let AssignmentExpression { let AssignmentExpression {
assignee, assignee,
expression, expression,
@@ -828,9 +864,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_function_invocation( fn expression_function_invocation(
&mut self, &mut self,
invoke_expr: Spanned<InvocationExpression>, invoke_expr: Spanned<InvocationExpression<'a>>,
stack: &mut VariableScope, stack: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let InvocationExpression { name, arguments } = invoke_expr.node; let InvocationExpression { name, arguments } = invoke_expr.node;
if !self.function_locations.contains_key(&name.node) { if !self.function_locations.contains_key(&name.node) {
@@ -845,12 +881,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
let Some(args) = self.function_metadata.get(&name.node) else { let Some(args) = self.function_metadata.get(&name.node) else {
// Should be covered by check above // Should be covered by check above
return Err(Error::UnknownIdentifier(name.node.clone(), name.span)); return Err(Error::UnknownIdentifier(name.node, name.span));
}; };
if args.len() != arguments.len() { if args.len() != arguments.len() {
self.errors self.errors
.push(Error::AgrumentMismatch(name.node.clone(), name.span)); .push(Error::AgrumentMismatch(name.node, name.span));
// Proceed anyway? The assembly will likely crash or act weird. // Proceed anyway? The assembly will likely crash or act weird.
// Best to skip generation of this call to prevent bad IC10 // Best to skip generation of this call to prevent bad IC10
return Ok(()); return Ok(());
@@ -859,7 +895,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// backup all used registers to the stack // backup all used registers to the stack
let active_registers = stack.registers().cloned().collect::<Vec<_>>(); let active_registers = stack.registers().cloned().collect::<Vec<_>>();
for register in &active_registers { for register in &active_registers {
stack.add_variable(format!("temp_{register}"), LocationRequest::Stack, None)?; stack.add_variable(
Cow::from(format!("temp_{register}")),
LocationRequest::Stack,
None,
)?;
self.write_output(format!("push r{register}"))?; self.write_output(format!("push r{register}"))?;
} }
for arg in arguments { for arg in arguments {
@@ -876,8 +916,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
_ => {} _ => {}
}, },
Expression::Variable(var_name) => { Expression::Variable(var_name) => {
let loc = let loc = match stack.get_location_of(&var_name.node, Some(var_name.span)) {
match stack.get_location_of(var_name.node.clone(), Some(var_name.span)) {
Ok(l) => l, Ok(l) => l,
Err(_) => { Err(_) => {
self.errors self.errors
@@ -975,7 +1014,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
for register in active_registers { for register in active_registers {
let VariableLocation::Stack(stack_offset) = stack let VariableLocation::Stack(stack_offset) = stack
.get_location_of(format!("temp_{register}"), None) .get_location_of(&Cow::from(format!("temp_{register}")), None)
.map_err(Error::Scope)? .map_err(Error::Scope)?
else { else {
// This shouldn't happen if we just added it // This shouldn't happen if we just added it
@@ -1001,7 +1040,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_device(&mut self, expr: DeviceDeclarationExpression) -> Result<(), Error> { fn expression_device(
&mut self,
expr: DeviceDeclarationExpression<'a>,
) -> Result<(), Error<'a>> {
if self.devices.contains_key(&expr.name.node) { if self.devices.contains_key(&expr.name.node) {
self.errors.push(Error::DuplicateIdentifier( self.errors.push(Error::DuplicateIdentifier(
expr.name.node.clone(), expr.name.node.clone(),
@@ -1017,11 +1059,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_if<'v>( fn expression_if(
&mut self, &mut self,
expr: IfExpression, expr: IfExpression<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let end_label = self.next_label_name(); let end_label = self.next_label_name();
let else_label = if expr.else_branch.is_some() { let else_label = if expr.else_branch.is_some() {
self.next_label_name() self.next_label_name()
@@ -1064,11 +1106,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_loop<'v>( fn expression_loop(
&mut self, &mut self,
expr: LoopExpression, expr: LoopExpression<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let start_label = self.next_label_name(); let start_label = self.next_label_name();
let end_label = self.next_label_name(); let end_label = self.next_label_name();
@@ -1090,11 +1132,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_while<'v>( fn expression_while(
&mut self, &mut self,
expr: WhileExpression, expr: WhileExpression<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let start_label = self.next_label_name(); let start_label = self.next_label_name();
let end_label = self.next_label_name(); let end_label = self.next_label_name();
@@ -1126,7 +1168,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Ok(()) Ok(())
} }
fn expression_break(&mut self) -> Result<(), Error> { fn expression_break(&mut self) -> Result<(), Error<'a>> {
if let Some((_, end_label)) = self.loop_stack.last() { if let Some((_, end_label)) = self.loop_stack.last() {
self.write_output(format!("j {end_label}"))?; self.write_output(format!("j {end_label}"))?;
Ok(()) Ok(())
@@ -1138,7 +1180,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
fn expression_continue(&mut self) -> Result<(), Error> { fn expression_continue(&mut self) -> Result<(), Error<'a>> {
if let Some((start_label, _)) = self.loop_stack.last() { if let Some((start_label, _)) = self.loop_stack.last() {
self.write_output(format!("j {start_label}"))?; self.write_output(format!("j {start_label}"))?;
Ok(()) Ok(())
@@ -1153,9 +1195,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
/// Helper to resolve a location to a register string (e.g., "r0"). /// Helper to resolve a location to a register string (e.g., "r0").
/// Note: This does not handle Stack locations automatically, as they require /// Note: This does not handle Stack locations automatically, as they require
/// instruction emission to load. Use `compile_operand` for general handling. /// instruction emission to load. Use `compile_operand` for general handling.
fn resolve_register(&self, loc: &VariableLocation) -> Result<String, Error> { fn resolve_register(&self, loc: &VariableLocation) -> Result<Cow<'a, str>, Error<'a>> {
match loc { match loc {
VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => Ok(format!("r{r}")), VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => {
Ok(Cow::from(format!("r{r}")))
}
VariableLocation::Constant(_) => Err(Error::Unknown( VariableLocation::Constant(_) => Err(Error::Unknown(
"Cannot resolve a constant value to register".into(), "Cannot resolve a constant value to register".into(),
None, None,
@@ -1177,19 +1221,19 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
/// so the caller can free it. /// so the caller can free it.
fn compile_operand( fn compile_operand(
&mut self, &mut self,
expr: Spanned<Expression>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope, scope: &mut VariableScope<'a>,
) -> Result<(String, Option<String>), Error> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
// Optimization for literals // Optimization for literals
if let Expression::Literal(spanned_lit) = &expr.node { if let Expression::Literal(spanned_lit) = &expr.node {
if let Literal::Number(n) = spanned_lit.node { if let Literal::Number(n) = spanned_lit.node {
return Ok((n.to_string(), None)); return Ok((Cow::from(n.to_string()), None));
} }
if let Literal::Boolean(b) = spanned_lit.node { if let Literal::Boolean(b) = spanned_lit.node {
return Ok((if b { "1".to_string() } else { "0".to_string() }, None)); return Ok((Cow::from(if b { "1" } else { "0" }), None));
} }
if let Literal::String(ref s) = spanned_lit.node { if let Literal::String(ref s) = spanned_lit.node {
return Ok((s.to_string(), None)); return Ok((s.clone(), None));
} }
} }
@@ -1199,7 +1243,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
&& let Expression::Literal(spanned_lit) = &inner.node && let Expression::Literal(spanned_lit) = &inner.node
&& let Literal::Number(n) = spanned_lit.node && let Literal::Number(n) = spanned_lit.node
{ {
return Ok((format!("-{}", n), None)); return Ok((Cow::from(format!("-{}", n)), None));
} }
let result_opt = self.expression(expr, scope)?; let result_opt = self.expression(expr, scope)?;
@@ -1208,23 +1252,24 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Some(r) => r, Some(r) => r,
None => { None => {
// Expression failed or returned void. Recover with dummy. // Expression failed or returned void. Recover with dummy.
return Ok(("r0".to_string(), None)); return Ok((Cow::from("r0"), None));
} }
}; };
match result.location { match result.location {
VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => { VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => {
Ok((format!("r{r}"), result.temp_name)) Ok((Cow::from(format!("r{r}")), result.temp_name))
} }
VariableLocation::Constant(lit) => match lit { VariableLocation::Constant(lit) => match lit {
Literal::Number(n) => Ok((n.to_string(), None)), Literal::Number(n) => Ok((Cow::from(n.to_string()), None)),
Literal::Boolean(b) => Ok((if b { "1" } else { "0" }.to_string(), None)), Literal::Boolean(b) => Ok((Cow::from(if b { "1" } else { "0" }), None)),
Literal::String(s) => Ok((s, None)), Literal::String(s) => Ok((s, None)),
}, },
VariableLocation::Stack(offset) => { VariableLocation::Stack(offset) => {
// If it's on the stack, we must load it into a temp to use it as an operand // If it's on the stack, we must load it into a temp to use it as an operand
let temp_name = self.next_temp_name(); let temp_name = self.next_temp_name();
let temp_loc = scope.add_variable(&temp_name, LocationRequest::Temp, None)?; let temp_loc =
scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?;
let temp_reg = self.resolve_register(&temp_loc)?; let temp_reg = self.resolve_register(&temp_loc)?;
self.write_output(format!( self.write_output(format!(
@@ -1247,9 +1292,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn compile_literal_or_variable( fn compile_literal_or_variable(
&mut self, &mut self,
val: LiteralOrVariable, val: LiteralOrVariable<'a>,
scope: &mut VariableScope, scope: &mut VariableScope<'a>,
) -> Result<(String, Option<String>), Error> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
let dummy_span = Span { let dummy_span = Span {
start_line: 0, start_line: 0,
start_col: 0, start_col: 0,
@@ -1273,12 +1318,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
) )
} }
fn expression_binary<'v>( fn expression_binary(
&mut self, &mut self,
expr: Spanned<BinaryExpression>, expr: Spanned<BinaryExpression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<CompilationResult, Error> { ) -> Result<CompilationResult<'a>, Error<'a>> {
fn fold_binary_expression(expr: &BinaryExpression) -> Option<Number> { fn fold_binary_expression<'a>(expr: &BinaryExpression<'a>) -> Option<Number> {
let (lhs, rhs) = match &expr { let (lhs, rhs) = match &expr {
BinaryExpression::Add(l, r) BinaryExpression::Add(l, r)
| BinaryExpression::Subtract(l, r) | BinaryExpression::Subtract(l, r)
@@ -1298,7 +1343,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
fn fold_expression(expr: &Expression) -> Option<Number> { fn fold_expression<'a>(expr: &Expression<'a>) -> Option<Number> {
match expr { match expr {
// 1. Base Case: It's already a number // 1. Base Case: It's already a number
Expression::Literal(lit) => match lit.node { Expression::Literal(lit) => match lit.node {
@@ -1346,7 +1391,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// Allocate result register // Allocate result register
let result_name = self.next_temp_name(); let result_name = self.next_temp_name();
let result_loc = scope.add_variable(&result_name, LocationRequest::Temp, None)?; let result_loc = scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?;
let result_reg = self.resolve_register(&result_loc)?; let result_reg = self.resolve_register(&result_loc)?;
// Emit instruction: op result lhs rhs // Emit instruction: op result lhs rhs
@@ -1366,17 +1411,18 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}) })
} }
fn expression_logical<'v>( fn expression_logical(
&mut self, &mut self,
expr: Spanned<LogicalExpression>, expr: Spanned<LogicalExpression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<CompilationResult, Error> { ) -> Result<CompilationResult<'a>, Error<'a>> {
match expr.node { match expr.node {
LogicalExpression::Not(inner) => { LogicalExpression::Not(inner) => {
let (inner_str, cleanup) = self.compile_operand(*inner, scope)?; let (inner_str, cleanup) = self.compile_operand(*inner, scope)?;
let result_name = self.next_temp_name(); let result_name = self.next_temp_name();
let result_loc = scope.add_variable(&result_name, LocationRequest::Temp, None)?; let result_loc =
scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?;
let result_reg = self.resolve_register(&result_loc)?; let result_reg = self.resolve_register(&result_loc)?;
// seq rX rY 0 => if rY == 0 set rX = 1 else rX = 0 // seq rX rY 0 => if rY == 0 set rX = 1 else rX = 0
@@ -1411,7 +1457,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// Allocate result register // Allocate result register
let result_name = self.next_temp_name(); let result_name = self.next_temp_name();
let result_loc = scope.add_variable(&result_name, LocationRequest::Temp, None)?; let result_loc =
scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?;
let result_reg = self.resolve_register(&result_loc)?; let result_reg = self.resolve_register(&result_loc)?;
// Emit instruction: op result lhs rhs // Emit instruction: op result lhs rhs
@@ -1433,11 +1480,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
fn expression_block<'v>( fn expression_block(
&mut self, &mut self,
mut expr: BlockExpression, mut expr: BlockExpression<'a>,
parent_scope: &mut VariableScope<'v>, parent_scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
// First, sort the expressions to ensure functions are hoisted // First, sort the expressions to ensure functions are hoisted
expr.0.sort_by(|a, b| { expr.0.sort_by(|a, b| {
if matches!( if matches!(
@@ -1499,17 +1546,21 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
/// Takes the result of the expression and stores it in VariableScope::RETURN_REGISTER /// Takes the result of the expression and stores it in VariableScope::RETURN_REGISTER
fn expression_return<'v>( fn expression_return(
&mut self, &mut self,
expr: Spanned<Expression>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<VariableLocation, Error> { ) -> Result<VariableLocation<'a>, Error<'a>> {
if let Expression::Negation(neg_expr) = &expr.node if let Expression::Negation(neg_expr) = &expr.node
&& let Expression::Literal(spanned_lit) = &neg_expr.node && let Expression::Literal(spanned_lit) = &neg_expr.node
&& let Literal::Number(neg_num) = &spanned_lit.node && let Literal::Number(neg_num) = &spanned_lit.node
{ {
let loc = VariableLocation::Persistant(VariableScope::RETURN_REGISTER); let loc = VariableLocation::Persistant(VariableScope::RETURN_REGISTER);
self.emit_variable_assignment("returnValue", &loc, format!("-{neg_num}"))?; self.emit_variable_assignment(
Cow::from("returnValue"),
&loc,
Cow::from(format!("-{neg_num}")),
)?;
return Ok(loc); return Ok(loc);
}; };
@@ -1562,17 +1613,17 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
Expression::Literal(spanned_lit) => match spanned_lit.node { Expression::Literal(spanned_lit) => match spanned_lit.node {
Literal::Number(num) => { Literal::Number(num) => {
self.emit_variable_assignment( self.emit_variable_assignment(
"returnValue", Cow::from("returnValue"),
&VariableLocation::Persistant(VariableScope::RETURN_REGISTER), &VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
num, Cow::from(num.to_string()),
)?; )?;
} }
Literal::Boolean(b) => { Literal::Boolean(b) => {
let val = if b { "1" } else { "0" }; let val = if b { "1" } else { "0" };
self.emit_variable_assignment( self.emit_variable_assignment(
"returnValue", Cow::from("returnValue"),
&VariableLocation::Persistant(VariableScope::RETURN_REGISTER), &VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
val, Cow::from(val.to_string()),
)?; )?;
} }
_ => {} _ => {}
@@ -1631,12 +1682,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// syscalls that return values will be stored in the VariableScope::RETURN_REGISTER // syscalls that return values will be stored in the VariableScope::RETURN_REGISTER
// register // register
fn expression_syscall_system<'v>( fn expression_syscall_system(
&mut self, &mut self,
expr: System, expr: System<'a>,
span: Span, span: Span,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<Option<CompilationResult>, Error> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
macro_rules! cleanup { macro_rules! cleanup {
($($to_clean:expr),*) => { ($($to_clean:expr),*) => {
$( $(
@@ -1707,7 +1758,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
.devices .devices
.get(&device_name) .get(&device_name)
.cloned() .cloned()
.unwrap_or("d0".to_string()); .unwrap_or(Cow::from("d0"));
let Spanned { let Spanned {
node: Literal::String(logic_type), node: Literal::String(logic_type),
@@ -1799,7 +1850,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
.devices .devices
.get(&device_name) .get(&device_name)
.cloned() .cloned()
.unwrap_or("d0".to_string()); .unwrap_or(Cow::from("d0"));
let Spanned { let Spanned {
node: Literal::String(logic_type), node: Literal::String(logic_type),
@@ -1889,11 +1940,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
fn expression_syscall_math<'v>( fn expression_syscall_math(
&mut self, &mut self,
expr: Math, expr: Math<'a>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<Option<CompilationResult>, Error> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
macro_rules! cleanup { macro_rules! cleanup {
($($to_clean:expr),*) => { ($($to_clean:expr),*) => {
$( $(
@@ -2085,11 +2136,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
/// Compile a function declaration. /// Compile a function declaration.
/// Calees are responsible for backing up any registers they wish to use. /// Calees are responsible for backing up any registers they wish to use.
fn expression_function<'v>( fn expression_function(
&mut self, &mut self,
expr: Spanned<FunctionExpression>, expr: Spanned<FunctionExpression<'a>>,
scope: &mut VariableScope<'v>, scope: &mut VariableScope<'a>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let FunctionExpression { let FunctionExpression {
name, name,
arguments, arguments,

View File

@@ -5,25 +5,28 @@
use lsp_types::{Diagnostic, DiagnosticSeverity}; use lsp_types::{Diagnostic, DiagnosticSeverity};
use parser::tree_node::{Literal, Span}; use parser::tree_node::{Literal, Span};
use std::collections::{HashMap, VecDeque}; use std::{
borrow::Cow,
collections::{HashMap, VecDeque},
};
use thiserror::Error; use thiserror::Error;
const TEMP: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; const TEMP: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
const PERSIST: [u8; 7] = [8, 9, 10, 11, 12, 13, 14]; const PERSIST: [u8; 7] = [8, 9, 10, 11, 12, 13, 14];
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum Error<'a> {
#[error("{0} already exists.")] #[error("{0} already exists.")]
DuplicateVariable(String, Option<Span>), DuplicateVariable(Cow<'a, str>, Option<Span>),
#[error("{0} does not exist.")] #[error("{0} does not exist.")]
UnknownVariable(String, Option<Span>), UnknownVariable(Cow<'a, str>, Option<Span>),
#[error("{0}")] #[error("{0}")]
Unknown(String, Option<Span>), Unknown(Cow<'a, str>, Option<Span>),
} }
impl From<Error> for lsp_types::Diagnostic { impl<'a> From<Error<'a>> for lsp_types::Diagnostic {
fn from(value: Error) -> Self { fn from(value: Error) -> Self {
match value { match value {
Error::DuplicateVariable(_, span) Error::DuplicateVariable(_, span)
@@ -50,7 +53,7 @@ pub enum LocationRequest {
} }
#[derive(Clone)] #[derive(Clone)]
pub enum VariableLocation { pub enum VariableLocation<'a> {
/// Represents a temporary register (r1 - r7) /// Represents a temporary register (r1 - r7)
Temporary(u8), Temporary(u8),
/// Represents a persistant register (r8 - r14) /// Represents a persistant register (r8 - r14)
@@ -58,15 +61,15 @@ pub enum VariableLocation {
/// Represents a a stack offset (current stack - offset = variable loc) /// Represents a a stack offset (current stack - offset = variable loc)
Stack(u16), Stack(u16),
/// Represents a constant value and should be directly substituted as such. /// Represents a constant value and should be directly substituted as such.
Constant(Literal), Constant(Literal<'a>),
/// Represents a device pin. This will contain the exact `d0-d5` string /// Represents a device pin. This will contain the exact `d0-d5` string
Device(String), Device(Cow<'a, str>),
} }
pub struct VariableScope<'a> { pub struct VariableScope<'a> {
temporary_vars: VecDeque<u8>, temporary_vars: VecDeque<u8>,
persistant_vars: VecDeque<u8>, persistant_vars: VecDeque<u8>,
var_lookup_table: HashMap<String, VariableLocation>, var_lookup_table: HashMap<Cow<'a, str>, VariableLocation<'a>>,
stack_offset: u16, stack_offset: u16,
parent: Option<&'a VariableScope<'a>>, parent: Option<&'a VariableScope<'a>>,
} }
@@ -123,12 +126,11 @@ impl<'a> VariableScope<'a> {
/// to the stack. /// to the stack.
pub fn add_variable( pub fn add_variable(
&mut self, &mut self,
var_name: impl Into<String>, var_name: Cow<'a, str>,
location: LocationRequest, location: LocationRequest,
span: Option<Span>, span: Option<Span>,
) -> Result<VariableLocation, Error> { ) -> Result<VariableLocation<'a>, Error<'a>> {
let var_name = var_name.into(); if self.var_lookup_table.contains_key(&var_name) {
if self.var_lookup_table.contains_key(var_name.as_str()) {
return Err(Error::DuplicateVariable(var_name, span)); return Err(Error::DuplicateVariable(var_name, span));
} }
let var_location = match location { let var_location = match location {
@@ -163,11 +165,10 @@ impl<'a> VariableScope<'a> {
pub fn define_const( pub fn define_const(
&mut self, &mut self,
var_name: impl Into<String>, var_name: Cow<'a, str>,
value: Literal, value: Literal<'a>,
span: Option<Span>, span: Option<Span>,
) -> Result<VariableLocation, Error> { ) -> Result<VariableLocation<'a>, Error<'a>> {
let var_name = var_name.into();
if self.var_lookup_table.contains_key(&var_name) { if self.var_lookup_table.contains_key(&var_name) {
return Err(Error::DuplicateVariable(var_name, span)); return Err(Error::DuplicateVariable(var_name, span));
} }
@@ -180,13 +181,11 @@ impl<'a> VariableScope<'a> {
pub fn get_location_of( pub fn get_location_of(
&self, &self,
var_name: impl Into<String>, var_name: &Cow<'a, str>,
span: Option<Span>, span: Option<Span>,
) -> Result<VariableLocation, Error> { ) -> Result<VariableLocation<'a>, Error<'a>> {
let var_name = var_name.into();
// 1. Check this scope // 1. Check this scope
if let Some(var) = self.var_lookup_table.get(var_name.as_str()) { if let Some(var) = self.var_lookup_table.get(var_name) {
if let VariableLocation::Stack(inserted_at_offset) = var { if let VariableLocation::Stack(inserted_at_offset) = var {
// Return offset relative to CURRENT sp // Return offset relative to CURRENT sp
return Ok(VariableLocation::Stack( return Ok(VariableLocation::Stack(
@@ -207,7 +206,7 @@ impl<'a> VariableScope<'a> {
return Ok(loc); return Ok(loc);
} }
Err(Error::UnknownVariable(var_name, span)) Err(Error::UnknownVariable(Cow::from(var_name.to_owned()), span))
} }
pub fn has_parent(&self) -> bool { pub fn has_parent(&self) -> bool {
@@ -217,11 +216,10 @@ impl<'a> VariableScope<'a> {
#[allow(dead_code)] #[allow(dead_code)]
pub fn free_temp( pub fn free_temp(
&mut self, &mut self,
var_name: impl Into<String>, var_name: Cow<'a, str>,
span: Option<Span>, span: Option<Span>,
) -> Result<(), Error> { ) -> Result<(), Error<'a>> {
let var_name = var_name.into(); let Some(location) = self.var_lookup_table.remove(&var_name) else {
let Some(location) = self.var_lookup_table.remove(var_name.as_str()) else {
return Err(Error::UnknownVariable(var_name, span)); return Err(Error::UnknownVariable(var_name, span));
}; };
@@ -231,7 +229,7 @@ impl<'a> VariableScope<'a> {
} }
VariableLocation::Persistant(_) => { VariableLocation::Persistant(_) => {
return Err(Error::UnknownVariable( return Err(Error::UnknownVariable(
String::from("Attempted to free a `let` variable."), Cow::from("Attempted to free a `let` variable."),
span, span,
)); ));
} }

View File

@@ -1518,14 +1518,14 @@ impl<'a> Parser<'a> {
} }
fn syscall(&mut self) -> Result<SysCall<'a>, Error<'a>> { fn syscall(&mut self) -> Result<SysCall<'a>, Error<'a>> {
fn check_length<'a, 't: 'a>( fn check_length<'a>(
parser: &'t Parser, span: Span,
arguments: &[Spanned<Expression<'a>>], arguments: &[Spanned<Expression<'a>>],
length: usize, length: usize,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
if arguments.len() != length { if arguments.len() != length {
return Err(Error::InvalidSyntax( return Err(Error::InvalidSyntax(
parser.current_span(), span,
format!("Expected {} arguments", length), format!("Expected {} arguments", length),
)); ));
} }
@@ -1586,17 +1586,17 @@ impl<'a> Parser<'a> {
match invocation.name.node.as_ref() { match invocation.name.node.as_ref() {
// System SysCalls // System SysCalls
"yield" => { "yield" => {
check_length(self, &invocation.arguments, 0)?; check_length(self.current_span(), &invocation.arguments, 0)?;
Ok(SysCall::System(sys_call::System::Yield)) Ok(SysCall::System(sys_call::System::Yield))
} }
"sleep" => { "sleep" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut arg = invocation.arguments.into_iter(); let mut arg = invocation.arguments.into_iter();
let expr = arg.next().ok_or(Error::UnexpectedEOF)?; let expr = arg.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::System(System::Sleep(boxed!(expr)))) Ok(SysCall::System(System::Sleep(boxed!(expr))))
} }
"hash" => { "hash" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let lit_str = literal_or_variable!(args.next()); let lit_str = literal_or_variable!(args.next());
@@ -1617,7 +1617,7 @@ impl<'a> Parser<'a> {
}))) })))
} }
"load" | "l" => { "load" | "l" => {
check_length(self, &invocation.arguments, 2)?; check_length(self.current_span(), &invocation.arguments, 2)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
@@ -1662,7 +1662,7 @@ impl<'a> Parser<'a> {
))) )))
} }
"loadBatched" | "lb" => { "loadBatched" | "lb" => {
check_length(self, &invocation.arguments, 3)?; check_length(self.current_span(), &invocation.arguments, 3)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
let device_hash = literal_or_variable!(tmp); let device_hash = literal_or_variable!(tmp);
@@ -1680,7 +1680,7 @@ impl<'a> Parser<'a> {
))) )))
} }
"loadBatchedNamed" | "lbn" => { "loadBatchedNamed" | "lbn" => {
check_length(self, &invocation.arguments, 4)?; check_length(self.current_span(), &invocation.arguments, 4)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
let dev_hash = literal_or_variable!(tmp); let dev_hash = literal_or_variable!(tmp);
@@ -1699,7 +1699,7 @@ impl<'a> Parser<'a> {
))) )))
} }
"set" | "s" => { "set" | "s" => {
check_length(self, &invocation.arguments, 3)?; check_length(self.current_span(), &invocation.arguments, 3)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
let device = literal_or_variable!(tmp); let device = literal_or_variable!(tmp);
@@ -1720,7 +1720,7 @@ impl<'a> Parser<'a> {
))) )))
} }
"setBatched" | "sb" => { "setBatched" | "sb" => {
check_length(self, &invocation.arguments, 3)?; check_length(self.current_span(), &invocation.arguments, 3)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
let device_hash = literal_or_variable!(tmp); let device_hash = literal_or_variable!(tmp);
@@ -1739,7 +1739,7 @@ impl<'a> Parser<'a> {
))) )))
} }
"setBatchedNamed" | "sbn" => { "setBatchedNamed" | "sbn" => {
check_length(self, &invocation.arguments, 4)?; check_length(self.current_span(), &invocation.arguments, 4)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next(); let tmp = args.next();
let device_hash = literal_or_variable!(tmp); let device_hash = literal_or_variable!(tmp);
@@ -1762,28 +1762,28 @@ impl<'a> Parser<'a> {
} }
// Math SysCalls // Math SysCalls
"acos" => { "acos" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next().ok_or(Error::UnexpectedEOF)?; let tmp = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Acos(boxed!(tmp)))) Ok(SysCall::Math(Math::Acos(boxed!(tmp))))
} }
"asin" => { "asin" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let tmp = args.next().ok_or(Error::UnexpectedEOF)?; let tmp = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Asin(boxed!(tmp)))) Ok(SysCall::Math(Math::Asin(boxed!(tmp))))
} }
"atan" => { "atan" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let expr = args.next().ok_or(Error::UnexpectedEOF)?; let expr = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Atan(boxed!(expr)))) Ok(SysCall::Math(Math::Atan(boxed!(expr))))
} }
"atan2" => { "atan2" => {
check_length(self, &invocation.arguments, 2)?; check_length(self.current_span(), &invocation.arguments, 2)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg1 = args.next().ok_or(Error::UnexpectedEOF)?; let arg1 = args.next().ok_or(Error::UnexpectedEOF)?;
let arg2 = args.next().ok_or(Error::UnexpectedEOF)?; let arg2 = args.next().ok_or(Error::UnexpectedEOF)?;
@@ -1791,42 +1791,42 @@ impl<'a> Parser<'a> {
Ok(SysCall::Math(Math::Atan2(boxed!(arg1), boxed!(arg2)))) Ok(SysCall::Math(Math::Atan2(boxed!(arg1), boxed!(arg2))))
} }
"abs" => { "abs" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let expr = args.next().ok_or(Error::UnexpectedEOF)?; let expr = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Abs(boxed!(expr)))) Ok(SysCall::Math(Math::Abs(boxed!(expr))))
} }
"ceil" => { "ceil" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Ceil(boxed!(arg)))) Ok(SysCall::Math(Math::Ceil(boxed!(arg))))
} }
"cos" => { "cos" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Cos(boxed!(arg)))) Ok(SysCall::Math(Math::Cos(boxed!(arg))))
} }
"floor" => { "floor" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Floor(boxed!(arg)))) Ok(SysCall::Math(Math::Floor(boxed!(arg))))
} }
"log" => { "log" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Log(boxed!(arg)))) Ok(SysCall::Math(Math::Log(boxed!(arg))))
} }
"max" => { "max" => {
check_length(self, &invocation.arguments, 2)?; check_length(self.current_span(), &invocation.arguments, 2)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg1 = args.next().ok_or(Error::UnexpectedEOF)?; let arg1 = args.next().ok_or(Error::UnexpectedEOF)?;
let arg2 = args.next().ok_or(Error::UnexpectedEOF)?; let arg2 = args.next().ok_or(Error::UnexpectedEOF)?;
@@ -1834,7 +1834,7 @@ impl<'a> Parser<'a> {
Ok(SysCall::Math(Math::Max(boxed!(arg1), boxed!(arg2)))) Ok(SysCall::Math(Math::Max(boxed!(arg1), boxed!(arg2))))
} }
"min" => { "min" => {
check_length(self, &invocation.arguments, 2)?; check_length(self.current_span(), &invocation.arguments, 2)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg1 = args.next().ok_or(Error::UnexpectedEOF)?; let arg1 = args.next().ok_or(Error::UnexpectedEOF)?;
let arg2 = args.next().ok_or(Error::UnexpectedEOF)?; let arg2 = args.next().ok_or(Error::UnexpectedEOF)?;
@@ -1842,32 +1842,32 @@ impl<'a> Parser<'a> {
Ok(SysCall::Math(Math::Min(boxed!(arg1), boxed!(arg2)))) Ok(SysCall::Math(Math::Min(boxed!(arg1), boxed!(arg2))))
} }
"rand" => { "rand" => {
check_length(self, &invocation.arguments, 0)?; check_length(self.current_span(), &invocation.arguments, 0)?;
Ok(SysCall::Math(Math::Rand)) Ok(SysCall::Math(Math::Rand))
} }
"sin" => { "sin" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Sin(boxed!(arg)))) Ok(SysCall::Math(Math::Sin(boxed!(arg))))
} }
"sqrt" => { "sqrt" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Sqrt(boxed!(arg)))) Ok(SysCall::Math(Math::Sqrt(boxed!(arg))))
} }
"tan" => { "tan" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;
Ok(SysCall::Math(Math::Tan(boxed!(arg)))) Ok(SysCall::Math(Math::Tan(boxed!(arg))))
} }
"trunc" => { "trunc" => {
check_length(self, &invocation.arguments, 1)?; check_length(self.current_span(), &invocation.arguments, 1)?;
let mut args = invocation.arguments.into_iter(); let mut args = invocation.arguments.into_iter();
let arg = args.next().ok_or(Error::UnexpectedEOF)?; let arg = args.next().ok_or(Error::UnexpectedEOF)?;