VariableManager lifetime errors
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user