feat(sets): range syntax in set literals — [lo..hi] (#105)

A set literal element may now be a constant range:

    e := [Red..Blue];        { {Red, Green, Blue} }
    e := [m0, m2..m4, m7];   { ranges mix with single members }

The parser builds a transient TSetRangeExpr for each lo..hi element; the
semantic pass (AnalyseSetLiteralExpr) expands it into the individual member
idents before any other consumer runs, so overload resolution, the bitmask
folder, the jumbo-set path, and both code generators see an ordinary member
list and need no range-specific logic.

Both bounds must be compile-time constants of the set's base type. A
reversed constant range [Blue..Red] is a compile-time error rather than a
silently empty set — matching Blaise's preference for rejecting
confusing-but-legal constructs over FPC's empty-set-with-warning behaviour.
Variable bounds [lo..hi] are rejected ("set range bound must be a
constant"); runtime-variable ranges are deferred.

TSetRangeExpr is wired into the .bif serialiser and the AST cloner so a
generic template body containing an unexpanded range round-trips through
separate compilation (verified by hand: a generic returning [m1..m3]
compiled to .o, then instantiated from the .bif with source hidden).

Set base types remain enumerations; the issue's set-of-byte example needs
ordinal-base set types, tracked separately in docs/future-improvements.adoc.
Range expansion is base-type-agnostic, so ranges will work for those
automatically once they land.

Docs: grammar.ebnf SetElement rule; language-rationale.adoc decision +
alternatives. bif-coverage.status regenerated for the new node.

FIXPOINT_OK + NATIVE_FIXPOINT_OK; full suite OK (3201 tests, 11 new).
This commit is contained in:
Graeme Geldenhuys 2026-06-15 17:14:05 +01:00
parent 4e90165b73
commit 9362114ee1
10 changed files with 451 additions and 37 deletions

View file

@ -71,6 +71,19 @@ type
destructor Destroy; override;
end;
{ A `lo..hi` range appearing as an element of a set literal, e.g.
[1..3] or [Red..Blue]. Both bounds must be compile-time constants;
uSemantic.AnalyseSetLiteralExpr expands the range into individual
member nodes (so codegen never sees this node), and rejects reversed
or non-constant ranges. Carried through the .bif serialiser because a
generic template body may contain an unexpanded range. }
TSetRangeExpr = class(TASTExpr)
public
LowExpr: TASTExpr; { owned }
HighExpr: TASTExpr; { owned }
destructor Destroy; override;
end;
TNilLiteral = class(TASTExpr); { nil keyword — type is tyNil }
TParamMode = (
@ -1236,6 +1249,12 @@ begin
inherited Destroy();
end;
destructor TSetRangeExpr.Destroy;
begin
{ LowExpr/HighExpr released by ARC field cleanup. }
inherited Destroy();
end;
{ TProcCall }
constructor TProcCall.Create;
@ -1718,6 +1737,7 @@ var
SL: TStringLiteral;
SS: TStringSubscriptExpr;
AL: TArrayLiteralExpr;
SRE: TSetRangeExpr;
IE: TIdentExpr;
FA: TFieldAccessExpr;
IsE: TIsExpr;
@ -1771,6 +1791,13 @@ begin
AL.IsConstArray := TArrayLiteralExpr(AExpr).IsConstArray;
Result := AL;
end
else if AExpr is TSetRangeExpr then
begin
SRE := TSetRangeExpr.Create();
SRE.LowExpr := CloneExpr(TSetRangeExpr(AExpr).LowExpr);
SRE.HighExpr := CloneExpr(TSetRangeExpr(AExpr).HighExpr);
Result := SRE;
end
else if AExpr is TIdentExpr then
begin
IE := TIdentExpr.Create();

View file

@ -109,6 +109,7 @@ type
function ParseForwardDecl(IsFunction: Boolean): TMethodDecl;
function ParseCompoundStmt: TCompoundStmt;
function ParseExpr: TASTExpr;
function ParseSetOrArrayElement: TASTExpr;
function ParseAddSub: TASTExpr;
function ParseTerm: TASTExpr;
function ParseFactor: TASTExpr;
@ -3620,6 +3621,28 @@ end;
{ Expression parsing — standard precedence climbing }
{ ------------------------------------------------------------------ }
{ Parse one element of a bracket literal [ ... ]. An ordinary element is a
plain expression; a `lo..hi` form (set range, issue #105) becomes a
TSetRangeExpr that uSemantic expands into individual set members. The
range form is only meaningful for set literals — uSemantic rejects it in
array-literal context. }
function TParser.ParseSetOrArrayElement: TASTExpr;
var
LowE: TASTExpr;
Range: TSetRangeExpr;
begin
LowE := Self.ParseExpr();
if not Check(tkDotDot) then
Exit(LowE);
Range := TSetRangeExpr.Create();
Range.Line := LowE.Line;
Range.Col := LowE.Col;
Range.LowExpr := LowE;
Advance(); { consume '..' }
Range.HighExpr := Self.ParseExpr();
Result := Range;
end;
function TParser.ParseExpr: TASTExpr;
var
Right: TASTExpr;
@ -4125,11 +4148,11 @@ begin
Advance(); { consume '[' }
if not Check(tkRBracket) then
begin
ArrNode.Elements.Add(ParseExpr());
ArrNode.Elements.Add(Self.ParseSetOrArrayElement());
while Check(tkComma) do
begin
Advance(); { consume ',' }
ArrNode.Elements.Add(ParseExpr());
ArrNode.Elements.Add(Self.ParseSetOrArrayElement());
end;
end;
Expect(tkRBracket);

View file

@ -240,6 +240,11 @@ type
function AnalyseStringSubscriptExpr(AExpr: TStringSubscriptExpr): TTypeDesc;
function AnalyseArrayLiteralExpr(AExpr: TArrayLiteralExpr): TTypeDesc;
function AnalyseSetLiteralExpr(AExpr: TArrayLiteralExpr; ASetType: TSetTypeDesc): TTypeDesc;
{ Expand [lo..hi] range elements of a set literal into individual member
idents (issue #105). Constant ascending ranges only. }
procedure ExpandSetRanges(AExpr: TArrayLiteralExpr; ABaseEnum: TEnumTypeDesc);
function SetRangeBoundOrdinal(ABound: TASTExpr; ABaseEnum: TEnumTypeDesc;
const AWhich: string): Integer;
{ Width (in bits) needed for the anonymous set type of an 'X in [a,b,c]'
literal: largest listed member ordinal + 1 when every element is a
compile-time enum constant; otherwise the full base-enum member count
@ -10228,15 +10233,127 @@ begin
Result := MaxOrd + 1;
end;
function TSemanticAnalyser.SetRangeBoundOrdinal(ABound: TASTExpr;
ABaseEnum: TEnumTypeDesc; const AWhich: string): Integer;
{ Resolve a set-range bound (lo or hi) to a compile-time ordinal of the
base enum. Rejects non-constant and wrong-type bounds. Issue #105. }
var
BType: TTypeDesc;
Sym: TSymbol;
begin
BType := AnalyseExpr(ABound);
if BType <> ABaseEnum then
SemanticError(
Format('Set range %s bound has type ''%s''; expected ''%s''',
[AWhich, BType.Name, ABaseEnum.Name]),
ABound.Line, ABound.Col);
if not ((ABound is TIdentExpr) and TIdentExpr(ABound).IsConstant) then
SemanticError(
Format('Set range %s bound must be a constant', [AWhich]),
ABound.Line, ABound.Col);
Sym := FTable.Lookup(TIdentExpr(ABound).Name);
if (Sym = nil) or (Sym.Kind <> skConstant) then
SemanticError(
Format('Set range %s bound ''%s'' is not a constant',
[AWhich, TIdentExpr(ABound).Name]),
ABound.Line, ABound.Col);
Result := Sym.ConstValue;
end;
procedure TSemanticAnalyser.ExpandSetRanges(AExpr: TArrayLiteralExpr;
ABaseEnum: TEnumTypeDesc);
{ Replace every TSetRangeExpr element [lo..hi] with the individual member
idents lo, lo+1, ..., hi. Constant ascending ranges only; a reversed
range is a compile-time error (not a silent empty set). Runs before the
element validation loop so the rest of the pipeline only ever sees plain
member idents. Issue #105. }
var
I, J: Integer;
Elem: TASTExpr;
Range: TSetRangeExpr;
LoOrd: Integer;
HiOrd: Integer;
NewList: TObjectList;
MemberId: TIdentExpr;
begin
{ Quick scan — nothing to do if there are no ranges. }
J := -1;
for I := 0 to AExpr.Elements.Count - 1 do
if TASTExpr(AExpr.Elements.Items[I]) is TSetRangeExpr then
begin
J := I;
Break;
end;
if J < 0 then Exit;
if ABaseEnum = nil then
SemanticError('Set range requires an enumeration base type',
AExpr.Line, AExpr.Col);
{ Build a fresh element list, expanding ranges into members. NewList does
NOT own its items — ownership of plain elements transfers from the old
list, and the generated member idents are handed to it too; the swap
below frees the old list (with the consumed ranges) without touching the
surviving plain elements. }
NewList := TObjectList.Create(False);
try
for I := 0 to AExpr.Elements.Count - 1 do
begin
Elem := TASTExpr(AExpr.Elements.Items[I]);
if not (Elem is TSetRangeExpr) then
begin
NewList.Add(Elem);
Continue;
end;
Range := TSetRangeExpr(Elem);
LoOrd := SetRangeBoundOrdinal(Range.LowExpr, ABaseEnum, 'low');
HiOrd := SetRangeBoundOrdinal(Range.HighExpr, ABaseEnum, 'high');
if HiOrd < LoOrd then
SemanticError(
Format('Set range is reversed (low ordinal %d > high ordinal %d) — ' +
'an empty range is almost always a mistake; use [] for an ' +
'empty set', [LoOrd, HiOrd]),
Range.Line, Range.Col);
for J := LoOrd to HiOrd do
begin
MemberId := TIdentExpr.Create();
MemberId.Line := Range.Line;
MemberId.Col := Range.Col;
MemberId.Name := ABaseEnum.Members.Strings[J];
MemberId.IsConstant := True;
MemberId.ConstValue := J;
MemberId.ResolvedType := ABaseEnum;
NewList.Add(MemberId);
end;
end;
{ Transfer expanded elements into a new owning list and swap. The old
Elements list owns its items; detach the survivors first so freeing it
only disposes the consumed TSetRangeExpr nodes. }
for I := AExpr.Elements.Count - 1 downto 0 do
if not (TASTExpr(AExpr.Elements.Items[I]) is TSetRangeExpr) then
AExpr.Elements.Extract(AExpr.Elements.Items[I]);
AExpr.Elements.Clear(); { frees the remaining TSetRangeExpr nodes }
for I := 0 to NewList.Count - 1 do
AExpr.Elements.Add(NewList.Items[I]);
finally
NewList.Free();
end;
end;
function TSemanticAnalyser.AnalyseSetLiteralExpr(AExpr: TArrayLiteralExpr;
ASetType: TSetTypeDesc): TTypeDesc;
{ Validates a set literal [elem, ...] against ASetType.
Elements must be constants or variables of the set's base enum type.
Range elements [lo..hi] are expanded to members first (issue #105).
An empty literal [] is valid and yields the set type with bitmask 0. }
var
ElemType: TTypeDesc;
I: Integer;
begin
if ASetType.BaseType is TEnumTypeDesc then
ExpandSetRanges(AExpr, TEnumTypeDesc(ASetType.BaseType))
else
ExpandSetRanges(AExpr, nil);
for I := 0 to AExpr.Elements.Count - 1 do
begin
ElemType := AnalyseExpr(TASTExpr(AExpr.Elements.Items[I]));

View file

@ -714,6 +714,10 @@ begin
else if AE is TArrayLiteralExpr then
Result := EncodeLpstr('alit') +
EncodeExprList(TArrayLiteralExpr(AE).Elements)
else if AE is TSetRangeExpr then
Result := EncodeLpstr('srng') +
EncodeExpr(TSetRangeExpr(AE).LowExpr) +
EncodeExpr(TSetRangeExpr(AE).HighExpr)
else if AE is TIsExpr then
Result := EncodeLpstr('isop') +
EncodeExpr(TIsExpr(AE).Obj) +
@ -1281,6 +1285,7 @@ var
AoE: TAddrOfExpr;
SS: TStringSubscriptExpr;
AL: TArrayLiteralExpr;
SRE: TSetRangeExpr;
IsE: TIsExpr;
AsE: TAsExpr;
SuE: TSupportsExpr;
@ -1385,6 +1390,13 @@ begin
ReadExprList(AText, APos, AL.Elements);
Result := AL;
end
else if Kind = 'srng' then
begin
SRE := TSetRangeExpr.Create();
SRE.LowExpr := ReadExpr(AText, APos);
SRE.HighExpr := ReadExpr(AText, APos);
Result := SRE;
end
else if Kind = 'isop' then
begin
IsE := TIsExpr.Create();

View file

@ -39,6 +39,7 @@ type
procedure TestRun_Set_LiteralArgument;
procedure TestRun_Set_EqualityWithLiteral;
procedure TestRun_Set_ForIn_PrintsMembers;
procedure TestRun_Set_RangeLiteral_Membership;
{ 33..64-member sets (the QBE 'l' / 64-bit register boundary) }
procedure TestRun_Set64_InOperator_HighBit;
@ -168,6 +169,27 @@ const
end.
''';
{ Set range literal (issue #105): [m1..m3] and a mixed [m0, m2..m4, m7]. }
SrcSetRange = '''
program Prg;
type
TC = (m0, m1, m2, m3, m4, m5, m6, m7);
TCS = set of TC;
var
e: TCS;
begin
e := [m1..m3];
if m0 in e then WriteLn('y') else WriteLn('n');
if m2 in e then WriteLn('y') else WriteLn('n');
if m3 in e then WriteLn('y') else WriteLn('n');
if m4 in e then WriteLn('y') else WriteLn('n');
e := [m0, m2..m4, m7];
if m1 in e then WriteLn('y') else WriteLn('n');
if m2 in e then WriteLn('y') else WriteLn('n');
if m7 in e then WriteLn('y') else WriteLn('n');
end.
''';
BigEnum64 =
'''
type
@ -293,6 +315,15 @@ begin
AssertRunsOnAll(SrcForInSet, '0' + LE + '2' + LE, 0);
end;
procedure TE2ESetOpsTests.TestRun_Set_RangeLiteral_Membership;
begin
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
{ [m1..m3]: m0=n m2=y m3=y m4=n; [m0,m2..m4,m7]: m1=n m2=y m7=y }
AssertRunsOnAll(SrcSetRange,
'n' + LE + 'y' + LE + 'y' + LE + 'n' + LE +
'n' + LE + 'y' + LE + 'y' + LE, 0);
end;
procedure TE2ESetOpsTests.TestRun_Set64_InOperator_HighBit;
begin
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;

View file

@ -55,6 +55,20 @@ type
procedure TestSemantic_Set_BaseTypeMustBeEnum;
procedure TestSemantic_Set_LiteralElementMustMatchBase;
{ ------------------------------------------------------------------ }
{ ranges in set literals — [lo..hi] (issue #105) }
{ ------------------------------------------------------------------ }
procedure TestParse_Set_RangeLiteral;
procedure TestSemantic_Set_RangeLiteral_OK;
procedure TestSemantic_Set_RangeMixedWithSingles_OK;
procedure TestSemantic_Set_RangeEnum_OK;
procedure TestSemantic_Set_RangeReversed_Fails;
procedure TestSemantic_Set_RangeNonConstBound_Fails;
procedure TestSemantic_Set_RangeWrongBaseType_Fails;
procedure TestCodegen_Set_RangeExpandsToBitmask;
procedure TestCodegen_Set_RangeSingleElement;
procedure TestCodegen_Set_RangeMixed;
{ ------------------------------------------------------------------ }
{ codegen }
{ ------------------------------------------------------------------ }
@ -839,6 +853,102 @@ begin
SemanticFail(SrcSetBadLiteralElement);
end;
{ ------------------------------------------------------------------ }
{ ranges in set literals — [lo..hi] (issue #105) }
{ ------------------------------------------------------------------ }
{ Blaise set base types are enumerations (set of byte is a separate, tracked
feature — see docs/future-improvements.adoc). Use an enum with enough
members to exercise the ranges below. }
const
SetEnumDecl =
'type TC = (m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10); ' +
'TCS = set of TC; ';
SrcSetRange =
'program P; ' + SetEnumDecl + 'var e: TCS; ' +
'begin e := [m1..m3]; end.';
SrcSetRangeMixed =
'program P; ' + SetEnumDecl + 'var e: TCS; ' +
'begin e := [m1, m5..m7, m10]; end.';
SrcSetRangeEnum =
'program P; type TC = (Red, Green, Blue, Yellow); TCS = set of TC; var e: TCS; ' +
'begin e := [Red..Blue]; end.';
SrcSetRangeReversed =
'program P; ' + SetEnumDecl + 'var e: TCS; ' +
'begin e := [m5..m3]; end.';
SrcSetRangeNonConst =
'program P; ' + SetEnumDecl + 'var e: TCS; lo, hi: TC; ' +
'begin lo := m1; hi := m4; e := [lo..hi]; end.';
SrcSetRangeWrongBase =
'program P; type TC = (Red, Green); TCS = set of TC; ' +
'TD = (xa, xb, xc); var e: TCS; ' +
'begin e := [xa..xb]; end.';
procedure TSetTests.TestParse_Set_RangeLiteral;
begin
ParseOK(SrcSetRange);
end;
procedure TSetTests.TestSemantic_Set_RangeLiteral_OK;
begin
SemanticOK(SrcSetRange);
end;
procedure TSetTests.TestSemantic_Set_RangeMixedWithSingles_OK;
begin
SemanticOK(SrcSetRangeMixed);
end;
procedure TSetTests.TestSemantic_Set_RangeEnum_OK;
begin
SemanticOK(SrcSetRangeEnum);
end;
procedure TSetTests.TestSemantic_Set_RangeReversed_Fails;
begin
{ A constant reverse range [5..3] is a mistake, not a silent empty set. }
SemanticFail(SrcSetRangeReversed);
end;
procedure TSetTests.TestSemantic_Set_RangeNonConstBound_Fails;
begin
{ Variable bounds are not supported — both ends must be constant. }
SemanticFail(SrcSetRangeNonConst);
end;
procedure TSetTests.TestSemantic_Set_RangeWrongBaseType_Fails;
begin
SemanticFail(SrcSetRangeWrongBase);
end;
procedure TSetTests.TestCodegen_Set_RangeExpandsToBitmask;
var
IR: string;
begin
{ [1..3] → bits 1,2,3 → mask = 2 + 4 + 8 = 14 → "copy 14" }
IR := GenIR(SrcSetRange);
AssertTrue('range [1..3] folds to mask 14', Pos('copy 14', IR) > 0);
end;
procedure TSetTests.TestCodegen_Set_RangeSingleElement;
var
IR: string;
begin
{ [m3..m3] → just bit 3 → mask 8 }
IR := GenIR('program P; ' + SetEnumDecl + 'var e: TCS; ' +
'begin e := [m3..m3]; end.');
AssertTrue('range [m3..m3] folds to mask 8', Pos('copy 8', IR) > 0);
end;
procedure TSetTests.TestCodegen_Set_RangeMixed;
var
IR: string;
begin
{ [1, 5..7, 10] → bits 1,5,6,7,10 → 2+32+64+128+1024 = 1250 }
IR := GenIR(SrcSetRangeMixed);
AssertTrue('mixed range folds to mask 1250', Pos('copy 1250', IR) > 0);
end;
{ ------------------------------------------------------------------ }
{ codegen }
{ ------------------------------------------------------------------ }

View file

@ -34,6 +34,25 @@ prioritise them.
- reference to function/procedure (anonymous methods)
- cdecl/stdcall calling-convention markers on procedural types
=== Ordinal-based set types (`set of byte`, `set of 0..255`)
Set types currently require an enumeration base type; `set of byte` (and,
more generally, a set over an integer subrange) is rejected with
"Set base type 'byte' must be an enumeration type". FPC and Delphi accept
ordinal base types, so `set of byte` is standard Pascal.
Supporting it means teaching the set machinery to treat an ordinal range as
an implicit member set: the bit count is the range width (0..255 → 256 bits,
the jumbo-set path), element ordinals are the integer values themselves, and
membership/include/exclude lower exactly as they do for enum sets. The work
spans the semantic pass (base-type validation, bit-count derivation) and both
codegen backends, including the jumbo-set path for `set of byte`.
This was surfaced by issue #105, whose example used `set of byte`. The set
range syntax `[lo..hi]` requested by that issue was implemented independently
(see `docs/language-rationale.adoc`) and is base-type-agnostic — ranges will
work for ordinal sets automatically once this lands.
=== Method level attributes
Blaise only has class-level attribute RTTI today — there's no per-method attribute reflection, and adding it is a layout-changing compiler change (new method-table slot, stage-2 rebuild).

View file

@ -695,9 +695,20 @@ ProceduralType
The semantic pass distinguishes them by assignment-target type context:
when the LHS is a set type, LBRACKET ExprList RBRACKET is a set literal;
otherwise it is an array literal. An empty LBRACKET RBRACKET is valid
only as a set literal (the empty set). *)
only as a set literal (the empty set).
A set element may be a single value or a range `lo .. hi` (issue #105).
Both range bounds must be compile-time constants of the set's base type;
the semantic pass expands the range into its individual members and
rejects a reversed range (low ordinal > high ordinal). The range form is
meaningful only in set context — in array-literal context DOTDOT is a
syntax error. *)
SetLiteral
= LBRACKET [ Expr { COMMA Expr } ] RBRACKET
= LBRACKET [ SetElement { COMMA SetElement } ] RBRACKET
;
SetElement
= Expr [ DOTDOT Expr ]
;
TypeArgList

View file

@ -4277,3 +4277,63 @@ identifier.
* *Restrict the rule to reference types (classes, interfaces) only.* Rejected
as arbitrary — the confusion is identical for records, enums, aliases, and
built-ins, and a name-based rule is simpler to explain than a kind-based one.
== Set Literal Ranges
=== Decision
A set literal element may be a range `lo..hi`, expanding to every member from
`lo` to `hi` inclusive:
[source,pascal]
----
type
TColor = (Red, Green, Blue, Yellow, Cyan);
TColorSet = set of TColor;
var
e: TColorSet;
begin
e := [Red..Blue]; // {Red, Green, Blue}
e := [Red, Blue..Cyan]; // {Red, Blue, Yellow, Cyan} — ranges mix with singles
end;
----
Both bounds must be compile-time constants of the set's base type. A reversed
range (`[Blue..Red]`, low ordinal greater than high) is a compile-time error,
not a silently empty set. Variable bounds (`[lo..hi]` where `lo`/`hi` are
variables) are rejected with "set range bound must be a constant".
This matches the range form FPC and Delphi accept in set constructors, with two
deliberate restrictions (see below).
=== Rationale
`[1..10]` (or `[Red..Cyan]`) is far clearer than spelling out every member, and
the construct is standard Pascal — the reporter of issue #105 reasonably
expected it to work. The implementation expands each range into individual
member nodes during semantic analysis, so the rest of the pipeline — overload
resolution, the bitmask folder, the jumbo-set path, and both code generators —
sees an ordinary member list and needs no range-specific logic. A transient
`TSetRangeExpr` AST node carries the unexpanded range from the parser to that
expansion point; it is also wired into the `.bif` serialiser and the AST cloner
because a generic template body may contain an unexpanded range that is
serialised and re-instantiated later.
=== Alternatives considered
* *Treat a reversed constant range as an empty set (FPC behaviour).* Rejected.
FPC accepts `[5..3]` as empty (with a warning); when both bounds are
compile-time constants there is no legitimate reason to write a reversed
range — it is a typo, and `[]` already expresses the empty set
unambiguously. Erroring matches Blaise's preference for rejecting
confusing-but-legal constructs (cf. variable/type name clashes).
* *Support variable range bounds `[lo..hi]`.* Deferred. Runtime-variable
bounds require emitting a bit-setting loop in both backends across the
small-set and jumbo-set paths; the constant form covers the reported case and
the overwhelmingly common usage. The restriction is enforced with a clear
diagnostic rather than silently mis-compiling.
* *Support ranges over an ordinal base type (`set of byte`, `[1..3]`).* Out of
scope: Blaise set base types are enumerations today. Ordinal-based set types
are tracked separately (see `docs/future-improvements.adoc`); because range
expansion is base-type-agnostic, `[1..3]` will work automatically once they
land.

View file

@ -24,9 +24,13 @@ TStringSubscriptExpr.IndexExpr serialise
TArrayLiteralExpr.Elements serialise
TArrayLiteralExpr.IsConstArray safe
# TNilLiteral (uAST.pas:74)
# TSetRangeExpr (uAST.pas:80)
TSetRangeExpr.LowExpr serialise
TSetRangeExpr.HighExpr serialise
# TIdentExpr (uAST.pas:83)
# TNilLiteral (uAST.pas:87)
# TIdentExpr (uAST.pas:97)
TIdentExpr.Name serialise
TIdentExpr.ParamMode safe
TIdentExpr.IsConstant safe
@ -39,7 +43,7 @@ TIdentExpr.IsImplicitSelfMethod safe
TIdentExpr.IsMetaclassRef safe
TIdentExpr.ConstArraySymbol safe
# TFieldAccessExpr (uAST.pas:104)
# TFieldAccessExpr (uAST.pas:118)
TFieldAccessExpr.RecordName serialise
TFieldAccessExpr.FieldName serialise
TFieldAccessExpr.Base serialise
@ -64,29 +68,29 @@ TFieldAccessExpr.PropIndexExpr serialise
TFieldAccessExpr.IsCharAccess safe
TFieldAccessExpr.IsArrayAccess safe
# TIsExpr (uAST.pas:136)
# TIsExpr (uAST.pas:150)
TIsExpr.Obj serialise
TIsExpr.TypeName serialise
# TAsExpr (uAST.pas:144)
# TAsExpr (uAST.pas:158)
TAsExpr.Obj serialise
TAsExpr.TypeName serialise
# TSupportsExpr (uAST.pas:153)
# TSupportsExpr (uAST.pas:167)
TSupportsExpr.Obj serialise
TSupportsExpr.IntfTypeName serialise
TSupportsExpr.OutVarName serialise
TSupportsExpr.OutVarIsGlobal safe
# TBinaryExpr (uAST.pas:169)
# TBinaryExpr (uAST.pas:183)
TBinaryExpr.Op serialise
TBinaryExpr.Left serialise
TBinaryExpr.Right serialise
# TNotExpr (uAST.pas:177)
# TNotExpr (uAST.pas:191)
TNotExpr.Expr serialise
# TAssignment (uAST.pas:189)
# TAssignment (uAST.pas:203)
TAssignment.Name serialise
TAssignment.Expr serialise
TAssignment.IsVarParam safe
@ -95,23 +99,23 @@ TAssignment.IsThreadVar safe
TAssignment.IsWeakLhs safe
TAssignment.ImplicitSelfField safe
# TIfStmt (uAST.pas:205)
# TIfStmt (uAST.pas:219)
TIfStmt.Condition serialise
TIfStmt.ThenStmt serialise
TIfStmt.ElseStmt serialise
# TCompoundStmt (uAST.pas:213)
# TCompoundStmt (uAST.pas:227)
TCompoundStmt.Stmts serialise
# TWhileStmt (uAST.pas:220)
# TWhileStmt (uAST.pas:234)
TWhileStmt.Condition serialise
TWhileStmt.Body serialise
# TRepeatStmt (uAST.pas:227)
# TRepeatStmt (uAST.pas:241)
TRepeatStmt.Body serialise
TRepeatStmt.Condition serialise
# TForStmt (uAST.pas:234)
# TForStmt (uAST.pas:248)
TForStmt.VarName serialise
TForStmt.IsGlobal safe
TForStmt.StartExpr serialise
@ -119,7 +123,7 @@ TForStmt.EndExpr serialise
TForStmt.IsDownTo serialise
TForStmt.Body serialise
# TForInStmt (uAST.pas:245)
# TForInStmt (uAST.pas:259)
TForInStmt.VarName serialise
TForInStmt.VarIsGlobal safe
TForInStmt.CollExpr serialise
@ -139,34 +143,34 @@ TForInStmt.SetBitCount safe
TForInStmt.SetMaskVarName safe
TForInStmt.SetIsJumbo safe
# TTryFinallyStmt (uAST.pas:282)
# TTryFinallyStmt (uAST.pas:296)
TTryFinallyStmt.TryBody serialise
TTryFinallyStmt.FinallyBody serialise
# TTryExceptStmt (uAST.pas:299)
# TTryExceptStmt (uAST.pas:313)
TTryExceptStmt.TryBody serialise
TTryExceptStmt.Handlers serialise
TTryExceptStmt.ElseBody serialise
TTryExceptStmt.ExceptBody serialise
# TRaiseStmt (uAST.pas:312)
# TRaiseStmt (uAST.pas:326)
TRaiseStmt.Expr serialise
# TExitStmt (uAST.pas:323)
# TExitStmt (uAST.pas:337)
TExitStmt.Value safe
TExitStmt.ResultAssign safe
# TBreakStmt (uAST.pas:331)
# TBreakStmt (uAST.pas:345)
# TContinueStmt (uAST.pas:334)
# TContinueStmt (uAST.pas:348)
# TCaseStmt (uAST.pas:345)
# TCaseStmt (uAST.pas:359)
TCaseStmt.Selector serialise
TCaseStmt.Branches serialise
TCaseStmt.ElseStmt serialise
TCaseStmt.IsStringCase safe
# TFieldAssignment (uAST.pas:356)
# TFieldAssignment (uAST.pas:370)
TFieldAssignment.RecordName serialise
TFieldAssignment.FieldName serialise
TFieldAssignment.Expr serialise
@ -180,7 +184,7 @@ TFieldAssignment.PropIndexExpr serialise
TFieldAssignment.PropOwnerType safe
TFieldAssignment.IsElemWrite safe
# TStaticSubscriptAssign (uAST.pas:383)
# TStaticSubscriptAssign (uAST.pas:397)
TStaticSubscriptAssign.ArrayName serialise
TStaticSubscriptAssign.IndexExpr serialise
TStaticSubscriptAssign.ValueExpr serialise
@ -189,18 +193,18 @@ TStaticSubscriptAssign.IsGlobal safe
TStaticSubscriptAssign.IsVarParam safe
TStaticSubscriptAssign.IsImplicitSelf safe
# TPointerWriteStmt (uAST.pas:406)
# TPointerWriteStmt (uAST.pas:420)
TPointerWriteStmt.PtrExpr serialise
TPointerWriteStmt.ValExpr serialise
# TProcCall (uAST.pas:414)
# TProcCall (uAST.pas:428)
TProcCall.Name serialise
TProcCall.Args serialise
TProcCall.IsImplicitSelfMethod safe
TProcCall.IsIndirectCall safe
TProcCall.IndirectCallIsGlobal safe
# TFuncCallExpr (uAST.pas:427)
# TFuncCallExpr (uAST.pas:441)
TFuncCallExpr.Name serialise
TFuncCallExpr.Args serialise
TFuncCallExpr.IsImplicitSelfMethod safe
@ -210,18 +214,18 @@ TFuncCallExpr.IsBuiltinHasClassAttr safe
TFuncCallExpr.HasClassAttrClass safe
TFuncCallExpr.HasClassAttrAttr safe
# TIndirectFuncCallExpr (uAST.pas:453)
# TIndirectFuncCallExpr (uAST.pas:467)
TIndirectFuncCallExpr.CalleeExpr serialise
TIndirectFuncCallExpr.Args serialise
# TDerefExpr (uAST.pas:463)
# TDerefExpr (uAST.pas:477)
TDerefExpr.Expr serialise
# TAddrOfExpr (uAST.pas:470)
# TAddrOfExpr (uAST.pas:484)
TAddrOfExpr.Expr serialise
TAddrOfExpr.ResolvedFreeRoutine safe
# TMethodCallStmt (uAST.pas:482)
# TMethodCallStmt (uAST.pas:496)
TMethodCallStmt.ObjectName serialise
TMethodCallStmt.Name serialise
TMethodCallStmt.Args serialise
@ -232,11 +236,11 @@ TMethodCallStmt.IsVarParam safe
TMethodCallStmt.IsBuiltinToString safe
TMethodCallStmt.IsProcFieldCall safe
# TInheritedCallStmt (uAST.pas:514)
# TInheritedCallStmt (uAST.pas:528)
TInheritedCallStmt.Name serialise
TInheritedCallStmt.Args serialise
# TMethodCallExpr (uAST.pas:789)
# TMethodCallExpr (uAST.pas:803)
TMethodCallExpr.ObjectName serialise
TMethodCallExpr.Name serialise
TMethodCallExpr.Args serialise