diff --git a/Coder.Test/Serialization/NonFiniteDoubleSerializationTests.cs b/Coder.Test/Serialization/NonFiniteDoubleSerializationTests.cs
new file mode 100644
index 0000000..b4b4674
--- /dev/null
+++ b/Coder.Test/Serialization/NonFiniteDoubleSerializationTests.cs
@@ -0,0 +1,65 @@
+// Copyright (c) 2023-2026 ktsu-dev contributors
+
+namespace ktsu.Coder.Test.Serialization;
+
+using ktsu.Coder.Ast;
+using ktsu.Coder.Serialization;
+
+///
+/// Tests that infinite and NaN double literals survive a YAML round trip.
+///
+/// YamlDotNet writes them with the core schema's spellings (.inf, -.inf, .nan),
+/// which
+/// cannot read. The deserializer used to drop the literal, so a declaration initialised to infinity
+/// came back with no initialiser (ktsu-dev/Coder#78).
+///
+[TestClass]
+public class NonFiniteDoubleSerializationTests
+{
+ [TestMethod]
+ [DataRow(double.PositiveInfinity)]
+ [DataRow(double.NegativeInfinity)]
+ [DataRow(double.NaN)]
+ public void RoundTrip_NonFiniteLiteral_KeepsValue(double value)
+ {
+ string yaml = new YamlSerializer().Serialize(Literal.DecimalValue(value));
+
+ AstNode? deserialized = new YamlDeserializer().Deserialize(yaml);
+
+ LiteralExpression literal = Assert.IsInstanceOfType>(deserialized);
+ Assert.AreEqual(value, literal.Value);
+ }
+
+ [TestMethod]
+ public void RoundTrip_VariableInitialisedToInfinity_KeepsInitialiser()
+ {
+ VariableDeclaration declaration = new("inf", "double", Literal.DecimalValue(double.PositiveInfinity));
+ string yaml = new YamlSerializer().Serialize(declaration);
+
+ AstNode? deserialized = new YamlDeserializer().Deserialize(yaml);
+
+ VariableDeclaration roundTripped = Assert.IsInstanceOfType(deserialized);
+ LiteralExpression initialiser = Assert.IsInstanceOfType>(roundTripped.InitialValue);
+ Assert.AreEqual(double.PositiveInfinity, initialiser.Value);
+ }
+
+ [TestMethod]
+ [DataRow(".inf", double.PositiveInfinity)]
+ [DataRow(".Inf", double.PositiveInfinity)]
+ [DataRow(".INF", double.PositiveInfinity)]
+ [DataRow("+.inf", double.PositiveInfinity)]
+ [DataRow("-.inf", double.NegativeInfinity)]
+ [DataRow("-.INF", double.NegativeInfinity)]
+ [DataRow(".nan", double.NaN)]
+ [DataRow(".NaN", double.NaN)]
+ [DataRow(".NAN", double.NaN)]
+ public void Deserialize_CoreSchemaNonFiniteSpelling_ReadsValue(string spelling, double expected)
+ {
+ string yaml = new YamlSerializer().Serialize(Literal.DecimalValue(1.5)).Replace("1.5", spelling, StringComparison.Ordinal);
+
+ AstNode? deserialized = new YamlDeserializer().Deserialize(yaml);
+
+ LiteralExpression literal = Assert.IsInstanceOfType>(deserialized);
+ Assert.AreEqual(expected, literal.Value);
+ }
+}
diff --git a/Coder/Serialization/YamlDeserializer.cs b/Coder/Serialization/YamlDeserializer.cs
index bf22676..0a84ec1 100644
--- a/Coder/Serialization/YamlDeserializer.cs
+++ b/Coder/Serialization/YamlDeserializer.cs
@@ -766,6 +766,36 @@ private FieldDeclaration DeserializeFieldDeclaration(object? nodeData)
/// The key a node's single value is written under.
private const string ValueKey = "value";
+ ///
+ /// Parses a YAML float scalar, including the core schema's spellings of the non-finite values.
+ ///
+ /// The scalar's text.
+ /// The parsed value.
+ /// if is a float.
+ ///
+ /// The serializer writes infinity and NaN as .inf, -.inf and .nan, which
+ /// does not
+ /// read. Failing here drops the literal, so a declaration initialised to infinity would come back
+ /// with no initialiser at all (ktsu-dev/Coder#78).
+ ///
+ private static bool TryParseDouble(string? text, out double value)
+ {
+ switch (text)
+ {
+ case ".inf" or ".Inf" or ".INF" or "+.inf" or "+.Inf" or "+.INF":
+ value = double.PositiveInfinity;
+ return true;
+ case "-.inf" or "-.Inf" or "-.INF":
+ value = double.NegativeInfinity;
+ return true;
+ case ".nan" or ".NaN" or ".NAN":
+ value = double.NaN;
+ return true;
+ default:
+ return double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value);
+ }
+ }
+
/// The key a declaration's documentation is written under.
private const string DocumentationKey = "documentation";
@@ -1261,7 +1291,7 @@ private UnaryExpression DeserializeUnaryExpression(object? nodeData)
"String" => new LiteralExpression(value?.ToString() ?? string.Empty),
"Int32" when int.TryParse(value?.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int intValue) => new LiteralExpression(intValue),
"Boolean" when bool.TryParse(value?.ToString(), out bool boolValue) => new LiteralExpression(boolValue),
- "Double" when double.TryParse(value?.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double doubleValue) => new LiteralExpression(doubleValue),
+ "Double" when TryParseDouble(value?.ToString(), out double doubleValue) => new LiteralExpression(doubleValue),
_ => null,
};