more working syscalls
This commit is contained in:
@@ -33,6 +33,7 @@ fn test_sleep() -> anyhow::Result<()> {
|
|||||||
sleep(3);
|
sleep(3);
|
||||||
let sleepAmount = 15;
|
let sleepAmount = 15;
|
||||||
sleep(sleepAmount);
|
sleep(sleepAmount);
|
||||||
|
sleep(sleepAmount * 2);
|
||||||
"
|
"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@ fn test_sleep() -> anyhow::Result<()> {
|
|||||||
sleep 3
|
sleep 3
|
||||||
move r8 15 #sleepAmount
|
move r8 15 #sleepAmount
|
||||||
sleep r8
|
sleep r8
|
||||||
|
mul r1 r8 2
|
||||||
|
sleep r1
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -60,8 +63,7 @@ fn test_set_on_device() -> anyhow::Result<()> {
|
|||||||
device airConditioner = "d0";
|
device airConditioner = "d0";
|
||||||
let internalTemp = 20c;
|
let internalTemp = 20c;
|
||||||
|
|
||||||
let shouldToggleOn = internalTemp > 25c;
|
setOnDevice(airConditioner, "On", internalTemp > 25c);
|
||||||
setOnDevice(airConditioner, "On", shouldToggleOn);
|
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,8 +75,7 @@ fn test_set_on_device() -> anyhow::Result<()> {
|
|||||||
main:
|
main:
|
||||||
move r8 293.15 #internalTemp
|
move r8 293.15 #internalTemp
|
||||||
sgt r1 r8 298.15
|
sgt r1 r8 298.15
|
||||||
move r9 r1 #shouldToggleOn
|
s d0 On r1
|
||||||
s d0 On r9
|
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -82,6 +83,31 @@ fn test_set_on_device() -> anyhow::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_on_device_batched() -> anyhow::Result<()> {
|
||||||
|
let compiled = compile! {
|
||||||
|
debug
|
||||||
|
r#"
|
||||||
|
let doorHash = hash("Door");
|
||||||
|
setOnDeviceBatched(doorHash, "Lock", true);
|
||||||
|
"#
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled,
|
||||||
|
indoc! {
|
||||||
|
r#"
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
move r15 HASH("Door") #hash_ret
|
||||||
|
move r8 r15 #doorHash
|
||||||
|
sb r8 Lock 1
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_from_device() -> anyhow::Result<()> {
|
fn test_load_from_device() -> anyhow::Result<()> {
|
||||||
let compiled = compile! {
|
let compiled = compile! {
|
||||||
@@ -107,3 +133,27 @@ fn test_load_from_device() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash() -> anyhow::Result<()> {
|
||||||
|
let compiled = compile! {
|
||||||
|
debug
|
||||||
|
r#"
|
||||||
|
let nameHash = hash("testValue");
|
||||||
|
"#
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled,
|
||||||
|
indoc! {
|
||||||
|
r#"
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
move r15 HASH("testValue") #hash_ret
|
||||||
|
move r8 r15 #nameHash
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1023,7 +1023,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
System::Sleep(amt) => {
|
System::Sleep(amt) => {
|
||||||
let (var, cleanup) = self.compile_literal_or_variable(amt, scope)?;
|
let (var, cleanup) = self.compile_operand(*amt, scope)?;
|
||||||
self.write_output(format!("sleep {var}"))?;
|
self.write_output(format!("sleep {var}"))?;
|
||||||
if let Some(temp) = cleanup {
|
if let Some(temp) = cleanup {
|
||||||
scope.free_temp(temp)?;
|
scope.free_temp(temp)?;
|
||||||
@@ -1031,8 +1031,23 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
System::Hash(hash_arg) => {
|
||||||
|
let Literal::String(str_lit) = hash_arg else {
|
||||||
|
return Err(Error::AgrumentMismatch(
|
||||||
|
"Arg1 expected to be a string literal.".into(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let loc = VariableLocation::Persistant(VariableScope::RETURN_REGISTER);
|
||||||
|
self.emit_variable_assignment("hash_ret", &loc, format!(r#"HASH("{}")"#, str_lit))?;
|
||||||
|
|
||||||
|
Ok(Some(CompilationResult {
|
||||||
|
location: loc,
|
||||||
|
temp_name: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
System::SetOnDevice(device, logic_type, variable) => {
|
System::SetOnDevice(device, logic_type, variable) => {
|
||||||
let (variable, var_cleanup) = self.compile_literal_or_variable(variable, scope)?;
|
let (variable, var_cleanup) = self.compile_operand(*variable, scope)?;
|
||||||
|
|
||||||
let LiteralOrVariable::Variable(device) = device else {
|
let LiteralOrVariable::Variable(device) = device else {
|
||||||
return Err(Error::AgrumentMismatch(
|
return Err(Error::AgrumentMismatch(
|
||||||
@@ -1058,6 +1073,28 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
System::SetOnDeviceBatched(device_hash, logic_type, variable) => {
|
||||||
|
let (var, var_cleanup) = self.compile_operand(*variable, scope)?;
|
||||||
|
let (device_hash, device_hash_cleanup) =
|
||||||
|
self.compile_literal_or_variable(device_hash, scope)?;
|
||||||
|
let Literal::String(logic_type) = logic_type else {
|
||||||
|
return Err(Error::AgrumentMismatch(
|
||||||
|
"Arg2 expected to be a string".into(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write_output(format!("sb {} {} {}", device_hash, logic_type, var))?;
|
||||||
|
|
||||||
|
if let Some(var_cleanup) = var_cleanup {
|
||||||
|
scope.free_temp(var_cleanup)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(device_cleanup) = device_hash_cleanup {
|
||||||
|
scope.free_temp(device_cleanup)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
System::LoadFromDevice(device, logic_type) => {
|
System::LoadFromDevice(device, logic_type) => {
|
||||||
let LiteralOrVariable::Variable(device) = device else {
|
let LiteralOrVariable::Variable(device) = device else {
|
||||||
return Err(Error::AgrumentMismatch(
|
return Err(Error::AgrumentMismatch(
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ use tokenizer::{
|
|||||||
};
|
};
|
||||||
use tree_node::*;
|
use tree_node::*;
|
||||||
|
|
||||||
|
use crate::sys_call::System;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
/// A macro to create a boxed value.
|
/// A macro to create a boxed value.
|
||||||
macro_rules! boxed {
|
macro_rules! boxed {
|
||||||
@@ -63,6 +65,12 @@ macro_rules! token_from_option {
|
|||||||
None => return Err(Error::UnexpectedEOF),
|
None => return Err(Error::UnexpectedEOF),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(owned $token:expr) => {
|
||||||
|
match $token {
|
||||||
|
Some(token) => token,
|
||||||
|
None => return Err(Error::UnexpectedEOF),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! extract_token_data {
|
macro_rules! extract_token_data {
|
||||||
@@ -1039,9 +1047,22 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
"sleep" => {
|
"sleep" => {
|
||||||
check_length(self, &invocation.arguments, 1)?;
|
check_length(self, &invocation.arguments, 1)?;
|
||||||
let mut arg = invocation.arguments.iter();
|
let mut arg = invocation.arguments.into_iter();
|
||||||
let argument = literal_or_variable!(arg.next());
|
let expr = token_from_option!(owned arg.next());
|
||||||
Ok(SysCall::System(sys_call::System::Sleep(argument)))
|
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
||||||
|
}
|
||||||
|
"hash" => {
|
||||||
|
check_length(self, &invocation.arguments, 1)?;
|
||||||
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
let lit_str = literal_or_variable!(args.next());
|
||||||
|
|
||||||
|
let LiteralOrVariable::Literal(lit_str) = lit_str else {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
token_from_option!(self.current_token).clone(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SysCall::System(System::Hash(lit_str)))
|
||||||
}
|
}
|
||||||
"loadFromDevice" => {
|
"loadFromDevice" => {
|
||||||
check_length(self, &invocation.arguments, 2)?;
|
check_length(self, &invocation.arguments, 2)?;
|
||||||
@@ -1076,23 +1097,23 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
"loadBatchNamed" => {
|
"loadBatchNamed" => {
|
||||||
check_length(self, &invocation.arguments, 4)?;
|
check_length(self, &invocation.arguments, 4)?;
|
||||||
let mut args = invocation.arguments.iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
|
||||||
let device_hash = literal_or_variable!(args.next());
|
let device_hash = literal_or_variable!(args.next());
|
||||||
let name_hash = get_arg!(Literal, literal_or_variable!(args.next()));
|
let name_hash = token_from_option!(owned args.next());
|
||||||
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||||
let batch_mode = get_arg!(Literal, literal_or_variable!(args.next()));
|
let batch_mode = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||||
|
|
||||||
Ok(SysCall::System(sys_call::System::LoadBatchNamed(
|
Ok(SysCall::System(sys_call::System::LoadBatchNamed(
|
||||||
device_hash,
|
device_hash,
|
||||||
name_hash,
|
boxed!(name_hash),
|
||||||
logic_type,
|
logic_type,
|
||||||
batch_mode,
|
batch_mode,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
"setOnDevice" => {
|
"setOnDevice" => {
|
||||||
check_length(self, &invocation.arguments, 3)?;
|
check_length(self, &invocation.arguments, 3)?;
|
||||||
let mut args = invocation.arguments.iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
|
||||||
let device = literal_or_variable!(args.next());
|
let device = literal_or_variable!(args.next());
|
||||||
|
|
||||||
@@ -1104,12 +1125,54 @@ impl Parser {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let variable = literal_or_variable!(args.next());
|
let variable = token_from_option!(owned args.next());
|
||||||
|
|
||||||
Ok(SysCall::System(sys_call::System::SetOnDevice(
|
Ok(SysCall::System(sys_call::System::SetOnDevice(
|
||||||
device,
|
device,
|
||||||
Literal::String(logic_type),
|
Literal::String(logic_type),
|
||||||
variable,
|
boxed!(variable),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
"setOnDeviceBatched" => {
|
||||||
|
check_length(self, &invocation.arguments, 3)?;
|
||||||
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
|
||||||
|
let device = literal_or_variable!(args.next());
|
||||||
|
let Literal::String(logic_type) =
|
||||||
|
get_arg!(Literal, literal_or_variable!(args.next()))
|
||||||
|
else {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
token_from_option!(self.current_token).clone(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let variable = token_from_option!(owned args.next());
|
||||||
|
|
||||||
|
Ok(SysCall::System(System::SetOnDeviceBatched(
|
||||||
|
device,
|
||||||
|
Literal::String(logic_type),
|
||||||
|
boxed!(variable),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
"setOnDeviceBatchedNamed" => {
|
||||||
|
check_length(self, &invocation.arguments, 4)?;
|
||||||
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
|
||||||
|
let device = literal_or_variable!(args.next());
|
||||||
|
let name = literal_or_variable!(args.next());
|
||||||
|
let Literal::String(logic_type) =
|
||||||
|
get_arg!(Literal, literal_or_variable!(args.next()))
|
||||||
|
else {
|
||||||
|
return Err(Error::UnexpectedToken(
|
||||||
|
token_from_option!(self.current_token).clone(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let variable = token_from_option!(owned args.next());
|
||||||
|
|
||||||
|
Ok(SysCall::System(System::SetOnDeviceBatchedNamed(
|
||||||
|
device,
|
||||||
|
name,
|
||||||
|
Literal::String(logic_type),
|
||||||
|
boxed!(variable),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
// math calls
|
// math calls
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::tree_node::Literal;
|
use crate::tree_node::{Expression, Literal};
|
||||||
|
|
||||||
use super::LiteralOrVariable;
|
use super::LiteralOrVariable;
|
||||||
|
|
||||||
@@ -102,11 +102,11 @@ 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(LiteralOrVariable),
|
Sleep(Box<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")`
|
||||||
Hash(LiteralOrVariable),
|
Hash(Literal),
|
||||||
/// Represents a function which loads a device variable into a register.
|
/// Represents a function which loads a device variable into a register.
|
||||||
/// ## In Game
|
/// ## In Game
|
||||||
/// `l r? d? var`
|
/// `l r? d? var`
|
||||||
@@ -120,7 +120,7 @@ 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, Literal, Literal, Literal),
|
LoadBatchNamed(LiteralOrVariable, Box<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,7 +133,26 @@ pub enum System {
|
|||||||
/// `s d? logicType r?`
|
/// `s d? logicType r?`
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// `s d0 Setting r0`
|
/// `s d0 Setting r0`
|
||||||
SetOnDevice(LiteralOrVariable, Literal, LiteralOrVariable),
|
SetOnDevice(LiteralOrVariable, Literal, Box<Expression>),
|
||||||
|
/// Represents a function which stores a setting to all devices that match
|
||||||
|
/// the given deviceHash
|
||||||
|
/// ## In Game
|
||||||
|
/// `sb deviceHash logictype r?`
|
||||||
|
/// ## Example
|
||||||
|
/// `sb HASH("Doors") Lock 1`
|
||||||
|
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Expression>),
|
||||||
|
/// Represents a function which stores a setting to all devices that match
|
||||||
|
/// both the given deviceHash AND the given nameHash
|
||||||
|
/// ## In Game
|
||||||
|
/// `sbn deviceHash nameHash logicType r?`
|
||||||
|
/// ## Example
|
||||||
|
/// `sbn HASH("Doors") HASH("Exterior") Lock 1`
|
||||||
|
SetOnDeviceBatchedNamed(
|
||||||
|
LiteralOrVariable,
|
||||||
|
LiteralOrVariable,
|
||||||
|
Literal,
|
||||||
|
Box<Expression>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for System {
|
impl std::fmt::Display for System {
|
||||||
@@ -141,13 +160,19 @@ impl std::fmt::Display for System {
|
|||||||
match self {
|
match self {
|
||||||
System::Yield => write!(f, "yield()"),
|
System::Yield => write!(f, "yield()"),
|
||||||
System::Sleep(a) => write!(f, "sleep({})", a),
|
System::Sleep(a) => write!(f, "sleep({})", a),
|
||||||
System::Hash(a) => write!(f, "HASH({})", a),
|
System::Hash(a) => write!(f, "hash({})", a),
|
||||||
System::LoadFromDevice(a, b) => write!(f, "loadFromDevice({}, {})", a, b),
|
System::LoadFromDevice(a, b) => write!(f, "loadFromDevice({}, {})", a, b),
|
||||||
System::LoadBatch(a, b, c) => write!(f, "loadBatch({}, {}, {})", a, b, c),
|
System::LoadBatch(a, b, c) => write!(f, "loadBatch({}, {}, {})", a, b, c),
|
||||||
System::LoadBatchNamed(a, b, c, d) => {
|
System::LoadBatchNamed(a, b, c, d) => {
|
||||||
write!(f, "loadBatchNamed({}, {}, {}, {})", a, b, c, d)
|
write!(f, "loadBatchNamed({}, {}, {}, {})", a, b, c, d)
|
||||||
}
|
}
|
||||||
System::SetOnDevice(a, b, c) => write!(f, "setOnDevice({}, {}, {})", a, b, c),
|
System::SetOnDevice(a, b, c) => write!(f, "setOnDevice({}, {}, {})", a, b, c),
|
||||||
|
System::SetOnDeviceBatched(a, b, c) => {
|
||||||
|
write!(f, "setOnDeviceBatched({}, {}, {})", a, b, c)
|
||||||
|
}
|
||||||
|
System::SetOnDeviceBatchedNamed(a, b, c, d) => {
|
||||||
|
write!(f, "setOnDeviceBatchedNamed({}, {}, {}, {})", a, b, c, d)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,9 +200,11 @@ impl SysCall {
|
|||||||
identifier,
|
identifier,
|
||||||
"yield"
|
"yield"
|
||||||
| "sleep"
|
| "sleep"
|
||||||
| "HASH"
|
| "hash"
|
||||||
| "loadFromDevice"
|
| "loadFromDevice"
|
||||||
| "setOnDevice"
|
| "setOnDevice"
|
||||||
|
| "setOnDeviceBatched"
|
||||||
|
| "setOnDeviceBatchedNamed"
|
||||||
| "acos"
|
| "acos"
|
||||||
| "asin"
|
| "asin"
|
||||||
| "atan"
|
| "atan"
|
||||||
|
|||||||
Reference in New Issue
Block a user