Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Parsing errors on attributes preceding visibility sections.
- Parsing errors on attributes preceding `var` sections in type bodies.
- Parsing errors on anonymous enum and subrange types in record variant tags.
- Parsing errors on anonymous array, set and procedural types in generic arguments.
- Errors when parsing coverage reports if duplicate file names were present in the project.

## [1.21.0] - 2026-09-04
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -722,8 +722,12 @@ recordType : RECORD<RecordTypeNodeImpl>^ visibilitySection* re
;
recordVariantSection : CASE<RecordVariantSectionNodeImpl>^ recordVariantTag OF recordVariant+
;
recordVariantTag : (nameDeclaration ':')? typeReference
-> ^(TkRecordVariantTag<RecordVariantTagNodeImpl> nameDeclaration? typeReference)
recordVariantTag : (nameDeclaration ':')? recordVariantTagType
-> ^(TkRecordVariantTag<RecordVariantTagNodeImpl> nameDeclaration? recordVariantTagType)
;
recordVariantTagType : enumType
| subRangeType
| typeReference
;
recordVariant : expressionList ':' '(' fieldDecl* recordVariantSection? ')' ';'?
-> ^(TkRecordVariantItem<RecordVariantItemNodeImpl> expressionList fieldDecl* recordVariantSection? ';'?)
Expand Down Expand Up @@ -787,8 +791,13 @@ genericConstraint : typeReference -> ^(TkTypeConstraint<TypeConstrain
| INTERFACE<InterfaceConstraintNodeImpl>^
| UNMANAGED<UnmanagedConstraintNodeImpl>^
;
genericArguments : '<' typeReferenceOrStringOrFile (',' typeReferenceOrStringOrFile)* '>'
-> ^(TkGenericArguments<GenericArgumentsNodeImpl> '<' typeReferenceOrStringOrFile (',' typeReferenceOrStringOrFile)* '>')
genericArguments : '<' genericArgument (',' genericArgument)* '>'
-> ^(TkGenericArguments<GenericArgumentsNodeImpl> '<' genericArgument (',' genericArgument)* '>')
;
genericArgument : arrayType
| setType
| procedureType
| typeReferenceOrStringOrFile
;
routineNameGenericArguments : '<' typeReferenceOrStringOrFile (commaOrSemicolon typeReferenceOrStringOrFile)* '>'
-> ^(TkGenericArguments<GenericArgumentsNodeImpl> '<' typeReferenceOrStringOrFile (commaOrSemicolon typeReferenceOrStringOrFile)* '>')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ void testSemicolonSeparatedGenericArguments() {
assertParsed("SemicolonSeparatedGenericArguments.pas");
}

@Test
void testAnonymousTypeGenericArguments() {
assertParsed("AnonymousTypeGenericArguments.pas");
}

@Test
void testGreaterThanEqualAmbiguity() {
assertParsed("GreaterThanEqualAmbiguity.pas");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ void testRecordVariants() {
verifyUsages(24, 10, reference(35, 2));
}

@Test
void testRecordVariantAnonymousTagType() {
execute("RecordVariantAnonymousTagType.pas");
verifyUsages(7, 9, reference(18, 6));
verifyUsages(7, 16, reference(8, 6));
verifyUsages(7, 23, reference(9, 6), reference(18, 14));
}

@Test
void testAnonymousArrayGenericArgument() {
execute("AnonymousArrayGenericArgument.pas");
verifyUsages(6, 2, reference(12, 23));
verifyUsages(7, 2, reference(12, 34));
}

@Test
void testInheritedInvocations() {
execute("InheritedInvocations.pas");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
unit AnonymousTypeGenericArguments;

interface

type
TFoo = class
StaticArrays: TArray<array[Boolean] of Double>;
DynamicArrays: TArray<array of Integer>;
Sets: TArray<set of Byte>;
Procedures: TArray<procedure>;
Functions: TArray<function(Value: Integer): Integer>;
Methods: TArray<procedure of object>;
References: TArray<reference to procedure>;
Mixed: TDictionary<string, array[0..2] of Double>;
end;

implementation

end.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ VariantRecordWithMethods = record
1: (High, Low: Longint);
end;

VariantRecordWithAnonymousEnumTag = record
case Tag: (vtWord, vtLongint) of
vtWord: (Data: array[0..3] of Word);
vtLongint: (High, Low: Longint);
end;

VariantRecordWithSubRangeTag = record
case Tag: 0..1 of
0: (Data: array[0..3] of Word);
1: (High, Low: Longint);
end;


implementation

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
unit AnonymousArrayGenericArgument;

interface

type
TIndex = (iFirst, iSecond);
TElement = Double;
TBox<T> = class
end;

TFoo = class
Values: TBox<array[TIndex] of TElement>;
end;

implementation

end.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
unit RecordVariantAnonymousTagType;

interface

type
TRecord = record
case Kind: (rkInt, rkDbl) of
rkInt: (Int: Integer);
rkDbl: (Dbl: Double);
end;

implementation

procedure Test;
var
Rec: TRecord;
begin
Rec.Kind := rkDbl;
end;

end.
Loading