Dot operator for Sensor

main
Shad Amethyst 1 year ago
parent ed5de3aaa1
commit 00f992d459

@ -1,9 +1,7 @@
{ {
"comments": { "comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments // symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "//", "lineComment": "REM",
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
"blockComment": [ "/*", "*/" ]
}, },
// symbols used as brackets // symbols used as brackets
"brackets": [ "brackets": [

@ -23,7 +23,7 @@
}, },
{ {
"comment": "Keyword", "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" "name": "keyword.control.minbasic"
}, },
{ {
@ -33,7 +33,7 @@
}, },
{ {
"comment": "Operator", "comment": "Operator",
"match": "(?i)((\\+|=|<|>|<>|AND|OR))", "match": "(?i)(([+\\-*/\\.%]|[!=]=|<[=<]?|>[=>]?|<>|AND|OR))",
"name": "keyword.operator.minbasic" "name": "keyword.operator.minbasic"
}, },
{ {

@ -403,7 +403,7 @@ macro_rules! impl_op_basic_ast_expression {
type Output = BasicAstExpression; type Output = BasicAstExpression;
fn $fn_name(self, other: Self) -> Self { 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) = } 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 { if arguments.len() != 2 {
Err(ParseError::InvalidArgumentCount( Err(ParseError::InvalidArgumentCount(

@ -8,7 +8,7 @@ fn test_tokenize_basic() {
vec![ vec![
BasicToken::NewLine, BasicToken::NewLine,
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
], ],
); );
@ -20,7 +20,7 @@ fn test_tokenize_basic() {
BasicToken::Name(String::from("thing")), BasicToken::Name(String::from("thing")),
BasicToken::Assign, BasicToken::Assign,
BasicToken::Name(String::from("thing")), BasicToken::Name(String::from("thing")),
BasicToken::Operator(Operator::Div), BasicToken::Operator(Operator::Div.into()),
BasicToken::Integer(2) BasicToken::Integer(2)
], ],
); );
@ -33,7 +33,7 @@ fn test_tokenize_basic() {
BasicToken::Name(String::from("thing")), BasicToken::Name(String::from("thing")),
BasicToken::Assign, BasicToken::Assign,
BasicToken::Name(String::from("thing")), BasicToken::Name(String::from("thing")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Float(0.5), BasicToken::Float(0.5),
BasicToken::NewLine, BasicToken::NewLine,
BasicToken::Goto, BasicToken::Goto,
@ -51,7 +51,7 @@ fn test_tokenize_basic() {
BasicToken::NewLine, BasicToken::NewLine,
BasicToken::If, BasicToken::If,
BasicToken::Name(String::from("x")), BasicToken::Name(String::from("x")),
BasicToken::Operator(Operator::Gt), BasicToken::Operator(Operator::Gt.into()),
BasicToken::Integer(0), BasicToken::Integer(0),
BasicToken::Then, BasicToken::Then,
BasicToken::NewLine, BasicToken::NewLine,
@ -70,7 +70,7 @@ fn test_tokenize_basic() {
BasicToken::NewLine, BasicToken::NewLine,
BasicToken::If, BasicToken::If,
BasicToken::Name(String::from("x")), BasicToken::Name(String::from("x")),
BasicToken::Operator(Operator::Gt), BasicToken::Operator(Operator::Gt.into()),
BasicToken::Integer(0), BasicToken::Integer(0),
BasicToken::Then, BasicToken::Then,
BasicToken::NewLine, BasicToken::NewLine,
@ -147,11 +147,11 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_parse([ test_parse([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Integer(1), BasicToken::Integer(1),
]), ]),
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Add, Operator::Add.into(),
Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Variable(String::from("hello"))),
Box::new(BasicAstExpression::Integer(1)), Box::new(BasicAstExpression::Integer(1)),
) )
@ -160,16 +160,16 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_parse([ test_parse([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Integer(2), BasicToken::Integer(2),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
]), ]),
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Add, Operator::Add.into(),
Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Variable(String::from("hello"))),
Box::new(BasicAstExpression::Binary( Box::new(BasicAstExpression::Binary(
Operator::Mul, Operator::Mul.into(),
Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Integer(2)),
Box::new(BasicAstExpression::Variable(String::from("world"))), Box::new(BasicAstExpression::Variable(String::from("world"))),
)), )),
@ -179,15 +179,15 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_parse([ test_parse([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
BasicToken::Integer(2), BasicToken::Integer(2),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
]), ]),
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Add, Operator::Add.into(),
Box::new(BasicAstExpression::Binary( Box::new(BasicAstExpression::Binary(
Operator::Mul, Operator::Mul.into(),
Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Variable(String::from("hello"))),
Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Integer(2)),
)), )),
@ -198,18 +198,18 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_parse([ test_parse([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
BasicToken::OpenParen, BasicToken::OpenParen,
BasicToken::Integer(2), BasicToken::Integer(2),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
BasicToken::CloseParen, BasicToken::CloseParen,
]), ]),
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Mul, Operator::Mul.into(),
Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Variable(String::from("hello"))),
Box::new(BasicAstExpression::Binary( Box::new(BasicAstExpression::Binary(
Operator::Add, Operator::Add.into(),
Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Integer(2)),
Box::new(BasicAstExpression::Variable(String::from("world"))), Box::new(BasicAstExpression::Variable(String::from("world"))),
)), )),
@ -219,18 +219,18 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_parse([ test_parse([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::OpenParen, BasicToken::OpenParen,
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
BasicToken::Integer(2), BasicToken::Integer(2),
BasicToken::CloseParen, BasicToken::CloseParen,
]), ]),
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Add, Operator::Add.into(),
Box::new(BasicAstExpression::Variable(String::from("hello"))), Box::new(BasicAstExpression::Variable(String::from("hello"))),
Box::new(BasicAstExpression::Binary( Box::new(BasicAstExpression::Binary(
Operator::Mul, Operator::Mul.into(),
Box::new(BasicAstExpression::Variable(String::from("world"))), Box::new(BasicAstExpression::Variable(String::from("world"))),
Box::new(BasicAstExpression::Integer(2)), Box::new(BasicAstExpression::Integer(2)),
)), )),
@ -240,7 +240,7 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_err([ test_err([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
]), ]),
ParseError::ExpectedOperand ParseError::ExpectedOperand
); );
@ -248,10 +248,10 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_err([ test_err([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::OpenParen, BasicToken::OpenParen,
BasicToken::Name(String::from("world")), BasicToken::Name(String::from("world")),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
BasicToken::Integer(2), BasicToken::Integer(2),
]), ]),
ParseError::MissingToken(BasicToken::CloseParen) ParseError::MissingToken(BasicToken::CloseParen)
@ -260,16 +260,16 @@ fn test_operator_precedence() {
assert_eq!( assert_eq!(
test_err([ test_err([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::Operator(Operator::Mul), BasicToken::Operator(Operator::Mul.into()),
]), ]),
ParseError::UnexpectedToken(BasicToken::Operator(Operator::Mul)) ParseError::UnexpectedToken(BasicToken::Operator(Operator::Mul.into()))
); );
assert!(matches!( assert!(matches!(
test_err([ test_err([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::OpenParen, BasicToken::OpenParen,
]), ]),
ParseError::ExpectedOperand | ParseError::MissingToken(BasicToken::CloseParen) ParseError::ExpectedOperand | ParseError::MissingToken(BasicToken::CloseParen)
@ -278,7 +278,7 @@ fn test_operator_precedence() {
assert!(matches!( assert!(matches!(
test_err([ test_err([
BasicToken::Name(String::from("hello")), BasicToken::Name(String::from("hello")),
BasicToken::Operator(Operator::Add), BasicToken::Operator(Operator::Add.into()),
BasicToken::OpenParen, BasicToken::OpenParen,
BasicToken::CloseParen BasicToken::CloseParen
]), ]),
@ -286,8 +286,11 @@ fn test_operator_precedence() {
)); ));
assert_eq!( assert_eq!(
test_err([BasicToken::Operator(Operator::Add), BasicToken::Integer(2)]), test_err([
ParseError::UnexpectedToken(BasicToken::Operator(Operator::Add)) 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"), test_build_ast("IF X < 0 THEN\nX = 0-X\nEND IF"),
BasicAstBlock::new([BasicAstInstruction::IfThenElse( BasicAstBlock::new([BasicAstInstruction::IfThenElse(
BasicAstExpression::Binary( BasicAstExpression::Binary(
Operator::Lt, Operator::Lt.into(),
Box::new(BasicAstExpression::Variable(String::from("X"))), Box::new(BasicAstExpression::Variable(String::from("X"))),
Box::new(BasicAstExpression::Integer(0)) Box::new(BasicAstExpression::Integer(0))
), ),

@ -31,7 +31,7 @@ pub enum BasicToken {
Float(f64), Float(f64),
Name(String), Name(String),
String(String), String(String),
Operator(Operator), Operator(BasicOperator),
} }
/// Transforms a raw string into a sequence of `BasicToken`s /// Transforms a raw string into a sequence of `BasicToken`s
@ -90,7 +90,7 @@ pub fn tokenize(raw: &str) -> Result<Vec<BasicToken>, ParseError> {
let match_integer = Regex::new(r"^[0-9]+").unwrap(); let match_integer = Regex::new(r"^[0-9]+").unwrap();
let match_assign = Regex::new(r"^=").unwrap(); let match_assign = Regex::new(r"^=").unwrap();
let match_comma = 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_label_end = Regex::new(r"^:").unwrap();
let match_paren = Regex::new(r"^(?:\(|\))").unwrap(); let match_paren = Regex::new(r"^(?:\(|\))").unwrap();
// TODO: handle escapes // TODO: handle escapes
@ -126,8 +126,8 @@ pub fn tokenize(raw: &str) -> Result<Vec<BasicToken>, ParseError> {
"loop" => BasicToken::Loop, "loop" => BasicToken::Loop,
"gosub" => BasicToken::GoSub, "gosub" => BasicToken::GoSub,
"return" => BasicToken::Return, "return" => BasicToken::Return,
"and" => BasicToken::Operator(Operator::And), "and" => BasicToken::Operator(Operator::And.into()),
"or" => BasicToken::Operator(Operator::Or), "or" => BasicToken::Operator(Operator::Or.into()),
_ => unreachable!("{}", word), _ => unreachable!("{}", word),
}), }),
match_end => (BasicToken::End), match_end => (BasicToken::End),
@ -136,22 +136,23 @@ pub fn tokenize(raw: &str) -> Result<Vec<BasicToken>, ParseError> {
match_integer(int) => (BasicToken::Integer(int.parse().unwrap())), match_integer(int) => (BasicToken::Integer(int.parse().unwrap())),
match_comma => (BasicToken::Comma), match_comma => (BasicToken::Comma),
match_operator(op) => (BasicToken::Operator(match op { match_operator(op) => (BasicToken::Operator(match op {
"+" => Operator::Add, "+" => Operator::Add.into(),
"-" => Operator::Sub, "-" => Operator::Sub.into(),
"*" => Operator::Mul, "*" => Operator::Mul.into(),
"//" => Operator::IDiv, "//" => Operator::IDiv.into(),
"/" => Operator::Div, "/" => Operator::Div.into(),
"%" => Operator::Mod, "%" => Operator::Mod.into(),
"<" => Operator::Lt, "<" => Operator::Lt.into(),
"<=" => Operator::Lte, "<=" => Operator::Lte.into(),
">" => Operator::Gt, ">" => Operator::Gt.into(),
">=" => Operator::Gte, ">=" => Operator::Gte.into(),
"<<" => Operator::LShift, "<<" => Operator::LShift.into(),
">>" => Operator::RShift, ">>" => Operator::RShift.into(),
"==" => Operator::Eq, "==" => Operator::Eq.into(),
"<>" | "!=" => Operator::Neq, "<>" | "!=" => Operator::Neq.into(),
"&&" => Operator::And, "&&" => Operator::And.into(),
"||" => Operator::Or, "||" => Operator::Or.into(),
"." => BasicOperator::Sensor,
_ => unreachable!(), _ => unreachable!(),
})), })),
match_assign => (BasicToken::Assign), match_assign => (BasicToken::Assign),

@ -6,7 +6,11 @@ pub enum BasicAstExpression {
Float(f64), Float(f64),
Variable(String), Variable(String),
String(String), String(String),
Binary(Operator, Box<BasicAstExpression>, Box<BasicAstExpression>), Binary(
BasicOperator,
Box<BasicAstExpression>,
Box<BasicAstExpression>,
),
Unary(UnaryOperator, Box<BasicAstExpression>), Unary(UnaryOperator, Box<BasicAstExpression>),
} }

@ -40,6 +40,8 @@ pub enum MindustryOperation {
End, End,
Operator(String, Operator, Operand, Operand), Operator(String, Operator, Operand, Operand),
UnaryOperator(String, UnaryOperator, 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` /// Reads the value at the `index`-th place in `cell`
Read { Read {
@ -60,8 +62,14 @@ pub enum MindustryOperation {
/// Available to world processors only - flushes the print buffer to a global buffer /// Available to world processors only - flushes the print buffer to a global buffer
WorldPrintFlush(WorldPrintFlush), WorldPrintFlush(WorldPrintFlush),
// TODO: add RandOperator /// Reads `key` from `object` and puts its result into `out_name`.
Set(String, Operand), /// `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: /// A generic operation, with the following invariants:
/// - all of the operands are read-only /// - all of the operands are read-only
/// - there is no external dependency to other variables /// - there is no external dependency to other variables
@ -74,63 +82,78 @@ pub enum MindustryOperation {
GenericMut(String, String, Vec<Operand>), GenericMut(String, String, Vec<Operand>),
} }
impl MindustryOperation { macro_rules! impl_operands {
pub(crate) fn operands(&self) -> Box<[&Operand]> { (
match self { both: {
Self::Jump(_) | Self::JumpLabel(_) | Self::End => Box::new([]), $( $pattern:pat => $value:expr ),* $(,)?
Self::JumpIf(_label, _operator, lhs, rhs) => Box::new([lhs, rhs]), },
Self::Operator(_target, _operator, lhs, rhs) => Box::new([lhs, rhs]), mut: {
Self::UnaryOperator(_target, _operator, value) => Box::new([value]), $( $pattern_mut:pat => $value_mut:expr ),* $(,)?
Self::Set(_target, value) => Box::new([value]), },
Self::Generic(_name, operands) => { ref: {
operands.iter().collect::<Vec<_>>().into_boxed_slice() $( $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::<Vec<_>>().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> { impl_operands!(
match self { both: {
Self::Jump(_) | Self::JumpLabel(_) | Self::End => vec![], Self::Jump(_) | Self::JumpLabel(_) | Self::End => vec![],
Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs], Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs],
Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs], Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs],
Self::UnaryOperator(_target, _operator, value) => vec![value], Self::UnaryOperator(_target, _operator, value) => vec![value],
Self::Set(_target, value) => vec![value], Self::Set(_target, value) => vec![value],
Self::Generic(_name, operands) => operands.iter_mut().collect::<Vec<_>>(), Self::PrintFlush(cell) => vec![cell],
Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::<Vec<_>>(), Self::WorldPrintFlush(wpf) => match wpf {
Self::PrintFlush(cell) => vec![cell], WorldPrintFlush::Notify => vec![],
Self::WorldPrintFlush(wpf) => match wpf { WorldPrintFlush::Mission => vec![],
WorldPrintFlush::Notify => vec![], WorldPrintFlush::Announce(time) => vec![time],
WorldPrintFlush::Mission => vec![], WorldPrintFlush::Toast(time) => vec![time],
WorldPrintFlush::Announce(time) => vec![time], },
WorldPrintFlush::Toast(time) => vec![time], Self::Print(operand) => vec![operand],
}, Self::Read {
Self::Print(operand) => vec![operand], out_name: _,
Self::Read { cell,
out_name: _, index,
cell, } => vec![cell, index],
index, Self::Write { value, cell, index } => vec![value, cell, index],
} => vec![cell, index], Self::Sensor { out_name: _, object, key } => vec![object, key],
Self::Write { value, cell, index } => vec![value, cell, index], },
} mut: {
Self::Generic(_name, operands) => operands.iter_mut().collect::<Vec<_>>(),
Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::<Vec<_>>(),
},
ref: {
Self::Generic(_name, operands) => operands.iter().collect::<Vec<_>>(),
Self::GenericMut(_name, _out_name, operands) => operands.iter().collect::<Vec<_>>(),
} }
);
impl MindustryOperation {
pub(crate) fn mutates(&self, var_name: &str) -> bool { pub(crate) fn mutates(&self, var_name: &str) -> bool {
match self { match self {
Self::JumpLabel(_) Self::JumpLabel(_)
@ -152,6 +175,11 @@ impl MindustryOperation {
out_name, out_name,
cell: _, cell: _,
index: _, index: _,
}
| Self::Sensor {
out_name,
object: _,
key: _,
} => out_name == var_name, } => out_name == var_name,
Self::Print(_) | Self::PrintFlush(_) | Self::WorldPrintFlush(_) => { Self::Print(_) | Self::PrintFlush(_) | Self::WorldPrintFlush(_) => {
@ -177,6 +205,11 @@ impl MindustryOperation {
cell: _, cell: _,
index: _, index: _,
} }
| Self::Sensor {
out_name: _,
object: _,
key: _,
}
| Self::Print(_) | Self::Print(_)
| Self::PrintFlush(_) | Self::PrintFlush(_)
| Self::WorldPrintFlush(_) | Self::WorldPrintFlush(_)

@ -21,6 +21,30 @@ pub enum Operator {
Or, 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<Self> {
match raw {
"max" => Some(Self::Operator(Operator::Max)),
"min" => Some(Self::Operator(Operator::Min)),
"pow" => Some(Self::Operator(Operator::Pow)),
_ => None,
}
}
}
impl Operator { impl Operator {
pub(crate) fn precedence(self) -> u8 { pub(crate) fn precedence(self) -> u8 {
match self { match self {
@ -33,17 +57,25 @@ impl Operator {
_ => 128, _ => 128,
} }
} }
}
pub(crate) fn from_fn_name(raw: &str) -> Option<Self> { impl TryFrom<BasicOperator> for Operator {
match raw { type Error = ();
"max" => Some(Self::Max),
"min" => Some(Self::Min), fn try_from(value: BasicOperator) -> Result<Self, Self::Error> {
"pow" => Some(Self::Pow), match value {
_ => None, BasicOperator::Operator(op) => Ok(op),
BasicOperator::Sensor => Err(()),
} }
} }
} }
impl From<Operator> for BasicOperator {
fn from(value: Operator) -> Self {
Self::Operator(value)
}
}
pub(crate) fn format_operator(operator: Operator) -> &'static str { pub(crate) fn format_operator(operator: Operator) -> &'static str {
match operator { match operator {
Operator::Eq => "equal", Operator::Eq => "equal",

@ -120,6 +120,9 @@ impl std::fmt::Display for MindustryProgram {
WorldPrintFlush::Toast(time) => writeln!(f, "message toast {}", time)?, WorldPrintFlush::Toast(time) => writeln!(f, "message toast {}", time)?,
}; };
} }
MindustryOperation::Sensor { out_name, object, key } => {
writeln!(f, "sensor {out_name} {object} {key}")?;
}
} }
} }

@ -66,12 +66,24 @@ fn translate_expression(
let mut right = translate_expression(right.as_ref(), namer, right_name.clone()); let mut right = translate_expression(right.as_ref(), namer, right_name.clone());
res.append(&mut right); res.append(&mut right);
res.push(MindustryOperation::Operator(
target_name, match op {
*op, BasicOperator::Operator(op) => {
Operand::Variable(left_name), res.push(MindustryOperation::Operator(
Operand::Variable(right_name), 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 res
} }
@ -143,8 +155,8 @@ pub fn translate_ast(
String::from("__gosub_retaddr"), String::from("__gosub_retaddr"),
Operator::Mul, Operator::Mul,
Operand::Variable(String::from("__gosub_retaddr")), Operand::Variable(String::from("__gosub_retaddr")),
Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) Operand::Integer(MAX_INSTRUCTION_COUNT as i64),
); ));
res.push(MindustryOperation::Operator( res.push(MindustryOperation::Operator(
String::from("__gosub_retaddr"), String::from("__gosub_retaddr"),
Operator::Add, Operator::Add,
@ -159,20 +171,20 @@ pub fn translate_ast(
String::from("__return"), String::from("__return"),
Operator::Mod, Operator::Mod,
Operand::Variable(String::from("__gosub_retaddr")), Operand::Variable(String::from("__gosub_retaddr")),
Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) Operand::Integer(MAX_INSTRUCTION_COUNT as i64),
); ));
res.push(MindustryOperation::Operator( res.push(MindustryOperation::Operator(
String::from("__gosub_retaddr"), String::from("__gosub_retaddr"),
Operator::IDiv, Operator::IDiv,
Operand::Variable(String::from("__gosub_retaddr")), Operand::Variable(String::from("__gosub_retaddr")),
Operand::Integer(MAX_INSTRUCTION_COUNT as i64)) Operand::Integer(MAX_INSTRUCTION_COUNT as i64),
); ));
res.push(MindustryOperation::Operator( res.push(MindustryOperation::Operator(
String::from("@counter"), String::from("@counter"),
Operator::Add, Operator::Add,
Operand::Variable(String::from("__return")), 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 // Add a guard at the beginning of the program, to clear out the return address
has_return = true; has_return = true;
} }
@ -414,7 +426,10 @@ pub fn translate_ast(
} }
if has_return { 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 res

Loading…
Cancel
Save