Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/men-sharp-asm/src/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ impl Emulator {
_ => Value::Null,
},
HeapInit::Boolean(v) => Value::Boolean(*v),
HeapInit::SByte(v) => Value::Int32(i32::from(*v)),
HeapInit::Byte(v) => Value::Int32(i32::from(*v)),
HeapInit::Int16(v) => Value::Int32(i32::from(*v)),
HeapInit::UInt16(v) => Value::Int32(i32::from(*v)),
HeapInit::Int32(v) => Value::Int32(*v),
HeapInit::Int64(v) => Value::Int64(*v),
HeapInit::UInt32(v) => Value::UInt32(*v),
Expand Down Expand Up @@ -563,6 +567,12 @@ impl Emulator {
| "SystemInt32.__op_Remainder__SystemInt32_SystemInt32__SystemInt32" => {
binary_i32!(|a: i32, b: i32| Value::Int32(a.wrapping_rem(b)))
}
"SystemInt32.__op_LeftShift__SystemInt32_SystemInt32__SystemInt32" => {
binary_i32!(|a: i32, b: i32| Value::Int32(a.wrapping_shl(b as u32)))
}
"SystemInt32.__op_RightShift__SystemInt32_SystemInt32__SystemInt32" => {
binary_i32!(|a: i32, b: i32| Value::Int32(a.wrapping_shr(b as u32)))
}
"SystemInt32.__op_UnaryMinus__SystemInt32__SystemInt32" => {
let args = self.pop_arguments(2)?;
let a = self.heap[args[0]].as_i32()?;
Expand Down Expand Up @@ -1250,10 +1260,12 @@ impl Emulator {
Ok(())
}
"SystemConvert.__ToInt64__SystemInt32__SystemInt64"
| "SystemConvert.__ToInt64__SystemUInt32__SystemInt64"
| "SystemConvert.__ToInt64__SystemObject__SystemInt64" => {
let args = self.pop_arguments(2)?;
let value = match &self.heap[args[0]] {
Value::Int64(value) => *value,
Value::UInt32(value) => i64::from(*value),
other => i64::from(other.as_i32()?),
};
self.heap[args[1]] = Value::Int64(value);
Expand Down
33 changes: 33 additions & 0 deletions src/men-sharp-asm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,39 @@ pub use world::World;
mod tests {
use super::*;

#[test]
fn floating_metadata_uses_dotnet_special_value_spellings() {
// Unity Mono parses Infinity/-Infinity, not Rust's inf/-inf. Keep
// finite formatting (including signed zero) and NaN unchanged.
let mut asm = Asm::new();
for (name, value, expected) in [
("positive", f64::INFINITY, "Infinity"),
("negative", f64::NEG_INFINITY, "-Infinity"),
("nan", f64::NAN, "NaN"),
("finite", 1.25, "1.25"),
("zero", 0.0, "0.0"),
("negative_zero", -0.0, "-0.0"),
] {
asm.slot(
&format!("single_{name}"),
"SystemSingle",
HeapInit::Single(value as f32),
);
asm.slot(
&format!("double_{name}"),
"SystemDouble",
HeapInit::Double(value),
);
let meta = asm.program.to_meta_json().unwrap();
for (prefix, kind) in [("single", "Single"), ("double", "Double")] {
let entry = format!(
"\"name\": \"{prefix}_{name}\", \"kind\": \"{kind}\", \"value\": \"{expected}\""
);
assert!(meta.contains(&entry), "{meta}");
}
}
}

/// Small builder so tests read like assembly listings.
struct Asm {
program: Program,
Expand Down
42 changes: 40 additions & 2 deletions src/men-sharp-asm/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ pub type UdonType = String;
pub enum HeapInit {
Null,
Boolean(bool),
SByte(i8),
Byte(u8),
Int16(i16),
UInt16(u16),
Int32(i32),
Int64(i64),
UInt32(u32),
Expand Down Expand Up @@ -632,6 +636,18 @@ impl Program {
HeapInit::Boolean(v) => {
let _ = write!(out, "Boolean\", \"value\": \"{v}\"");
}
HeapInit::SByte(v) => {
let _ = write!(out, "SByte\", \"value\": \"{v}\"");
}
HeapInit::Byte(v) => {
let _ = write!(out, "Byte\", \"value\": \"{v}\"");
}
HeapInit::Int16(v) => {
let _ = write!(out, "Int16\", \"value\": \"{v}\"");
}
HeapInit::UInt16(v) => {
let _ = write!(out, "UInt16\", \"value\": \"{v}\"");
}
HeapInit::Int32(v) => {
let _ = write!(out, "Int32\", \"value\": \"{v}\"");
}
Expand All @@ -645,10 +661,32 @@ impl Program {
let _ = write!(out, "UInt64\", \"value\": \"{v}\"");
}
HeapInit::Single(v) => {
let _ = write!(out, "Single\", \"value\": \"{v:?}\"");
// Metadata is read by Unity Mono using invariant-culture Parse.
// Rust Debug spells infinity as inf, which that parser rejects.
if v.is_infinite() {
let text = if v.is_sign_negative() {
"-Infinity"
} else {
"Infinity"
};
let _ = write!(out, "Single\", \"value\": \"{text}\"");
} else {
let _ = write!(out, "Single\", \"value\": \"{v:?}\"");
}
}
HeapInit::Double(v) => {
let _ = write!(out, "Double\", \"value\": \"{v:?}\"");
// Metadata is read by Unity Mono using invariant-culture Parse.
// Rust Debug spells infinity as inf, which that parser rejects.
if v.is_infinite() {
let text = if v.is_sign_negative() {
"-Infinity"
} else {
"Infinity"
};
let _ = write!(out, "Double\", \"value\": \"{text}\"");
} else {
let _ = write!(out, "Double\", \"value\": \"{v:?}\"");
}
}
HeapInit::Decimal(v) => {
out.push_str("Decimal\", \"value\": ");
Expand Down
20 changes: 20 additions & 0 deletions src/men-sharp-codegen/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3156,6 +3156,26 @@ impl<'a, 'ast> Generator<'a, 'ast> {
);
return Some(slot);
}
// Metadata stores all small integer constants as Int/UInt,
// but their boxed heap values must retain the declared type.
let integer = match constant {
ExternalConstant::Int(v) => Some(*v),
ExternalConstant::UInt(v) => i64::try_from(*v).ok(),
_ => None,
};
if let Some(value) = integer {
let name = self.heap_type(ty);
let init = match name.as_str() {
"SystemSByte" => Some(HeapInit::SByte(value as i8)),
"SystemByte" => Some(HeapInit::Byte(value as u8)),
"SystemInt16" => Some(HeapInit::Int16(value as i16)),
"SystemUInt16" => Some(HeapInit::UInt16(value as u16)),
_ => None,
};
if let Some(init) = init {
return Some(self.constant(&name, &value.to_string(), init));
}
}
let slot = match constant {
ExternalConstant::Int(value) => match self.heap_type(ty).as_str() {
"SystemInt64" => self.constant(
Expand Down
22 changes: 15 additions & 7 deletions src/men-sharp-codegen/src/generator/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,19 +887,27 @@ impl<'a, 'ast> Generator<'a, 'ast> {
divisor_type: &Type,
span: Range<usize>,
) {
if self.heap_type(divisor_type) != "SystemInt32" {
return;
}
if let HeapInit::Int32(value) = self.program.data[divisor.0].init
&& value != 0
let name = self.heap_type(divisor_type);
let init = match name.as_str() {
"SystemInt32" => HeapInit::Int32(0),
"SystemInt64" => HeapInit::Int64(0),
"SystemUInt32" => HeapInit::UInt32(0),
"SystemUInt64" => HeapInit::UInt64(0),
_ => return,
};
if matches!(self.program.data[divisor.0].init,
HeapInit::Int32(v) if v != 0)
|| matches!(self.program.data[divisor.0].init, HeapInit::Int64(v) if v != 0)
|| matches!(self.program.data[divisor.0].init, HeapInit::UInt32(v) if v != 0)
|| matches!(self.program.data[divisor.0].init, HeapInit::UInt64(v) if v != 0)
{
return;
}
let zero = self.int_constant(0);
let zero = self.constant(&name, "0", init);
let is_zero = self.temp("SystemBoolean");
self.call_extern(
ctx,
"SystemInt32.__op_Equality__SystemInt32_SystemInt32__SystemBoolean",
&format!("{name}.__op_Equality__{name}_{name}__SystemBoolean"),
&[divisor, zero, is_zero],
span.clone(),
);
Expand Down
Loading
Loading