Fixed compiler bug that causes args.next to be invoked more than the 1 expected time
This commit is contained in:
@@ -63,7 +63,7 @@ fn test_set_on_device() -> anyhow::Result<()> {
|
|||||||
device airConditioner = "d0";
|
device airConditioner = "d0";
|
||||||
let internalTemp = 20c;
|
let internalTemp = 20c;
|
||||||
|
|
||||||
setOnDevice(airConditioner, "On", internalTemp > 25c);
|
set(airConditioner, "On", internalTemp > 25c);
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ fn test_set_on_device_batched() -> anyhow::Result<()> {
|
|||||||
debug
|
debug
|
||||||
r#"
|
r#"
|
||||||
const doorHash = hash("Door");
|
const doorHash = hash("Door");
|
||||||
setOnDeviceBatched(doorHash, "Lock", true);
|
setBatched(doorHash, "Lock", true);
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,29 +109,25 @@ fn test_set_on_device_batched() -> anyhow::Result<()> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_set_on_device_batched_named() -> anyhow::Result<()> {
|
fn test_set_on_device_batched_named() -> anyhow::Result<()> {
|
||||||
let compiled = compile! {
|
let compiled = compile! {
|
||||||
result
|
debug
|
||||||
r#"
|
r#"
|
||||||
device dev = "d0";
|
device dev = "d0";
|
||||||
const devName = hash("test");
|
const devName = hash("test");
|
||||||
|
|
||||||
let myVar = lbn(dev, devName, "On", 12);
|
sbn(dev, devName, "On", 12);
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{compiled:?}");
|
assert_eq!(
|
||||||
|
compiled,
|
||||||
assert!(compiled.is_empty());
|
indoc! {
|
||||||
|
"
|
||||||
// assert_eq!(
|
j main
|
||||||
// compiled,
|
main:
|
||||||
// indoc! {
|
sbn d0 -662733300 On 12
|
||||||
// "
|
"
|
||||||
// j main
|
}
|
||||||
// main:
|
);
|
||||||
// lbn r8 d0
|
|
||||||
// "
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -143,7 +139,7 @@ fn test_load_from_device() -> anyhow::Result<()> {
|
|||||||
r#"
|
r#"
|
||||||
device airCon = "d0";
|
device airCon = "d0";
|
||||||
|
|
||||||
let setting = loadFromDevice(airCon, "On");
|
let setting = load(airCon, "On");
|
||||||
"#
|
"#
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ quick_error! {
|
|||||||
ConstAssignment(ident: String, span: Span) {
|
ConstAssignment(ident: String, span: Span) {
|
||||||
display("Attempted to re-assign a value to const variable `{ident}`")
|
display("Attempted to re-assign a value to const variable `{ident}`")
|
||||||
}
|
}
|
||||||
|
DeviceAssignment(ident: String, span: Span) {
|
||||||
|
display("Attempted to re-assign a value to a device const `{ident}`")
|
||||||
|
}
|
||||||
Unknown(reason: String, span: Option<Span>) {
|
Unknown(reason: String, span: Option<Span>) {
|
||||||
display("{reason}")
|
display("{reason}")
|
||||||
}
|
}
|
||||||
@@ -104,6 +107,7 @@ impl From<Error> for lsp_types::Diagnostic {
|
|||||||
| UnknownIdentifier(_, span)
|
| UnknownIdentifier(_, span)
|
||||||
| InvalidDevice(_, span)
|
| InvalidDevice(_, span)
|
||||||
| ConstAssignment(_, span)
|
| ConstAssignment(_, span)
|
||||||
|
| DeviceAssignment(_, span)
|
||||||
| AgrumentMismatch(_, span) => Diagnostic {
|
| AgrumentMismatch(_, span) => Diagnostic {
|
||||||
range: span.into(),
|
range: span.into(),
|
||||||
message: value.to_string(),
|
message: value.to_string(),
|
||||||
@@ -348,6 +352,13 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
temp_name: None, // User variable, do not free
|
temp_name: None, // User variable, do not free
|
||||||
})),
|
})),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
// fallback, check devices
|
||||||
|
if let Some(device) = self.devices.get(&name.node) {
|
||||||
|
Ok(Some(CompilationResult {
|
||||||
|
location: VariableLocation::Device(device.clone()),
|
||||||
|
temp_name: None,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
self.errors
|
self.errors
|
||||||
.push(Error::UnknownIdentifier(name.node.clone(), name.span));
|
.push(Error::UnknownIdentifier(name.node.clone(), name.span));
|
||||||
Ok(Some(CompilationResult {
|
Ok(Some(CompilationResult {
|
||||||
@@ -357,6 +368,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Expression::MemberAccess(access) => {
|
Expression::MemberAccess(access) => {
|
||||||
// "load" behavior (e.g. `let x = d0.On`)
|
// "load" behavior (e.g. `let x = d0.On`)
|
||||||
let MemberAccessExpression { object, member } = access.node;
|
let MemberAccessExpression { object, member } = access.node;
|
||||||
@@ -467,6 +479,14 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
VariableLocation::Device(_) => {
|
||||||
|
return Err(Error::Unknown(
|
||||||
|
r#"Attempted to emit a variable assignent for device.
|
||||||
|
This is a Compiler bug and should be reported to the developer."#
|
||||||
|
.into(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -622,7 +642,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
))?;
|
))?;
|
||||||
format!("r{}", VariableScope::TEMP_STACK_REGISTER)
|
format!("r{}", VariableScope::TEMP_STACK_REGISTER)
|
||||||
}
|
}
|
||||||
VariableLocation::Constant(_) => unreachable!(),
|
VariableLocation::Constant(_) | VariableLocation::Device(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
self.emit_variable_assignment(&name_str, &var_loc, src_str)?;
|
self.emit_variable_assignment(&name_str, &var_loc, src_str)?;
|
||||||
(var_loc, None)
|
(var_loc, None)
|
||||||
@@ -765,6 +785,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
VariableLocation::Constant(_) => {
|
VariableLocation::Constant(_) => {
|
||||||
return Err(Error::ConstAssignment(identifier.node, identifier.span));
|
return Err(Error::ConstAssignment(identifier.node, identifier.span));
|
||||||
}
|
}
|
||||||
|
VariableLocation::Device(_) => {
|
||||||
|
return Err(Error::DeviceAssignment(identifier.node, identifier.span));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = cleanup {
|
if let Some(name) = cleanup {
|
||||||
@@ -879,6 +902,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
VariableScope::TEMP_STACK_REGISTER
|
VariableScope::TEMP_STACK_REGISTER
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
VariableLocation::Device(_) => {
|
||||||
|
return Err(Error::Unknown(
|
||||||
|
r#"Attempted to pass a device contant into a function argument. These values can be used without scope."#.into(),
|
||||||
|
Some(arg.span),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Binary(bin_expr) => {
|
Expression::Binary(bin_expr) => {
|
||||||
@@ -1128,6 +1157,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
"Cannot resolve a constant value to register".into(),
|
"Cannot resolve a constant value to register".into(),
|
||||||
None,
|
None,
|
||||||
)),
|
)),
|
||||||
|
VariableLocation::Device(_) => Err(Error::Unknown(
|
||||||
|
"Cannot resolve a device to a register".into(),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
VariableLocation::Stack(_) => Err(Error::Unknown(
|
VariableLocation::Stack(_) => Err(Error::Unknown(
|
||||||
"Cannot resolve Stack location directly to register string without context".into(),
|
"Cannot resolve Stack location directly to register string without context".into(),
|
||||||
None,
|
None,
|
||||||
@@ -1205,6 +1238,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
// We return the NEW temp name to be freed.
|
// We return the NEW temp name to be freed.
|
||||||
Ok((temp_reg, Some(temp_name)))
|
Ok((temp_reg, Some(temp_name)))
|
||||||
}
|
}
|
||||||
|
VariableLocation::Device(d) => Ok((d, None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1505,6 +1539,12 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
VariableScope::TEMP_STACK_REGISTER
|
VariableScope::TEMP_STACK_REGISTER
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
VariableLocation::Device(_) => {
|
||||||
|
return Err(Error::Unknown(
|
||||||
|
"You can not return a device from a function.".into(),
|
||||||
|
Some(var_name.span),
|
||||||
|
));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.errors.push(Error::UnknownIdentifier(
|
self.errors.push(Error::UnknownIdentifier(
|
||||||
@@ -1706,15 +1746,17 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
let (value, value_cleanup) = self.compile_operand(*val_expr, scope)?;
|
let (value, value_cleanup) = self.compile_operand(*val_expr, scope)?;
|
||||||
let (device_hash, device_hash_cleanup) =
|
let (device_hash, device_hash_cleanup) =
|
||||||
self.compile_literal_or_variable(device_hash.node, scope)?;
|
self.compile_literal_or_variable(device_hash.node, scope)?;
|
||||||
|
|
||||||
let (name_hash, name_hash_cleanup) =
|
let (name_hash, name_hash_cleanup) =
|
||||||
self.compile_literal_or_variable(name_hash.node, scope)?;
|
self.compile_literal_or_variable(name_hash.node, scope)?;
|
||||||
|
|
||||||
let (logic_type, logic_type_cleanup) = self.compile_literal_or_variable(
|
let (logic_type, logic_type_cleanup) = self.compile_literal_or_variable(
|
||||||
LiteralOrVariable::Literal(logic_type.node),
|
LiteralOrVariable::Literal(logic_type.node),
|
||||||
scope,
|
scope,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.write_output(format!(
|
self.write_output(format!(
|
||||||
"snb {} {} {} {}",
|
"sbn {} {} {} {}",
|
||||||
device_hash, name_hash, logic_type, value
|
device_hash, name_hash, logic_type, value
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
@@ -1725,7 +1767,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
logic_type_cleanup
|
logic_type_cleanup
|
||||||
);
|
);
|
||||||
|
|
||||||
todo!()
|
Ok(None)
|
||||||
}
|
}
|
||||||
System::LoadFromDevice(device, logic_type) => {
|
System::LoadFromDevice(device, logic_type) => {
|
||||||
let Spanned {
|
let Spanned {
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ pub enum VariableLocation {
|
|||||||
Stack(u16),
|
Stack(u16),
|
||||||
/// Represents a constant value and should be directly substituted as such.
|
/// Represents a constant value and should be directly substituted as such.
|
||||||
Constant(Literal),
|
Constant(Literal),
|
||||||
|
/// Represents a device pin. This will contain the exact `d0-d5` string
|
||||||
|
Device(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VariableScope<'a> {
|
pub struct VariableScope<'a> {
|
||||||
|
|||||||
@@ -1586,7 +1586,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
macro_rules! literal_or_variable {
|
macro_rules! literal_or_variable {
|
||||||
($iter:expr) => {
|
($iter:expr) => {
|
||||||
match $iter {
|
match &$iter {
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
match &expr.node {
|
match &expr.node {
|
||||||
@@ -1599,9 +1599,9 @@ impl<'a> Parser<'a> {
|
|||||||
node: LiteralOrVariable::Variable(ident.clone()),
|
node: LiteralOrVariable::Variable(ident.clone()),
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::InvalidSyntax(
|
||||||
self.current_span(),
|
expr.span,
|
||||||
self.current_token.clone().ok_or(Error::UnexpectedEOF)?,
|
"Expected a literal or variable".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1625,8 +1625,8 @@ impl<'a> Parser<'a> {
|
|||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::InvalidSyntax(
|
return Err(Error::InvalidSyntax(
|
||||||
self.current_span(),
|
$arg.span,
|
||||||
String::from("Expected a variable"),
|
format!("Expected a {}", stringify!($matcher).to_lowercase()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1656,9 +1656,9 @@ impl<'a> Parser<'a> {
|
|||||||
span,
|
span,
|
||||||
} = lit_str
|
} = lit_str
|
||||||
else {
|
else {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::InvalidSyntax(
|
||||||
self.current_span(),
|
lit_str.span,
|
||||||
self.current_token.clone().ok_or(Error::UnexpectedEOF)?,
|
"Expected a string literal".to_string(),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1671,7 +1671,8 @@ impl<'a> Parser<'a> {
|
|||||||
check_length(self, &invocation.arguments, 2)?;
|
check_length(self, &invocation.arguments, 2)?;
|
||||||
let mut args = invocation.arguments.into_iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
|
|
||||||
let device = literal_or_variable!(args.next());
|
let tmp = args.next();
|
||||||
|
let device = literal_or_variable!(tmp);
|
||||||
let next_arg = args.next();
|
let next_arg = args.next();
|
||||||
|
|
||||||
let variable = match next_arg {
|
let variable = match next_arg {
|
||||||
@@ -1682,16 +1683,16 @@ impl<'a> Parser<'a> {
|
|||||||
span: spanned_lit.span,
|
span: spanned_lit.span,
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::InvalidSyntax(
|
||||||
self.current_span(),
|
spanned_lit.span,
|
||||||
self.current_token.clone().ok_or(Error::UnexpectedEOF)?,
|
"Expected a string literal".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::InvalidSyntax(
|
||||||
self.current_span(),
|
expr.span,
|
||||||
self.current_token.clone().ok_or(Error::UnexpectedEOF)?,
|
"Expected a string literal".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1739,8 +1740,12 @@ impl<'a> Parser<'a> {
|
|||||||
"set" | "s" => {
|
"set" | "s" => {
|
||||||
check_length(self, &invocation.arguments, 3)?;
|
check_length(self, &invocation.arguments, 3)?;
|
||||||
let mut args = invocation.arguments.into_iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
let device = literal_or_variable!(args.next());
|
let tmp = args.next();
|
||||||
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
let device = literal_or_variable!(tmp);
|
||||||
|
|
||||||
|
let tmp = args.next();
|
||||||
|
let logic_type = get_arg!(Literal, literal_or_variable!(tmp));
|
||||||
|
|
||||||
let variable = args.next().ok_or(Error::UnexpectedEOF)?;
|
let variable = args.next().ok_or(Error::UnexpectedEOF)?;
|
||||||
Ok(SysCall::System(sys_call::System::SetOnDevice(
|
Ok(SysCall::System(sys_call::System::SetOnDevice(
|
||||||
device,
|
device,
|
||||||
@@ -1754,8 +1759,11 @@ impl<'a> Parser<'a> {
|
|||||||
"setBatched" | "sb" => {
|
"setBatched" | "sb" => {
|
||||||
check_length(self, &invocation.arguments, 3)?;
|
check_length(self, &invocation.arguments, 3)?;
|
||||||
let mut args = invocation.arguments.into_iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
let device_hash = literal_or_variable!(args.next());
|
let tmp = args.next();
|
||||||
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
let device_hash = literal_or_variable!(tmp);
|
||||||
|
|
||||||
|
let tmp = args.next();
|
||||||
|
let logic_type = get_arg!(Literal, literal_or_variable!(tmp));
|
||||||
let variable = args.next().ok_or(Error::UnexpectedEOF)?;
|
let variable = args.next().ok_or(Error::UnexpectedEOF)?;
|
||||||
|
|
||||||
Ok(SysCall::System(sys_call::System::SetOnDeviceBatched(
|
Ok(SysCall::System(sys_call::System::SetOnDeviceBatched(
|
||||||
@@ -1770,10 +1778,17 @@ impl<'a> Parser<'a> {
|
|||||||
"setBatchedNamed" | "sbn" => {
|
"setBatchedNamed" | "sbn" => {
|
||||||
check_length(self, &invocation.arguments, 4)?;
|
check_length(self, &invocation.arguments, 4)?;
|
||||||
let mut args = invocation.arguments.into_iter();
|
let mut args = invocation.arguments.into_iter();
|
||||||
let device_hash = literal_or_variable!(args.next());
|
let tmp = args.next();
|
||||||
let name_hash = literal_or_variable!(args.next());
|
let device_hash = literal_or_variable!(tmp);
|
||||||
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
|
||||||
let expr = Box::new(args.next().ok_or(Error::UnexpectedEOF)?);
|
let tmp = args.next();
|
||||||
|
let name_hash = literal_or_variable!(tmp);
|
||||||
|
|
||||||
|
let tmp = args.next();
|
||||||
|
let logic_type = get_arg!(Literal, literal_or_variable!(tmp));
|
||||||
|
|
||||||
|
let tmp = args.next();
|
||||||
|
let expr = Box::new(tmp.ok_or(Error::UnexpectedEOF)?);
|
||||||
|
|
||||||
Ok(SysCall::System(System::SetOnDeviceBatchedNamed(
|
Ok(SysCall::System(System::SetOnDeviceBatchedNamed(
|
||||||
device_hash,
|
device_hash,
|
||||||
|
|||||||
Reference in New Issue
Block a user