fcl-passrc: parse delphi generic arrays

git-svn-id: trunk@42529 -
This commit is contained in:
Mattias Gaertner 2019-07-29 14:19:50 +00:00
parent 92f085fdd9
commit a84eae8c2e
4 changed files with 205 additions and 121 deletions

View File

@ -2080,6 +2080,7 @@ type
function IsArrayExpr(Expr: TParamsExpr): TPasArrayType; function IsArrayExpr(Expr: TParamsExpr): TPasArrayType;
function IsArrayOperatorAdd(Expr: TPasExpr): boolean; function IsArrayOperatorAdd(Expr: TPasExpr): boolean;
function IsTypeCast(Params: TParamsExpr): boolean; function IsTypeCast(Params: TParamsExpr): boolean;
function GetTypeParameterCount(aType: TPasGenericType): integer;
function IsInterfaceType(const ResolvedEl: TPasResolverResult; function IsInterfaceType(const ResolvedEl: TPasResolverResult;
IntfType: TPasClassInterfaceType): boolean; overload; IntfType: TPasClassInterfaceType): boolean; overload;
function IsInterfaceType(TypeEl: TPasType; IntfType: TPasClassInterfaceType): boolean; overload; function IsInterfaceType(TypeEl: TPasType; IntfType: TPasClassInterfaceType): boolean; overload;
@ -7729,10 +7730,13 @@ begin
for i:=0 to Members.Count-1 do for i:=0 to Members.Count-1 do
begin begin
Decl:=TPasElement(Members[i]); Decl:=TPasElement(Members[i]);
if (CompareText(Decl.Name,aClass.Name)=0) if (CompareText(Decl.Name,aClass.Name)<>0)
and (Decl<>aClass) then or (Decl=aClass) then continue;
RaiseMsg(20180212144132,nDuplicateIdentifier,sDuplicateIdentifier, if (Decl is TPasGenericType)
[Decl.Name,GetElementSourcePosStr(Decl)],aClass); and (GetTypeParameterCount(TPasGenericType(Decl))<>GetTypeParameterCount(aClass)) then
continue;
RaiseMsg(20180212144132,nDuplicateIdentifier,sDuplicateIdentifier,
[Decl.Name,GetElementSourcePosStr(Decl)],aClass);
end; end;
exit; exit;
end; end;
@ -13971,7 +13975,8 @@ begin
begin begin
Item:=TPSSpecializedItem(SpecializedTypes[i]); Item:=TPSSpecializedItem(SpecializedTypes[i]);
j:=length(Item.Params)-1; j:=length(Item.Params)-1;
while (j>=0) and (Item.Params[j]=ParamsResolved[j]) do dec(j); while (j>=0) and IsSameType(Item.Params[j],ParamsResolved[j],prraNone) do
dec(j);
if j<0 then if j<0 then
break; break;
Item:=nil; Item:=nil;
@ -14162,6 +14167,12 @@ begin
Scope:=TPasGenericScope(PushScope(NewEl,TPasRecordScope)); Scope:=TPasGenericScope(PushScope(NewEl,TPasRecordScope));
Scope.VisibilityContext:=NewEl; Scope.VisibilityContext:=NewEl;
end end
else if NewEl is TPasClassType then
begin
//AddClassType();
//FinishAncestors();
RaiseNotYetImplemented(20190728134934,El);
end
else else
RaiseNotYetImplemented(20190728134933,El); RaiseNotYetImplemented(20190728134933,El);
Scope.SpecializedFrom:=GenericType; Scope.SpecializedFrom:=GenericType;
@ -23498,6 +23509,13 @@ begin
exit(true); exit(true);
end; end;
function TPasResolver.GetTypeParameterCount(aType: TPasGenericType): integer;
begin
if aType=nil then exit(0);
if aType.GenericTemplateTypes=nil then exit(0);
Result:=aType.GenericTemplateTypes.Count;
end;
function TPasResolver.IsInterfaceType(const ResolvedEl: TPasResolverResult; function TPasResolver.IsInterfaceType(const ResolvedEl: TPasResolverResult;
IntfType: TPasClassInterfaceType): boolean; IntfType: TPasClassInterfaceType): boolean;
begin begin

