From f4dbea2532abfffff01c2e4c6115d7932b1f3110 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 25 Jul 2026 11:14:33 +0000 Subject: [PATCH] Fix exponent literals in static artifacts Co-authored-by: Ademar Gonzalez --- IronKernel.Tests/CliTests.fs | 28 ++++++++++++++++++++++++++++ IronKernel/StaticCompiler.fs | 15 +++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/IronKernel.Tests/CliTests.fs b/IronKernel.Tests/CliTests.fs index ff9a0b1..4a0fa9f 100644 --- a/IronKernel.Tests/CliTests.fs +++ b/IronKernel.Tests/CliTests.fs @@ -142,6 +142,34 @@ let ``managed artifact runs without Kernel source or runtime compilation`` () = finally Directory.Delete(root, true) +[] +let ``managed artifact preserves exponent-form double literals`` () = + let root = Path.Combine(Path.GetTempPath(), "ironkernel-managed-exponent-" + Guid.NewGuid().ToString("N")) + let script = Path.Combine(root, "exponent.ikr") + let output = Path.Combine(root, "publish") + Directory.CreateDirectory(root) |> ignore + try + File.WriteAllText(script, "1e20") + let artifact = + match compileFileToManagedArtifact Minimal script output with + | Choice1Of2 error -> failwith (showError error) + | Choice2Of2 path -> path + + let startInfo = ProcessStartInfo("dotnet") + startInfo.UseShellExecute <- false + startInfo.RedirectStandardError <- true + startInfo.RedirectStandardOutput <- true + startInfo.ArgumentList.Add artifact + use child = Process.Start startInfo + let stdout = child.StandardOutput.ReadToEnd() + let stderr = child.StandardError.ReadToEnd() + child.WaitForExit() + Assert.Equal(0, child.ExitCode) + Assert.Equal("", stdout.Trim()) + Assert.Equal("", stderr.Trim()) + finally + Directory.Delete(root, true) + [] let ``managed artifact supports definitions and lazy conditionals`` () = let root = Path.Combine(Path.GetTempPath(), "ironkernel-managed-control-flow-" + Guid.NewGuid().ToString("N")) diff --git a/IronKernel/StaticCompiler.fs b/IronKernel/StaticCompiler.fs index b420347..6d2bb43 100644 --- a/IronKernel/StaticCompiler.fs +++ b/IronKernel/StaticCompiler.fs @@ -18,6 +18,18 @@ module StaticCompiler = let private quote (value: string) = Text.Json.JsonSerializer.Serialize(value, stringLiteralOptions) + let private doubleLiteral (value: double) = + if Double.IsNaN value then "System.Double.NaN" + elif Double.IsPositiveInfinity value then "System.Double.PositiveInfinity" + elif Double.IsNegativeInfinity value then "System.Double.NegativeInfinity" + else + let literal = value.ToString("R", CultureInfo.InvariantCulture) + if literal.Contains('.') then literal + else + let exponentIndex = literal.IndexOfAny([|'E'; 'e'|]) + if exponentIndex >= 0 then literal.Insert(exponentIndex, ".0") + else literal + ".0" + let private sequenceOptions values = let mutable result = Some [] for value in List.rev values do @@ -50,8 +62,7 @@ module StaticCompiler = | Obj (:? float32 as value) -> Some("Obj(box " + value.ToString("R", CultureInfo.InvariantCulture) + "f)") | Obj (:? double as value) -> - let literal = value.ToString("R", CultureInfo.InvariantCulture) - Some("Obj(box " + (if literal.Contains('.') then literal else literal + ".0") + ")") + Some("Obj(box " + doubleLiteral value + ")") | Vector values -> values |> Array.map emitValue