v1 constant expressions

This commit is contained in:
2025-12-04 21:18:57 -07:00
parent 4b6c7eb63c
commit d34ce32d97
2 changed files with 106 additions and 9 deletions

View File

@@ -4,10 +4,10 @@ use parser::{
Parser as ASTParser,
sys_call::{SysCall, System},
tree_node::{
AssignmentExpression, BinaryExpression, BlockExpression, DeviceDeclarationExpression,
Expression, FunctionExpression, IfExpression, InvocationExpression, Literal,
LiteralOrVariable, LogicalExpression, LoopExpression, MemberAccessExpression, Span,
Spanned, WhileExpression,
AssignmentExpression, BinaryExpression, BlockExpression, ConstDeclarationExpression,
DeviceDeclarationExpression, Expression, FunctionExpression, IfExpression,
InvocationExpression, Literal, LiteralOrVariable, LogicalExpression, LoopExpression,
MemberAccessExpression, Span, Spanned, WhileExpression,
},
};
use quick_error::quick_error;
@@ -34,6 +34,20 @@ macro_rules! debug {
};
}
fn extract_literal(literal: Literal, allow_strings: bool) -> Result<String, Error> {
if !allow_strings && matches!(literal, Literal::String(_)) {
return Err(Error::Unknown(
"Literal strings are not allowed in this context".to_string(),
None,
));
}
Ok(match literal {
Literal::String(s) => s,
Literal::Number(n) => n.to_string(),
Literal::Boolean(b) => if b { "1" } else { "0" }.into(),
})
}
quick_error! {
#[derive(Debug)]
pub enum Error {
@@ -58,6 +72,9 @@ quick_error! {
AgrumentMismatch(func_name: String, span: Span) {
display("Incorrect number of arguments passed into `{func_name}`")
}
ConstAssignment(ident: String, span: Span) {
display("Attempted to re-assign a value to const variable `{ident}`")
}
Unknown(reason: String, span: Option<Span>) {
display("{reason}")
}
@@ -84,6 +101,7 @@ impl From<Error> for lsp_types::Diagnostic {
DuplicateIdentifier(_, span)
| UnknownIdentifier(_, span)
| InvalidDevice(_, span)
| ConstAssignment(_, span)
| AgrumentMismatch(_, span) => Diagnostic {
range: span.into(),
message: value.to_string(),
@@ -267,6 +285,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// decl_expr is Box<Spanned<Expression>>
self.expression_declaration(var_name, *decl_expr, scope)
}
Expression::ConstDeclaration(const_decl_expr) => {
self.expression_const_declaration(const_decl_expr.node, scope)?;
Ok(None)
}
Expression::Assignment(assign_expr) => {
self.expression_assignment(assign_expr.node, scope)?;
Ok(None)
@@ -435,6 +457,14 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
VariableLocation::Stack(_) => {
self.write_output(format!("push {}{debug_tag}", source_value.into()))?;
}
VariableLocation::Constant(_) => {
return Err(Error::Unknown(
r#"Attempted to emit a variable assignent for a constant value.
This is a Compiler bug and should be reported to the developer."#
.into(),
None,
));
}
}
Ok(())
@@ -581,6 +611,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
))?;
format!("r{}", VariableScope::TEMP_STACK_REGISTER)
}
VariableLocation::Constant(_) => unreachable!(),
};
self.emit_variable_assignment(&name_str, &var_loc, src_str)?;
(var_loc, None)
@@ -638,6 +669,22 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}))
}
fn expression_const_declaration<'v>(
&mut self,
expr: ConstDeclarationExpression,
scope: &mut VariableScope<'v>,
) -> Result<CompilationResult, Error> {
let ConstDeclarationExpression {
name: const_name,
value: const_value,
} = expr;
Ok(CompilationResult {
location: scope.define_const(const_name.node, const_value.node)?,
temp_name: None,
})
}
fn expression_assignment<'v>(
&mut self,
expr: AssignmentExpression,
@@ -685,6 +732,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
VariableScope::TEMP_STACK_REGISTER
))?;
}
VariableLocation::Constant(_) => {
return Err(Error::ConstAssignment(identifier.node, identifier.span));
}
}
if let Some(name) = cleanup {
@@ -782,6 +832,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
VariableLocation::Persistant(reg) | VariableLocation::Temporary(reg) => {
self.write_output(format!("push r{reg}"))?;
}
VariableLocation::Constant(lit) => {
self.write_output(format!("push {}", extract_literal(lit, false)?))?;
}
VariableLocation::Stack(stack_offset) => {
self.write_output(format!(
"sub r{0} sp {stack_offset}",
@@ -1041,6 +1094,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn resolve_register(&self, loc: &VariableLocation) -> Result<String, Error> {
match loc {
VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => Ok(format!("r{r}")),
VariableLocation::Constant(_) => Err(Error::Unknown(
"Cannot resolve a constant value to register".into(),
None,
)),
VariableLocation::Stack(_) => Err(Error::Unknown(
"Cannot resolve Stack location directly to register string without context".into(),
None,
@@ -1090,6 +1147,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => {
Ok((format!("r{r}"), result.temp_name))
}
VariableLocation::Constant(lit) => match lit {
Literal::Number(n) => Ok((n.to_string(), None)),
Literal::Boolean(b) => Ok((if b { "1" } else { "0" }.to_string(), None)),
Literal::String(s) => Ok((s, None)),
},
VariableLocation::Stack(offset) => {
// 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();
@@ -1256,11 +1318,18 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
) -> Result<(), Error> {
// First, sort the expressions to ensure functions are hoisted
expr.0.sort_by(|a, b| {
if matches!(b.node, Expression::Function(_))
&& matches!(a.node, Expression::Function(_))
{
if matches!(
b.node,
Expression::Function(_) | Expression::ConstDeclaration(_)
) && matches!(
a.node,
Expression::Function(_) | Expression::ConstDeclaration(_)
) {
std::cmp::Ordering::Equal
} else if matches!(a.node, Expression::Function(_)) {
} else if matches!(
a.node,
Expression::Function(_) | Expression::ConstDeclaration(_)
) {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
@@ -1332,6 +1401,14 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
debug!(self, "#returnValue")
))?;
}
VariableLocation::Constant(lit) => {
let str = extract_literal(lit, false)?;
self.write_output(format!(
"move r{} {str} {}",
VariableScope::RETURN_REGISTER,
debug!(self, "#returnValue")
))?
}
VariableLocation::Stack(offset) => {
self.write_output(format!(
"sub r{} sp {offset}",