test generated enums have values + report parse errors

This commit is contained in:
Rachel Powers
2024-04-22 13:14:07 -07:00
parent d50803b03f
commit 16e11c5bce
6 changed files with 156 additions and 83 deletions

View File

@@ -44,13 +44,15 @@ fn write_repr_enum<'a, T: std::io::Write, I, P>(
.map(|s| format!("serialize = \"{s}\""))
.collect::<Vec<String>>()
.join(", ");
let deprecated_str = if variant.deprecated {
", deprecated = \"true\"".to_owned()
} else {
"".to_owned()
};
let props_str = if let Some(val) = &variant.value {
format!(", props( value = \"{val}\"{deprecated_str})")
let mut props = Vec::new();
if variant.deprecated {
props.push("deprecated = \"true\"".to_owned());
}
if let Some(val) = &variant.value {
props.push(format!("value = \"{val}\""));
}
let props_str = if !props.is_empty() {
format!(", props( {} )", props.join(", "))
} else {
"".to_owned()
};
@@ -70,7 +72,7 @@ fn write_logictypes() {
let output_file = File::create(dest_path).unwrap();
let mut writer = BufWriter::new(&output_file);
let mut logictypes: Vec<(String, EnumVariant<u8>)> = Vec::new();
let mut logictypes: Vec<(String, EnumVariant<u16>)> = Vec::new();
let l_infile = Path::new("data/logictypes.txt");
let l_contents = fs::read_to_string(l_infile).unwrap();
@@ -78,7 +80,7 @@ fn write_logictypes() {
let mut it = line.splitn(3, ' ');
let name = it.next().unwrap();
let val_str = it.next().unwrap();
let val: Option<u8> = val_str.parse().ok();
let val: Option<u16> = val_str.parse().ok();
let docs = it.next();
let deprecated = docs
.map(|docs| docs.trim().to_uppercase() == "DEPRECATED")

View File

@@ -7,18 +7,16 @@ AutoLand 226 Engages the automatic landing algorithm. The rocket will automatica
AutoShutOff 218 Turns off all devices in the rocket upon reaching destination
Bpm 103 Bpm
BurnTimeRemaining 225 Estimated time in seconds until fuel is depleted. Calculated based on current fuel usage.
Bypass None Bypasses some internal behavoiur of the atmospherics device.
CelestialHash 242
CelestialParentHash 250
Channel None Channel on a cable network which should be considered volatile
Channel0 165 Channel on a cable network which should be considered volatile
Channel1 166 Channel on a cable network which should be considered volatile
Channel2 167 Channel on a cable network which should be considered volatile
Channel3 168 Channel on a cable network which should be considered volatile
Channel4 169 Channel on a cable network which should be considered volatile
Channel5 170 Channel on a cable network which should be considered volatile
Channel6 171 Channel on a cable network which should be considered volatile
Channel7 172 Channel on a cable network which should be considered volatile
Channel0 165 Channel 0 on a cable network which should be considered volatile
Channel1 166 Channel 1 on a cable network which should be considered volatile
Channel2 167 Channel 2 on a cable network which should be considered volatile
Channel3 168 Channel 3 on a cable network which should be considered volatile
Channel4 169 Channel 4 on a cable network which should be considered volatile
Channel5 170 Channel 5 on a cable network which should be considered volatile
Channel6 171 Channel 6 on a cable network which should be considered volatile
Channel7 172 Channel 7 on a cable network which should be considered volatile
Charge 11 The current charge the device has
Chart 256
ChartedNavPoints 259
@@ -92,7 +90,6 @@ OperationalTemperatureEfficiency 150 How the input pipe's temperature effects th
OrbitPeriod 245
Orientation 230
Output 70 The output operation for a sort handling device, such as a stacker or sorter, when in logic mode the device will only action one repetition when set zero or above and then back to -1 and await further instructions
OverShootTarget None How far is the landing rocket going to overshoot its landing target at its current thrust. Expressed as a negative value in meters. ensure this is at zero by the time a rocket lands or risk total loss of rocket.
PassedMoles 234
Plant 68 Performs the planting action for any plant based machinery
PlantEfficiency1 52 DEPRECATED
@@ -228,7 +225,6 @@ SizeX 160 Size on the X (right) axis of the object in largeGrids (a largeGrid is
SizeY 161 Size on the Y(Up) axis of the object in largeGrids (a largeGrid is 2meters)
SizeZ 162 Size on the Z(Forward) axis of the object in largeGrids (a largeGrid is 2meters)
SolarAngle 22 Solar angle of the device
SolarConstant None Solar constant of the world
SolarIrradiance 176
SoundAlert 175 Plays a sound alert on the devices speaker
Stress 156 Machines get stressed when working hard. When Stress reaches 100 the machine will automatically shut down
@@ -257,7 +253,6 @@ TotalMolesOutput 135 Returns the total moles of the device's Output Network
TotalMolesOutput2 145 Returns the total moles of the device's Output2 Network
TotalQuantity 265
TrueAnomaly 251
Unknown None No description available
VelocityMagnitude 79 The current magnitude of the velocity vector
VelocityRelativeX 80 The current velocity X relative to the forward vector of this
VelocityRelativeY 81 The current velocity Y relative to the forward vector of this

View File

@@ -8,7 +8,7 @@ import xml.etree.ElementTree as ET
from collections import defaultdict
from itertools import chain
from pathlib import Path
from typing import Any # type:ignore[reportAny]
def intOrNone(val: str):
try:
@@ -219,23 +219,28 @@ def extract_data(install_path: Path, data_path: Path, language: str):
logic_types_path = Path("data") / "logictypes.txt"
with logic_types_path.open(mode="w") as f:
for t, (v, help) in sorted(logictypes.items()):
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
if v is not None:
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
slot_logic_types_path = Path("data") / "slotlogictypes.txt"
with slot_logic_types_path.open(mode="w") as f:
for t, (v, help) in sorted(slotlogictypes.items()):
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
if v is not None:
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
batch_modes_path = Path("data") / "batchmodes.txt"
with batch_modes_path.open(mode="w") as f:
for t, (v, help) in sorted(batchmodes.items()):
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
if v is not None:
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
reagent_modes_path = Path("data") / "reagentmodes.txt"
with reagent_modes_path.open(mode="w") as f:
for t, (v, help) in sorted(reagentmodes.items()):
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
if v is not None:
_ = f.write(f"{t} {v} {help.replace("\r", "").replace("\n", "\\n")}\n")
enums_path = Path("data") / "enums.txt"
with enums_path.open(mode="w") as f:
for name, (val, help) in sorted(enums.items()):
_ = f.write(f"{name} {val} {help.replace("\r", "").replace("\n", "\\n")}\n")
if val is not None:
_ = f.write(f"{name} {val} {help.replace("\r", "").replace("\n", "\\n")}\n")
if __name__ == "__main__":
main()

View File

@@ -378,13 +378,37 @@ impl Operand {
identifier: _,
} => {
if let Some(lt) = logic_type {
Ok(lt.get_str("value").unwrap().parse::<u16>().unwrap() as f64)
Ok(lt
.get_str("value")
.ok_or_else(|| ICError::NoGeneratedValue(lt.to_string()))?
.parse::<u16>()
.map_err(|_| {
ICError::BadGeneratedValueParse(lt.to_string(), "u16".to_owned())
})? as f64)
} else if let Some(slt) = slot_logic_type {
Ok(slt.get_str("value").unwrap().parse::<u16>().unwrap() as f64)
Ok(slt
.get_str("value")
.ok_or_else(|| ICError::NoGeneratedValue(slt.to_string()))?
.parse::<u8>()
.map_err(|_| {
ICError::BadGeneratedValueParse(slt.to_string(), "u8".to_owned())
})? as f64)
} else if let Some(bm) = batch_mode {
Ok(bm.get_str("value").unwrap().parse::<u8>().unwrap() as f64)
Ok(bm
.get_str("value")
.ok_or_else(|| ICError::NoGeneratedValue(bm.to_string()))?
.parse::<u8>()
.map_err(|_| {
ICError::BadGeneratedValueParse(bm.to_string(), "u8".to_owned())
})? as f64)
} else if let Some(rm) = reagent_mode {
Ok(rm.get_str("value").unwrap().parse::<u8>().unwrap() as f64)
Ok(rm
.get_str("value")
.ok_or_else(|| ICError::NoGeneratedValue(rm.to_string()))?
.parse::<u8>()
.map_err(|_| {
ICError::BadGeneratedValueParse(rm.to_string(), "u8".to_owned())
})? as f64)
} else {
Err(interpreter::ICError::TypeValueNotKnown)
}
@@ -400,6 +424,49 @@ impl Operand {
}
}
pub fn as_value_i64(
&self,
ic: &interpreter::IC,
signed: bool,
inst: InstructionOp,
index: u32,
) -> Result<i64, interpreter::ICError> {
match self {
Self::Number(num) => Ok(num.value_i64()),
_ => {
let val = self.as_value(ic, inst, index)?;
if val < -9.223_372_036_854_776E18 {
Err(interpreter::ICError::ShiftUnderflowI64)
} else if val <= 9.223_372_036_854_776E18 {
Ok(interpreter::f64_to_i64(val, signed))
} else {
Err(interpreter::ICError::ShiftOverflowI64)
}
}
}
}
pub fn as_value_i32(
&self,
ic: &interpreter::IC,
inst: InstructionOp,
index: u32,
) -> Result<i32, interpreter::ICError> {
match self {
Self::Number(num) => Ok(num.value_i64() as i32),
_ => {
let val = self.as_value(ic, inst, index)?;
if val < -2147483648.0 {
Err(interpreter::ICError::ShiftUnderflowI32)
} else if val <= 2147483647.0 {
Ok(val as i32)
} else {
Err(interpreter::ICError::ShiftOverflowI32)
}
}
}
}
pub fn as_register(
&self,
ic: &interpreter::IC,
@@ -462,39 +529,6 @@ impl Operand {
}
}
pub fn as_value_i64(
&self,
ic: &interpreter::IC,
signed: bool,
inst: InstructionOp,
index: u32,
) -> Result<i64, interpreter::ICError> {
let val = self.as_value(ic, inst, index)?;
if val < -9.223_372_036_854_776E18 {
Err(interpreter::ICError::ShiftUnderflowI64)
} else if val <= 9.223_372_036_854_776E18 {
Ok(interpreter::f64_to_i64(val, signed))
} else {
Err(interpreter::ICError::ShiftOverflowI64)
}
}
pub fn as_value_i32(
&self,
ic: &interpreter::IC,
inst: InstructionOp,
index: u32,
) -> Result<i32, interpreter::ICError> {
let val = self.as_value(ic, inst, index)?;
if val < -2147483648.0 {
Err(interpreter::ICError::ShiftUnderflowI32)
} else if val <= 2147483647.0 {
Ok(val as i32)
} else {
Err(interpreter::ICError::ShiftOverflowI32)
}
}
pub fn as_logic_type(
&self,
ic: &interpreter::IC,
@@ -757,7 +791,7 @@ impl FromStr for Operand {
let num_str = rest_iter
.take_while_ref(|c| c.is_ascii_hexdigit())
.collect::<String>();
let num = i64::from_str_radix(&num_str, 16).unwrap() as f64;
let num = i64::from_str_radix(&num_str, 16).unwrap();
if rest_iter.next().is_none() {
Ok(Operand::Number(Number::Hexadecimal(num)))
} else {
@@ -774,7 +808,7 @@ impl FromStr for Operand {
let num_str = rest_iter
.take_while_ref(|c| c.is_digit(2))
.collect::<String>();
let num = i64::from_str_radix(&num_str, 2).unwrap() as f64;
let num = i64::from_str_radix(&num_str, 2).unwrap();
if rest_iter.next().is_none() {
Ok(Operand::Number(Number::Binary(num)))
} else {
@@ -898,12 +932,10 @@ impl Display for Operand {
Operand::Number(number) => match number {
Number::Float(_) => Display::fmt(&number.value(), f),
Number::Hexadecimal(n) => {
// FIXME: precision loss here, maybe we should track the source i64?
write!(f, "${:x}", *n as i64)
write!(f, "${:x}", *n)
}
Number::Binary(n) => {
// FIXME: precision loss here, maybe we should track the source i64?
write!(f, "%{:b}", *n as i64)
write!(f, "%{:b}", *n)
}
Number::Constant(c) => {
dbg!(c);
@@ -1016,8 +1048,8 @@ impl Display for Identifier {
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Number {
Float(f64),
Binary(f64),
Hexadecimal(f64),
Binary(i64),
Hexadecimal(i64),
Constant(f64),
String(String),
Enum(f64),
@@ -1026,14 +1058,19 @@ pub enum Number {
impl Number {
pub fn value(&self) -> f64 {
match self {
Number::Enum(val)
| Number::Float(val)
| Number::Binary(val)
| Number::Constant(val)
| Number::Hexadecimal(val) => *val,
Number::Enum(val) | Number::Float(val) | Number::Constant(val) => *val,
Number::Binary(val) | Number::Hexadecimal(val) => *val as f64,
Number::String(s) => const_crc32::crc32(s.as_bytes()) as i32 as f64,
}
}
pub fn value_i64(&self) -> i64 {
match self {
Number::Enum(val) | Number::Float(val) | Number::Constant(val) => *val as i64,
Number::Binary(val) | Number::Hexadecimal(val) => *val,
Number::String(s) => const_crc32::crc32(s.as_bytes()) as i32 as i64,
}
}
}
#[cfg(test)]
@@ -1094,7 +1131,7 @@ mod tests {
indirection: 0,
target: 0,
}),
Operand::Number(Number::Hexadecimal(4095.0)),
Operand::Number(Number::Hexadecimal(4095)),
],
},),),
comment: None,
@@ -1324,7 +1361,7 @@ mod tests {
indirection: 0,
target: 1,
}),
Operand::Number(Number::Hexadecimal(255.0)),
Operand::Number(Number::Hexadecimal(255)),
],
},),),
comment: None,
@@ -1337,7 +1374,7 @@ mod tests {
indirection: 0,
target: 1,
}),
Operand::Number(Number::Binary(8.0)),
Operand::Number(Number::Binary(8)),
],
},),),
comment: None,
@@ -1418,4 +1455,34 @@ mod tests {
test_roundtrip("$abcd");
test_roundtrip("%1001");
}
#[test]
fn all_generated_enums_have_value() {
use strum::IntoEnumIterator;
for lt in LogicType::iter() {
println!("testing LogicType.{lt}");
let value = lt.get_str("value");
assert!(value.is_some());
assert!(value.unwrap().parse::<u16>().is_ok());
}
for slt in SlotLogicType::iter() {
println!("testing SlotLogicType.{slt}");
let value = slt.get_str("value");
assert!(value.is_some());
assert!(value.unwrap().parse::<u8>().is_ok());
}
for bm in BatchMode::iter() {
println!("testing BatchMode.{bm}");
let value = bm.get_str("value");
assert!(value.is_some());
assert!(value.unwrap().parse::<u8>().is_ok());
}
for rm in ReagentMode::iter() {
println!("testing ReagentMode.{rm}");
let value = rm.get_str("value");
assert!(value.is_some());
assert!(value.unwrap().parse::<u8>().is_ok());
}
}
}

View File

@@ -119,6 +119,10 @@ pub enum ICError {
ChannelIndexOutOfRange(usize),
#[error("slot has no occupant")]
SlotNotOccupied,
#[error("generated Enum {0} has no value attached. Report this error.")]
NoGeneratedValue(String),
#[error("generated Enum {0}'s value does not parse as {1} . Report this error.")]
BadGeneratedValueParse(String, String),
}
impl ICError {

View File

@@ -59,8 +59,8 @@ export type OperandReagentMode = { readonly ReagentMode: string };
export type Identifier = { readonly Identifier: { name: string } };
export type NumberFloat = { readonly Float: number };
export type NumberBinary = { readonly Binary: number };
export type NumberHexadecimal = { readonly Hexadecimal: number };
export type NumberBinary = { readonly Binary: BigInt };
export type NumberHexadecimal = { readonly Hexadecimal: BigInt };
export type NumberConstant = { readonly Constant: number };
export type NumberString = { readonly String: string };
export type NumberEnum = { readonly Enum: number };