diff --git a/GUIDE.md b/GUIDE.md index 0d2a465..38bd08b 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -243,13 +243,25 @@ The "return stack" is cleared at the beginning of the generated program. `mlog` provides several ways for processors to interact with the in-game world, which are reflected in MinBasic using functions: - +LET enoughHealth = reactor.health >= reactor.maxHealth / 2 +LET enoughCryofluid = reactor.cryofluid >= reactor.liquidCapacity + +IF NOT(enoughHealth AND enoughCryofluid) THEN + reactor.enabled = false +ELSE + reactor.enabled = true +END IF +``` + +When reading, the dot operator translates to the `sensor` instruction, and replaces the key with its corresponding `@`-variable (`block1.health` becomes `sensor @health block1`, `@unit.x` becomes `sensor @x @unit`, etc.) + +When writing, the `control` instruction is used when possible, namely with `.enabled`, `.config` and `.color`. +Otherwise, the `setprop` instruction is used, which is only available to world processors, and the key is replaced with its corresponding `@`-variable. diff --git a/examples/reactor-safety.mbas b/examples/reactor-safety.mbas new file mode 100644 index 0000000..8852dc9 --- /dev/null +++ b/examples/reactor-safety.mbas @@ -0,0 +1,11 @@ +REM A simple program to shut down reactors when their health of cryofluid amount dips too low +LET reactor = reactor1 + +LET enoughHealth = reactor.health >= reactor.maxHealth / 2 +LET enoughCryofluid = reactor.cryofluid >= reactor.liquidCapacity + +IF NOT(enoughHealth AND enoughCryofluid) THEN + reactor.enabled = false +ELSE + reactor.enabled = true +END IF diff --git a/src/optimize/dead.rs b/src/optimize/dead.rs index ca8e742..3277708 100644 --- a/src/optimize/dead.rs +++ b/src/optimize/dead.rs @@ -31,7 +31,9 @@ pub(crate) fn optimize_dead_code(program: MindustryProgram) -> MindustryProgram replace_if( program, |_instructions, instruction, _index| match instruction { - MindustryOperation::Set(name, _) | MindustryOperation::Operator(name, _, _, _) => { + MindustryOperation::Set(name, _) + | MindustryOperation::Operator(name, _, _, _) + | MindustryOperation::UnaryOperator(name, _, _) => { if !is_temporary_variable(name) { return None; } diff --git a/src/optimize/jump.rs b/src/optimize/jump.rs index 10dc70e..8c1f5b7 100644 --- a/src/optimize/jump.rs +++ b/src/optimize/jump.rs @@ -48,6 +48,11 @@ pub fn optimize_jump_op(program: MindustryProgram) -> MindustryProgram { { Lookaround::Stop((*operator, lhs.clone(), rhs.clone())) } + MindustryOperation::UnaryOperator(name, operator, value) + if *name == var_name && *operator == UnaryOperator::Not => + { + Lookaround::Stop((Operator::Eq, value.clone(), Operand::Integer(0))) + } x if x.mutates(&var_name) || x.breaks_flow() => Lookaround::Abort, _ => Lookaround::Continue, }, diff --git a/src/repr/operator.rs b/src/repr/operator.rs index 7da5aed..9290f73 100644 --- a/src/repr/operator.rs +++ b/src/repr/operator.rs @@ -108,7 +108,7 @@ pub enum UnaryOperator { Ceil, Rand, Sqrt, - // Not, + Not, } impl TryFrom<&str> for UnaryOperator { @@ -121,17 +121,8 @@ impl TryFrom<&str> for UnaryOperator { "ceil" => Ok(Self::Ceil), "rand" => Ok(Self::Rand), "sqrt" => Ok(Self::Sqrt), + "not" => Ok(Self::Not), _ => Err(()), } } } - -pub(crate) fn format_unary_operator(operator: UnaryOperator) -> &'static str { - match operator { - UnaryOperator::Floor => "floor", - UnaryOperator::Round => "round", - UnaryOperator::Ceil => "ceil", - UnaryOperator::Rand => "rand", - UnaryOperator::Sqrt => "sqrt", - } -} diff --git a/src/translate/display.rs b/src/translate/display.rs index 7baadf4..6a9e424 100644 --- a/src/translate/display.rs +++ b/src/translate/display.rs @@ -148,6 +148,18 @@ impl std::fmt::Display for MindustryProgram { } } +fn format_unary_operator(operator: UnaryOperator) -> &'static str { + match operator { + UnaryOperator::Floor => "floor", + UnaryOperator::Round => "round", + UnaryOperator::Ceil => "ceil", + UnaryOperator::Rand => "rand", + UnaryOperator::Sqrt => "sqrt", + // Note: we use `equal x 0` to implement the binary NOT operation + UnaryOperator::Not => "equal", + } +} + fn format_condition(operator: Operator) -> &'static str { match operator { Operator::Eq => "equal",