Runtime leak tracker (blaise_arc.pas):
- Open-addressing hash map (1024 buckets, 16 bytes each) tracks every
live class instance; zero overhead when disabled.
- _LeakTrackerEnable() activates tracking and registers _LeakTrackerReport
via atexit; called from $main when --debug is passed.
- _LeakTrackerRegister(UserPtr, ClassName) inserts into the map; called
from codegen at every constructor site (both TFieldAccessExpr and
TMethodCallExpr paths).
- _ClassRelease unregisters on refcount-zero free via LTDelete.
- Report written to stderr lists count + class name of each survivor.
Compiler (--debug flag):
- New --debug CLI flag sets FDebugMode on TCodeGenQBE; emits
call $_LeakTrackerEnable() in EmitMainHeader after unit init calls,
and call $_LeakTrackerRegister(...) after every _ClassAlloc site.
- --debug-opdf remains independent (OPDF only, no leak tracking).
- SetDebugMode(Bool) added to TCodeGenQBE public API for e2e tests.
Pointer/PtrUInt cast pairs (semantic + codegen):
- Pointer(intOrPtrExpr) validated in AnalyseFuncCallExpr; accepts
integer, pointer, class, metaclass, procedural, and nil sources.
- PtrUInt(intOrPtrExpr) same validation; resolves to tyUInt64.
- Codegen: w-to-l widening uses extuw for Pointer/PChar targets
(zero-extend, not sign-extend) to preserve address semantics.
- Four new unit tests in cp.test.pointers.pas.
E2E test infrastructure:
- CompileAndRunWithRTLDebug added to TE2ETestCase base for in-process
debug-mode compilation without recursive overload ambiguity.
- cp.test.e2e.leakcheck.pas: 5 tests covering no-leak silence,
single leak, multiple leaks, reference cycles, and debug-off.
2258 tests pass; fixpoint verified.
Adds a real 64-bit unsigned integer type with two equivalent names:
UInt64 (Delphi style, matches the existing Int64) and QWord (FPC
style). PtrUInt now aliases UInt64 too — it's the natural pointer-
sized unsigned on 64-bit.
Language semantics:
- Arithmetic on UInt64 uses udiv/urem; add/sub/mul/and/or/xor/shl/shr
are bit-identical to their signed counterparts.
- Comparisons use unsigned QBE ops (cultl, cugtl, ...).
- Int64 <-> UInt64 mixing requires an explicit cast; the two types are
not implicitly convertible in either direction.
- Decimal/hex literals in the (2^63, 2^64-1) range are typed as
UInt64. Smaller literals stay Integer/Int64.
- SizeOf(UInt64) = SizeOf(QWord) = 8.
Runtime:
- New _UInt64ToStr in blaise_str.pas plus a WriteDecimalU helper that
uses UInt64 arithmetic.
- SysWriteUInt64 added to the platform abstraction and implemented in
the POSIX layer. WriteLn(UInt64) routes through it.
- IntToStr(UInt64) routes to _UInt64ToStr; explicit UInt64ToStr is
also exposed as a builtin.
Bootstrap notes:
- Older release binaries cannot compile the runtime any more because
rtl.platform.pas declares SysWriteUInt64. A stage-2 rebuild from a
fresh stage-1 is required after this commit on any worktree with an
older stage-1, per CLAUDE.md.
- The parser stages literal Value through local var-params rather than
writing directly to the new TIntLiteral.IsUInt64 field via class-field
out-params. Working around a stage-1 codegen bug where var-param
calls that target a class field silently fail to write back.
Docs:
- docs/grammar.ebnf: built-in type list expanded with UInt64/QWord,
integer-literal typing rules documented.
- docs/language-rationale.adoc: integer types table updated with the
unsigned variants, Int64<->UInt64 strict conversion rule explained.
Tests:
- 15 new tests in cp.test.uint64.pas covering symbol-table
registration, codegen instruction picking (udiv/urem/cultl/cugtl),
literal-range typing, and e2e round-trips.
- Full suite: 2151 tests pass (up from 2132).
- Fixpoint clean at stage-3/stage-4 (expected: type-system change).
Port all exception frame management, type identity, and runtime check
functions from C to pure Pascal (blaise_exc.pas). Replace libc
setjmp/longjmp with a minimal custom implementation in x86_64 assembly
(blaise_setjmp_x86_64.s, ~40 lines) that saves only the 8 callee-saved
registers (64-byte jmp_buf vs libc's 200-byte one).
This eliminates the last C source file from the runtime build. The only
non-Pascal code in the runtime is now the assembly setjmp stub.
Changes:
- runtime/src/main/asm/blaise_setjmp_x86_64.s: _blaise_setjmp/_blaise_longjmp
- runtime/src/main/pascal/blaise_exc.pas: _PushExcFrame, _PopExcFrame,
_Raise, _Reraise, _CurrentException, _CurrentExceptionMessage,
_IsInstance, _ImplementsInterface, _GetItab, _Raise_InvalidCast,
_CheckNil — all ported from blaise_exc.c
- uCodeGenQBE.pas: emit call $_blaise_setjmp instead of call $setjmp
- cp.test.exceptions.pas: IR assertion updated for new symbol name
- runtime/Makefile: assembly rule, Pascal blaise_exc build, C rules removed
- .gitignore: whitelist runtime/src/main/asm/*.s
- runtime/src/main/c/blaise_exc.c: deleted
2083 tests pass, fixpoint verified (stage-3/stage-4).
Rewrites strutils.pas from an empty stub into a complete pure Blaise Pascal
implementation with no external C dependencies. All helpers previously
planned for blaise_str.pas are implemented directly in StrUtils using only
compiler built-ins (Length, Pos, LowerCase, Copy, SetLength, PosEx).
- ContainsStr/ContainsText, StartsStr/StartsText, EndsStr/EndsText
- LeftStr, RightStr, MidStr
- IndexStr, IndexText
- ReplaceStr, ReplaceText
- DupeString, ReverseString, StuffString
- TrimLeft, TrimRight
- PadLeft, PadRight
- CountOccurrences, RemovePrefix, RemoveSuffix
- IsEmptyOrWhitespace
- JoinStr
- TStringBuilder — efficient incremental string builder (mirrors TIRBuffer)
Adds ExpandFileName to sysutils.pas as a pure Pascal path normaliser that
resolves '.' and '..' segments without symlink following, matching
Delphi/FPC behaviour.
Fixes cp.test.multiwrite.pas: unqualified CountOccurrences calls now use
Self. prefix to prevent name shadowing by StrUtils.CountOccurrences, which
has reversed parameter order (Sub, S vs Haystack, Needle).
Adds cp.test.strutils.pas (IR + type-check unit tests) and
cp.test.e2e.strutils.pas (compile→run E2E tests) covering all new
functions. Total test count: 1698.
Fixpoint verified at stage-3/stage-4.
Remove the -alpha suffix now that the compiler has reached self-hosting
fixpoint: stage-3 (hand source compiled by stage-2, itself compiled by
stage-1) produces byte-identical IR to stage-2. This is the first
official release of the Blaise compiler.
Fix TProgram.Uses reserved-word clash (renamed to UsedUnits), nested
brace-comment in uParser.pas, and missing uAST in Blaise.pas uses clause.
Vendor QBE 1.2 source in vendor/qbe/ (built locally with make; binary
excluded via .gitignore). End-to-end pipeline confirmed: Blaise compiles
Hello World and Calc (6*7=42) to native x86_64 Linux binaries.
71/71 FPCUnit tests passing.