First pass getting loadReagent support into the compiler with optimizations
This commit is contained in:
@@ -208,3 +208,29 @@ fn test_set_slot() -> anyhow::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_reagent() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
r#"
|
||||
device thingy = "d0";
|
||||
|
||||
let something = lr(thingy, "Contents", hash("Iron"));
|
||||
"#
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
"
|
||||
j main
|
||||
main:
|
||||
lr r15 d0 Contents -666742878
|
||||
move r8 r15
|
||||
"
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2296,6 +2296,48 @@ impl<'a> Compiler<'a> {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
System::LoadReagent(device, reagent_mode, reagent_hash) => {
|
||||
let Spanned {
|
||||
node: LiteralOrVariable::Variable(device_spanned),
|
||||
..
|
||||
} = device
|
||||
else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg1 expected to be a variable".into(),
|
||||
span,
|
||||
));
|
||||
};
|
||||
|
||||
let (device, device_cleanup) = self.compile_literal_or_variable(
|
||||
LiteralOrVariable::Variable(device_spanned),
|
||||
scope,
|
||||
)?;
|
||||
|
||||
let (reagent_mode, reagent_cleanup) = self.compile_literal_or_variable(
|
||||
LiteralOrVariable::Literal(reagent_mode.node),
|
||||
scope,
|
||||
)?;
|
||||
|
||||
let (reagent_hash, reagent_hash_cleanup) =
|
||||
self.compile_operand(*reagent_hash, scope)?;
|
||||
|
||||
self.write_instruction(
|
||||
Instruction::LoadReagent(
|
||||
Operand::Register(VariableScope::RETURN_REGISTER),
|
||||
device,
|
||||
reagent_mode,
|
||||
reagent_hash,
|
||||
),
|
||||
Some(span),
|
||||
)?;
|
||||
|
||||
cleanup!(reagent_cleanup, reagent_hash_cleanup, device_cleanup);
|
||||
|
||||
Ok(Some(CompileLocation {
|
||||
location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
|
||||
temp_name: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ macro_rules! with_syscalls {
|
||||
"loadBatched",
|
||||
"loadBatchedNamed",
|
||||
"loadSlot",
|
||||
"loadReagent",
|
||||
"set",
|
||||
"setBatched",
|
||||
"setBatchedNamed",
|
||||
@@ -35,6 +36,7 @@ macro_rules! with_syscalls {
|
||||
"lb",
|
||||
"lbn",
|
||||
"ls",
|
||||
"lr",
|
||||
"s",
|
||||
"sb",
|
||||
"sbn",
|
||||
|
||||
@@ -191,6 +191,9 @@ pub enum Instruction<'a> {
|
||||
/// `sbn deviceHash nameHash type value` - Set Batch Named
|
||||
StoreBatchNamed(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
|
||||
|
||||
/// `lr register device reagentMode int`
|
||||
LoadReagent(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
|
||||
|
||||
/// `j label` - Unconditional Jump
|
||||
Jump(Operand<'a>),
|
||||
/// `jal label` - Jump and Link (Function Call)
|
||||
@@ -311,6 +314,9 @@ impl<'a> fmt::Display for Instruction<'a> {
|
||||
Instruction::StoreBatchNamed(d_hash, n_hash, typ, val) => {
|
||||
write!(f, "sbn {} {} {} {}", d_hash, n_hash, typ, val)
|
||||
}
|
||||
Instruction::LoadReagent(reg, device, reagent_mode, reagent_hash) => {
|
||||
write!(f, "lr {} {} {} {}", reg, device, reagent_mode, reagent_hash)
|
||||
}
|
||||
Instruction::Jump(lbl) => write!(f, "j {}", lbl),
|
||||
Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl),
|
||||
Instruction::JumpRelative(off) => write!(f, "jr {}", off),
|
||||
|
||||
@@ -565,6 +565,7 @@ fn get_destination_reg(instr: &Instruction) -> Option<u8> {
|
||||
| Instruction::Sqrt(Operand::Register(r), _)
|
||||
| Instruction::Tan(Operand::Register(r), _)
|
||||
| Instruction::Trunc(Operand::Register(r), _)
|
||||
| Instruction::LoadReagent(Operand::Register(r), _, _, _)
|
||||
| Instruction::Pop(Operand::Register(r)) => Some(*r),
|
||||
_ => None,
|
||||
}
|
||||
@@ -595,6 +596,9 @@ fn set_destination_reg<'a>(instr: &Instruction<'a>, new_reg: u8) -> Option<Instr
|
||||
c.clone(),
|
||||
d.clone(),
|
||||
)),
|
||||
Instruction::LoadReagent(_, b, c, d) => {
|
||||
Some(Instruction::LoadReagent(r, b.clone(), c.clone(), d.clone()))
|
||||
}
|
||||
Instruction::SetEq(_, a, b) => Some(Instruction::SetEq(r, a.clone(), b.clone())),
|
||||
Instruction::SetNe(_, a, b) => Some(Instruction::SetNe(r, a.clone(), b.clone())),
|
||||
Instruction::SetGt(_, a, b) => Some(Instruction::SetGt(r, a.clone(), b.clone())),
|
||||
|
||||
@@ -1909,6 +1909,20 @@ impl<'a> Parser<'a> {
|
||||
Box::new(expr),
|
||||
)))
|
||||
}
|
||||
"loadReagent" | "lr" => {
|
||||
let mut args = args!(3);
|
||||
let next = args.next();
|
||||
let device = literal_or_variable!(next);
|
||||
let next = args.next();
|
||||
let reagent_mode = get_arg!(Literal, literal_or_variable!(next));
|
||||
let reagent_hash = args.next().ok_or(Error::UnexpectedEOF)?;
|
||||
|
||||
Ok(SysCall::System(System::LoadReagent(
|
||||
device,
|
||||
reagent_mode,
|
||||
Box::new(reagent_hash),
|
||||
)))
|
||||
}
|
||||
|
||||
// Math SysCalls
|
||||
"acos" => {
|
||||
|
||||
@@ -237,6 +237,18 @@ documented! {
|
||||
Spanned<Literal<'a>>,
|
||||
Spanned<Literal<'a>>,
|
||||
Box<Spanned<Expression<'a>>>
|
||||
),
|
||||
/// Loads reagent of device's ReagentMode where a hash of the reagent type to check for
|
||||
///
|
||||
/// ## IC10
|
||||
/// `lr r? device(d?|r?|id) reagentMode int`
|
||||
/// ## Slang
|
||||
/// `let result = loadReagent(deviceHash, "ReagentMode", reagentHash);`
|
||||
/// `let result = lr(deviceHash, "ReagentMode", reagentHash);`
|
||||
LoadReagent(
|
||||
Spanned<LiteralOrVariable<'a>>,
|
||||
Spanned<Literal<'a>>,
|
||||
Box<Spanned<Expression<'a>>>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -261,6 +273,7 @@ impl<'a> std::fmt::Display for System<'a> {
|
||||
}
|
||||
System::LoadSlot(a, b, c) => write!(f, "loadSlot({}, {}, {})", a, b, c),
|
||||
System::SetSlot(a, b, c, d) => write!(f, "setSlot({}, {}, {}, {})", a, b, c, d),
|
||||
System::LoadReagent(a, b, c) => write!(f, "loadReagent({}, {}, {})", a, b, c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user