Add obejct.key = value instructions

main
Shad Amethyst 1 year ago
parent d59eaaa385
commit 96fe0484f8

@ -0,0 +1,5 @@
REM Available to any processor, using the `control` instruction
reactor1.enabled = false
REM Only available to world processors, using the `setprop` instruction
@unit.health = @unit.health / 2

@ -1,4 +1,9 @@
use crate::{parse::ParseError, parse::ParseErrorKind, prelude::*, translate::{Namer, translate_expression}};
use crate::{
parse::ParseError,
parse::ParseErrorKind,
prelude::*,
translate::{translate_expression, Namer},
};
pub trait BuiltinFunction {
fn validate_args(
@ -27,13 +32,24 @@ macro_rules! expect_n_args {
};
}
fn translate_arguments(arguments: &[BasicAstExpression], namer: &mut Namer, config: &Config) -> (Vec<String>, MindustryProgram) {
let names = (0..arguments.len()).map(|_| namer.temporary()).collect::<Vec<_>>();
fn translate_arguments(
arguments: &[BasicAstExpression],
namer: &mut Namer,
config: &Config,
) -> (Vec<String>, MindustryProgram) {
let names = (0..arguments.len())
.map(|_| namer.temporary())
.collect::<Vec<_>>();
let mut res = MindustryProgram::new();
for (index, arg) in arguments.iter().enumerate() {
res.append(&mut translate_expression(arg, namer, names[index].clone(), config));
res.append(&mut translate_expression(
arg,
namer,
names[index].clone(),
config,
));
}
(names, res)
@ -87,12 +103,10 @@ impl BuiltinFunction for SensorOperator {
match &args[1] {
BasicAstExpression::Variable(_name) => Ok(()),
other => {
Err(ParseError::new(
ParseErrorKind::InvalidArgument(other.clone()),
call_span
))
}
other => Err(ParseError::new(
ParseErrorKind::InvalidArgument(other.clone()),
call_span,
)),
}
}
@ -112,7 +126,7 @@ impl BuiltinFunction for SensorOperator {
res.push(MindustryOperation::Sensor {
out_name: target_name,
object: Operand::Variable(object_name),
key: Operand::Variable(format!("@{}", key))
key: Operand::Variable(format!("@{}", key)),
});
res

@ -65,7 +65,7 @@ pub fn build_ast(
break;
};
match &drop_position(tokens.peek(3))[..] {
match &drop_position(tokens.peek(4))[..] {
[BasicToken::NewLine, BasicToken::Integer(label), ..] => {
tokens.take(2);
instructions.push(BasicAstInstruction::JumpLabel(label.to_string()));
@ -268,15 +268,33 @@ pub fn build_ast(
tokens.take(1);
instructions.push(BasicAstInstruction::Return);
}
// == Misc ==
[BasicToken::Name(variable_name), BasicToken::Assign, ..] => {
tokens.take(2);
// == Assign ==
[BasicToken::Let, BasicToken::Name(variable_name), BasicToken::Assign, ..]
| [BasicToken::Name(variable_name), BasicToken::Assign, ..] => {
if let [(BasicToken::Let, _)] = &tokens.peek(1)[..] {
tokens.take(3);
} else {
tokens.take(2);
}
let expression = parse_expression(&mut tokens, config)?;
instructions.push(BasicAstInstruction::Assign(
variable_name.clone(),
expression,
));
}
[BasicToken::Name(variable_name), BasicToken::Operator(BasicOperator::Sensor), BasicToken::Name(key_name), BasicToken::Assign, ..] =>
{
let object = BasicAstExpression::Variable(variable_name.clone());
let key = SetPropOrControlKey::from(key_name.as_str());
tokens.take(4);
let value = parse_expression(&mut tokens, config)?;
instructions.push(BasicAstInstruction::SetPropOrControl(key, object, value));
}
// == Misc ==
[BasicToken::Print, ..] => {
tokens.take(1);
@ -596,23 +614,23 @@ pub(crate) fn parse_expression(
}
BasicOperator::Sensor => {
if let Some(fn_config) = config.builtin_functions.get("__sensor_operator") {
let arguments = vec![
ast,
rhs
];
let arguments = vec![ast, rhs];
fn_config.validate_args(&arguments, operator_pos)?;
BasicAstExpression::BuiltinFunction(String::from("__sensor_operator"), arguments)
BasicAstExpression::BuiltinFunction(
String::from("__sensor_operator"),
arguments,
)
} else {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken(BasicToken::Operator(BasicOperator::Sensor)),
operator_pos
ParseErrorKind::UnexpectedToken(BasicToken::Operator(
BasicOperator::Sensor,
)),
operator_pos,
));
}
}
};
}
Ok(ast)

@ -21,6 +21,7 @@ fn test_tokenize_basic() {
test_drop_position(tokenize("let thing = thing / 2")),
vec![
BasicToken::NewLine,
BasicToken::Let,
BasicToken::Name(String::from("thing")),
BasicToken::Assign,
BasicToken::Name(String::from("thing")),

@ -32,6 +32,7 @@ pub enum BasicToken {
Name(String),
String(String),
Operator(BasicOperator),
Let,
}
/// Transforms a raw string into a sequence of `BasicToken`s
@ -110,7 +111,7 @@ pub fn tokenize(raw: &str) -> Result<Vec<(BasicToken, Position)>, ParseError> {
// Main match clause for tokens
match_token!(line, res, line_index, ch;
match_space => (),
match_let => (),
match_let => (BasicToken::Let),
match_comment => (),
match_jump => (BasicToken::Goto),
match_word(word) => (match word.to_lowercase().as_str().trim() {

@ -6,15 +6,31 @@ pub enum BasicAstExpression {
Float(f64),
Variable(String),
String(String),
Binary(
Operator,
Box<BasicAstExpression>,
Box<BasicAstExpression>,
),
Binary(Operator, Box<BasicAstExpression>, Box<BasicAstExpression>),
Unary(UnaryOperator, Box<BasicAstExpression>),
BuiltinFunction(String, Vec<BasicAstExpression>),
}
/// The set of keys for `control` that accept one operand, and otherwise a key for `setprop`
#[derive(Clone, Debug, PartialEq)]
pub enum SetPropOrControlKey {
ControlEnabled,
ControlConfig,
ControlColor,
SetProp(String),
}
impl From<&str> for SetPropOrControlKey {
fn from(value: &str) -> Self {
match value {
"enabled" => Self::ControlEnabled,
"config" => Self::ControlConfig,
"color" => Self::ControlColor,
other => Self::SetProp(format!("@{}", other)),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum BasicAstInstruction {
JumpLabel(String),
@ -39,6 +55,7 @@ pub enum BasicAstInstruction {
},
While(BasicAstExpression, BasicAstBlock),
DoWhile(BasicAstExpression, BasicAstBlock),
SetPropOrControl(SetPropOrControlKey, BasicAstExpression, BasicAstExpression),
}
#[derive(Clone, Debug, PartialEq, Default)]

@ -72,6 +72,13 @@ pub enum MindustryOperation {
key: Operand,
},
/// Sets a property of a given block, only available to world processors
WorldSetProp {
key: Operand,
object: Operand,
value: Operand,
},
/// A generic operation, with the following invariants:
/// - all of the operands are read-only
/// - there is no external dependency to other variables
@ -144,6 +151,7 @@ impl_operands!(
} => vec![cell, index],
Self::Write { value, cell, index } => vec![value, cell, index],
Self::Sensor { out_name: _, object, key } => vec![object, key],
Self::WorldSetProp { key, object, value } => vec![key, object, value],
},
mut: {
Self::Generic(_name, operands) => operands.iter_mut().collect::<Vec<_>>(),
@ -170,7 +178,12 @@ impl MindustryOperation {
cell: _,
index: _,
}
| Self::Control(_, _) => false,
| Self::Control(_, _)
| Self::WorldSetProp {
value: _,
object: _,
key: _,
} => false,
Self::Operator(out_name, _, _, _)
| Self::UnaryOperator(out_name, _, _)
@ -220,7 +233,12 @@ impl MindustryOperation {
| Self::WorldPrintFlush(_)
| Self::Generic(_, _)
| Self::GenericMut(_, _, _)
| Self::Control(_, _) => false,
| Self::Control(_, _)
| Self::WorldSetProp {
value: _,
object: _,
key: _,
} => false,
Self::Set(var_name, _)
| Self::Operator(var_name, _, _, _)

@ -134,6 +134,9 @@ impl std::fmt::Display for MindustryProgram {
}
writeln!(f)?;
}
MindustryOperation::WorldSetProp { key, object, value } => {
writeln!(f, "setprop {} {} {}", key, object, value)?;
}
}
}

@ -357,6 +357,50 @@ pub fn translate_ast(
res.push(MindustryOperation::Print(Operand::Variable(tmp_name)));
}
}
Instr::SetPropOrControl(key, object, value) => {
let object_name = namer.temporary();
res.append(&mut translate_expression(
object,
namer,
object_name.clone(),
config,
));
let value_name = namer.temporary();
res.append(&mut translate_expression(
value,
namer,
value_name.clone(),
config,
));
match key {
SetPropOrControlKey::ControlEnabled
| SetPropOrControlKey::ControlConfig
| SetPropOrControlKey::ControlColor => {
let key = match key {
SetPropOrControlKey::ControlEnabled => String::from("enabled"),
SetPropOrControlKey::ControlConfig => String::from("config"),
SetPropOrControlKey::ControlColor => String::from("color"),
_ => unreachable!(),
};
res.push(MindustryOperation::Control(
key,
vec![
Operand::Variable(object_name),
Operand::Variable(value_name),
],
));
}
SetPropOrControlKey::SetProp(key) => {
res.push(MindustryOperation::WorldSetProp {
key: Operand::Variable(key.clone()),
object: Operand::Variable(object_name),
value: Operand::Variable(value_name),
});
}
}
}
Instr::CallBuiltin(name, arguments) if name == "read" => translate_call!(
"read",
arguments,

@ -0,0 +1,9 @@
set main__tmp_0 reactor1
set main__tmp_1 false
control enabled main__tmp_0 main__tmp_1
set main__tmp_2 @unit
set main__tmp_6 @unit
sensor main__tmp_4 main__tmp_6 @health
set main__tmp_5 2
op div main__tmp_3 main__tmp_4 main__tmp_5
setprop @health main__tmp_2 main__tmp_3

@ -0,0 +1,6 @@
control enabled reactor1 false
set main__tmp_2 @unit
set main__tmp_6 @unit
sensor main__tmp_4 main__tmp_6 @health
op div main__tmp_3 main__tmp_4 2
setprop @health main__tmp_2 main__tmp_3
Loading…
Cancel
Save