diff --git a/minbasic-vscode/language-configuration.json b/minbasic-vscode/language-configuration.json index 8f162a0..c6ee036 100644 --- a/minbasic-vscode/language-configuration.json +++ b/minbasic-vscode/language-configuration.json @@ -1,9 +1,7 @@ { "comments": { // symbol used for single line comment. Remove this entry if your language does not support line comments - "lineComment": "//", - // symbols used for start and end a block comment. Remove this entry if your language does not support block comments - "blockComment": [ "/*", "*/" ] + "lineComment": "REM", }, // symbols used as brackets "brackets": [ @@ -27,4 +25,4 @@ ["\"", "\""], ["'", "'"] ] -} \ No newline at end of file +} diff --git a/minbasic-vscode/syntaxes/minbasic.tmLanguage.json b/minbasic-vscode/syntaxes/minbasic.tmLanguage.json index a81e426..1ce8cfd 100644 --- a/minbasic-vscode/syntaxes/minbasic.tmLanguage.json +++ b/minbasic-vscode/syntaxes/minbasic.tmLanguage.json @@ -23,7 +23,7 @@ }, { "comment": "Keyword", - "match": "(?i)(\\b((END ?)?IF|(END )?SELECT|(RESUME )?NEXT|CASE|CLOSE|DO|ELSE|FOR|GOSUB|GOTO|LOOP|ON|OPEN|RETURN|THEN|TO|UNTIL|WHILE)\\b)", + "match": "(?i)(\\b((END ?)?IF|(END )?SELECT|(RESUME )?NEXT|CASE|CLOSE|DO|ELSE|FOR|GOSUB|GOTO|LOOP|ON|RETURN|THEN|TO|WHILE|WEND|END)\\b)", "name": "keyword.control.minbasic" }, { @@ -33,7 +33,7 @@ }, { "comment": "Operator", - "match": "(?i)((\\+|=|<|>|<>|AND|OR))", + "match": "(?i)(([+\\-*/\\.%]|[!=]=|<[=<]?|>[=>]?|<>|AND|OR))", "name": "keyword.operator.minbasic" }, { diff --git a/src/parse/ast.rs b/src/parse/ast.rs index d9925ed..33531c3 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -403,7 +403,7 @@ macro_rules! impl_op_basic_ast_expression { type Output = BasicAstExpression; fn $fn_name(self, other: Self) -> Self { - Self::Binary($self_op, Box::new(self), Box::new(other)) + Self::Binary($self_op.into(), Box::new(self), Box::new(other)) } } }; @@ -469,7 +469,7 @@ pub(crate) fn parse_expression( )) } } else if let Some(binary_operator) = - Operator::from_fn_name(fn_name_lowercase.as_str()) + BasicOperator::from_fn_name(fn_name_lowercase.as_str()) { if arguments.len() != 2 { Err(ParseError::InvalidArgumentCount( diff --git a/src/parse/test.rs b/src/parse/test.rs index 142b020..bf4ccbd 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -8,7 +8,7 @@ fn test_tokenize_basic() { vec![ BasicToken::NewLine, BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Name(String::from("world")), ], ); @@ -20,7 +20,7 @@ fn test_tokenize_basic() { BasicToken::Name(String::from("thing")), BasicToken::Assign, BasicToken::Name(String::from("thing")), - BasicToken::Operator(Operator::Div), + BasicToken::Operator(Operator::Div.into()), BasicToken::Integer(2) ], ); @@ -33,7 +33,7 @@ fn test_tokenize_basic() { BasicToken::Name(String::from("thing")), BasicToken::Assign, BasicToken::Name(String::from("thing")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Float(0.5), BasicToken::NewLine, BasicToken::Goto, @@ -51,7 +51,7 @@ fn test_tokenize_basic() { BasicToken::NewLine, BasicToken::If, BasicToken::Name(String::from("x")), - BasicToken::Operator(Operator::Gt), + BasicToken::Operator(Operator::Gt.into()), BasicToken::Integer(0), BasicToken::Then, BasicToken::NewLine, @@ -70,7 +70,7 @@ fn test_tokenize_basic() { BasicToken::NewLine, BasicToken::If, BasicToken::Name(String::from("x")), - BasicToken::Operator(Operator::Gt), + BasicToken::Operator(Operator::Gt.into()), BasicToken::Integer(0), BasicToken::Then, BasicToken::NewLine, @@ -147,11 +147,11 @@ fn test_operator_precedence() { assert_eq!( test_parse([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Integer(1), ]), BasicAstExpression::Binary( - Operator::Add, + Operator::Add.into(), Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Integer(1)), ) @@ -160,16 +160,16 @@ fn test_operator_precedence() { assert_eq!( test_parse([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Integer(2), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Mul.into()), BasicToken::Name(String::from("world")), ]), BasicAstExpression::Binary( - Operator::Add, + Operator::Add.into(), Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Binary( - Operator::Mul, + Operator::Mul.into(), Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Variable(String::from("world"))), )), @@ -179,15 +179,15 @@ fn test_operator_precedence() { assert_eq!( test_parse([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Mul.into()), BasicToken::Integer(2), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Name(String::from("world")), ]), BasicAstExpression::Binary( - Operator::Add, + Operator::Add.into(), Box::new(BasicAstExpression::Binary( - Operator::Mul, + Operator::Mul.into(), Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Integer(2)), )), @@ -198,18 +198,18 @@ fn test_operator_precedence() { assert_eq!( test_parse([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Mul.into()), BasicToken::OpenParen, BasicToken::Integer(2), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::Name(String::from("world")), BasicToken::CloseParen, ]), BasicAstExpression::Binary( - Operator::Mul, + Operator::Mul.into(), Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Binary( - Operator::Add, + Operator::Add.into(), Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Variable(String::from("world"))), )), @@ -219,18 +219,18 @@ fn test_operator_precedence() { assert_eq!( test_parse([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::OpenParen, BasicToken::Name(String::from("world")), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Mul.into()), BasicToken::Integer(2), BasicToken::CloseParen, ]), BasicAstExpression::Binary( - Operator::Add, + Operator::Add.into(), Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Binary( - Operator::Mul, + Operator::Mul.into(), Box::new(BasicAstExpression::Variable(String::from("world"))), Box::new(BasicAstExpression::Integer(2)), )), @@ -240,7 +240,7 @@ fn test_operator_precedence() { assert_eq!( test_err([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), ]), ParseError::ExpectedOperand ); @@ -248,10 +248,10 @@ fn test_operator_precedence() { assert_eq!( test_err([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::OpenParen, BasicToken::Name(String::from("world")), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Mul.into()), BasicToken::Integer(2), ]), ParseError::MissingToken(BasicToken::CloseParen) @@ -260,16 +260,16 @@ fn test_operator_precedence() { assert_eq!( test_err([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), - BasicToken::Operator(Operator::Mul), + BasicToken::Operator(Operator::Add.into()), + BasicToken::Operator(Operator::Mul.into()), ]), - ParseError::UnexpectedToken(BasicToken::Operator(Operator::Mul)) + ParseError::UnexpectedToken(BasicToken::Operator(Operator::Mul.into())) ); assert!(matches!( test_err([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::OpenParen, ]), ParseError::ExpectedOperand | ParseError::MissingToken(BasicToken::CloseParen) @@ -278,7 +278,7 @@ fn test_operator_precedence() { assert!(matches!( test_err([ BasicToken::Name(String::from("hello")), - BasicToken::Operator(Operator::Add), + BasicToken::Operator(Operator::Add.into()), BasicToken::OpenParen, BasicToken::CloseParen ]), @@ -286,8 +286,11 @@ fn test_operator_precedence() { )); assert_eq!( - test_err([BasicToken::Operator(Operator::Add), BasicToken::Integer(2)]), - ParseError::UnexpectedToken(BasicToken::Operator(Operator::Add)) + test_err([ + BasicToken::Operator(Operator::Add.into()), + BasicToken::Integer(2) + ]), + ParseError::UnexpectedToken(BasicToken::Operator(Operator::Add.into())) ); } @@ -321,7 +324,7 @@ fn test_ast_basics() { test_build_ast("IF X < 0 THEN\nX = 0-X\nEND IF"), BasicAstBlock::new([BasicAstInstruction::IfThenElse( BasicAstExpression::Binary( - Operator::Lt, + Operator::Lt.into(), Box::new(BasicAstExpression::Variable(String::from("X"))), Box::new(BasicAstExpression::Integer(0)) ), diff --git a/src/parse/tokenize.rs b/src/parse/tokenize.rs index b2c77c3..25c9b76 100644 --- a/src/parse/tokenize.rs +++ b/src/parse/tokenize.rs @@ -31,7 +31,7 @@ pub enum BasicToken { Float(f64), Name(String), String(String), - Operator(Operator), + Operator(BasicOperator), } /// Transforms a raw string into a sequence of `BasicToken`s @@ -90,7 +90,7 @@ pub fn tokenize(raw: &str) -> Result, ParseError> { let match_integer = Regex::new(r"^[0-9]+").unwrap(); let match_assign = Regex::new(r"^=").unwrap(); let match_comma = Regex::new(r"^,").unwrap(); - let match_operator = Regex::new(r"^(?:[+\-*/%]|//|[<>]=?|[!=]=|<>|<<|>>|&&|\|\|)").unwrap(); + let match_operator = Regex::new(r"^(?:[+\-*/%\.]|//|[<>]=?|[!=]=|<>|<<|>>|&&|\|\|)").unwrap(); let match_label_end = Regex::new(r"^:").unwrap(); let match_paren = Regex::new(r"^(?:\(|\))").unwrap(); // TODO: handle escapes @@ -126,8 +126,8 @@ pub fn tokenize(raw: &str) -> Result, ParseError> { "loop" => BasicToken::Loop, "gosub" => BasicToken::GoSub, "return" => BasicToken::Return, - "and" => BasicToken::Operator(Operator::And), - "or" => BasicToken::Operator(Operator::Or), + "and" => BasicToken::Operator(Operator::And.into()), + "or" => BasicToken::Operator(Operator::Or.into()), _ => unreachable!("{}", word), }), match_end => (BasicToken::End), @@ -136,22 +136,23 @@ pub fn tokenize(raw: &str) -> Result, ParseError> { match_integer(int) => (BasicToken::Integer(int.parse().unwrap())), match_comma => (BasicToken::Comma), match_operator(op) => (BasicToken::Operator(match op { - "+" => Operator::Add, - "-" => Operator::Sub, - "*" => Operator::Mul, - "//" => Operator::IDiv, - "/" => Operator::Div, - "%" => Operator::Mod, - "<" => Operator::Lt, - "<=" => Operator::Lte, - ">" => Operator::Gt, - ">=" => Operator::Gte, - "<<" => Operator::LShift, - ">>" => Operator::RShift, - "==" => Operator::Eq, - "<>" | "!=" => Operator::Neq, - "&&" => Operator::And, - "||" => Operator::Or, + "+" => Operator::Add.into(), + "-" => Operator::Sub.into(), + "*" => Operator::Mul.into(), + "//" => Operator::IDiv.into(), + "/" => Operator::Div.into(), + "%" => Operator::Mod.into(), + "<" => Operator::Lt.into(), + "<=" => Operator::Lte.into(), + ">" => Operator::Gt.into(), + ">=" => Operator::Gte.into(), + "<<" => Operator::LShift.into(), + ">>" => Operator::RShift.into(), + "==" => Operator::Eq.into(), + "<>" | "!=" => Operator::Neq.into(), + "&&" => Operator::And.into(), + "||" => Operator::Or.into(), + "." => BasicOperator::Sensor, _ => unreachable!(), })), match_assign => (BasicToken::Assign), diff --git a/src/repr/basic.rs b/src/repr/basic.rs index e0c09c9..971a781 100644 --- a/src/repr/basic.rs +++ b/src/repr/basic.rs @@ -6,7 +6,11 @@ pub enum BasicAstExpression { Float(f64), Variable(String), String(String), - Binary(Operator, Box, Box), + Binary( + BasicOperator, + Box, + Box, + ), Unary(UnaryOperator, Box), } diff --git a/src/repr/mlog.rs b/src/repr/mlog.rs index 4ce71ea..830efa9 100644 --- a/src/repr/mlog.rs +++ b/src/repr/mlog.rs @@ -40,6 +40,8 @@ pub enum MindustryOperation { End, Operator(String, Operator, Operand, Operand), UnaryOperator(String, UnaryOperator, Operand), + /// Copies the value of rhs into lhs + Set(String, Operand), /// Reads the value at the `index`-th place in `cell` Read { @@ -60,8 +62,14 @@ pub enum MindustryOperation { /// Available to world processors only - flushes the print buffer to a global buffer WorldPrintFlush(WorldPrintFlush), - // TODO: add RandOperator - Set(String, Operand), + /// Reads `key` from `object` and puts its result into `out_name`. + /// `object` may be a connection, an entity, a block, a unit type, etc. + Sensor { + out_name: String, + object: Operand, + key: Operand, + }, + /// A generic operation, with the following invariants: /// - all of the operands are read-only /// - there is no external dependency to other variables @@ -74,63 +82,78 @@ pub enum MindustryOperation { GenericMut(String, String, Vec), } -impl MindustryOperation { - pub(crate) fn operands(&self) -> Box<[&Operand]> { - match self { - Self::Jump(_) | Self::JumpLabel(_) | Self::End => Box::new([]), - Self::JumpIf(_label, _operator, lhs, rhs) => Box::new([lhs, rhs]), - Self::Operator(_target, _operator, lhs, rhs) => Box::new([lhs, rhs]), - Self::UnaryOperator(_target, _operator, value) => Box::new([value]), - Self::Set(_target, value) => Box::new([value]), - Self::Generic(_name, operands) => { - operands.iter().collect::>().into_boxed_slice() +macro_rules! impl_operands { + ( + both: { + $( $pattern:pat => $value:expr ),* $(,)? + }, + mut: { + $( $pattern_mut:pat => $value_mut:expr ),* $(,)? + }, + ref: { + $( $pattern_ref:pat => $value_ref:expr ),* $(,)? + } $(,)? + ) => { + impl MindustryOperation { + pub(crate) fn operands(&self) -> Vec<&Operand> { + match self { + $( + $pattern => $value + ),* , + $( + $pattern_ref => $value_ref + ),* + } } - Self::GenericMut(_name, _out_name, operands) => { - operands.iter().collect::>().into_boxed_slice() + + pub(crate) fn operands_mut(&mut self) -> Vec<&mut Operand> { + match self { + $( + $pattern => $value + ),* , + $( + $pattern_mut => $value_mut + ),* + } } - Self::PrintFlush(cell) => Box::new([cell]), - Self::WorldPrintFlush(wpf) => match wpf { - WorldPrintFlush::Notify => Box::new([]), - WorldPrintFlush::Mission => Box::new([]), - WorldPrintFlush::Announce(time) => Box::new([time]), - WorldPrintFlush::Toast(time) => Box::new([time]), - }, - Self::Print(operand) => Box::new([operand]), - Self::Read { - out_name: _, - cell, - index, - } => Box::new([cell, index]), - Self::Write { value, cell, index } => Box::new([value, cell, index]), } } +} - pub(crate) fn operands_mut(&mut self) -> Vec<&mut Operand> { - match self { - Self::Jump(_) | Self::JumpLabel(_) | Self::End => vec![], - Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs], - Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs], - Self::UnaryOperator(_target, _operator, value) => vec![value], - Self::Set(_target, value) => vec![value], - Self::Generic(_name, operands) => operands.iter_mut().collect::>(), - Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::>(), - Self::PrintFlush(cell) => vec![cell], - Self::WorldPrintFlush(wpf) => match wpf { - WorldPrintFlush::Notify => vec![], - WorldPrintFlush::Mission => vec![], - WorldPrintFlush::Announce(time) => vec![time], - WorldPrintFlush::Toast(time) => vec![time], - }, - Self::Print(operand) => vec![operand], - Self::Read { - out_name: _, - cell, - index, - } => vec![cell, index], - Self::Write { value, cell, index } => vec![value, cell, index], - } +impl_operands!( + both: { + Self::Jump(_) | Self::JumpLabel(_) | Self::End => vec![], + Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs], + Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs], + Self::UnaryOperator(_target, _operator, value) => vec![value], + Self::Set(_target, value) => vec![value], + Self::PrintFlush(cell) => vec![cell], + Self::WorldPrintFlush(wpf) => match wpf { + WorldPrintFlush::Notify => vec![], + WorldPrintFlush::Mission => vec![], + WorldPrintFlush::Announce(time) => vec![time], + WorldPrintFlush::Toast(time) => vec![time], + }, + Self::Print(operand) => vec![operand], + Self::Read { + out_name: _, + cell, + index, + } => vec![cell, index], + Self::Write { value, cell, index } => vec![value, cell, index], + Self::Sensor { out_name: _, object, key } => vec![object, key], + }, + mut: { + Self::Generic(_name, operands) => operands.iter_mut().collect::>(), + Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::>(), + }, + ref: { + Self::Generic(_name, operands) => operands.iter().collect::>(), + Self::GenericMut(_name, _out_name, operands) => operands.iter().collect::>(), } +); +impl MindustryOperation { pub(crate) fn mutates(&self, var_name: &str) -> bool { match self { Self::JumpLabel(_) @@ -152,6 +175,11 @@ impl MindustryOperation { out_name, cell: _, index: _, + } + | Self::Sensor { + out_name, + object: _, + key: _, } => out_name == var_name, Self::Print(_) | Self::PrintFlush(_) | Self::WorldPrintFlush(_) => { @@ -177,6 +205,11 @@ impl MindustryOperation { cell: _, index: _, } + | Self::Sensor { + out_name: _, + object: _, + key: _, + } | Self::Print(_) | Self::PrintFlush(_) | Self::WorldPrintFlush(_) diff --git a/src/repr/operator.rs b/src/repr/operator.rs index 41795b4..b352dbb 100644 --- a/src/repr/operator.rs +++ b/src/repr/operator.rs @@ -21,6 +21,30 @@ pub enum Operator { Or, } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum BasicOperator { + Operator(Operator), + Sensor, +} + +impl BasicOperator { + pub(crate) fn precedence(self) -> u8 { + match self { + Self::Sensor => 20, + Self::Operator(op) => op.precedence(), + } + } + + pub(crate) fn from_fn_name(raw: &str) -> Option { + match raw { + "max" => Some(Self::Operator(Operator::Max)), + "min" => Some(Self::Operator(Operator::Min)), + "pow" => Some(Self::Operator(Operator::Pow)), + _ => None, + } + } +} + impl Operator { pub(crate) fn precedence(self) -> u8 { match self { @@ -33,17 +57,25 @@ impl Operator { _ => 128, } } +} - pub(crate) fn from_fn_name(raw: &str) -> Option { - match raw { - "max" => Some(Self::Max), - "min" => Some(Self::Min), - "pow" => Some(Self::Pow), - _ => None, +impl TryFrom for Operator { + type Error = (); + + fn try_from(value: BasicOperator) -> Result { + match value { + BasicOperator::Operator(op) => Ok(op), + BasicOperator::Sensor => Err(()), } } } +impl From for BasicOperator { + fn from(value: Operator) -> Self { + Self::Operator(value) + } +} + pub(crate) fn format_operator(operator: Operator) -> &'static str { match operator { Operator::Eq => "equal", diff --git a/src/translate/display.rs b/src/translate/display.rs index 6c406b7..6bb42ad 100644 --- a/src/translate/display.rs +++ b/src/translate/display.rs @@ -120,6 +120,9 @@ impl std::fmt::Display for MindustryProgram { WorldPrintFlush::Toast(time) => writeln!(f, "message toast {}", time)?, }; } + MindustryOperation::Sensor { out_name, object, key } => { + writeln!(f, "sensor {out_name} {object} {key}")?; + } } } diff --git a/src/translate/mod.rs b/src/translate/mod.rs index 4310995..ad876ec 100644 --- a/src/translate/mod.rs +++ b/src/translate/mod.rs @@ -66,12 +66,24 @@ fn translate_expression( let mut right = translate_expression(right.as_ref(), namer, right_name.clone()); res.append(&mut right); - res.push(MindustryOperation::Operator( - target_name, - *op, - Operand::Variable(left_name), - Operand::Variable(right_name), - )); + + match op { + BasicOperator::Operator(op) => { + res.push(MindustryOperation::Operator( + target_name, + *op, + Operand::Variable(left_name), + Operand::Variable(right_name), + )); + } + BasicOperator::Sensor => { + res.push(MindustryOperation::Sensor { + out_name: target_name, + object: Operand::Variable(left_name), + key: Operand::Variable(right_name), + }); + } + } res } @@ -143,8 +155,8 @@ pub fn translate_ast( String::from("__gosub_retaddr"), Operator::Mul, Operand::Variable(String::from("__gosub_retaddr")), - Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) - ); + Operand::Integer(MAX_INSTRUCTION_COUNT as i64), + )); res.push(MindustryOperation::Operator( String::from("__gosub_retaddr"), Operator::Add, @@ -159,20 +171,20 @@ pub fn translate_ast( String::from("__return"), Operator::Mod, Operand::Variable(String::from("__gosub_retaddr")), - Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) - ); + Operand::Integer(MAX_INSTRUCTION_COUNT as i64), + )); res.push(MindustryOperation::Operator( String::from("__gosub_retaddr"), Operator::IDiv, Operand::Variable(String::from("__gosub_retaddr")), - Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) - ); + Operand::Integer(MAX_INSTRUCTION_COUNT as i64), + )); res.push(MindustryOperation::Operator( String::from("@counter"), Operator::Add, Operand::Variable(String::from("__return")), - Operand::Integer(1)) - ); + Operand::Integer(1), + )); // Add a guard at the beginning of the program, to clear out the return address has_return = true; } @@ -414,7 +426,10 @@ pub fn translate_ast( } if has_return { - res.0.insert(0, MindustryOperation::Set(String::from("__gosub_retaddr"), Operand::Integer(0))); + res.0.insert( + 0, + MindustryOperation::Set(String::from("__gosub_retaddr"), Operand::Integer(0)), + ); } res