View File

@ -88,7 +88,7 @@ const
nParserDefaultPropertyMustBeArray = 2042; nParserDefaultPropertyMustBeArray = 2042;
nParserUnknownProcedureType = 2043; nParserUnknownProcedureType = 2043;
nParserGenericArray1Element = 2044; nParserGenericArray1Element = 2044;
nParserGenericClassOrArray = 2045; nParserTypeParamsNotAllowedOnType = 2045;
nParserDuplicateIdentifier = 2046; nParserDuplicateIdentifier = 2046;
nParserDefaultParameterRequiredFor = 2047; nParserDefaultParameterRequiredFor = 2047;
nParserOnlyOneVariableCanBeInitialized = 2048; nParserOnlyOneVariableCanBeInitialized = 2048;
@ -149,7 +149,7 @@ resourcestring
SParserDefaultPropertyMustBeArray = 'The default property must be an array property'; SParserDefaultPropertyMustBeArray = 'The default property must be an array property';
SParserUnknownProcedureType = 'Unknown procedure type "%d"'; SParserUnknownProcedureType = 'Unknown procedure type "%d"';
SParserGenericArray1Element = 'Generic arrays can have only 1 template element'; SParserGenericArray1Element = 'Generic arrays can have only 1 template element';
SParserGenericClassOrArray = 'Generic can only be used with classes or arrays'; SParserTypeParamsNotAllowedOnType = 'Type parameters not allowed on this type';
SParserDuplicateIdentifier = 'Duplicate identifier "%s"'; SParserDuplicateIdentifier = 'Duplicate identifier "%s"';
SParserDefaultParameterRequiredFor = 'Default parameter required for "%s"'; SParserDefaultParameterRequiredFor = 'Default parameter required for "%s"';
SParserOnlyOneVariableCanBeInitialized = 'Only one variable can be initialized'; SParserOnlyOneVariableCanBeInitialized = 'Only one variable can be initialized';
@ -331,6 +331,7 @@ type
procedure ParseExcExpectedIdentifier; procedure ParseExcExpectedIdentifier;
procedure ParseExcSyntaxError; procedure ParseExcSyntaxError;
procedure ParseExcTokenError(const Arg: string); procedure ParseExcTokenError(const Arg: string);
procedure ParseTypeParamsNotAllowed;
function OpLevel(t: TToken): Integer; function OpLevel(t: TToken): Integer;
Function TokenToExprOp (AToken : TToken) : TExprOpCode; Function TokenToExprOp (AToken : TToken) : TExprOpCode;
function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement): TPasElement;overload; function CreateElement(AClass: TPTreeElement; const AName: String; AParent: TPasElement): TPasElement;overload;
@ -408,7 +409,8 @@ type
function ResolveTypeReference(Name: string; Parent: TPasElement): TPasType; function ResolveTypeReference(Name: string; Parent: TPasElement): TPasType;
function ParseComplexType(Parent : TPasElement = Nil): TPasType; function ParseComplexType(Parent : TPasElement = Nil): TPasType;
function ParseTypeDecl(Parent: TPasElement): TPasType; function ParseTypeDecl(Parent: TPasElement): TPasType;
function ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false; GenericArgs: TFPList = nil): TPasType; function ParseGenericTypeDecl(Parent: TPasElement; AddToParent: boolean): TPasGenericType;
function ParseType(Parent: TPasElement; const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false): TPasType;
function ParseReferenceToProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasProcedureType; function ParseReferenceToProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasProcedureType;
function ParseProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; const PT: TProcType): TPasProcedureType; function ParseProcedureType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; const PT: TProcType): TPasProcedureType;
function ParseStringType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasAliasType; function ParseStringType(Parent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String): TPasAliasType;
@ -422,7 +424,7 @@ type
function ParseEnumType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String): TPasEnumType; function ParseEnumType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String): TPasEnumType;
function ParseSetType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String; AIsPacked : Boolean = False): TPasSetType; function ParseSetType(Parent: TPasElement; Const NamePos: TPasSourcePos; const TypeName: String; AIsPacked : Boolean = False): TPasSetType;
function ParseSpecializeType(Parent: TPasElement; Const TypeName: String): TPasSpecializeType; function ParseSpecializeType(Parent: TPasElement; Const TypeName: String): TPasSpecializeType;
Function ParseClassDecl(Parent: TPasElement; Const NamePos: TPasSourcePos; Const AClassName: String; AObjKind: TPasObjKind; PackMode : TPackMode= pmNone; GenericArgs: TFPList = nil): TPasType; Function ParseClassDecl(Parent: TPasElement; Const NamePos: TPasSourcePos; Const AClassName: String; AObjKind: TPasObjKind; PackMode : TPackMode= pmNone): TPasType;
Function ParseProperty(Parent : TPasElement; Const AName : String; AVisibility : TPasMemberVisibility; IsClassField: boolean) : TPasProperty; Function ParseProperty(Parent : TPasElement; Const AName : String; AVisibility : TPasMemberVisibility; IsClassField: boolean) : TPasProperty;
function ParseRangeType(AParent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; Full: Boolean = True): TPasRangeType; function ParseRangeType(AParent: TPasElement; Const NamePos: TPasSourcePos; Const TypeName: String; Full: Boolean = True): TPasRangeType;
procedure ParseExportDecl(Parent: TPasElement; List: TFPList); procedure ParseExportDecl(Parent: TPasElement; List: TFPList);
@ -1016,6 +1018,11 @@ begin
ParseExc(nParserExpectTokenError,SParserExpectTokenError,[Arg]); ParseExc(nParserExpectTokenError,SParserExpectTokenError,[Arg]);
end; end;
procedure TPasParser.ParseTypeParamsNotAllowed;
begin
ParseExc(nParserTypeParamsNotAllowedOnType,sParserTypeParamsNotAllowedOnType,[]);
end;
constructor TPasParser.Create(AScanner: TPascalScanner; constructor TPasParser.Create(AScanner: TPascalScanner;
AFileResolver: TBaseFileResolver; AEngine: TPasTreeContainer); AFileResolver: TBaseFileResolver; AEngine: TPasTreeContainer);
begin begin
@ -1785,7 +1792,7 @@ begin
end; end;
function TPasParser.ParseType(Parent: TPasElement; function TPasParser.ParseType(Parent: TPasElement;
const NamePos: TPasSourcePos; const TypeName: String = ''; Full: Boolean = false; GenericArgs : TFPList = Nil const NamePos: TPasSourcePos; const TypeName: String; Full: Boolean
): TPasType; ): TPasType;
Const Const
@ -1814,9 +1821,9 @@ begin
// types only allowed when full // types only allowed when full
tkObject: Result := ParseClassDecl(Parent, NamePos, TypeName, okObject,PM); tkObject: Result := ParseClassDecl(Parent, NamePos, TypeName, okObject,PM);
tkDispInterface: tkDispInterface:
Result := ParseClassDecl(Parent, NamePos, TypeName, okDispInterface); Result := ParseClassDecl(Parent, NamePos, TypeName, okDispInterface,PM);
tkInterface: tkInterface:
Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface); Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface,PM);
tkSpecialize: tkSpecialize:
Result:=ParseSpecializeType(Parent,TypeName); Result:=ParseSpecializeType(Parent,TypeName);
tkClass: tkClass:
@ -1833,9 +1840,9 @@ begin
end; end;
UngetToken; UngetToken;
if isHelper then if isHelper then
Result:=ParseClassDecl(Parent,NamePos,TypeName,okClassHelper,PM, GenericArgs) Result:=ParseClassDecl(Parent,NamePos,TypeName,okClassHelper, PM)
else else
Result:=ParseClassDecl(Parent, NamePos, TypeName, okClass, PM, GenericArgs); Result:=ParseClassDecl(Parent, NamePos, TypeName, okClass, PM);
end; end;
tkType: tkType:
begin begin
@ -3355,33 +3362,20 @@ var
Scanner.SetForceCaret(NewBlock=declType); Scanner.SetForceCaret(NewBlock=declType);
end; end;
procedure InitGenericType(NewEl: TPasGenericType; GenericTemplateTypes: TFPList);
begin
Declarations.Declarations.Add(NewEl);
{$IFDEF CheckPasTreeRefCount}NewEl.ChangeRefId('CreateElement','TPasDeclarations.Children');{$ENDIF}
NewEl.SetGenericTemplates(GenericTemplateTypes);
Engine.FinishScope(stGenericTypeTemplates,NewEl);
end;
var var
ConstEl: TPasConst; ConstEl: TPasConst;
ResStrEl: TPasResString; ResStrEl: TPasResString;
TypeEl: TPasType; TypeEl: TPasType;
ClassEl: TPasClassType; ClassEl: TPasClassType;
ArrEl : TPasArrayType;
List: TFPList; List: TFPList;
i,j: Integer; i,j: Integer;
ExpEl: TPasExportSymbol; ExpEl: TPasExportSymbol;
PropEl : TPasProperty; PropEl : TPasProperty;
TypeName: String; PT : TProcType;
PT , ProcType: TProcType;
NamePos: TPasSourcePos;
ok: Boolean; ok: Boolean;
Proc: TPasProcedure; Proc: TPasProcedure;
RecordEl: TPasRecordType;
Attr: TPasAttributes; Attr: TPasAttributes;
CurEl: TPasElement; CurEl: TPasElement;
ProcTypeEl: TPasProcedureType;
begin begin
CurBlock := declNone; CurBlock := declNone;
HadTypeSection:=false; HadTypeSection:=false;
@ -3600,73 +3594,7 @@ begin
if CurBlock = declType then if CurBlock = declType then
begin begin
CheckToken(tkIdentifier); CheckToken(tkIdentifier);
TypeName := CurTokenString; ParseGenericTypeDecl(Declarations,true);
NamePos:=CurSourcePos;
List:=TFPList.Create;
try
ReadGenericArguments(List,Declarations);
ExpectToken(tkEqual);
NextToken;
Case CurToken of
tkObject,
tkClass :
begin
ClassEl := TPasClassType(CreateElement(TPasClassType,
TypeName, Declarations, NamePos));
Declarations.Classes.Add(ClassEl);
InitGenericType(ClassEl,List);
NextToken;
DoParseClassType(ClassEl);
CheckHint(ClassEl,True);
Engine.FinishScope(stTypeDef,ClassEl);
end;
tkRecord:
begin
RecordEl := TPasRecordType(CreateElement(TPasRecordType,
TypeName, Declarations, NamePos));
Declarations.Classes.Add(RecordEl);
InitGenericType(RecordEl,List);
NextToken;
ParseRecordMembers(RecordEl,tkend,
(msAdvancedRecords in Scanner.CurrentModeSwitches)
and not (Declarations is TProcedureBody)
and (RecordEl.Name<>''));
CheckHint(RecordEl,True);
Engine.FinishScope(stTypeDef,RecordEl);
end;
tkArray:
begin
ArrEl := TPasArrayType(CreateElement(TPasArrayType, TypeName, Declarations, NamePos));
Declarations.Types.Add(ArrEl);
InitGenericType(ArrEl,List);
DoParseArrayType(ArrEl);
CheckHint(ArrEl,True);
Engine.FinishScope(stTypeDef,ArrEl);
end;
tkprocedure,tkfunction:
begin
if CurToken=tkFunction then
begin
ProcTypeEl := CreateFunctionType(TypeName, 'Result', Declarations, False, NamePos);
ProcType:=ptFunction;
end
else
begin
ProcTypeEl := TPasProcedureType(CreateElement(TPasProcedureType, TypeName, Declarations, NamePos));
ProcType:=ptProcedure;
end;
Declarations.Functions.Add(ProcTypeEl);
InitGenericType(ProcTypeEl,List);
ParseProcedureOrFunction(ProcTypeEl, ProcTypeEl, ProcType, True);
end;
else
ParseExc(nParserGenericClassOrArray,SParserGenericClassOrArray);
end;
finally
for i:=0 to List.Count-1 do
TPasElement(List[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
List.Free;
end;
end end
else if CurBlock = declNone then else if CurBlock = declNone then
begin begin
@ -4339,36 +4267,140 @@ begin
end; end;
function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType; function TPasParser.ParseTypeDecl(Parent: TPasElement): TPasType;
var
TypeName: String;
NamePos: TPasSourcePos;
OldForceCaret , IsDelphiGenericType: Boolean;
begin
OldForceCaret:=Scanner.SetForceCaret(True);
try
IsDelphiGenericType:=false;
if (msDelphi in CurrentModeswitches) then
begin
NextToken;
IsDelphiGenericType:=CurToken=tkLessThan;
UngetToken;
end;
if IsDelphiGenericType then
Result:=ParseGenericTypeDecl(Parent,false)
else
begin
TypeName := CurTokenString;
NamePos:=CurSourcePos;
ExpectToken(tkEqual);
Result:=ParseType(Parent,NamePos,TypeName,True);
end;
finally
Scanner.SetForceCaret(OldForceCaret);
end;
end;
function TPasParser.ParseGenericTypeDecl(Parent: TPasElement;
AddToParent: boolean): TPasGenericType;
procedure InitGenericType(NewEl: TPasGenericType; GenericTemplateTypes: TFPList);
begin
ParseGenericTypeDecl:=NewEl;
if AddToParent then
begin
if Parent is TPasDeclarations then
begin
TPasDeclarations(Parent).Declarations.Add(NewEl);
{$IFDEF CheckPasTreeRefCount}NewEl.ChangeRefId('CreateElement','TPasDeclarations.Children');{$ENDIF}
end
else if Parent is TPasMembersType then
begin
TPasMembersType(Parent).Members.Add(NewEl);
{$IFDEF CheckPasTreeRefCount}NewEl.ChangeRefId('CreateElement','TPasMembersType.Members');{$ENDIF}
end;
end;
NewEl.SetGenericTemplates(GenericTemplateTypes);
Engine.FinishScope(stGenericTypeTemplates,NewEl);
end;
var var
TypeName: String; TypeName: String;
NamePos: TPasSourcePos; NamePos: TPasSourcePos;
OldForceCaret : Boolean; List: TFPList;
List : TFPList; ClassEl: TPasClassType;
RecordEl: TPasRecordType;
ArrEl: TPasArrayType;
ProcTypeEl: TPasProcedureType;
ProcType: TProcType;
i: Integer; i: Integer;
begin begin
Result:=nil;
TypeName := CurTokenString; TypeName := CurTokenString;
NamePos:=CurSourcePos; NamePos := CurSourcePos;
List:=Nil; List:=TFPList.Create;
OldForceCaret:=Scanner.SetForceCaret(True);
try try
NextToken; ReadGenericArguments(List,Parent);
if (CurToken=tkLessThan) and (msDelphi in CurrentModeswitches) then
List:=TFPList.Create;
UnGetToken; // ReadGenericArguments starts at <
if Assigned(List) then
ReadGenericArguments(List,Parent);
ExpectToken(tkEqual); ExpectToken(tkEqual);
Result:=ParseType(Parent,NamePos,TypeName,True,List); NextToken;
finally Case CurToken of
Scanner.SetForceCaret(OldForceCaret); tkObject,
if List<>nil then tkClass :
begin
ClassEl := TPasClassType(CreateElement(TPasClassType,
TypeName, Parent, NamePos));
if AddToParent and (Parent is TPasDeclarations) then
TPasDeclarations(Parent).Classes.Add(ClassEl);
InitGenericType(ClassEl,List);
NextToken;
DoParseClassType(ClassEl);
CheckHint(ClassEl,True);
Engine.FinishScope(stTypeDef,ClassEl);
end;
tkRecord:
begin
RecordEl := TPasRecordType(CreateElement(TPasRecordType,
TypeName, Parent, NamePos));
if AddToParent and (Parent is TPasDeclarations) then
TPasDeclarations(Parent).Classes.Add(RecordEl);
InitGenericType(RecordEl,List);
NextToken;
ParseRecordMembers(RecordEl,tkend,
(msAdvancedRecords in Scanner.CurrentModeSwitches)
and not (Parent is TProcedureBody)
and (RecordEl.Name<>''));
CheckHint(RecordEl,True);
Engine.FinishScope(stTypeDef,RecordEl);
end;
tkArray:
begin
ArrEl := TPasArrayType(CreateElement(TPasArrayType, TypeName, Parent, NamePos));
if AddToParent and (Parent is TPasDeclarations) then
TPasDeclarations(Parent).Types.Add(ArrEl);
InitGenericType(ArrEl,List);
DoParseArrayType(ArrEl);
CheckHint(ArrEl,True);
Engine.FinishScope(stTypeDef,ArrEl);
end;
tkprocedure,tkfunction:
begin begin
for i:=0 to List.Count-1 do if CurToken=tkFunction then
TPasElement(List[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF}; begin
List.Free; ProcTypeEl := CreateFunctionType(TypeName, 'Result', Parent, False, NamePos);
ProcType:=ptFunction;
end
else
begin
ProcTypeEl := TPasProcedureType(CreateElement(TPasProcedureType,
TypeName, Parent, NamePos));
ProcType:=ptProcedure;
end;
if AddToParent and (Parent is TPasDeclarations) then
TPasDeclarations(Parent).Functions.Add(ProcTypeEl);
InitGenericType(ProcTypeEl,List);
ParseProcedureOrFunction(ProcTypeEl, ProcTypeEl, ProcType, True);
end; end;
else
ParseTypeParamsNotAllowed;
end;
finally
for i:=0 to List.Count-1 do
TPasElement(List[i]).Release{$IFDEF CheckPasTreeRefCount}('CreateElement'){$ENDIF};
List.Free;
end; end;
end; end;
@ -7204,7 +7236,7 @@ end;
function TPasParser.ParseClassDecl(Parent: TPasElement; function TPasParser.ParseClassDecl(Parent: TPasElement;
const NamePos: TPasSourcePos; const AClassName: String; const NamePos: TPasSourcePos; const AClassName: String;
AObjKind: TPasObjKind; PackMode: TPackMode; GenericArgs: TFPList): TPasType; AObjKind: TPasObjKind; PackMode: TPackMode): TPasType;
Var Var
ok: Boolean; ok: Boolean;
@ -7267,7 +7299,7 @@ begin
if AExternalName<>'' then if AExternalName<>'' then
PCT.ExternalName:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalName,''''); PCT.ExternalName:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalName,'''');
if AExternalNameSpace<>'' then if AExternalNameSpace<>'' then
PCT.ExternalNameSpace:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalNameSpace,''''); PCT.ExternalNameSpace:={$ifdef pas2js}DeQuoteString{$else}AnsiDequotedStr{$endif}(AExternalNameSpace,'''');
PCT.ObjKind := AObjKind; PCT.ObjKind := AObjKind;
PCT.PackMode:=PackMode; PCT.PackMode:=PackMode;
if AObjKind=okInterface then if AObjKind=okInterface then
@ -7275,8 +7307,6 @@ begin
if SameText(Scanner.CurrentValueSwitch[vsInterfaces],'CORBA') then if SameText(Scanner.CurrentValueSwitch[vsInterfaces],'CORBA') then
PCT.InterfaceType:=citCorba; PCT.InterfaceType:=citCorba;
end; end;
if Assigned(GenericArgs) then
PCT.SetGenericTemplates(GenericArgs);
DoParseClassType(PCT); DoParseClassType(PCT);
Engine.FinishScope(stTypeDef,Result); Engine.FinishScope(stTypeDef,Result);
ok:=true; ok:=true;

View File

@ -16,6 +16,7 @@ Type
Procedure TestObjectGenerics; Procedure TestObjectGenerics;
Procedure TestRecordGenerics; Procedure TestRecordGenerics;
Procedure TestArrayGenerics; Procedure TestArrayGenerics;
Procedure TestArrayGenericsDelphi;
Procedure TestProcTypeGenerics; Procedure TestProcTypeGenerics;
Procedure TestGenericConstraint; Procedure TestGenericConstraint;
Procedure TestGenericInterfaceConstraint; Procedure TestGenericInterfaceConstraint;
@ -67,6 +68,17 @@ begin
ParseDeclarations; ParseDeclarations;
end; end;
procedure TTestGenerics.TestArrayGenericsDelphi;
begin
Add([
'{$mode delphi}',
'Type',
' TSome<T> = array of T;',
' TStatic<R,T> = array[R] of T;',
'']);
ParseDeclarations;
end;
procedure TTestGenerics.TestProcTypeGenerics; procedure TTestGenerics.TestProcTypeGenerics;
begin begin
Add([ Add([

View File

@ -29,11 +29,15 @@ type
// ToDo: constraint T:Unit2.TGen<word> // ToDo: constraint T:Unit2.TGen<word>
procedure TestGen_GenericNotFoundFail; procedure TestGen_GenericNotFoundFail;
procedure TestGen_RecordLocalNameDuplicateFail; procedure TestGen_RecordLocalNameDuplicateFail;
procedure TestGen_Record; // ToDo procedure TestGen_Record;
// ToDo: type TBird<T> = record end; var b: TBird<word>.T; fail //procedure TestGen_RecordDelphi;
// ToDo: enums within generic // ToDo: enums within generic
procedure TestGen_Class;
//procedure TestGen_ClassDelphi;
// ToDo: generic class // ToDo: generic class
// ToDo: generic class forward // ToDo: generic class forward (constraints must be repeated)
// ToDo: generic class forward constraints mismatch fail
// ToDo: generic class overload
// ToDo: ancestor cycle: TBird<T> = class(TBird<word>) fail // ToDo: ancestor cycle: TBird<T> = class(TBird<word>) fail
// ToDo: class-of // ToDo: class-of
// ToDo: UnitA.impl uses UnitB.intf uses UnitA.intf, UnitB has specialize of UnitA // ToDo: UnitA.impl uses UnitB.intf uses UnitA.intf, UnitB has specialize of UnitA
@ -179,6 +183,26 @@ begin
ParseProgram; ParseProgram;
end; end;
procedure TTestResolveGenerics.TestGen_Class;
begin
exit;
StartProgram(false);
Add([
'{$mode objfpc}',
'type',
' {#Typ}T = word;',
' generic TBird<{#Templ}T> = class',
' {=Templ}v: T;',
' end;',
'var',
' b: specialize TBird<word>;',
' {=Typ}w: T;',
'begin',
' b.v:=w;',
'']);
ParseProgram;
end;
initialization initialization
RegisterTests([TTestResolveGenerics]); RegisterTests([TTestResolveGenerics]);