Compilation errors solved
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
#![allow(clippy::result_large_err)]
|
||||||
use crate::variable_manager::{self, LocationRequest, VariableLocation, VariableScope};
|
use crate::variable_manager::{self, LocationRequest, VariableLocation, VariableScope};
|
||||||
use parser::{
|
use parser::{
|
||||||
Parser as ASTParser,
|
Parser as ASTParser,
|
||||||
@@ -115,9 +116,27 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
let Some(expr) = expr else { return Ok(()) };
|
let Some(expr) = expr else { return Ok(()) };
|
||||||
|
|
||||||
|
// Wrap the root expression in a dummy span for consistency,
|
||||||
|
// since parse_all returns an unspanned Expression (usually Block)
|
||||||
|
// that contains spanned children.
|
||||||
|
// We know parse_all returns Expression::Block which has an internal span,
|
||||||
|
// but for type consistency we wrap it.
|
||||||
|
let span = if let Expression::Block(ref block) = expr {
|
||||||
|
block.span
|
||||||
|
} else {
|
||||||
|
Span {
|
||||||
|
start_line: 0,
|
||||||
|
end_line: 0,
|
||||||
|
start_col: 0,
|
||||||
|
end_col: 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let spanned_root = Spanned { node: expr, span };
|
||||||
|
|
||||||
self.write_output("j main")?;
|
self.write_output("j main")?;
|
||||||
// We ignore the result of the root expression (usually a block)
|
// We ignore the result of the root expression (usually a block)
|
||||||
let _ = self.expression(expr, &mut VariableScope::default())?;
|
let _ = self.expression(spanned_root, &mut VariableScope::default())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +160,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
fn expression<'v>(
|
fn expression<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: Expression,
|
expr: Spanned<Expression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<Option<CompilationResult>, Error> {
|
) -> Result<Option<CompilationResult>, Error> {
|
||||||
match expr {
|
match expr.node {
|
||||||
Expression::Function(expr_func) => {
|
Expression::Function(expr_func) => {
|
||||||
self.expression_function(expr_func, scope)?;
|
self.expression_function(expr_func, scope)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -161,9 +180,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.expression_loop(expr_loop.node, scope)?;
|
self.expression_loop(expr_loop.node, scope)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Expression::Syscall(spanned_syscall) => {
|
Expression::Syscall(Spanned {
|
||||||
self.expression_syscall_system(spanned_syscall.node, spanned_syscall.span, scope)
|
node: SysCall::System(system),
|
||||||
}
|
span,
|
||||||
|
}) => self.expression_syscall_system(system, span, scope),
|
||||||
Expression::While(expr_while) => {
|
Expression::While(expr_while) => {
|
||||||
self.expression_while(expr_while.node, scope)?;
|
self.expression_while(expr_while.node, scope)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -180,8 +200,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.expression_device(expr_dev.node, expr_dev.span)?;
|
self.expression_device(expr_dev.node, expr_dev.span)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Expression::Declaration(var_name, expr) => {
|
Expression::Declaration(var_name, decl_expr) => {
|
||||||
self.expression_declaration(var_name, **expr, scope)
|
// decl_expr is Box<Spanned<Expression>>
|
||||||
|
self.expression_declaration(var_name, *decl_expr, scope)
|
||||||
}
|
}
|
||||||
Expression::Assignment(assign_expr) => {
|
Expression::Assignment(assign_expr) => {
|
||||||
self.expression_assignment(assign_expr.node, scope)?;
|
self.expression_assignment(assign_expr.node, scope)?;
|
||||||
@@ -204,11 +225,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Expression::Binary(bin_expr) => {
|
Expression::Binary(bin_expr) => {
|
||||||
let result = self.expression_binary(bin_expr.node, scope)?;
|
let result = self.expression_binary(bin_expr, scope)?;
|
||||||
Ok(Some(result))
|
Ok(Some(result))
|
||||||
}
|
}
|
||||||
Expression::Logical(log_expr) => {
|
Expression::Logical(log_expr) => {
|
||||||
let result = self.expression_logical(log_expr.node, scope)?;
|
let result = self.expression_logical(log_expr, scope)?;
|
||||||
Ok(Some(result))
|
Ok(Some(result))
|
||||||
}
|
}
|
||||||
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
||||||
@@ -242,7 +263,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
temp_name: None, // User variable, do not free
|
temp_name: None, // User variable, do not free
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Expression::Priority(inner_expr) => self.expression(**inner_expr, scope),
|
Expression::Priority(inner_expr) => self.expression(*inner_expr, scope),
|
||||||
Expression::Negation(inner_expr) => {
|
Expression::Negation(inner_expr) => {
|
||||||
// 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)?;
|
||||||
@@ -264,9 +285,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
_ => Err(Error::Unknown(
|
_ => Err(Error::Unknown(
|
||||||
format!(
|
format!(
|
||||||
"Expression type not yet supported in general expression context: {:?}",
|
"Expression type not yet supported in general expression context: {:?}",
|
||||||
expr
|
expr.node
|
||||||
),
|
),
|
||||||
None,
|
Some(expr.span),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,15 +319,15 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
fn expression_declaration<'v>(
|
fn expression_declaration<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var_name: Spanned<String>,
|
var_name: Spanned<String>,
|
||||||
expr: Expression,
|
expr: Spanned<Expression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<Option<CompilationResult>, Error> {
|
) -> Result<Option<CompilationResult>, Error> {
|
||||||
let name_str = var_name.node;
|
let name_str = var_name.node;
|
||||||
let name_span = var_name.span;
|
let name_span = var_name.span;
|
||||||
|
|
||||||
// optimization. Check for a negated numeric literal
|
// optimization. Check for a negated numeric literal
|
||||||
if let Expression::Negation(box_expr) = &expr
|
if let Expression::Negation(box_expr) = &expr.node
|
||||||
&& let Expression::Literal(spanned_lit) = &**box_expr
|
&& 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)?;
|
let loc = scope.add_variable(&name_str, LocationRequest::Persist)?;
|
||||||
@@ -317,7 +338,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (loc, temp_name) = match expr {
|
let (loc, temp_name) = match expr.node {
|
||||||
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
||||||
Literal::Number(num) => {
|
Literal::Number(num) => {
|
||||||
let var_location =
|
let var_location =
|
||||||
@@ -379,7 +400,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
// Support assigning binary expressions to variables directly
|
// Support assigning binary expressions to variables directly
|
||||||
Expression::Binary(bin_expr) => {
|
Expression::Binary(bin_expr) => {
|
||||||
let result = self.expression_binary(bin_expr.node, scope)?;
|
let result = self.expression_binary(bin_expr, scope)?;
|
||||||
let var_loc = scope.add_variable(&name_str, LocationRequest::Persist)?;
|
let var_loc = scope.add_variable(&name_str, LocationRequest::Persist)?;
|
||||||
|
|
||||||
// Move result from temp to new persistent variable
|
// Move result from temp to new persistent variable
|
||||||
@@ -393,7 +414,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
(var_loc, None)
|
(var_loc, None)
|
||||||
}
|
}
|
||||||
Expression::Logical(log_expr) => {
|
Expression::Logical(log_expr) => {
|
||||||
let result = self.expression_logical(log_expr.node, scope)?;
|
let result = self.expression_logical(log_expr, scope)?;
|
||||||
let var_loc = scope.add_variable(&name_str, LocationRequest::Persist)?;
|
let var_loc = scope.add_variable(&name_str, LocationRequest::Persist)?;
|
||||||
|
|
||||||
// Move result from temp to new persistent variable
|
// Move result from temp to new persistent variable
|
||||||
@@ -530,7 +551,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.write_output(format!("push r{register}"))?;
|
self.write_output(format!("push r{register}"))?;
|
||||||
}
|
}
|
||||||
for arg in arguments {
|
for arg in arguments {
|
||||||
match arg {
|
match arg.node {
|
||||||
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
||||||
Literal::Number(num) => {
|
Literal::Number(num) => {
|
||||||
let num_str = num.to_string();
|
let num_str = num.to_string();
|
||||||
@@ -569,7 +590,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
Expression::Binary(bin_expr) => {
|
Expression::Binary(bin_expr) => {
|
||||||
// Compile the binary expression to a temp register
|
// Compile the binary expression to a temp register
|
||||||
let result = self.expression_binary(bin_expr.node, stack)?;
|
let result = self.expression_binary(bin_expr, stack)?;
|
||||||
let reg_str = self.resolve_register(&result.location)?;
|
let reg_str = self.resolve_register(&result.location)?;
|
||||||
self.write_output(format!("push {reg_str}"))?;
|
self.write_output(format!("push {reg_str}"))?;
|
||||||
if let Some(name) = result.temp_name {
|
if let Some(name) = result.temp_name {
|
||||||
@@ -578,7 +599,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
Expression::Logical(log_expr) => {
|
Expression::Logical(log_expr) => {
|
||||||
// Compile the logical expression to a temp register
|
// Compile the logical expression to a temp register
|
||||||
let result = self.expression_logical(log_expr.node, stack)?;
|
let result = self.expression_logical(log_expr, stack)?;
|
||||||
let reg_str = self.resolve_register(&result.location)?;
|
let reg_str = self.resolve_register(&result.location)?;
|
||||||
self.write_output(format!("push {reg_str}"))?;
|
self.write_output(format!("push {reg_str}"))?;
|
||||||
if let Some(name) = result.temp_name {
|
if let Some(name) = result.temp_name {
|
||||||
@@ -603,7 +624,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}"))
|
.get_location_of(format!("temp_{register}"))
|
||||||
.map_err(|e| Error::ScopeError(e))?
|
.map_err(Error::ScopeError)?
|
||||||
else {
|
else {
|
||||||
// This shouldn't happen if we just added it
|
// This shouldn't happen if we just added it
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
@@ -672,7 +693,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.write_output(format!("j {end_label}"))?;
|
self.write_output(format!("j {end_label}"))?;
|
||||||
self.write_output(format!("{else_label}:"))?;
|
self.write_output(format!("{else_label}:"))?;
|
||||||
|
|
||||||
match *expr.else_branch.unwrap() {
|
match expr.else_branch.unwrap().node {
|
||||||
Expression::Block(block) => self.expression_block(block.node, scope)?,
|
Expression::Block(block) => self.expression_block(block.node, scope)?,
|
||||||
Expression::If(if_expr) => self.expression_if(if_expr.node, scope)?,
|
Expression::If(if_expr) => self.expression_if(if_expr.node, scope)?,
|
||||||
_ => unreachable!("Parser ensures else branch is Block or If"),
|
_ => unreachable!("Parser ensures else branch is Block or If"),
|
||||||
@@ -789,11 +810,11 @@ 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: Expression,
|
expr: Spanned<Expression>,
|
||||||
scope: &mut VariableScope,
|
scope: &mut VariableScope,
|
||||||
) -> Result<(String, Option<String>), Error> {
|
) -> Result<(String, Option<String>), Error> {
|
||||||
// Optimization for literals
|
// Optimization for literals
|
||||||
if let Expression::Literal(spanned_lit) = &expr {
|
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((n.to_string(), None));
|
||||||
}
|
}
|
||||||
@@ -804,8 +825,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
// Optimization for negated literals used as operands.
|
// Optimization for negated literals used as operands.
|
||||||
// E.g., `1 + -2` -> return "-2" string, no register used.
|
// E.g., `1 + -2` -> return "-2" string, no register used.
|
||||||
if let Expression::Negation(inner) = &expr
|
if let Expression::Negation(inner) = &expr.node
|
||||||
&& let Expression::Literal(spanned_lit) = &**inner
|
&& 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((format!("-{}", n), None));
|
||||||
@@ -848,36 +869,35 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
val: LiteralOrVariable,
|
val: LiteralOrVariable,
|
||||||
scope: &mut VariableScope,
|
scope: &mut VariableScope,
|
||||||
) -> Result<(String, Option<String>), Error> {
|
) -> Result<(String, Option<String>), Error> {
|
||||||
let expr = match val {
|
|
||||||
LiteralOrVariable::Literal(l) => {
|
|
||||||
// We need to manufacture a spanned literal
|
|
||||||
// Since this method is usually called from contexts where we lost the original span
|
|
||||||
// (Syscall enums don't keep span on inner literals usually, but we passed span to expression_syscall_system)
|
|
||||||
// Actually, LiteralOrVariable stores Spanned<String> for variables, but Literals are just Literal.
|
|
||||||
// We'll create a dummy span for the Literal if we have to wrap it back in Expression.
|
|
||||||
// Or better, just handle logic here.
|
|
||||||
let dummy_span = Span {
|
let dummy_span = Span {
|
||||||
start_line: 0,
|
start_line: 0,
|
||||||
start_col: 0,
|
start_col: 0,
|
||||||
end_line: 0,
|
end_line: 0,
|
||||||
end_col: 0,
|
end_col: 0,
|
||||||
};
|
};
|
||||||
Expression::Literal(Spanned {
|
|
||||||
|
let expr = match val {
|
||||||
|
LiteralOrVariable::Literal(l) => Expression::Literal(Spanned {
|
||||||
node: l,
|
node: l,
|
||||||
span: dummy_span,
|
span: dummy_span,
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
LiteralOrVariable::Variable(v) => Expression::Variable(v),
|
LiteralOrVariable::Variable(v) => Expression::Variable(v),
|
||||||
};
|
};
|
||||||
self.compile_operand(expr, scope)
|
self.compile_operand(
|
||||||
|
Spanned {
|
||||||
|
node: expr,
|
||||||
|
span: dummy_span,
|
||||||
|
},
|
||||||
|
scope,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_binary<'v>(
|
fn expression_binary<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: BinaryExpression,
|
expr: Spanned<BinaryExpression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<CompilationResult, Error> {
|
) -> Result<CompilationResult, Error> {
|
||||||
let (op_str, left_expr, right_expr) = match expr {
|
let (op_str, left_expr, right_expr) = match expr.node {
|
||||||
BinaryExpression::Add(l, r) => ("add", l, r),
|
BinaryExpression::Add(l, r) => ("add", l, r),
|
||||||
BinaryExpression::Multiply(l, r) => ("mul", l, r),
|
BinaryExpression::Multiply(l, r) => ("mul", l, r),
|
||||||
BinaryExpression::Divide(l, r) => ("div", l, r),
|
BinaryExpression::Divide(l, r) => ("div", l, r),
|
||||||
@@ -915,10 +935,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
fn expression_logical<'v>(
|
fn expression_logical<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: LogicalExpression,
|
expr: Spanned<LogicalExpression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<CompilationResult, Error> {
|
) -> Result<CompilationResult, Error> {
|
||||||
match expr {
|
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)?;
|
||||||
|
|
||||||
@@ -939,7 +959,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (op_str, left_expr, right_expr) = match expr {
|
let (op_str, left_expr, right_expr) = match expr.node {
|
||||||
LogicalExpression::And(l, r) => ("and", l, r),
|
LogicalExpression::And(l, r) => ("and", l, r),
|
||||||
LogicalExpression::Or(l, r) => ("or", l, r),
|
LogicalExpression::Or(l, r) => ("or", l, r),
|
||||||
LogicalExpression::Equal(l, r) => ("seq", l, r),
|
LogicalExpression::Equal(l, r) => ("seq", l, r),
|
||||||
@@ -1012,7 +1032,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.expression_return(*ret_expr, scope)?;
|
self.expression_return(*ret_expr, scope)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let result = self.expression(expr.node, scope)?;
|
let result = self.expression(expr, scope)?;
|
||||||
// If the expression was a statement that returned a temp result (e.g. `1 + 2;` line),
|
// If the expression was a statement that returned a temp result (e.g. `1 + 2;` line),
|
||||||
// we must free it to avoid leaking registers.
|
// we must free it to avoid leaking registers.
|
||||||
if let Some(comp_res) = result
|
if let Some(comp_res) = result
|
||||||
@@ -1030,11 +1050,11 @@ 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<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: Expression,
|
expr: Spanned<Expression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<VariableLocation, Error> {
|
) -> Result<VariableLocation, Error> {
|
||||||
if let Expression::Negation(neg_expr) = &expr
|
if let Expression::Negation(neg_expr) = &expr.node
|
||||||
&& let Expression::Literal(spanned_lit) = &**neg_expr
|
&& 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);
|
||||||
@@ -1042,7 +1062,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
return Ok(loc);
|
return Ok(loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
match expr {
|
match expr.node {
|
||||||
Expression::Variable(var_name) => match scope
|
Expression::Variable(var_name) => match scope
|
||||||
.get_location_of(&var_name.node)
|
.get_location_of(&var_name.node)
|
||||||
.map_err(|_| Error::UnknownIdentifier(var_name.node, var_name.span))?
|
.map_err(|_| Error::UnknownIdentifier(var_name.node, var_name.span))?
|
||||||
@@ -1085,7 +1105,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Expression::Binary(bin_expr) => {
|
Expression::Binary(bin_expr) => {
|
||||||
let result = self.expression_binary(bin_expr.node, scope)?;
|
let result = self.expression_binary(bin_expr, scope)?;
|
||||||
let result_reg = self.resolve_register(&result.location)?;
|
let result_reg = self.resolve_register(&result.location)?;
|
||||||
self.write_output(format!(
|
self.write_output(format!(
|
||||||
"move r{} {}",
|
"move r{} {}",
|
||||||
@@ -1097,7 +1117,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Logical(log_expr) => {
|
Expression::Logical(log_expr) => {
|
||||||
let result = self.expression_logical(log_expr.node, scope)?;
|
let result = self.expression_logical(log_expr, scope)?;
|
||||||
let result_reg = self.resolve_register(&result.location)?;
|
let result_reg = self.resolve_register(&result.location)?;
|
||||||
self.write_output(format!(
|
self.write_output(format!(
|
||||||
"move r{} {}",
|
"move r{} {}",
|
||||||
@@ -1336,7 +1356,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.expression_return(*ret_expr, &mut block_scope)?;
|
self.expression_return(*ret_expr, &mut block_scope)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let result = self.expression(expr.node, &mut block_scope)?;
|
let result = self.expression(expr, &mut block_scope)?;
|
||||||
// Free unused statement results
|
// Free unused statement results
|
||||||
if let Some(comp_res) = result
|
if let Some(comp_res) = result
|
||||||
&& let Some(name) = comp_res.temp_name
|
&& let Some(name) = comp_res.temp_name
|
||||||
@@ -1350,7 +1370,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
// Get the saved return address and save it back into `ra`
|
// Get the saved return address and save it back into `ra`
|
||||||
let VariableLocation::Stack(ra_stack_offset) = block_scope
|
let VariableLocation::Stack(ra_stack_offset) = block_scope
|
||||||
.get_location_of(format!("{}_ra", name.node))
|
.get_location_of(format!("{}_ra", name.node))
|
||||||
.map_err(|e| Error::ScopeError(e))?
|
.map_err(Error::ScopeError)?
|
||||||
else {
|
else {
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
"Stored return address not in stack as expected".into(),
|
"Stored return address not in stack as expected".into(),
|
||||||
@@ -1375,4 +1395,3 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -934,7 +934,7 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut arguments = Vec::<Expression>::new();
|
let mut arguments = Vec::<Spanned<Expression>>::new();
|
||||||
|
|
||||||
while !token_matches!(
|
while !token_matches!(
|
||||||
self.get_next()?.ok_or(Error::UnexpectedEOF)?,
|
self.get_next()?.ok_or(Error::UnexpectedEOF)?,
|
||||||
@@ -949,7 +949,7 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments.push(expression.node);
|
arguments.push(expression);
|
||||||
|
|
||||||
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
|
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
|
||||||
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
|
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
|
||||||
@@ -1308,7 +1308,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn syscall(&mut self) -> Result<SysCall, Error> {
|
fn syscall(&mut self) -> Result<SysCall, Error> {
|
||||||
fn check_length(
|
fn check_length(
|
||||||
parser: &Parser,
|
parser: &Parser,
|
||||||
arguments: &[Expression],
|
arguments: &[Spanned<Expression>],
|
||||||
length: usize,
|
length: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if arguments.len() != length {
|
if arguments.len() != length {
|
||||||
@@ -1323,10 +1323,18 @@ impl<'a> Parser<'a> {
|
|||||||
macro_rules! literal_or_variable {
|
macro_rules! literal_or_variable {
|
||||||
($iter:expr) => {
|
($iter:expr) => {
|
||||||
match $iter {
|
match $iter {
|
||||||
Some(Expression::Literal(literal)) => {
|
Some(expr) => match &expr.node {
|
||||||
|
Expression::Literal(literal) => {
|
||||||
LiteralOrVariable::Literal(literal.node.clone())
|
LiteralOrVariable::Literal(literal.node.clone())
|
||||||
}
|
}
|
||||||
Some(Expression::Variable(ident)) => LiteralOrVariable::Variable(ident),
|
Expression::Variable(ident) => LiteralOrVariable::Variable(ident.clone()),
|
||||||
|
_ => {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
self.current_span(),
|
||||||
|
self.current_token.clone().unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
self.current_span(),
|
self.current_span(),
|
||||||
@@ -1360,18 +1368,8 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
"sleep" => {
|
"sleep" => {
|
||||||
check_length(self, &invocation.arguments, 1)?;
|
check_length(self, &invocation.arguments, 1)?;
|
||||||
// arguments is Vec<Expression>.
|
|
||||||
let mut arg = invocation.arguments.into_iter();
|
let mut arg = invocation.arguments.into_iter();
|
||||||
let expr = arg.next().unwrap();
|
let expr = arg.next().unwrap();
|
||||||
|
|
||||||
// We need to wrap `expr` into a `Box<Spanned<Expression>>`?
|
|
||||||
// Wait, System::Sleep takes Box<Expression>.
|
|
||||||
// Expression variants are Spanned.
|
|
||||||
// But Expression IS NOT Spanned<Expression>.
|
|
||||||
// Expression enum contains Spanned<BinaryExpression>, etc.
|
|
||||||
// But `Expression` itself is the node.
|
|
||||||
// The issue: `expr` is `Expression` (which is Spanned internally).
|
|
||||||
// `System::Sleep(Box<Expression>)`.
|
|
||||||
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
||||||
}
|
}
|
||||||
"hash" => {
|
"hash" => {
|
||||||
@@ -1396,7 +1394,8 @@ impl<'a> Parser<'a> {
|
|||||||
let next_arg = args.next();
|
let next_arg = args.next();
|
||||||
|
|
||||||
let variable = match next_arg {
|
let variable = match next_arg {
|
||||||
Some(Expression::Literal(spanned_lit)) => match spanned_lit.node {
|
Some(expr) => match expr.node {
|
||||||
|
Expression::Literal(spanned_lit) => match spanned_lit.node {
|
||||||
Literal::String(s) => s,
|
Literal::String(s) => s,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
@@ -1411,6 +1410,13 @@ impl<'a> Parser<'a> {
|
|||||||
self.current_token.clone().unwrap(),
|
self.current_token.clone().unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
self.current_span(),
|
||||||
|
self.current_token.clone().unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(SysCall::System(sys_call::System::LoadFromDevice(
|
Ok(SysCall::System(sys_call::System::LoadFromDevice(
|
||||||
@@ -1431,11 +1437,35 @@ impl<'a> Parser<'a> {
|
|||||||
boxed!(variable),
|
boxed!(variable),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
// Fallback for brevity in this response
|
"setOnDeviceBatched" => {
|
||||||
_ => Err(Error::UnsupportedKeyword(
|
check_length(self, &invocation.arguments, 3)?;
|
||||||
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
let device_hash = literal_or_variable!(args.next());
|
||||||
|
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||||
|
let variable = args.next().unwrap();
|
||||||
|
Ok(SysCall::System(sys_call::System::SetOnDeviceBatched(
|
||||||
|
device_hash,
|
||||||
|
Literal::String(logic_type.to_string().replace("\"", "")),
|
||||||
|
boxed!(variable),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// For Math functions or unknown functions
|
||||||
|
if SysCall::is_syscall(&invocation.name.node) {
|
||||||
|
// Attempt to parse as math if applicable, or error if strict
|
||||||
|
// Here we are falling back to simple handling or error.
|
||||||
|
// Since Math isn't fully expanded in this snippet, we return Unsupported.
|
||||||
|
Err(Error::UnsupportedKeyword(
|
||||||
self.current_span(),
|
self.current_span(),
|
||||||
self.current_token.clone().unwrap(),
|
self.current_token.clone().unwrap(),
|
||||||
)),
|
))
|
||||||
|
} else {
|
||||||
|
Err(Error::UnsupportedKeyword(
|
||||||
|
self.current_span(),
|
||||||
|
self.current_token.clone().unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::tree_node::{Expression, Literal};
|
use crate::tree_node::{Expression, Literal, Spanned};
|
||||||
|
|
||||||
use super::LiteralOrVariable;
|
use super::LiteralOrVariable;
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ pub enum System {
|
|||||||
/// Represents a function that can be called to sleep for a certain amount of time.
|
/// Represents a function that can be called to sleep for a certain amount of time.
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
/// `sleep a(r?|num)`
|
/// `sleep a(r?|num)`
|
||||||
Sleep(Box<Expression>),
|
Sleep(Box<Spanned<Expression>>),
|
||||||
/// Gets the in-game hash for a specific prefab name.
|
/// Gets the in-game hash for a specific prefab name.
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
/// `HASH("prefabName")`
|
/// `HASH("prefabName")`
|
||||||
@@ -120,7 +120,12 @@ pub enum System {
|
|||||||
/// lbn r? deviceHash nameHash logicType batchMode
|
/// lbn r? deviceHash nameHash logicType batchMode
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
/// lbn r0 HASH("StructureWallLight") HASH("wallLight") On Minimum
|
/// lbn r0 HASH("StructureWallLight") HASH("wallLight") On Minimum
|
||||||
LoadBatchNamed(LiteralOrVariable, Box<Expression>, Literal, Literal),
|
LoadBatchNamed(
|
||||||
|
LiteralOrVariable,
|
||||||
|
Box<Spanned<Expression>>,
|
||||||
|
Literal,
|
||||||
|
Literal,
|
||||||
|
),
|
||||||
/// Loads a LogicType from all connected network devices, aggregating them via a
|
/// Loads a LogicType from all connected network devices, aggregating them via a
|
||||||
/// batchMode
|
/// batchMode
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
@@ -133,14 +138,14 @@ pub enum System {
|
|||||||
/// `s d? logicType r?`
|
/// `s d? logicType r?`
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// `s d0 Setting r0`
|
/// `s d0 Setting r0`
|
||||||
SetOnDevice(LiteralOrVariable, Literal, Box<Expression>),
|
SetOnDevice(LiteralOrVariable, Literal, Box<Spanned<Expression>>),
|
||||||
/// Represents a function which stores a setting to all devices that match
|
/// Represents a function which stores a setting to all devices that match
|
||||||
/// the given deviceHash
|
/// the given deviceHash
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
/// `sb deviceHash logicType r?`
|
/// `sb deviceHash logicType r?`
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// `sb HASH("Doors") Lock 1`
|
/// `sb HASH("Doors") Lock 1`
|
||||||
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Expression>),
|
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Spanned<Expression>>),
|
||||||
/// Represents a function which stores a setting to all devices that match
|
/// Represents a function which stores a setting to all devices that match
|
||||||
/// both the given deviceHash AND the given nameHash
|
/// both the given deviceHash AND the given nameHash
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
@@ -151,7 +156,7 @@ pub enum System {
|
|||||||
LiteralOrVariable,
|
LiteralOrVariable,
|
||||||
LiteralOrVariable,
|
LiteralOrVariable,
|
||||||
Literal,
|
Literal,
|
||||||
Box<Expression>,
|
Box<Spanned<Expression>>,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,3 +229,4 @@ impl SysCall {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ impl std::fmt::Display for BlockExpression {
|
|||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct InvocationExpression {
|
pub struct InvocationExpression {
|
||||||
pub name: Spanned<String>,
|
pub name: Spanned<String>,
|
||||||
pub arguments: Vec<Expression>,
|
pub arguments: Vec<Spanned<Expression>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for InvocationExpression {
|
impl std::fmt::Display for InvocationExpression {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![allow(clippy::result_large_err)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quick_error;
|
extern crate quick_error;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user