WIP - temperature literals
This commit is contained in:
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
|
use sys_call::SysCall;
|
||||||
use tree_node::*;
|
use tree_node::*;
|
||||||
|
|
||||||
quick_error! {
|
quick_error! {
|
||||||
@@ -165,14 +166,7 @@ impl Parser {
|
|||||||
let expr = Some(match current_token.token_type {
|
let expr = Some(match current_token.token_type {
|
||||||
// match unsupported keywords
|
// match unsupported keywords
|
||||||
TokenType::Keyword(e)
|
TokenType::Keyword(e)
|
||||||
if matches_keyword!(
|
if matches_keyword!(e, Keyword::Enum, Keyword::If, Keyword::Else) =>
|
||||||
e,
|
|
||||||
Keyword::Import,
|
|
||||||
Keyword::Export,
|
|
||||||
Keyword::Enum,
|
|
||||||
Keyword::If,
|
|
||||||
Keyword::Else
|
|
||||||
) =>
|
|
||||||
{
|
{
|
||||||
return Err(ParseError::UnsupportedKeyword(current_token.clone()))
|
return Err(ParseError::UnsupportedKeyword(current_token.clone()))
|
||||||
}
|
}
|
||||||
@@ -187,6 +181,11 @@ impl Parser {
|
|||||||
// match functions with a `fn` keyword
|
// match functions with a `fn` keyword
|
||||||
TokenType::Keyword(Keyword::Fn) => Expression::FunctionExpression(self.function()?),
|
TokenType::Keyword(Keyword::Fn) => Expression::FunctionExpression(self.function()?),
|
||||||
|
|
||||||
|
// match syscalls with a `syscall` keyword
|
||||||
|
TokenType::Identifier(ref id) if SysCall::is_syscall(id) => {
|
||||||
|
Expression::SyscallExpression(self.syscall()?)
|
||||||
|
}
|
||||||
|
|
||||||
// match a variable expression with opening parenthesis
|
// match a variable expression with opening parenthesis
|
||||||
TokenType::Identifier(_)
|
TokenType::Identifier(_)
|
||||||
if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) =>
|
if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) =>
|
||||||
@@ -689,6 +688,10 @@ impl Parser {
|
|||||||
body: self.block()?,
|
body: self.block()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn syscall(&mut self) -> Result<SysCall, ParseError> {
|
||||||
|
todo!("Syscalls are not implemented yet.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -704,12 +707,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unsupported_keywords() -> Result<()> {
|
fn test_unsupported_keywords() -> Result<()> {
|
||||||
let mut parser = parser!("import x;");
|
|
||||||
assert!(parser.parse().is_err());
|
|
||||||
|
|
||||||
let mut parser = parser!("export x;");
|
|
||||||
assert!(parser.parse().is_err());
|
|
||||||
|
|
||||||
let mut parser = parser!("enum x;");
|
let mut parser = parser!("enum x;");
|
||||||
assert!(parser.parse().is_err());
|
assert!(parser.parse().is_err());
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{Literal, LiteralOrVariable};
|
use super::LiteralOrVariable;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Math {
|
pub enum Math {
|
||||||
@@ -68,6 +68,29 @@ pub enum Math {
|
|||||||
Trunc(LiteralOrVariable),
|
Trunc(LiteralOrVariable),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Math {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Math::Acos(a) => write!(f, "acos {}", a),
|
||||||
|
Math::Asin(a) => write!(f, "asin {}", a),
|
||||||
|
Math::Atan(a) => write!(f, "atan {}", a),
|
||||||
|
Math::Atan2(a, b) => write!(f, "atan2 {} {}", a, b),
|
||||||
|
Math::Abs(a) => write!(f, "abs {}", a),
|
||||||
|
Math::Ceil(a) => write!(f, "ceil {}", a),
|
||||||
|
Math::Cos(a) => write!(f, "cos {}", a),
|
||||||
|
Math::Floor(a) => write!(f, "floor {}", a),
|
||||||
|
Math::Log(a) => write!(f, "log {}", a),
|
||||||
|
Math::Max(a, b) => write!(f, "max {} {}", a, b),
|
||||||
|
Math::Min(a, b) => write!(f, "min {} {}", a, b),
|
||||||
|
Math::Rand => write!(f, "rand"),
|
||||||
|
Math::Sin(a) => write!(f, "sin {}", a),
|
||||||
|
Math::Sqrt(a) => write!(f, "sqrt {}", a),
|
||||||
|
Math::Tan(a) => write!(f, "tan {}", a),
|
||||||
|
Math::Trunc(a) => write!(f, "trunc {}", a),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum System {
|
pub enum System {
|
||||||
/// Pauses execution for exactly 1 tick and then resumes.
|
/// Pauses execution for exactly 1 tick and then resumes.
|
||||||
@@ -78,22 +101,10 @@ pub enum System {
|
|||||||
/// ## In Game
|
/// ## In Game
|
||||||
/// `sleep a(r?|num)`
|
/// `sleep a(r?|num)`
|
||||||
Sleep(LiteralOrVariable),
|
Sleep(LiteralOrVariable),
|
||||||
/// Represents a function that can be called to load a variable from a device into a register.
|
|
||||||
/// ## In Game
|
|
||||||
/// `l r? d? logicType`
|
|
||||||
LoadVar(Literal, Literal),
|
|
||||||
/// 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(LiteralOrVariable),
|
||||||
/// Represents a function which will clear the stack for a provided device.
|
|
||||||
/// ## In Game
|
|
||||||
/// `clr d?`
|
|
||||||
StackClear(Literal),
|
|
||||||
/// Represents a function which reads a value from a device at a specific address and stores it in a register.
|
|
||||||
/// ## In Game
|
|
||||||
/// `get r? d? address(r?|num)`
|
|
||||||
Get(Literal, LiteralOrVariable),
|
|
||||||
/// 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`
|
||||||
@@ -109,6 +120,18 @@ pub enum System {
|
|||||||
Store(String, LiteralOrVariable, LiteralOrVariable),
|
Store(String, LiteralOrVariable, LiteralOrVariable),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for System {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
System::Yield => write!(f, "yield"),
|
||||||
|
System::Sleep(a) => write!(f, "sleep {}", a),
|
||||||
|
System::Hash(a) => write!(f, "HASH({})", a),
|
||||||
|
System::Load(a, b) => write!(f, "l {} {}", a, b),
|
||||||
|
System::Store(a, b, c) => write!(f, "s {} {} {}", a, b, c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
/// This represents built in functions that cannot be overwritten, but can be invoked by the user as functions.
|
/// This represents built in functions that cannot be overwritten, but can be invoked by the user as functions.
|
||||||
pub enum SysCall {
|
pub enum SysCall {
|
||||||
@@ -116,3 +139,23 @@ pub enum SysCall {
|
|||||||
/// Represents any mathmatical function that can be called.
|
/// Represents any mathmatical function that can be called.
|
||||||
Math(Math),
|
Math(Math),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for SysCall {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SysCall::System(s) => write!(f, "{}", s),
|
||||||
|
SysCall::Math(m) => write!(f, "{}", m),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysCall {
|
||||||
|
pub fn is_syscall(identifier: &str) -> bool {
|
||||||
|
match identifier {
|
||||||
|
"yield" | "sleep" | "HASH" | "loadFromDevice" | "setOnDevice" => true,
|
||||||
|
"acos" | "asin" | "atan" | "atan2" | "abs" | "ceil" | "cos" | "floor" | "log"
|
||||||
|
| "max" | "min" | "rand" | "sin" | "sqrt" | "tan" | "trunc" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::tokenizer::token::Number;
|
use crate::tokenizer::token::Number;
|
||||||
|
|
||||||
|
use super::sys_call::SysCall;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Number(Number),
|
Number(Number),
|
||||||
@@ -144,6 +146,15 @@ pub enum LiteralOrVariable {
|
|||||||
Variable(String),
|
Variable(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for LiteralOrVariable {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
LiteralOrVariable::Literal(l) => write!(f, "{}", l),
|
||||||
|
LiteralOrVariable::Variable(v) => write!(f, "{}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct DeviceDeclarationExpression {
|
pub struct DeviceDeclarationExpression {
|
||||||
/// any variable-like name
|
/// any variable-like name
|
||||||
@@ -174,6 +185,7 @@ pub enum Expression {
|
|||||||
ReturnExpression(Box<Expression>),
|
ReturnExpression(Box<Expression>),
|
||||||
Variable(String),
|
Variable(String),
|
||||||
DeviceDeclarationExpression(DeviceDeclarationExpression),
|
DeviceDeclarationExpression(DeviceDeclarationExpression),
|
||||||
|
SyscallExpression(SysCall),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Expression {
|
impl std::fmt::Display for Expression {
|
||||||
@@ -192,6 +204,7 @@ impl std::fmt::Display for Expression {
|
|||||||
Expression::PriorityExpression(e) => write!(f, "({})", e),
|
Expression::PriorityExpression(e) => write!(f, "({})", e),
|
||||||
Expression::ReturnExpression(e) => write!(f, "(return {})", e),
|
Expression::ReturnExpression(e) => write!(f, "(return {})", e),
|
||||||
Expression::DeviceDeclarationExpression(e) => write!(f, "{}", e),
|
Expression::DeviceDeclarationExpression(e) => write!(f, "{}", e),
|
||||||
|
Expression::SyscallExpression(e) => write!(f, "{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::{
|
|||||||
io::{BufReader, Cursor, Read, Seek, SeekFrom},
|
io::{BufReader, Cursor, Read, Seek, SeekFrom},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
use token::{Keyword, Number, Symbol, Token, TokenType};
|
use token::{Keyword, Number, Symbol, Temperature, Token, TokenType};
|
||||||
|
|
||||||
quick_error! {
|
quick_error! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -274,7 +274,7 @@ impl Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tokenizes a number literal
|
/// Tokenizes a number literal. Also handles temperatures with a suffix of `c`, `f`, or `k`.
|
||||||
fn tokenize_number(&mut self, first_char: char) -> Result<Token, TokenizerError> {
|
fn tokenize_number(&mut self, first_char: char) -> Result<Token, TokenizerError> {
|
||||||
let mut primary = String::with_capacity(16);
|
let mut primary = String::with_capacity(16);
|
||||||
let mut decimal: Option<String> = None;
|
let mut decimal: Option<String> = None;
|
||||||
@@ -315,29 +315,40 @@ impl Tokenizer {
|
|||||||
self.next_char()?;
|
self.next_char()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(decimal) = decimal {
|
let number: Number = if let Some(decimal) = decimal {
|
||||||
let decimal_scale = decimal.len() as u32;
|
let decimal_scale = decimal.len() as u32;
|
||||||
let number = format!("{}{}", primary, decimal)
|
let number = format!("{}{}", primary, decimal)
|
||||||
.parse::<i128>()
|
.parse::<i128>()
|
||||||
.map_err(|e| TokenizerError::NumberParseError(e, self.line, self.column))?;
|
.map_err(|e| TokenizerError::NumberParseError(e, self.line, self.column))?;
|
||||||
|
Number::Decimal(
|
||||||
|
Decimal::try_from_i128_with_scale(number, decimal_scale)
|
||||||
|
.map_err(|e| TokenizerError::DecimalParseError(e, line, column))?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Number::Integer(
|
||||||
|
primary
|
||||||
|
.parse()
|
||||||
|
.map_err(|e| TokenizerError::NumberParseError(e, line, column))?,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if the next char is a temperature suffix
|
||||||
|
if let Some(next_char) = self.peek_next_char()? {
|
||||||
|
let temperature = match next_char {
|
||||||
|
'c' => Temperature::Celsius(number),
|
||||||
|
'f' => Temperature::Fahrenheit(number),
|
||||||
|
'k' => Temperature::Kelvin(number),
|
||||||
|
_ => return Ok(Token::new(TokenType::Number(number), line, column)),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next_char()?;
|
||||||
Ok(Token::new(
|
Ok(Token::new(
|
||||||
TokenType::Number(Number::Decimal(
|
TokenType::Temperature(temperature),
|
||||||
Decimal::try_from_i128_with_scale(number, decimal_scale)
|
|
||||||
.map_err(|e| TokenizerError::DecimalParseError(e, line, column))?,
|
|
||||||
)),
|
|
||||||
line,
|
line,
|
||||||
column,
|
column,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Token::new(
|
Ok(Token::new(TokenType::Number(number), line, column))
|
||||||
TokenType::Number(Number::Integer(
|
|
||||||
primary
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| TokenizerError::NumberParseError(e, line, column))?,
|
|
||||||
)),
|
|
||||||
line,
|
|
||||||
column,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,8 +415,6 @@ impl Tokenizer {
|
|||||||
"else" if next_ws!() => keyword!(Else),
|
"else" if next_ws!() => keyword!(Else),
|
||||||
"return" if next_ws!() => keyword!(Return),
|
"return" if next_ws!() => keyword!(Return),
|
||||||
"enum" if next_ws!() => keyword!(Enum),
|
"enum" if next_ws!() => keyword!(Enum),
|
||||||
"import" if next_ws!() => keyword!(Import),
|
|
||||||
"export" if next_ws!() => keyword!(Export),
|
|
||||||
"device" if next_ws!() => keyword!(Device),
|
"device" if next_ws!() => keyword!(Device),
|
||||||
|
|
||||||
// boolean literals
|
// boolean literals
|
||||||
@@ -622,19 +631,29 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skip_line() -> Result<()> {
|
fn test_temperature_unit() -> Result<()> {
|
||||||
let mut tokenizer = Tokenizer::from(String::from(
|
let mut tokenizer = Tokenizer::from(String::from("10c 10f 10k"));
|
||||||
r#"
|
|
||||||
This is a skippable line"#,
|
|
||||||
));
|
|
||||||
|
|
||||||
tokenizer.skip_line()?;
|
let token = tokenizer.next_token()?.unwrap();
|
||||||
|
|
||||||
assert_eq!(tokenizer.line, 2);
|
assert_eq!(
|
||||||
assert_eq!(tokenizer.column, 1);
|
token.token_type,
|
||||||
|
TokenType::Temperature(Temperature::Celsius(Number::Integer(10)))
|
||||||
|
);
|
||||||
|
|
||||||
let next_char = tokenizer.next_char()?;
|
let token = tokenizer.next_token()?.unwrap();
|
||||||
assert_eq!(next_char, Some('T'));
|
|
||||||
|
assert_eq!(
|
||||||
|
token.token_type,
|
||||||
|
TokenType::Temperature(Temperature::Fahrenheit(Number::Integer(10)))
|
||||||
|
);
|
||||||
|
|
||||||
|
let token = tokenizer.next_token()?.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
token.token_type,
|
||||||
|
TokenType::Temperature(Temperature::Kelvin(Number::Integer(10)))
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -772,8 +791,7 @@ This is a skippable line"#,
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keyword_parse() -> Result<()> {
|
fn test_keyword_parse() -> Result<()> {
|
||||||
let mut tokenizer =
|
let mut tokenizer = Tokenizer::from(String::from("let fn if else return enum"));
|
||||||
Tokenizer::from(String::from("let fn if else return enum import export"));
|
|
||||||
|
|
||||||
let expected_tokens = vec![
|
let expected_tokens = vec![
|
||||||
TokenType::Keyword(Keyword::Let),
|
TokenType::Keyword(Keyword::Let),
|
||||||
@@ -782,8 +800,6 @@ This is a skippable line"#,
|
|||||||
TokenType::Keyword(Keyword::Else),
|
TokenType::Keyword(Keyword::Else),
|
||||||
TokenType::Keyword(Keyword::Return),
|
TokenType::Keyword(Keyword::Return),
|
||||||
TokenType::Keyword(Keyword::Enum),
|
TokenType::Keyword(Keyword::Enum),
|
||||||
TokenType::Keyword(Keyword::Import),
|
|
||||||
TokenType::Keyword(Keyword::Export),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for expected_token in expected_tokens {
|
for expected_token in expected_tokens {
|
||||||
|
|||||||
@@ -20,6 +20,23 @@ impl Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Hash, Eq, Clone)]
|
||||||
|
pub enum Temperature {
|
||||||
|
Celsius(Number),
|
||||||
|
Fahrenheit(Number),
|
||||||
|
Kelvin(Number),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Temperature {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Temperature::Celsius(n) => write!(f, "{}°C", n),
|
||||||
|
Temperature::Fahrenheit(n) => write!(f, "{}°F", n),
|
||||||
|
Temperature::Kelvin(n) => write!(f, "{}K", n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Hash, Eq, Clone)]
|
#[derive(Debug, PartialEq, Hash, Eq, Clone)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
/// Represents a string token
|
/// Represents a string token
|
||||||
@@ -34,6 +51,7 @@ pub enum TokenType {
|
|||||||
Identifier(String),
|
Identifier(String),
|
||||||
/// Represents a symbol token
|
/// Represents a symbol token
|
||||||
Symbol(Symbol),
|
Symbol(Symbol),
|
||||||
|
Temperature(Temperature),
|
||||||
/// Represents an end of file token
|
/// Represents an end of file token
|
||||||
EOF,
|
EOF,
|
||||||
}
|
}
|
||||||
@@ -47,6 +65,7 @@ impl std::fmt::Display for TokenType {
|
|||||||
TokenType::Keyword(k) => write!(f, "{:?}", k),
|
TokenType::Keyword(k) => write!(f, "{:?}", k),
|
||||||
TokenType::Identifier(i) => write!(f, "{}", i),
|
TokenType::Identifier(i) => write!(f, "{}", i),
|
||||||
TokenType::Symbol(s) => write!(f, "{:?}", s),
|
TokenType::Symbol(s) => write!(f, "{:?}", s),
|
||||||
|
TokenType::Temperature(t) => write!(f, "{}", t),
|
||||||
TokenType::EOF => write!(f, "EOF"),
|
TokenType::EOF => write!(f, "EOF"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,8 +191,6 @@ pub enum Keyword {
|
|||||||
Return,
|
Return,
|
||||||
/// Represents the `enum` keyword
|
/// Represents the `enum` keyword
|
||||||
Enum,
|
Enum,
|
||||||
/// Represents an import keyword
|
/// Represents the `loop` keyword
|
||||||
Import,
|
Loop,
|
||||||
/// Represents an export keyword
|
|
||||||
Export,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
fn doStuff(i) {
|
device airConditioner = "d1";
|
||||||
|
device roomTemperatureSensor = "d2";
|
||||||
|
|
||||||
|
loop {
|
||||||
|
|
||||||
|
let currentTemperature = loadFromDevice(roomTemperatureSensor, "Temperature");
|
||||||
|
|
||||||
|
if (currentTemperature > 25c) {
|
||||||
|
setOnDevice(airConditioner, "On", true);
|
||||||
|
} else if (currentTemperature <= 20c) {
|
||||||
|
setOnDevice(airConditioner, "On", false);
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
doStuff(25 * 2);
|
|
||||||
Reference in New Issue
Block a user