The "mandatory parentheses on zero-argument calls" rule (language-
rationale.adoc) was enforced in expression position but NOT in statement
position: a bare `Foo;`, `Obj.Method;`, or `Obj.Free;` used as a statement
compiled silently, building a paren-less TProcCall / TMethodCallStmt. Issue
#148 reported `tester.print;` (a unit's global object method call) being
accepted without its mandatory ().
The statement parser now raises the same "requires () for a call" diagnostic
the inherited-call and expression-position paths already use, at the two
fall-through sites:
* bare unqualified call `Foo` with no '(' (the final ProcCall else-branch);
* bare `Obj.Method` with no '(' and no further '.' chain.
Field reads, field assignments, indexed writes, and '.'-chains are unaffected
(only a terminating bare reference is rejected). Expression-position calls
were already enforced.
Enforcing the rule required the compiler, RTL, and stdlib to comply first
(self-hosting): swept bare calls in uSemantic (Flush/RepairGenericInstances),
runtime.arc/runtime.exc (_libc_abort), blaise.codegen.native.backend
(FAsm.AppendLine), and a json.writer doc example. The test suite embedded
many bare calls in inline program strings — all updated to carry (); adding
() never changes behaviour since these were always calls.
cp.test.parser.pas gains two parse-error tests (proc and method bare calls);
the old TestProcCall_NoParens, which asserted the bug, is inverted. grammar.ebnf
SubscriptMethodCall made parens mandatory and an example corrected; rationale
notes statement-position enforcement.
Adopts the Swift/LLVM model: Apache License 2.0 with the Runtime Library
Exception text used verbatim by the Swift project. SPDX identifier:
Apache-2.0 WITH Swift-exception.
Apache 2.0 brings an explicit patent grant and patent-retaliation clause
that BSD-3 lacks. The Runtime Library Exception ensures binaries
produced by the Blaise compiler do not inherit attribution obligations
from the linked-in RTL.
* LICENSE — full Apache 2.0 + RLE text (replaces the deleted LICENCE).
* NOTICE — project header plus QBE attribution (MIT, vendored).
* docs/language-rationale.adoc — new Project Governance section
capturing the decision, alternatives considered, and rationale.
* SPDX headers updated across all .pas, .pp, .inc, .c source files,
build scripts, PasBuild plugins, and the Makefile.
* project.xml license field updated.
* tools/migrate_full.py HEADER template updated so generated
self-hosting source carries the new licence.
New builtins: CompareStr, CompareText (→ _StringCompare/_StringCompareText),
ZeroMem (→ memset), _ClassAddRef/_ClassRelease for manual ARC management.
EmitPointerWrite now emits retain/release when the base type is tyString,
enabling ARC-correct string storage in ^string arrays. ZeroMem is used to
zero-initialise newly grown string slots so the "release old" half of ARC
never sees uninitialised memory.
Classes.pas: TObjectList (^Pointer array, no ARC overhead) and TStringList
(^string + ^Pointer parallel arrays, sorted binary search via CompareText,
complete Delete/Insert/Clear with correct ARC). Generics.Collections and
phase3_milestone updated to zero-init new array slots, fixing previously
hidden memory safety issues revealed by the EmitPointerWrite ARC fix.
785 tests pass, zero Valgrind errors.
Compiler:
- TRecordTypeDesc gains HasDestroyMethod boolean property, set by the
semantic analyser whenever a class (regular or generic instantiation)
declares a 'Destroy' method.
- EmitFieldCleanupFn emits a call to $<TypeName>_Destroy before the
ARC field-release loop when HasDestroyMethod is set, giving classes a
hook to free raw resources (malloc buffers etc.) at refcount zero.
RTL (Generics.Collections):
- TList<T> and TDictionary<K,V> replace 'procedure Free' with
'procedure Destroy'. Destroy frees the internal raw buffers (FData /
FKeys / FValues) and nils them, making re-entrant calls safe.
Free is no longer user-defined on these classes so List.Free uses
the built-in ARC release path (_ClassRelease + slot nil-out).
tests/phase3_milestone.pas:
- TIntList and TStrIntDict migrated to Destroy (removed FreeMem(Self)
which was unsafe under universal ARC on TObject).
Tests (718 total, 0 failures):
- cp.test.arc: 3 new IR tests for Destroy dispatch in field cleanup fn
(non-generic, absent-on-class-without-Destroy, generic instantiation).
- cp.test.e2e: 4 new end-to-end / valgrind tests — ClassDestroy frees
buffer, TList ARC lifecycle, Phase3Milestone stdout and valgrind-clean.
Four bugs fixed on the path to the milestone:
1. Non-generic class fields resolved with FindType instead of
FindTypeOrInstantiate — typed pointer fields (^Integer, ^string) in
concrete classes failed with 'Unknown type'.
2. Integer/Boolean/Int64 local variables not zero-initialised — QBE
validator rejected 'slot read but never stored to' for variables
written only through var-param pointers.
3. Class method var-param signature wrong — EmitMethodDef emitted the
param type (w for Integer) rather than 'l' (pointer) for var params;
EmitParamAllocs spilled the pointer with storew instead of storel.
4. Method call sites did not pass addresses for var-param arguments —
EmitMethodCallExpr always called EmitExpr (value load) rather than
forwarding %_var_Name (address) for IsVarParam params.
Milestone result (valgrind --leak-check=full):
7 allocs, 7 frees, 0 bytes in use at exit, ERROR SUMMARY: 0 errors