From c94718cc3ac04ad8061a3f14c0bd584134358648 Mon Sep 17 00:00:00 2001 From: Markus Alexander Kuppe Date: Sat, 25 Oct 2025 18:02:13 -0700 Subject: [PATCH 1/2] Add IOUtils!zeroPadN function and corresponding tests for zero-padding natural numbers. [Feature] Signed-off-by: Markus Alexander Kuppe --- modules/IOUtils.tla | 30 ++++++++++++++++++++++++++++++ tests/IOUtilsTests.tla | 9 +++++++++ 2 files changed, 39 insertions(+) diff --git a/modules/IOUtils.tla b/modules/IOUtils.tla index d4a413c..c8f914c 100644 --- a/modules/IOUtils.tla +++ b/modules/IOUtils.tla @@ -16,6 +16,8 @@ LOCAL INSTANCE TLC LOCAL INSTANCE Integers +LOCAL INSTANCE Sequences +LOCAL INSTANCE SequencesExt (*************************************************************************) (* Imports the definitions from the modules, but doesn't export them. *) (*************************************************************************) @@ -126,4 +128,32 @@ IOEnv == atoi(str) == CHOOSE i \in Int : ToString(i) = str +(***************************************************************************) +(* Pads a natural number with leading zeros to achieve a specified width. *) +(* *) +(* This function converts a natural number to a string and pads it with *) +(* leading zeros if necessary to reach the specified width. If the *) +(* number's string representation is already equal to or longer than the *) +(* specified width, no padding is added. *) +(* *) +(* Parameters: *) +(* - n: The natural number to be padded (must be >= 0) *) +(* - width: The desired total width of the resulting string *) +(* *) +(* Examples: *) +(* zeroPadN(42, 5) = "00042" *) +(* zeroPadN(123, 3) = "123" *) +(* zeroPadN(7, 1) = "7" *) +(* zeroPadN(0, 4) = "0000" *) +(* *) +(* Note: Negative numbers are not supported and may produce unexpected *) +(* results. *) +(* *) +(* Returns a sequence of characters representing the zero-padded number. *) +(***************************************************************************) +zeroPadN(n, width) == + LET s == ToString(n) + padLen == width - Len(s) + zeros == [i \in 1..padLen |-> "0"] + IN FoldLeft(LAMBDA acc, z: acc \o z, "", zeros) \o s ============================================================================ diff --git a/tests/IOUtilsTests.tla b/tests/IOUtilsTests.tla index ad9db20..82f05b4 100644 --- a/tests/IOUtilsTests.tla +++ b/tests/IOUtilsTests.tla @@ -98,6 +98,15 @@ ASSUME AssertError( "The argument of atoi should be a string, but instead it is:\n\"foo\"", atoi("foo")) +\* Test zeroPadN function with various inputs +ASSUME(AssertEq(zeroPadN(42, 5), "00042")) +ASSUME(AssertEq(zeroPadN(123, 3), "123")) +ASSUME(AssertEq(zeroPadN(7, 1), "7")) +ASSUME(AssertEq(zeroPadN(0, 4), "0000")) +ASSUME(AssertEq(zeroPadN(999, 2), "999")) +ASSUME(AssertEq(zeroPadN(1000, 6), "001000")) +ASSUME(AssertEq(zeroPadN(0, 1), "0")) + --------------------------------------------------------------------------------------------------------------------------- ASSUME PrintT("IOUtilsTests!C") From 33203b5a00402026f03ad50a7782ae68fec7c9f6 Mon Sep 17 00:00:00 2001 From: Markus Alexander Kuppe Date: Sat, 25 Oct 2025 18:05:53 -0700 Subject: [PATCH 2/2] Enhance SVGSerialize to use zero-padded frame numbers for consistent file sorting. (Up to 99 frames seems reasonable) The following snippet produces the expected result: ```bash convert -delay 100 -loop 0 *.svg animation.gif ``` [Feature] Signed-off-by: Markus Alexander Kuppe --- modules/SVG.tla | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/SVG.tla b/modules/SVG.tla index a746ec4..caab322 100644 --- a/modules/SVG.tla +++ b/modules/SVG.tla @@ -230,14 +230,16 @@ PointOnLine(from, to, segment) == (* SVGSerialize(SVGDoc(myElements, 0, 0, 800, 600, <<>>), *) (* "svg_frame_", TLCGet("level")) *) (* *) -(* This creates files like: svg_frame_1.svg, *) -(* svg_frame_2.svg, etc. *) +(* This creates files like: svg_frame_01.svg, *) +(* svg_frame_02.svg, etc. *) (**************************************************************************) SVGSerialize(svg, frameNamePrefix, frameNumber) == LET IO == INSTANCE IOUtils IN IO!Serialize( SVGElemToString(svg), - frameNamePrefix \o ToString(frameNumber) \o ".svg", + \* Construct the filename using the prefix and a zero-padded frame + \* number so that files sort correctly lexicographically. + frameNamePrefix \o IO!zeroPadN(frameNumber, 2) \o ".svg", [format |-> "TXT", charset |-> "UTF-8", openOptions |-> <<"WRITE", "CREATE", "TRUNCATE_EXISTING">>])