mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 09:49:35 +02:00
fcl-passrc: fixed parsing objfpc inline specialize
git-svn-id: trunk@42251 -
This commit is contained in:
parent
6c1593652b
commit
fb29815fbf
@ -1525,6 +1525,7 @@ type
|
|||||||
procedure FinishClassOfType(El: TPasClassOfType); virtual;
|
procedure FinishClassOfType(El: TPasClassOfType); virtual;
|
||||||
procedure FinishPointerType(El: TPasPointerType); virtual;
|
procedure FinishPointerType(El: TPasPointerType); virtual;
|
||||||
procedure FinishArrayType(El: TPasArrayType); virtual;
|
procedure FinishArrayType(El: TPasArrayType); virtual;
|
||||||
|
procedure FinishGenericTemplateType(El: TPasGenericTemplateType); virtual;
|
||||||
procedure FinishResourcestring(El: TPasResString); virtual;
|
procedure FinishResourcestring(El: TPasResString); virtual;
|
||||||
procedure FinishProcedure(aProc: TPasProcedure); virtual;
|
procedure FinishProcedure(aProc: TPasProcedure); virtual;
|
||||||
procedure FinishProcedureType(El: TPasProcedureType); virtual;
|
procedure FinishProcedureType(El: TPasProcedureType); virtual;
|
||||||
@ -5397,7 +5398,9 @@ begin
|
|||||||
EmitTypeHints(El,TPasAliasType(El).DestType);
|
EmitTypeHints(El,TPasAliasType(El).DestType);
|
||||||
end
|
end
|
||||||
else if (C=TPasPointerType) then
|
else if (C=TPasPointerType) then
|
||||||
EmitTypeHints(El,TPasPointerType(El).DestType);
|
EmitTypeHints(El,TPasPointerType(El).DestType)
|
||||||
|
else if C=TPasGenericTemplateType then
|
||||||
|
FinishGenericTemplateType(TPasGenericTemplateType(El));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPasResolver.FinishEnumType(El: TPasEnumType);
|
procedure TPasResolver.FinishEnumType(El: TPasEnumType);
|
||||||
@ -5801,6 +5804,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPasResolver.FinishGenericTemplateType(El: TPasGenericTemplateType);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Expr: TPasExpr;
|
||||||
|
Value: String;
|
||||||
|
begin
|
||||||
|
for i:=0 to length(El.Constraints)-1 do
|
||||||
|
begin
|
||||||
|
Expr:=El.Constraints[i];
|
||||||
|
if (Expr.ClassType=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent) then
|
||||||
|
begin
|
||||||
|
Value:=TPrimitiveExpr(Expr).Value;
|
||||||
|
if SameText(Value,'class') then
|
||||||
|
; // ToDo
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPasResolver.FinishResourcestring(El: TPasResString);
|
procedure TPasResolver.FinishResourcestring(El: TPasResString);
|
||||||
var
|
var
|
||||||
ResolvedEl: TPasResolverResult;
|
ResolvedEl: TPasResolverResult;
|
||||||
@ -15852,6 +15873,7 @@ begin
|
|||||||
// resolved when finished
|
// resolved when finished
|
||||||
else if AClass=TPasImplCommand then
|
else if AClass=TPasImplCommand then
|
||||||
else if AClass=TPasAttributes then
|
else if AClass=TPasAttributes then
|
||||||
|
else if AClass=TPasGenericTemplateType then
|
||||||
else if AClass=TPasUnresolvedUnitRef then
|
else if AClass=TPasUnresolvedUnitRef then
|
||||||
RaiseMsg(20171018121900,nCantFindUnitX,sCantFindUnitX,[AName],El)
|
RaiseMsg(20171018121900,nCantFindUnitX,sCantFindUnitX,[AName],El)
|
||||||
else
|
else
|
||||||
|
@ -58,6 +58,7 @@ resourcestring
|
|||||||
SPasTreeClassType = 'class';
|
SPasTreeClassType = 'class';
|
||||||
SPasTreeInterfaceType = 'interface';
|
SPasTreeInterfaceType = 'interface';
|
||||||
SPasTreeSpecializedType = 'specialized class type';
|
SPasTreeSpecializedType = 'specialized class type';
|
||||||
|
SPasTreeSpecializedExpr = 'specialize expr';
|
||||||
SPasClassHelperType = 'class helper type';
|
SPasClassHelperType = 'class helper type';
|
||||||
SPasRecordHelperType = 'record helper type';
|
SPasRecordHelperType = 'record helper type';
|
||||||
SPasTypeHelperType = 'type helper type';
|
SPasTypeHelperType = 'type helper type';
|
||||||
@ -564,28 +565,27 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function ElementTypeName: string; override;
|
function ElementTypeName: string; override;
|
||||||
function GetDeclaration(full: boolean) : string; override;
|
function GetDeclaration(full: boolean) : string; override;
|
||||||
|
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
|
||||||
|
const Arg: Pointer); override;
|
||||||
procedure AddParam(El: TPasElement);
|
procedure AddParam(El: TPasElement);
|
||||||
public
|
public
|
||||||
Params: TFPList; // list of TPasType or TPasExpr
|
Params: TFPList; // list of TPasType or TPasExpr
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TInlineTypeExpr - base class TInlineSpecializeExpr }
|
{ TInlineSpecializeExpr - A<B,C> }
|
||||||
|
|
||||||
TInlineTypeExpr = class(TPasExpr)
|
TInlineSpecializeExpr = class(TPasExpr)
|
||||||
public
|
public
|
||||||
|
constructor Create(const AName: string; AParent: TPasElement); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function ElementTypeName: string; override;
|
function ElementTypeName: string; override;
|
||||||
function GetDeclaration(full : Boolean): string; override;
|
function GetDeclaration(full : Boolean): string; override;
|
||||||
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
|
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
|
||||||
const Arg: Pointer); override;
|
const Arg: Pointer); override;
|
||||||
procedure ClearTypeReferences(aType: TPasElement); override;
|
procedure AddParam(El: TPasElement);
|
||||||
public
|
public
|
||||||
DestType: TPasType; // TPasSpecializeType
|
NameExpr: TPasExpr; // TPrimitiveExpr
|
||||||
end;
|
Params: TFPList; // list of TPasType or TPasExpr
|
||||||
|
|
||||||
{ TInlineSpecializeExpr - A<B,C> }
|
|
||||||
|
|
||||||
TInlineSpecializeExpr = class(TInlineTypeExpr)
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TPasRangeType }
|
{ TPasRangeType }
|
||||||
@ -731,9 +731,18 @@ type
|
|||||||
Function IsAdvancedRecord : Boolean;
|
Function IsAdvancedRecord : Boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TPasGenericTemplateType }
|
||||||
|
|
||||||
TPasGenericTemplateType = Class(TPasType)
|
TPasGenericTemplateType = Class(TPasType)
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
function GetDeclaration(full : boolean) : string; override;
|
||||||
|
procedure ForEachCall(const aMethodCall: TOnForEachPasElement;
|
||||||
|
const Arg: Pointer); override;
|
||||||
|
procedure AddConstraint(Expr: TPasExpr);
|
||||||
Public
|
Public
|
||||||
TypeConstraint : String;
|
TypeConstraint: String deprecated; // deprecated in fpc 3.3.1
|
||||||
|
Constraints: TPasExprArray;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TPasObjKind = (
|
TPasObjKind = (
|
||||||
@ -1753,6 +1762,54 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TPasGenericTemplateType }
|
||||||
|
|
||||||
|
destructor TPasGenericTemplateType.Destroy;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i:=0 to length(Constraints)-1 do
|
||||||
|
Constraints[i].Release;
|
||||||
|
Constraints:=nil;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPasGenericTemplateType.GetDeclaration(full: boolean): string;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result:=inherited GetDeclaration(full);
|
||||||
|
if length(Constraints)>0 then
|
||||||
|
begin
|
||||||
|
Result:=Result+': ';
|
||||||
|
for i:=0 to length(Constraints)-1 do
|
||||||
|
begin
|
||||||
|
if i>0 then
|
||||||
|
Result:=Result+',';
|
||||||
|
Result:=Result+Constraints[i].GetDeclaration(false);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPasGenericTemplateType.ForEachCall(
|
||||||
|
const aMethodCall: TOnForEachPasElement; const Arg: Pointer);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
inherited ForEachCall(aMethodCall, Arg);
|
||||||
|
for i:=0 to length(Constraints)-1 do
|
||||||
|
ForEachChildCall(aMethodCall,Arg,Constraints[i],false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPasGenericTemplateType.AddConstraint(Expr: TPasExpr);
|
||||||
|
var
|
||||||
|
l: Integer;
|
||||||
|
begin
|
||||||
|
l:=Length(Constraints);
|
||||||
|
SetLength(Constraints,l+1);
|
||||||
|
Constraints[l]:=Expr;
|
||||||
|
end;
|
||||||
|
|
||||||
{$IFDEF HasPTDumpStack}
|
{$IFDEF HasPTDumpStack}
|
||||||
procedure PTDumpStack;
|
procedure PTDumpStack;
|
||||||
begin
|
begin
|
||||||
@ -1831,34 +1888,61 @@ begin
|
|||||||
SemicolonAtEOL := true;
|
SemicolonAtEOL := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TInlineTypeExpr }
|
{ TInlineSpecializeExpr }
|
||||||
|
|
||||||
destructor TInlineTypeExpr.Destroy;
|
constructor TInlineSpecializeExpr.Create(const AName: string;
|
||||||
|
AParent: TPasElement);
|
||||||
begin
|
begin
|
||||||
ReleaseAndNil(TPasElement(DestType){$IFDEF CheckPasTreeRefCount},'TInlineTypeExpr.DestType'{$ENDIF});
|
if AName='' then ;
|
||||||
|
inherited Create(AParent, pekSpecialize, eopNone);
|
||||||
|
Params:=TFPList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TInlineSpecializeExpr.Destroy;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
ReleaseAndNil(TPasElement(NameExpr));
|
||||||
|
for i:=0 to Params.Count-1 do
|
||||||
|
TPasElement(Params[i]).Release{$IFDEF CheckPasTreeRefCount}('TInlineSpecializeExpr.Params'){$ENDIF};
|
||||||
|
FreeAndNil(Params);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TInlineTypeExpr.ElementTypeName: string;
|
function TInlineSpecializeExpr.ElementTypeName: string;
|
||||||
begin
|
begin
|
||||||
Result := DestType.ElementTypeName;
|
Result:=SPasTreeSpecializedExpr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TInlineTypeExpr.GetDeclaration(full: Boolean): string;
|
function TInlineSpecializeExpr.GetDeclaration(full: Boolean): string;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
Result:=DestType.GetDeclaration(full);
|
Result:='specialize ';
|
||||||
|
Result:=Result+NameExpr.GetDeclaration(full);
|
||||||
|
Result:=Result+'<';
|
||||||
|
for i:=0 to Params.Count-1 do
|
||||||
|
begin
|
||||||
|
if i>0 then
|
||||||
|
Result:=Result+',';
|
||||||
|
Result:=Result+TPasElement(Params[i]).GetDeclaration(false);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TInlineTypeExpr.ForEachCall(
|
procedure TInlineSpecializeExpr.ForEachCall(
|
||||||
const aMethodCall: TOnForEachPasElement; const Arg: Pointer);
|
const aMethodCall: TOnForEachPasElement; const Arg: Pointer);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
DestType.ForEachChildCall(aMethodCall,Arg,DestType,true);
|
inherited ForEachCall(aMethodCall, Arg);
|
||||||
|
ForEachChildCall(aMethodCall,Arg,NameExpr,false);
|
||||||
|
for i:=0 to Params.Count-1 do
|
||||||
|
ForEachChildCall(aMethodCall,Arg,TPasElement(Params[i]),true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TInlineTypeExpr.ClearTypeReferences(aType: TPasElement);
|
procedure TInlineSpecializeExpr.AddParam(El: TPasElement);
|
||||||
begin
|
begin
|
||||||
if DestType=aType then
|
Params.Add(El);
|
||||||
ReleaseAndNil(TPasElement(DestType){$IFDEF CheckPasTreeRefCount},'TInlineTypeExpr.DestType'{$ENDIF});
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TPasSpecializeType }
|
{ TPasSpecializeType }
|
||||||
@ -1903,6 +1987,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPasSpecializeType.ForEachCall(
|
||||||
|
const aMethodCall: TOnForEachPasElement; const Arg: Pointer);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
inherited ForEachCall(aMethodCall, Arg);
|
||||||
|
for i:=0 to Params.Count-1 do
|
||||||
|
ForEachChildCall(aMethodCall,Arg,TPasElement(Params[i]),true);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPasSpecializeType.AddParam(El: TPasElement);
|
procedure TPasSpecializeType.AddParam(El: TPasElement);
|
||||||
begin
|
begin
|
||||||
Params.Add(El);
|
Params.Add(El);
|
||||||
|
@ -72,7 +72,7 @@ const
|
|||||||
nParserNotAProcToken = 2026;
|
nParserNotAProcToken = 2026;
|
||||||
nRangeExpressionExpected = 2027;
|
nRangeExpressionExpected = 2027;
|
||||||
nParserExpectCase = 2028;
|
nParserExpectCase = 2028;
|
||||||
// free 2029;
|
nParserGenericFunctionNeedsGenericKeyword = 2029;
|
||||||
nLogStartImplementation = 2030;
|
nLogStartImplementation = 2030;
|
||||||
nLogStartInterface = 2031;
|
nLogStartInterface = 2031;
|
||||||
nParserNoConstructorAllowed = 2032;
|
nParserNoConstructorAllowed = 2032;
|
||||||
@ -132,7 +132,7 @@ resourcestring
|
|||||||
SParserNotAProcToken = 'Not a procedure or function token';
|
SParserNotAProcToken = 'Not a procedure or function token';
|
||||||
SRangeExpressionExpected = 'Range expression expected';
|
SRangeExpressionExpected = 'Range expression expected';
|
||||||
SParserExpectCase = 'Case label expression expected';
|
SParserExpectCase = 'Case label expression expected';
|
||||||
// free for 2029
|
SParserGenericFunctionNeedsGenericKeyword = 'Generic function needs keyword generic';
|
||||||
SLogStartImplementation = 'Start parsing implementation section.';
|
SLogStartImplementation = 'Start parsing implementation section.';
|
||||||
SLogStartInterface = 'Start parsing interface section';
|
SLogStartInterface = 'Start parsing interface section';
|
||||||
SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Records';
|
SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Records';
|
||||||
@ -319,7 +319,7 @@ type
|
|||||||
procedure ParseClassMembers(AType: TPasClassType);
|
procedure ParseClassMembers(AType: TPasClassType);
|
||||||
procedure ProcessMethod(AType: TPasClassType; IsClass : Boolean; AVisibility : TPasMemberVisibility);
|
procedure ProcessMethod(AType: TPasClassType; IsClass : Boolean; AVisibility : TPasMemberVisibility);
|
||||||
procedure ReadGenericArguments(List : TFPList;Parent : TPasElement);
|
procedure ReadGenericArguments(List : TFPList;Parent : TPasElement);
|
||||||
procedure ReadSpecializeArguments(Spec: TPasSpecializeType);
|
procedure ReadSpecializeArguments(Spec: TPasElement);
|
||||||
function ReadDottedIdentifier(Parent: TPasElement; out Expr: TPasExpr; NeedAsString: boolean): String;
|
function ReadDottedIdentifier(Parent: TPasElement; out Expr: TPasExpr; NeedAsString: boolean): String;
|
||||||
function CheckProcedureArgs(Parent: TPasElement;
|
function CheckProcedureArgs(Parent: TPasElement;
|
||||||
Args: TFPList; // list of TPasArgument
|
Args: TFPList; // list of TPasArgument
|
||||||
@ -1587,7 +1587,7 @@ begin
|
|||||||
Expr:=nil;
|
Expr:=nil;
|
||||||
ST:=nil;
|
ST:=nil;
|
||||||
try
|
try
|
||||||
if not (msDelphi in CurrentModeswitches) and (CurToken=tkspecialize) then
|
if CurToken=tkspecialize then
|
||||||
begin
|
begin
|
||||||
IsSpecialize:=true;
|
IsSpecialize:=true;
|
||||||
NextToken;
|
NextToken;
|
||||||
@ -1739,7 +1739,8 @@ begin
|
|||||||
Result := ParseClassDecl(Parent, NamePos, TypeName, okDispInterface);
|
Result := ParseClassDecl(Parent, NamePos, TypeName, okDispInterface);
|
||||||
tkInterface:
|
tkInterface:
|
||||||
Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
|
Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
|
||||||
tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName);
|
tkSpecialize:
|
||||||
|
Result:=ParseSpecializeType(Parent,TypeName);
|
||||||
tkClass:
|
tkClass:
|
||||||
begin
|
begin
|
||||||
isHelper:=false;
|
isHelper:=false;
|
||||||
@ -2165,6 +2166,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasParser.ParseExprOperand(AParent: TPasElement): TPasExpr;
|
function TPasParser.ParseExprOperand(AParent: TPasElement): TPasExpr;
|
||||||
|
type
|
||||||
|
TAllow = (aCannot, aCan, aMust);
|
||||||
|
|
||||||
Function IsWriteOrStr(P : TPasExpr) : boolean;
|
Function IsWriteOrStr(P : TPasExpr) : boolean;
|
||||||
|
|
||||||
@ -2235,17 +2238,17 @@ var
|
|||||||
Last, Func, Expr: TPasExpr;
|
Last, Func, Expr: TPasExpr;
|
||||||
Params: TParamsExpr;
|
Params: TParamsExpr;
|
||||||
Bin: TBinaryExpr;
|
Bin: TBinaryExpr;
|
||||||
ok, CanSpecialize: Boolean;
|
ok: Boolean;
|
||||||
|
CanSpecialize: TAllow;
|
||||||
aName: String;
|
aName: String;
|
||||||
ISE: TInlineSpecializeExpr;
|
ISE: TInlineSpecializeExpr;
|
||||||
ST: TPasSpecializeType;
|
|
||||||
SrcPos, ScrPos: TPasSourcePos;
|
SrcPos, ScrPos: TPasSourcePos;
|
||||||
ProcType: TProcType;
|
ProcType: TProcType;
|
||||||
ProcExpr: TProcedureExpr;
|
ProcExpr: TProcedureExpr;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
CanSpecialize:=false;
|
CanSpecialize:=aCannot;
|
||||||
aName:='';
|
aName:='';
|
||||||
case CurToken of
|
case CurToken of
|
||||||
tkString: Last:=CreatePrimitiveExpr(AParent,pekString,CurTokenString);
|
tkString: Last:=CreatePrimitiveExpr(AParent,pekString,CurTokenString);
|
||||||
@ -2253,13 +2256,20 @@ begin
|
|||||||
tkNumber: Last:=CreatePrimitiveExpr(AParent,pekNumber,CurTokenString);
|
tkNumber: Last:=CreatePrimitiveExpr(AParent,pekNumber,CurTokenString);
|
||||||
tkIdentifier:
|
tkIdentifier:
|
||||||
begin
|
begin
|
||||||
CanSpecialize:=true;
|
CanSpecialize:=aCan;
|
||||||
aName:=CurTokenText;
|
aName:=CurTokenText;
|
||||||
if (CompareText(aName,'self')=0) and not (tkself in Scanner.NonTokens) then
|
if (CompareText(aName,'self')=0) and not (tkself in Scanner.NonTokens) then
|
||||||
Last:=CreateSelfExpr(AParent)
|
Last:=CreateSelfExpr(AParent)
|
||||||
else
|
else
|
||||||
Last:=CreatePrimitiveExpr(AParent,pekIdent,aName);
|
Last:=CreatePrimitiveExpr(AParent,pekIdent,aName);
|
||||||
end;
|
end;
|
||||||
|
tkspecialize:
|
||||||
|
begin
|
||||||
|
CanSpecialize:=aMust;
|
||||||
|
ExpectToken(tkIdentifier);
|
||||||
|
aName:=CurTokenText;
|
||||||
|
Last:=CreatePrimitiveExpr(AParent,pekIdent,aName);
|
||||||
|
end;
|
||||||
tkfalse, tktrue: Last:=CreateBoolConstExpr(AParent,pekBoolConst, CurToken=tktrue);
|
tkfalse, tktrue: Last:=CreateBoolConstExpr(AParent,pekBoolConst, CurToken=tktrue);
|
||||||
tknil: Last:=CreateNilExpr(AParent);
|
tknil: Last:=CreateNilExpr(AParent);
|
||||||
tkSquaredBraceOpen:
|
tkSquaredBraceOpen:
|
||||||
@ -2288,7 +2298,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
tkself:
|
tkself:
|
||||||
begin
|
begin
|
||||||
CanSpecialize:=true;
|
CanSpecialize:=aCan;
|
||||||
aName:=CurTokenText;
|
aName:=CurTokenText;
|
||||||
Last:=CreateSelfExpr(AParent);
|
Last:=CreateSelfExpr(AParent);
|
||||||
end;
|
end;
|
||||||
@ -2350,6 +2360,13 @@ begin
|
|||||||
begin
|
begin
|
||||||
ScrPos:=CurTokenPos;
|
ScrPos:=CurTokenPos;
|
||||||
NextToken;
|
NextToken;
|
||||||
|
if CurToken=tkspecialize then
|
||||||
|
begin
|
||||||
|
if CanSpecialize=aMust then
|
||||||
|
CheckToken(tkLessThan);
|
||||||
|
CanSpecialize:=aMust;
|
||||||
|
NextToken;
|
||||||
|
end;
|
||||||
if CurToken in [tkIdentifier,tktrue,tkfalse,tkself] then // true and false are sub identifiers as well
|
if CurToken in [tkIdentifier,tktrue,tkfalse,tkself] then // true and false are sub identifiers as well
|
||||||
begin
|
begin
|
||||||
aName:=aName+'.'+CurTokenString;
|
aName:=aName+'.'+CurTokenString;
|
||||||
@ -2374,34 +2391,32 @@ begin
|
|||||||
Params.Value:=Result;
|
Params.Value:=Result;
|
||||||
Result.Parent:=Params;
|
Result.Parent:=Params;
|
||||||
Result:=Params;
|
Result:=Params;
|
||||||
CanSpecialize:=false;
|
CanSpecialize:=aCannot;
|
||||||
Func:=nil;
|
Func:=nil;
|
||||||
end;
|
end;
|
||||||
tkCaret:
|
tkCaret:
|
||||||
begin
|
begin
|
||||||
Result:=CreateUnaryExpr(AParent,Result,TokenToExprOp(CurToken));
|
Result:=CreateUnaryExpr(AParent,Result,TokenToExprOp(CurToken));
|
||||||
NextToken;
|
NextToken;
|
||||||
CanSpecialize:=false;
|
CanSpecialize:=aCannot;
|
||||||
Func:=nil;
|
Func:=nil;
|
||||||
end;
|
end;
|
||||||
tkLessThan:
|
tkLessThan:
|
||||||
begin
|
begin
|
||||||
SrcPos:=CurTokenPos;
|
SrcPos:=CurTokenPos;
|
||||||
if (not CanSpecialize) or not IsSpecialize then
|
if CanSpecialize=aCannot then
|
||||||
|
break
|
||||||
|
else if (CanSpecialize=aCan) and not IsSpecialize then
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// an inline specialization (e.g. A<B,C>)
|
// an inline specialization (e.g. A<B,C>)
|
||||||
ISE:=TInlineSpecializeExpr(CreateElement(TInlineSpecializeExpr,'',AParent,SrcPos));
|
ISE:=TInlineSpecializeExpr(CreateElement(TInlineSpecializeExpr,'',AParent,SrcPos));
|
||||||
ISE.Kind:=pekSpecialize;
|
ReadSpecializeArguments(ISE);
|
||||||
ST:=TPasSpecializeType(CreateElement(TPasSpecializeType,'',ISE,SrcPos));
|
ISE.NameExpr:=Result;
|
||||||
ISE.DestType:=ST;
|
|
||||||
ReadSpecializeArguments(ST);
|
|
||||||
ST.DestType:=ResolveTypeReference(aName,ST);
|
|
||||||
ST.Expr:=Result;
|
|
||||||
Result:=ISE;
|
Result:=ISE;
|
||||||
ISE:=nil;
|
ISE:=nil;
|
||||||
CanSpecialize:=false;
|
CanSpecialize:=aCannot;
|
||||||
NextToken;
|
NextToken;
|
||||||
end;
|
end;
|
||||||
Func:=nil;
|
Func:=nil;
|
||||||
@ -3585,6 +3600,9 @@ begin
|
|||||||
Declarations.Declarations.Add(ArrEl);
|
Declarations.Declarations.Add(ArrEl);
|
||||||
Declarations.Types.Add(ArrEl);
|
Declarations.Types.Add(ArrEl);
|
||||||
CheckHint(ArrEl,True);
|
CheckHint(ArrEl,True);
|
||||||
|
{$IFDEF VerbosePasResolver}
|
||||||
|
ParseExcTokenError('20190619145000');
|
||||||
|
{$ENDIF}
|
||||||
ArrEl.ElType.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
|
ArrEl.ElType.Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
|
||||||
ArrEl.ElType:=TPasGenericTemplateType(List[0]);
|
ArrEl.ElType:=TPasGenericTemplateType(List[0]);
|
||||||
List.Clear;
|
List.Clear;
|
||||||
@ -4008,12 +4026,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$warn 5043 off}
|
||||||
procedure TPasParser.ReadGenericArguments(List: TFPList; Parent: TPasElement);
|
procedure TPasParser.ReadGenericArguments(List: TFPList; Parent: TPasElement);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
N : String;
|
N : String;
|
||||||
T : TPasGenericTemplateType;
|
T : TPasGenericTemplateType;
|
||||||
|
Expr: TPasExpr;
|
||||||
begin
|
begin
|
||||||
ExpectToken(tkLessThan);
|
ExpectToken(tkLessThan);
|
||||||
repeat
|
repeat
|
||||||
@ -4022,17 +4040,46 @@ begin
|
|||||||
List.Add(T);
|
List.Add(T);
|
||||||
NextToken;
|
NextToken;
|
||||||
if Curtoken = tkColon then
|
if Curtoken = tkColon then
|
||||||
begin
|
repeat
|
||||||
T.TypeConstraint:=ExpectIdentifier;
|
NextToken;
|
||||||
NextToken;
|
// comma separated list: identifier, class, record, constructor
|
||||||
end;
|
if CurToken in [tkclass,tkrecord,tkconstructor] then
|
||||||
if not (CurToken in [tkComma,tkSemicolon,tkGreaterThan]) then
|
begin
|
||||||
ParseExc(nParserExpectToken2Error,SParserExpectToken2Error,
|
if T.TypeConstraint='' then
|
||||||
[TokenInfos[tkComma], TokenInfos[tkGreaterThan]]);
|
T.TypeConstraint:=CurTokenString;
|
||||||
until CurToken = tkGreaterThan;
|
Expr:=CreatePrimitiveExpr(T,pekIdent,CurTokenText);
|
||||||
|
NextToken;
|
||||||
|
end
|
||||||
|
else if CurToken=tkIdentifier then
|
||||||
|
begin
|
||||||
|
if T.TypeConstraint='' then
|
||||||
|
T.TypeConstraint:=ReadDottedIdentifier(T,Expr,true)
|
||||||
|
else
|
||||||
|
ReadDottedIdentifier(T,Expr,false);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
CheckToken(tkIdentifier);
|
||||||
|
T.AddConstraint(Expr);
|
||||||
|
until CurToken<>tkComma;
|
||||||
|
Engine.FinishScope(stTypeDef,T);
|
||||||
|
until not (CurToken in [tkSemicolon,tkComma]);
|
||||||
|
if CurToken<>tkGreaterThan then
|
||||||
|
ParseExc(nParserExpectToken2Error,SParserExpectToken2Error,
|
||||||
|
[TokenInfos[tkComma], TokenInfos[tkGreaterThan]]);
|
||||||
end;
|
end;
|
||||||
|
{$warn 5043 on}
|
||||||
|
|
||||||
procedure TPasParser.ReadSpecializeArguments(Spec: TPasSpecializeType);
|
procedure TPasParser.ReadSpecializeArguments(Spec: TPasElement);
|
||||||
|
|
||||||
|
procedure AddParam(El: TPasElement);
|
||||||
|
begin
|
||||||
|
if Spec is TPasSpecializeType then
|
||||||
|
TPasSpecializeType(Spec).AddParam(El)
|
||||||
|
else if Spec is TInlineSpecializeExpr then
|
||||||
|
TInlineSpecializeExpr(Spec).AddParam(El)
|
||||||
|
else
|
||||||
|
ParseExcTokenError('[20190619112611] '+Spec.ClassName);
|
||||||
|
end;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
Name : String;
|
Name : String;
|
||||||
@ -4042,6 +4089,7 @@ Var
|
|||||||
Expr: TPasExpr;
|
Expr: TPasExpr;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
//writeln('START TPasParser.ReadSpecializeArguments ',CurTokenText,' ',CurTokenString);
|
||||||
CheckToken(tkLessThan);
|
CheckToken(tkLessThan);
|
||||||
NextToken;
|
NextToken;
|
||||||
Expr:=nil;
|
Expr:=nil;
|
||||||
@ -4049,7 +4097,8 @@ begin
|
|||||||
NestedSpec:=nil;
|
NestedSpec:=nil;
|
||||||
try
|
try
|
||||||
repeat
|
repeat
|
||||||
if not (msDelphi in CurrentModeswitches) and (CurToken=tkspecialize) then
|
//writeln('ARG TPasParser.ReadSpecializeArguments ',CurTokenText,' ',CurTokenString);
|
||||||
|
if CurToken=tkspecialize then
|
||||||
begin
|
begin
|
||||||
IsNested:=true;
|
IsNested:=true;
|
||||||
NextToken;
|
NextToken;
|
||||||
@ -4060,6 +4109,7 @@ begin
|
|||||||
CheckToken(tkIdentifier);
|
CheckToken(tkIdentifier);
|
||||||
Expr:=nil;
|
Expr:=nil;
|
||||||
Name:=ReadDottedIdentifier(Spec,Expr,true);
|
Name:=ReadDottedIdentifier(Spec,Expr,true);
|
||||||
|
//writeln('AFTER NAME TPasParser.ReadSpecializeArguments ',CurTokenText,' ',CurTokenString);
|
||||||
|
|
||||||
if CurToken=tkLessThan then
|
if CurToken=tkLessThan then
|
||||||
begin
|
begin
|
||||||
@ -4075,18 +4125,19 @@ begin
|
|||||||
// read nested specialize arguments
|
// read nested specialize arguments
|
||||||
ReadSpecializeArguments(NestedSpec);
|
ReadSpecializeArguments(NestedSpec);
|
||||||
// add nested specialize
|
// add nested specialize
|
||||||
Spec.AddParam(NestedSpec);
|
AddParam(NestedSpec);
|
||||||
NestedSpec:=nil;
|
NestedSpec:=nil;
|
||||||
NextToken;
|
NextToken;
|
||||||
end
|
end
|
||||||
else if IsNested then
|
else if IsNested then
|
||||||
CheckToken(tkLessThan)
|
CheckToken(tkLessThan) // specialize keyword without <
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// simple type reference
|
// simple type reference
|
||||||
Spec.AddParam(Expr);
|
AddParam(Expr);
|
||||||
Expr:=nil;
|
Expr:=nil;
|
||||||
end;
|
end;
|
||||||
|
//writeln('AFTER PARAMS TPasParser.ReadSpecializeArguments ',CurTokenText,' ',CurTokenString);
|
||||||
|
|
||||||
if CurToken=tkComma then
|
if CurToken=tkComma then
|
||||||
begin
|
begin
|
||||||
@ -6043,7 +6094,8 @@ begin
|
|||||||
tkEOF:
|
tkEOF:
|
||||||
CheckToken(tkend);
|
CheckToken(tkend);
|
||||||
tkAt,tkAtAt,
|
tkAt,tkAtAt,
|
||||||
tkIdentifier,tkNumber,tkString,tkfalse,tktrue,tkChar,
|
tkIdentifier,tkspecialize,
|
||||||
|
tkNumber,tkString,tkfalse,tktrue,tkChar,
|
||||||
tkBraceOpen,tkSquaredBraceOpen,
|
tkBraceOpen,tkSquaredBraceOpen,
|
||||||
tkMinus,tkPlus,tkinherited:
|
tkMinus,tkPlus,tkinherited:
|
||||||
begin
|
begin
|
||||||
@ -6207,9 +6259,9 @@ function TPasParser.ParseProcedureOrFunctionDecl(Parent: TPasElement;
|
|||||||
if CurToken=tkDot then
|
if CurToken=tkDot then
|
||||||
Result:=Result+'.'+ExpectIdentifier
|
Result:=Result+'.'+ExpectIdentifier
|
||||||
else if CurToken=tkLessThan then
|
else if CurToken=tkLessThan then
|
||||||
begin // <> can be ignored, we read the list but discard its content
|
begin
|
||||||
if (not MustBeGeneric) and not (msDelphi in CurrentModeswitches) then
|
if (not MustBeGeneric) and not (msDelphi in CurrentModeswitches) then
|
||||||
ParseExcTokenError('('); // e.g. "generic" is missing in mode objfpc
|
ParseExc(nParserGenericFunctionNeedsGenericKeyword,SParserGenericFunctionNeedsGenericKeyword);
|
||||||
UnGetToken;
|
UnGetToken;
|
||||||
L:=TFPList.Create;
|
L:=TFPList.Create;
|
||||||
Try
|
Try
|
||||||
|
@ -3432,16 +3432,22 @@ begin
|
|||||||
'FPC','DEFAULT':
|
'FPC','DEFAULT':
|
||||||
SetMode(msFpc,FPCModeSwitches,false,bsFPCMode);
|
SetMode(msFpc,FPCModeSwitches,false,bsFPCMode);
|
||||||
'OBJFPC':
|
'OBJFPC':
|
||||||
|
begin
|
||||||
SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
|
SetMode(msObjfpc,OBJFPCModeSwitches,true,bsObjFPCMode);
|
||||||
|
UnsetNonToken(tkgeneric);
|
||||||
|
UnsetNonToken(tkspecialize);
|
||||||
|
end;
|
||||||
'DELPHI':
|
'DELPHI':
|
||||||
begin
|
begin
|
||||||
SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
|
SetMode(msDelphi,DelphiModeSwitches,true,bsDelphiMode,[bsPointerMath]);
|
||||||
SetNonToken(tkgeneric);
|
SetNonToken(tkgeneric);
|
||||||
|
SetNonToken(tkspecialize);
|
||||||
end;
|
end;
|
||||||
'DELPHIUNICODE':
|
'DELPHIUNICODE':
|
||||||
begin
|
begin
|
||||||
SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
|
SetMode(msDelphiUnicode,DelphiUnicodeModeSwitches,true,bsDelphiUnicodeMode,[bsPointerMath]);
|
||||||
SetNonToken(tkgeneric);
|
SetNonToken(tkgeneric);
|
||||||
|
SetNonToken(tkspecialize);
|
||||||
end;
|
end;
|
||||||
'TP':
|
'TP':
|
||||||
SetMode(msTP7,TPModeSwitches,false);
|
SetMode(msTP7,TPModeSwitches,false);
|
||||||
|
@ -17,6 +17,7 @@ Type
|
|||||||
Procedure TestRecordGenerics;
|
Procedure TestRecordGenerics;
|
||||||
Procedure TestArrayGenerics;
|
Procedure TestArrayGenerics;
|
||||||
Procedure TestGenericConstraint;
|
Procedure TestGenericConstraint;
|
||||||
|
Procedure TestGenericInterfaceConstraint; // ToDo
|
||||||
Procedure TestDeclarationConstraint;
|
Procedure TestDeclarationConstraint;
|
||||||
Procedure TestSpecializationDelphi;
|
Procedure TestSpecializationDelphi;
|
||||||
Procedure TestDeclarationDelphi;
|
Procedure TestDeclarationDelphi;
|
||||||
@ -26,7 +27,8 @@ Type
|
|||||||
Procedure TestInlineSpecializationInArgument;
|
Procedure TestInlineSpecializationInArgument;
|
||||||
Procedure TestSpecializeNested;
|
Procedure TestSpecializeNested;
|
||||||
Procedure TestInlineSpecializeInStatement;
|
Procedure TestInlineSpecializeInStatement;
|
||||||
Procedure TestGenericFunction; // ToDo
|
Procedure TestInlineSpecializeInStatementDelphi;
|
||||||
|
Procedure TestGenericFunction;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -69,6 +71,32 @@ begin
|
|||||||
'Generic TSomeClass<T: TObject> = class',
|
'Generic TSomeClass<T: TObject> = class',
|
||||||
' b : T;',
|
' b : T;',
|
||||||
'end;',
|
'end;',
|
||||||
|
'Generic TBird<T: class> = class',
|
||||||
|
' c : TBird<T>;',
|
||||||
|
'end;',
|
||||||
|
'Generic TEagle<T: record> = class',
|
||||||
|
'end;',
|
||||||
|
'Generic TEagle<T: constructor> = class',
|
||||||
|
'end;',
|
||||||
|
'']);
|
||||||
|
ParseDeclarations;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestGenerics.TestGenericInterfaceConstraint;
|
||||||
|
begin
|
||||||
|
Add([
|
||||||
|
'Type',
|
||||||
|
'TIntfA = interface end;',
|
||||||
|
'TIntfB = interface end;',
|
||||||
|
'TBird = class(TInterfacedObject,TIntfA,TIntfB) end;',
|
||||||
|
'Generic TAnt<T: TIntfA, TIntfB> = class',
|
||||||
|
' b: T;',
|
||||||
|
' c: TAnt<T>;',
|
||||||
|
'end;',
|
||||||
|
'Generic TFly<T: TIntfA, TIntfB; S> = class',
|
||||||
|
' b: S;',
|
||||||
|
' c: TFly<T>;',
|
||||||
|
'end;',
|
||||||
'']);
|
'']);
|
||||||
ParseDeclarations;
|
ParseDeclarations;
|
||||||
end;
|
end;
|
||||||
@ -80,8 +108,8 @@ begin
|
|||||||
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
||||||
Source.Add('Type');
|
Source.Add('Type');
|
||||||
Source.Add(' TSomeClass<T: T2> = Class(TObject)');
|
Source.Add(' TSomeClass<T: T2> = Class(TObject)');
|
||||||
Source.Add(' b : T;');
|
Source.Add(' b : T;');
|
||||||
Source.Add('end;');
|
Source.Add(' end;');
|
||||||
ParseDeclarations;
|
ParseDeclarations;
|
||||||
AssertNotNull('have generic definition',Declarations.Classes);
|
AssertNotNull('have generic definition',Declarations.Classes);
|
||||||
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
||||||
@ -105,9 +133,9 @@ begin
|
|||||||
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
||||||
Source.Add('Type');
|
Source.Add('Type');
|
||||||
Source.Add(' TSomeClass<T,T2> = Class(TObject)');
|
Source.Add(' TSomeClass<T,T2> = Class(TObject)');
|
||||||
Source.Add(' b : T;');
|
Source.Add(' b : T;');
|
||||||
Source.Add(' b2 : T2;');
|
Source.Add(' b2 : T2;');
|
||||||
Source.Add('end;');
|
Source.Add(' end;');
|
||||||
ParseDeclarations;
|
ParseDeclarations;
|
||||||
AssertNotNull('have generic definition',Declarations.Classes);
|
AssertNotNull('have generic definition',Declarations.Classes);
|
||||||
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
||||||
@ -126,9 +154,9 @@ begin
|
|||||||
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches ;
|
||||||
Source.Add('Type');
|
Source.Add('Type');
|
||||||
Source.Add(' TSomeClass<T,T2> = Class(TSomeGeneric<Integer,Integer>)');
|
Source.Add(' TSomeClass<T,T2> = Class(TSomeGeneric<Integer,Integer>)');
|
||||||
Source.Add(' b : T;');
|
Source.Add(' b : T;');
|
||||||
Source.Add(' b2 : T2;');
|
Source.Add(' b2 : T2;');
|
||||||
Source.Add('end;');
|
Source.Add(' end;');
|
||||||
ParseDeclarations;
|
ParseDeclarations;
|
||||||
AssertNotNull('have generic definition',Declarations.Classes);
|
AssertNotNull('have generic definition',Declarations.Classes);
|
||||||
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
||||||
@ -148,9 +176,9 @@ begin
|
|||||||
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches;
|
Scanner.CurrentModeSwitches:=[msDelphi]+Scanner.CurrentModeSwitches;
|
||||||
Source.Add('Type');
|
Source.Add('Type');
|
||||||
Source.Add(' TSomeClass<T;T2> = Class(TObject)');
|
Source.Add(' TSomeClass<T;T2> = Class(TObject)');
|
||||||
Source.Add(' b : T;');
|
Source.Add(' b : T;');
|
||||||
Source.Add(' b2 : T2;');
|
Source.Add(' b2 : T2;');
|
||||||
Source.Add('end;');
|
Source.Add(' end;');
|
||||||
ParseDeclarations;
|
ParseDeclarations;
|
||||||
AssertNotNull('have generic definition',Declarations.Classes);
|
AssertNotNull('have generic definition',Declarations.Classes);
|
||||||
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
AssertEquals('have generic definition',1,Declarations.Classes.Count);
|
||||||
@ -207,12 +235,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTestGenerics.TestInlineSpecializeInStatement;
|
procedure TTestGenerics.TestInlineSpecializeInStatement;
|
||||||
|
begin
|
||||||
|
Add([
|
||||||
|
'begin',
|
||||||
|
' t:=specialize a<b>;',
|
||||||
|
' t:=a.specialize b<c>;',
|
||||||
|
'']);
|
||||||
|
ParseModule;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestGenerics.TestInlineSpecializeInStatementDelphi;
|
||||||
begin
|
begin
|
||||||
Add([
|
Add([
|
||||||
'begin',
|
'begin',
|
||||||
' vec:=TVector<double>.create;',
|
' vec:=TVector<double>.create;',
|
||||||
' b:=a<b;',
|
' b:=a<b;',
|
||||||
' t:=a<b.c<d,e.f>>;',
|
' t:=a<b.c<d,e.f>>;',
|
||||||
|
' t:=a.b<c>;',
|
||||||
|
' t:=a<b>.c;',
|
||||||
|
// forbidden:' t:=a<b<c>.d>;',
|
||||||
'']);
|
'']);
|
||||||
ParseModule;
|
ParseModule;
|
||||||
end;
|
end;
|
||||||
@ -224,7 +265,7 @@ begin
|
|||||||
'begin',
|
'begin',
|
||||||
'end;',
|
'end;',
|
||||||
'begin',
|
'begin',
|
||||||
//' specialize IfThen<word>(true,2,3);',
|
' specialize IfThen<word>(true,2,3);',
|
||||||
'']);
|
'']);
|
||||||
ParseModule;
|
ParseModule;
|
||||||
end;
|
end;
|
||||||
|
@ -7,7 +7,7 @@ uses
|
|||||||
Classes, consoletestrunner, tcscanner, tctypeparser, tcstatements,
|
Classes, consoletestrunner, tcscanner, tctypeparser, tcstatements,
|
||||||
tcbaseparser, tcmoduleparser, tconstparser, tcvarparser, tcclasstype,
|
tcbaseparser, tcmoduleparser, tconstparser, tcvarparser, tcclasstype,
|
||||||
tcexprparser, tcprocfunc, tcpassrcutil, tcresolver, tcgenerics,
|
tcexprparser, tcprocfunc, tcpassrcutil, tcresolver, tcgenerics,
|
||||||
tcuseanalyzer, pasresolveeval;
|
tcuseanalyzer, pasresolveeval, tcresolvegenerics;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user