From c3ed2c89d6c03efaeb1de70a15cd52b5d4a82b00 Mon Sep 17 00:00:00 2001 From: Graeme Geldenhuys Date: Mon, 29 Jun 2026 12:53:25 +0100 Subject: [PATCH] fix(debug-opdf): emit recPrimitive for Double and Single MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Float-typed variables (Double, Single) were invisible in pdr — locals, print, gl and every other inspection command failed for floats while integers, strings, classes and records-of-int-and-string worked. The OPDF emitter never produced a recPrimitive for tyDouble/tySingle: EmitTypeDesc did not dispatch the float kinds, so a float variable's GlobalVar/LocalVar record referenced a TypeID with no corresponding type record, and pdr could not resolve the type to read the value. EmitTypeDesc now routes tyDouble/tySingle to EmitPrimitive, which emits the record with SizeInBytes (8/4), IsSigned=1, and a new SubKind=SK_FLOAT (4). The pdr side already handled this fully: the adapter maps SubKind skFloat to Category tcFloat and TFloatEvaluator reads the IEEE 754 value by size — it was only waiting for the compiler to emit the record. Verified end to end with pdr: a global, a local, and a Double record field all print their values (d = 3.14159, s = 2.5, pt.Z = 9.81), and locals lists them. IR tests assert the Double/Single recPrimitive carries SubKind=4 and the correct size. --- compiler/src/main/pascal/uDebugOPDF.pas | 9 ++++- compiler/src/test/pascal/cp.test.opdf.pas | 40 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/compiler/src/main/pascal/uDebugOPDF.pas b/compiler/src/main/pascal/uDebugOPDF.pas index 1631fc8..9899e98 100644 --- a/compiler/src/main/pascal/uDebugOPDF.pas +++ b/compiler/src/main/pascal/uDebugOPDF.pas @@ -140,6 +140,8 @@ const SK_INTEGER = 0; SK_BOOLEAN = 1; + { SK_CHAR = 2; SK_WIDECHAR = 3; — reserved by the OPDF spec, not emitted yet } + SK_FLOAT = 4; { Single, Double — pdr renders via TFloatEvaluator } LOC_RBP = 1; LOC_RBP_INDIRECT = 3; { frame slot holds the value's address } @@ -369,7 +371,8 @@ begin if HasBeenEmitted(CName) then Exit; case AType.Kind of tyInteger, tyInt64, tyUInt32, tyUInt64, - tySmallInt, tyWord, tyByte, tyBoolean: + tySmallInt, tyWord, tyByte, tyBoolean, + tyDouble, tySingle: EmitPrimitive(AType); tyString: EmitUtf8Str(); @@ -407,6 +410,10 @@ begin tyBoolean: begin SubKind := SK_BOOLEAN; IsSigned := 0; end; tyInt64, tyInteger, tySmallInt: begin SubKind := SK_INTEGER; IsSigned := 1; end; + tyDouble, tySingle: + { Single (4B) / Double (8B) — pdr keys off SubKind=skFloat + and reads the IEEE 754 value by SizeInBytes. } + begin SubKind := SK_FLOAT; IsSigned := 1; end; else SubKind := SK_INTEGER; IsSigned := 0; end; diff --git a/compiler/src/test/pascal/cp.test.opdf.pas b/compiler/src/test/pascal/cp.test.opdf.pas index 1f3e04d..7361f4a 100644 --- a/compiler/src/test/pascal/cp.test.opdf.pas +++ b/compiler/src/test/pascal/cp.test.opdf.pas @@ -27,6 +27,8 @@ type procedure TestOPDF_Primitive_Integer; procedure TestOPDF_Primitive_Boolean; procedure TestOPDF_Primitive_Int64; + procedure TestOPDF_Primitive_Double_SubKindFloat; + procedure TestOPDF_Primitive_Single_SubKindFloat; procedure TestOPDF_AnsiStr_Record; procedure TestOPDF_GlobalVar_QuadLabel; procedure TestOPDF_GlobalVar_RecType; @@ -175,6 +177,44 @@ begin AssertTrue('recPrimitive Int64 present', Contains(IR, '# recPrimitive: Int64')); end; +procedure TOPDFTests.TestOPDF_Primitive_Double_SubKindFloat; +{ Regression: float types emitted NO recPrimitive at all, so a Double/Single + variable referenced a TypeID with no type record and pdr could not print it + (locals/print/gl all failed for floats). A Double must now emit a recPrimitive + with SubKind=SK_FLOAT(4) and SizeInBytes=8 so pdr's TFloatEvaluator + (Category=tcFloat, keyed off SubKind in [skFloat, skCurrency]) renders it. } +var + IR: string; + P: Integer; +begin + IR := GenOPDF('program P; var D: Double; begin D := 1.5 end.'); + AssertTrue('recPrimitive Double comment', Contains(IR, '# recPrimitive: Double')); + AssertTrue('Double name emitted', Contains(IR, '.ascii "Double"')); + P := Pos('# recPrimitive: Double', IR); + AssertTrue('Double recPrimitive present', P >= 0); + { SubKind must be SK_FLOAT (4) and size 8, in the Double record's payload. } + AssertTrue('Double SubKind = 4 (skFloat)', + Pos('.byte 4 # SubKind', Copy(IR, P, 220)) >= 0); + AssertTrue('Double SizeInBytes = 8', + Pos('.byte 8 # SizeInBytes', Copy(IR, P, 220)) >= 0); +end; + +procedure TOPDFTests.TestOPDF_Primitive_Single_SubKindFloat; +{ Single is the 4-byte float counterpart; same recPrimitive shape, size 4. } +var + IR: string; + P: Integer; +begin + IR := GenOPDF('program P; var S: Single; begin S := 1.5 end.'); + AssertTrue('recPrimitive Single comment', Contains(IR, '# recPrimitive: Single')); + P := Pos('# recPrimitive: Single', IR); + AssertTrue('Single recPrimitive present', P >= 0); + AssertTrue('Single SubKind = 4 (skFloat)', + Pos('.byte 4 # SubKind', Copy(IR, P, 220)) >= 0); + AssertTrue('Single SizeInBytes = 4', + Pos('.byte 4 # SizeInBytes', Copy(IR, P, 220)) >= 0); +end; + procedure TOPDFTests.TestOPDF_AnsiStr_Record; var IR: string;