Rename Collections.pas to Generics.Collections.pas; support dotted uses names

Parser: extend UsesClause to accept dotted unit names (IDENT { DOT IDENT }),
so 'uses Generics.Collections;' parses correctly. The dot-separated
segments are joined into a single string in UsedUnits (e.g. 'Generics.Collections').

RTL: rename Collections.pas → Generics.Collections.pas and update the
unit header to 'unit Generics.Collections' to match FPC's naming and
mirror Delphi's System.Generics.Collections for source-level compatibility.

Grammar: add UnitName rule documenting the dotted-name syntax and its
path-separator semantics.

Tests: 1 new parser test (TestProgramWithDottedUnitName); 569 total, 0 failures.
This commit is contained in:
Graeme Geldenhuys 2026-04-22 08:57:47 +01:00
parent 6c3de2b39a
commit f05982f8c5
4 changed files with 51 additions and 5 deletions

View file

@ -206,21 +206,43 @@ begin
end;
procedure TParser.ParseUses(AProg: TProgram);
var
UName: string;
begin
Expect(tkUses);
if not Check(tkIdent) then
raise EParseError.CreateFmt('Expected unit name after ''uses'' at line %d col %d',
[FCurrent.Line, FCurrent.Col]);
AProg.UsedUnits.Add(FCurrent.Value);
UName := FCurrent.Value;
Advance;
while Check(tkDot) do
begin
Advance;
if not Check(tkIdent) then
raise EParseError.CreateFmt('Expected identifier after ''.'' in unit name at line %d col %d',
[FCurrent.Line, FCurrent.Col]);
UName := UName + '.' + FCurrent.Value;
Advance;
end;
AProg.UsedUnits.Add(UName);
while Check(tkComma) do
begin
Advance;
if not Check(tkIdent) then
raise EParseError.CreateFmt('Expected unit name after '','' at line %d col %d',
[FCurrent.Line, FCurrent.Col]);
AProg.UsedUnits.Add(FCurrent.Value);
UName := FCurrent.Value;
Advance;
while Check(tkDot) do
begin
Advance;
if not Check(tkIdent) then
raise EParseError.CreateFmt('Expected identifier after ''.'' in unit name at line %d col %d',
[FCurrent.Line, FCurrent.Col]);
UName := UName + '.' + FCurrent.Value;
Advance;
end;
AProg.UsedUnits.Add(UName);
end;
Expect(tkSemicolon);
end;

View file

@ -18,6 +18,7 @@ type
procedure TestProgramName;
procedure TestProgramWithUses;
procedure TestProgramWithMultipleUses;
procedure TestProgramWithDottedUnitName;
{ Var block }
procedure TestSingleVarDecl;
@ -119,6 +120,20 @@ begin
end;
end;
procedure TParserTests.TestProgramWithDottedUnitName;
var
Prog: TProgram;
begin
Prog := ParseSource('program P; uses Generics.Collections, SysUtils; begin end.');
try
AssertEquals('Uses count', 2, Prog.UsedUnits.Count);
AssertEquals('Dotted unit name', 'Generics.Collections', Prog.UsedUnits[0]);
AssertEquals('Plain unit name', 'SysUtils', Prog.UsedUnits[1]);
finally
Prog.Free;
end;
end;
{ Var block }
procedure TParserTests.TestSingleVarDecl;

View file

@ -128,9 +128,17 @@ ImplementationSection
;
UsesClause
= USES IDENT { COMMA IDENT } SEMICOLON
= USES UnitName { COMMA UnitName } SEMICOLON
;
UnitName
= IDENT { DOT IDENT }
;
(* Dotted unit names map to path-separated files: Generics.Collections →
* Generics/Collections.pas. The dot is part of the name, not a field
* access operator; it is only valid in the UsesClause position. *)
(* ═══════════════════════════════════════════════════════════════════════════
* BLOCK

View file

@ -1,6 +1,7 @@
unit Collections;
unit Generics.Collections;
// Blaise RTL — generic collections.
// Blaise RTL — generic collections (mirrors Delphi's System.Generics.Collections
// and FPC's Generics.Collections for source-level compatibility).
//
// NOTE: This file is compiled by the Blaise compiler, not FPC.
// It uses Blaise syntax and semantics.