v1 constant expressions
This commit is contained in:
@@ -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}",
|
||||
|
||||
Reference in New Issue
Block a user