Attempt to fold constants when folding expressions
This commit is contained in:
@@ -287,3 +287,68 @@ fn test_load_reagent() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_clr() -> anyhow::Result<()> {
|
||||||
|
let compiled = compile! {
|
||||||
|
check
|
||||||
|
"
|
||||||
|
device stackDevice = \"d0\";
|
||||||
|
clr(stackDevice);
|
||||||
|
let deviceRef = 5;
|
||||||
|
clr(deviceRef);
|
||||||
|
"
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
compiled.errors.is_empty(),
|
||||||
|
"Expected no errors, got: {:?}",
|
||||||
|
compiled.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled.output,
|
||||||
|
indoc! {
|
||||||
|
"
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
clr d0
|
||||||
|
move r8 5
|
||||||
|
clr r8
|
||||||
|
"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_rmap() -> anyhow::Result<()> {
|
||||||
|
let compiled = compile! {
|
||||||
|
check
|
||||||
|
"
|
||||||
|
device printer = \"d0\";
|
||||||
|
let reagentHash = 12345;
|
||||||
|
let itemHash = rmap(printer, reagentHash);
|
||||||
|
"
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
compiled.errors.is_empty(),
|
||||||
|
"Expected no errors, got: {:?}",
|
||||||
|
compiled.errors
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compiled.output,
|
||||||
|
indoc! {
|
||||||
|
"
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
move r8 12345
|
||||||
|
rmap r15 d0 r8
|
||||||
|
move r9 r15
|
||||||
|
"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -2286,7 +2286,10 @@ impl<'a> Compiler<'a> {
|
|||||||
expr: Spanned<BinaryExpression<'a>>,
|
expr: Spanned<BinaryExpression<'a>>,
|
||||||
scope: &mut VariableScope<'a, '_>,
|
scope: &mut VariableScope<'a, '_>,
|
||||||
) -> Result<CompileLocation<'a>, Error<'a>> {
|
) -> Result<CompileLocation<'a>, Error<'a>> {
|
||||||
fn fold_binary_expression<'a>(expr: &BinaryExpression<'a>) -> Option<Number> {
|
fn fold_binary_expression<'a>(
|
||||||
|
expr: &BinaryExpression<'a>,
|
||||||
|
scope: &VariableScope<'a, '_>,
|
||||||
|
) -> Option<Number> {
|
||||||
fn number_to_i64(n: Number) -> Option<i64> {
|
fn number_to_i64(n: Number) -> Option<i64> {
|
||||||
match n {
|
match n {
|
||||||
Number::Integer(i, _) => i64::try_from(i).ok(),
|
Number::Integer(i, _) => i64::try_from(i).ok(),
|
||||||
@@ -2315,7 +2318,7 @@ impl<'a> Compiler<'a> {
|
|||||||
| BinaryExpression::LeftShift(l, r)
|
| BinaryExpression::LeftShift(l, r)
|
||||||
| BinaryExpression::RightShiftArithmetic(l, r)
|
| BinaryExpression::RightShiftArithmetic(l, r)
|
||||||
| BinaryExpression::RightShiftLogical(l, r) => {
|
| BinaryExpression::RightShiftLogical(l, r) => {
|
||||||
(fold_expression(l)?, fold_expression(r)?)
|
(fold_expression(l, scope)?, fold_expression(r, scope)?)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2359,7 +2362,10 @@ impl<'a> Compiler<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_expression<'a>(expr: &Expression<'a>) -> Option<Number> {
|
fn fold_expression<'a>(
|
||||||
|
expr: &Expression<'a>,
|
||||||
|
scope: &VariableScope<'a, '_>,
|
||||||
|
) -> Option<Number> {
|
||||||
match expr {
|
match expr {
|
||||||
// 1. Base Case: It's already a number
|
// 1. Base Case: It's already a number
|
||||||
Expression::Literal(lit) => match lit.node {
|
Expression::Literal(lit) => match lit.node {
|
||||||
@@ -2368,18 +2374,28 @@ impl<'a> Compiler<'a> {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 2. Handle Parentheses: Just recurse deeper
|
// 2. Handle Parentheses: Just recurse deeper
|
||||||
Expression::Priority(inner) => fold_expression(&inner.node),
|
Expression::Priority(inner) => fold_expression(&inner.node, scope),
|
||||||
|
|
||||||
// 3. Handle Negation: Recurse, then negate
|
// 3. Handle Negation: Recurse, then negate
|
||||||
Expression::Negation(inner) => {
|
Expression::Negation(inner) => {
|
||||||
let val = fold_expression(&inner.node)?;
|
let val = fold_expression(&inner.node, scope)?;
|
||||||
Some(-val) // Requires impl Neg for Number
|
Some(-val) // Requires impl Neg for Number
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Handle Binary Ops: Recurse BOTH sides, then combine
|
// 4. Handle Binary Ops: Recurse BOTH sides, then combine
|
||||||
Expression::Binary(bin) => fold_binary_expression(&bin.node),
|
Expression::Binary(bin) => fold_binary_expression(&bin.node, scope),
|
||||||
|
|
||||||
// 5. Handle hash() syscall - evaluates to a constant at compile time
|
// 5. Handle Variable Reference: Check if it's a const
|
||||||
|
Expression::Variable(var_id) => {
|
||||||
|
if let Ok(var_loc) = scope.get_location_of(var_id, None) {
|
||||||
|
if let VariableLocation::Constant(Literal::Number(num)) = var_loc {
|
||||||
|
return Some(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Handle hash() syscall - evaluates to a constant at compile time
|
||||||
Expression::Syscall(Spanned {
|
Expression::Syscall(Spanned {
|
||||||
node:
|
node:
|
||||||
SysCall::System(System::Hash(Spanned {
|
SysCall::System(System::Hash(Spanned {
|
||||||
@@ -2391,7 +2407,7 @@ impl<'a> Compiler<'a> {
|
|||||||
return Some(Number::Integer(crc_hash_signed(str_to_hash), Unit::None));
|
return Some(Number::Integer(crc_hash_signed(str_to_hash), Unit::None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Handle hash() macro as invocation - evaluates to a constant at compile time
|
// 7. Handle hash() macro as invocation - evaluates to a constant at compile time
|
||||||
Expression::Invocation(inv) => {
|
Expression::Invocation(inv) => {
|
||||||
if inv.node.name.node == "hash" && inv.node.arguments.len() == 1 {
|
if inv.node.name.node == "hash" && inv.node.arguments.len() == 1 {
|
||||||
if let Expression::Literal(Spanned {
|
if let Expression::Literal(Spanned {
|
||||||
@@ -2406,12 +2422,12 @@ impl<'a> Compiler<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Anything else cannot be compile-time folded
|
// 8. Anything else cannot be compile-time folded
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(const_lit) = fold_binary_expression(&expr.node) {
|
if let Some(const_lit) = fold_binary_expression(&expr.node, scope) {
|
||||||
return Ok(CompileLocation {
|
return Ok(CompileLocation {
|
||||||
location: VariableLocation::Constant(Literal::Number(const_lit)),
|
location: VariableLocation::Constant(Literal::Number(const_lit)),
|
||||||
temp_name: None,
|
temp_name: None,
|
||||||
@@ -2925,6 +2941,13 @@ impl<'a> Compiler<'a> {
|
|||||||
cleanup!(var_cleanup);
|
cleanup!(var_cleanup);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
System::Clr(device) => {
|
||||||
|
let (op, var_cleanup) = self.compile_operand(*device, scope)?;
|
||||||
|
self.write_instruction(Instruction::Clr(op), Some(span))?;
|
||||||
|
|
||||||
|
cleanup!(var_cleanup);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
System::Hash(hash_arg) => {
|
System::Hash(hash_arg) => {
|
||||||
let Spanned {
|
let Spanned {
|
||||||
node: Literal::String(str_lit),
|
node: Literal::String(str_lit),
|
||||||
@@ -3244,6 +3267,42 @@ impl<'a> Compiler<'a> {
|
|||||||
|
|
||||||
cleanup!(reagent_cleanup, reagent_hash_cleanup, device_cleanup);
|
cleanup!(reagent_cleanup, reagent_hash_cleanup, device_cleanup);
|
||||||
|
|
||||||
|
Ok(Some(CompileLocation {
|
||||||
|
location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
|
||||||
|
temp_name: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
System::Rmap(device, 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_hash, reagent_hash_cleanup) =
|
||||||
|
self.compile_operand(*reagent_hash, scope)?;
|
||||||
|
|
||||||
|
self.write_instruction(
|
||||||
|
Instruction::Rmap(
|
||||||
|
Operand::Register(VariableScope::RETURN_REGISTER),
|
||||||
|
device,
|
||||||
|
reagent_hash,
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
cleanup!(reagent_hash_cleanup, device_cleanup);
|
||||||
|
|
||||||
Ok(Some(CompileLocation {
|
Ok(Some(CompileLocation {
|
||||||
location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
|
location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER),
|
||||||
temp_name: None,
|
temp_name: None,
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ macro_rules! with_syscalls {
|
|||||||
// Big names
|
// Big names
|
||||||
"yield",
|
"yield",
|
||||||
"sleep",
|
"sleep",
|
||||||
|
"clr",
|
||||||
"hash",
|
"hash",
|
||||||
"load",
|
"load",
|
||||||
"loadBatched",
|
"loadBatched",
|
||||||
"loadBatchedNamed",
|
"loadBatchedNamed",
|
||||||
"loadSlot",
|
"loadSlot",
|
||||||
"loadReagent",
|
"loadReagent",
|
||||||
|
"rmap",
|
||||||
"set",
|
"set",
|
||||||
"setBatched",
|
"setBatched",
|
||||||
"setBatchedNamed",
|
"setBatchedNamed",
|
||||||
|
|||||||
@@ -195,6 +195,9 @@ pub enum Instruction<'a> {
|
|||||||
/// `lr register device reagentMode int`
|
/// `lr register device reagentMode int`
|
||||||
LoadReagent(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
|
LoadReagent(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>),
|
||||||
|
|
||||||
|
/// `rmap register device reagentHash` - Resolve Reagent to Item Hash
|
||||||
|
Rmap(Operand<'a>, Operand<'a>, Operand<'a>),
|
||||||
|
|
||||||
/// `j label` - Unconditional Jump
|
/// `j label` - Unconditional Jump
|
||||||
Jump(Operand<'a>),
|
Jump(Operand<'a>),
|
||||||
/// `jal label` - Jump and Link (Function Call)
|
/// `jal label` - Jump and Link (Function Call)
|
||||||
@@ -267,6 +270,8 @@ pub enum Instruction<'a> {
|
|||||||
Yield,
|
Yield,
|
||||||
/// `sleep val` - Sleep for seconds
|
/// `sleep val` - Sleep for seconds
|
||||||
Sleep(Operand<'a>),
|
Sleep(Operand<'a>),
|
||||||
|
/// `clr val` - Clear stack memory on device
|
||||||
|
Clr(Operand<'a>),
|
||||||
|
|
||||||
/// `alias name target` - Define Alias (Usually handled by compiler, but good for IR)
|
/// `alias name target` - Define Alias (Usually handled by compiler, but good for IR)
|
||||||
Alias(Cow<'a, str>, Operand<'a>),
|
Alias(Cow<'a, str>, Operand<'a>),
|
||||||
@@ -328,6 +333,9 @@ impl<'a> fmt::Display for Instruction<'a> {
|
|||||||
Instruction::LoadReagent(reg, device, reagent_mode, reagent_hash) => {
|
Instruction::LoadReagent(reg, device, reagent_mode, reagent_hash) => {
|
||||||
write!(f, "lr {} {} {} {}", reg, device, reagent_mode, reagent_hash)
|
write!(f, "lr {} {} {} {}", reg, device, reagent_mode, reagent_hash)
|
||||||
}
|
}
|
||||||
|
Instruction::Rmap(reg, device, reagent_hash) => {
|
||||||
|
write!(f, "rmap {} {} {}", reg, device, reagent_hash)
|
||||||
|
}
|
||||||
Instruction::Jump(lbl) => write!(f, "j {}", lbl),
|
Instruction::Jump(lbl) => write!(f, "j {}", lbl),
|
||||||
Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl),
|
Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl),
|
||||||
Instruction::JumpRelative(off) => write!(f, "jr {}", off),
|
Instruction::JumpRelative(off) => write!(f, "jr {}", off),
|
||||||
@@ -363,6 +371,7 @@ impl<'a> fmt::Display for Instruction<'a> {
|
|||||||
}
|
}
|
||||||
Instruction::Yield => write!(f, "yield"),
|
Instruction::Yield => write!(f, "yield"),
|
||||||
Instruction::Sleep(val) => write!(f, "sleep {}", val),
|
Instruction::Sleep(val) => write!(f, "sleep {}", val),
|
||||||
|
Instruction::Clr(val) => write!(f, "clr {}", val),
|
||||||
Instruction::Alias(name, target) => write!(f, "alias {} {}", name, target),
|
Instruction::Alias(name, target) => write!(f, "alias {} {}", name, target),
|
||||||
Instruction::Define(name, val) => write!(f, "define {} {}", name, val),
|
Instruction::Define(name, val) => write!(f, "define {} {}", name, val),
|
||||||
Instruction::LabelDef(lbl) => write!(f, "{}:", lbl),
|
Instruction::LabelDef(lbl) => write!(f, "{}:", lbl),
|
||||||
|
|||||||
@@ -90,4 +90,23 @@ mod bitwise_tests {
|
|||||||
let output = compile_with_and_without_optimization(source);
|
let output = compile_with_and_without_optimization(source);
|
||||||
insta::assert_snapshot!(output);
|
insta::assert_snapshot!(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bitwise_with_const() {
|
||||||
|
let source = indoc! {r#"
|
||||||
|
device sorterOutput = "d0";
|
||||||
|
|
||||||
|
const ingotSortClass = 19;
|
||||||
|
const equals = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
yield();
|
||||||
|
clr(sorterOutput);
|
||||||
|
sorterOutput[0] = (ingotSortClass << 16) | (equals << 8) | 3;
|
||||||
|
}
|
||||||
|
"#};
|
||||||
|
|
||||||
|
let output = compile_with_and_without_optimization(source);
|
||||||
|
insta::assert_snapshot!(output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
source: libs/integration_tests/src/bitwise_tests.rs
|
||||||
|
expression: output
|
||||||
|
---
|
||||||
|
## Unoptimized Output
|
||||||
|
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
__internal_L1:
|
||||||
|
yield
|
||||||
|
clr d0
|
||||||
|
put d0 0 1245187
|
||||||
|
j __internal_L1
|
||||||
|
__internal_L2:
|
||||||
|
|
||||||
|
## Optimized Output
|
||||||
|
|
||||||
|
yield
|
||||||
|
clr d0
|
||||||
|
put d0 0 1245187
|
||||||
|
j 0
|
||||||
@@ -43,6 +43,7 @@ pub fn get_destination_reg(instr: &Instruction) -> Option<u8> {
|
|||||||
| Instruction::Tan(Operand::Register(r), _)
|
| Instruction::Tan(Operand::Register(r), _)
|
||||||
| Instruction::Trunc(Operand::Register(r), _)
|
| Instruction::Trunc(Operand::Register(r), _)
|
||||||
| Instruction::LoadReagent(Operand::Register(r), _, _, _)
|
| Instruction::LoadReagent(Operand::Register(r), _, _, _)
|
||||||
|
| Instruction::Rmap(Operand::Register(r), _, _)
|
||||||
| Instruction::Pop(Operand::Register(r)) => Some(*r),
|
| Instruction::Pop(Operand::Register(r)) => Some(*r),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@@ -107,6 +108,7 @@ pub fn set_destination_reg<'a>(instr: &Instruction<'a>, new_reg: u8) -> Option<I
|
|||||||
Instruction::Sqrt(_, a) => Some(Instruction::Sqrt(r, a.clone())),
|
Instruction::Sqrt(_, a) => Some(Instruction::Sqrt(r, a.clone())),
|
||||||
Instruction::Tan(_, a) => Some(Instruction::Tan(r, a.clone())),
|
Instruction::Tan(_, a) => Some(Instruction::Tan(r, a.clone())),
|
||||||
Instruction::Trunc(_, a) => Some(Instruction::Trunc(r, a.clone())),
|
Instruction::Trunc(_, a) => Some(Instruction::Trunc(r, a.clone())),
|
||||||
|
Instruction::Rmap(_, a, b) => Some(Instruction::Rmap(r, a.clone(), b.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,6 +138,7 @@ pub fn reg_is_read(instr: &Instruction, reg: u8) -> bool {
|
|||||||
| Instruction::BranchLe(a, b, _) => check(a) || check(b),
|
| Instruction::BranchLe(a, b, _) => check(a) || check(b),
|
||||||
Instruction::BranchEqZero(a, _) | Instruction::BranchNeZero(a, _) => check(a),
|
Instruction::BranchEqZero(a, _) | Instruction::BranchNeZero(a, _) => check(a),
|
||||||
Instruction::LoadReagent(_, device, _, item_hash) => check(device) || check(item_hash),
|
Instruction::LoadReagent(_, device, _, item_hash) => check(device) || check(item_hash),
|
||||||
|
Instruction::Rmap(_, device, reagent_hash) => check(device) || check(reagent_hash),
|
||||||
Instruction::LoadSlot(_, dev, slot, _) => check(dev) || check(slot),
|
Instruction::LoadSlot(_, dev, slot, _) => check(dev) || check(slot),
|
||||||
Instruction::LoadBatch(_, dev, _, mode) => check(dev) || check(mode),
|
Instruction::LoadBatch(_, dev, _, mode) => check(dev) || check(mode),
|
||||||
Instruction::LoadBatchNamed(_, d_hash, n_hash, _, mode) => {
|
Instruction::LoadBatchNamed(_, d_hash, n_hash, _, mode) => {
|
||||||
|
|||||||
@@ -1960,6 +1960,11 @@ impl<'a> Parser<'a> {
|
|||||||
let expr = args.next().ok_or_else(|| self.unexpected_eof())?;
|
let expr = args.next().ok_or_else(|| self.unexpected_eof())?;
|
||||||
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
||||||
}
|
}
|
||||||
|
"clr" => {
|
||||||
|
let mut args = args!(1);
|
||||||
|
let expr = args.next().ok_or_else(|| self.unexpected_eof())?;
|
||||||
|
Ok(SysCall::System(System::Clr(boxed!(expr))))
|
||||||
|
}
|
||||||
"hash" => {
|
"hash" => {
|
||||||
let mut args = args!(1);
|
let mut args = args!(1);
|
||||||
let lit_str = literal_or_variable!(args.next());
|
let lit_str = literal_or_variable!(args.next());
|
||||||
@@ -2191,6 +2196,17 @@ impl<'a> Parser<'a> {
|
|||||||
Box::new(reagent_hash),
|
Box::new(reagent_hash),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
"rmap" => {
|
||||||
|
let mut args = args!(2);
|
||||||
|
let next = args.next();
|
||||||
|
let device = literal_or_variable!(next);
|
||||||
|
let reagent_hash = args.next().ok_or_else(|| self.unexpected_eof())?;
|
||||||
|
|
||||||
|
Ok(SysCall::System(System::Rmap(
|
||||||
|
device,
|
||||||
|
Box::new(reagent_hash),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
// Math SysCalls
|
// Math SysCalls
|
||||||
"acos" => {
|
"acos" => {
|
||||||
|
|||||||
@@ -142,6 +142,12 @@ documented! {
|
|||||||
/// ## Slang
|
/// ## Slang
|
||||||
/// `sleep(number|var);`
|
/// `sleep(number|var);`
|
||||||
Sleep(Box<Spanned<Expression<'a>>>),
|
Sleep(Box<Spanned<Expression<'a>>>),
|
||||||
|
/// Clears stack memory on the provided device.
|
||||||
|
/// ## IC10
|
||||||
|
/// `clr d?`
|
||||||
|
/// ## Slang
|
||||||
|
/// `clr(device);`
|
||||||
|
Clr(Box<Spanned<Expression<'a>>>),
|
||||||
/// Gets the in-game hash for a specific prefab name. NOTE! This call is COMPLETELY
|
/// Gets the in-game hash for a specific prefab name. NOTE! This call is COMPLETELY
|
||||||
/// optimized away unless you bind it to a `let` variable. If you use a `const` variable
|
/// optimized away unless you bind it to a `let` variable. If you use a `const` variable
|
||||||
/// however, the hash is correctly computed at compile time and substitued automatically.
|
/// however, the hash is correctly computed at compile time and substitued automatically.
|
||||||
@@ -249,6 +255,17 @@ documented! {
|
|||||||
Spanned<LiteralOrVariable<'a>>,
|
Spanned<LiteralOrVariable<'a>>,
|
||||||
Spanned<Literal<'a>>,
|
Spanned<Literal<'a>>,
|
||||||
Box<Spanned<Expression<'a>>>
|
Box<Spanned<Expression<'a>>>
|
||||||
|
),
|
||||||
|
/// Maps a reagent hash to the item hash that fulfills it on a device
|
||||||
|
///
|
||||||
|
/// ## IC10
|
||||||
|
/// `rmap r? d? reagentHash(r?|num)`
|
||||||
|
/// ## Slang
|
||||||
|
/// `let itemHash = rmap(device, reagentHash);`
|
||||||
|
/// `let itemHash = rmap(device, reagentHashValue);`
|
||||||
|
Rmap(
|
||||||
|
Spanned<LiteralOrVariable<'a>>,
|
||||||
|
Box<Spanned<Expression<'a>>>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,6 +275,7 @@ impl<'a> std::fmt::Display for System<'a> {
|
|||||||
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::Clr(a) => write!(f, "clr({})", 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),
|
||||||
@@ -274,6 +292,7 @@ impl<'a> std::fmt::Display for System<'a> {
|
|||||||
System::LoadSlot(a, b, c) => write!(f, "loadSlot({}, {}, {})", a, b, c),
|
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::SetSlot(a, b, c, d) => write!(f, "setSlot({}, {}, {}, {})", a, b, c, d),
|
||||||
System::LoadReagent(a, b, c) => write!(f, "loadReagent({}, {}, {})", a, b, c),
|
System::LoadReagent(a, b, c) => write!(f, "loadReagent({}, {}, {})", a, b, c),
|
||||||
|
System::Rmap(a, b) => write!(f, "rmap({}, {})", a, b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user