* Support for functions in records

git-svn-id: trunk@29553 -
This commit is contained in:
michael 2015-01-26 09:54:15 +00:00
parent 817555cd6e
commit a842569bf1
3 changed files with 70 additions and 10 deletions

View File

@ -63,7 +63,7 @@ resourcestring
SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Record helpers'; SParserNoConstructorAllowed = 'Constructors or Destructors are not allowed in Interfaces or Record helpers';
SParserNoFieldsAllowed = 'Fields are not allowed in Interfaces'; SParserNoFieldsAllowed = 'Fields are not allowed in Interfaces';
SParserInvalidRecordVisibility = 'Records can only have public and (strict) private as visibility specifiers'; SParserInvalidRecordVisibility = 'Records can only have public and (strict) private as visibility specifiers';
SErrRecordMethodsNotAllowed = 'Record methods not allowed at this location.';
type type
TPasParserLogHandler = Procedure (Sender : TObject; Const Msg : String) of object; TPasParserLogHandler = Procedure (Sender : TObject; Const Msg : String) of object;
TPParserLogEvent = (pleInterface,pleImplementation); TPParserLogEvent = (pleInterface,pleImplementation);
@ -150,7 +150,7 @@ type
Procedure DoLog(Const Msg : String; SkipSourceInfo : Boolean = False);overload; Procedure DoLog(Const Msg : String; SkipSourceInfo : Boolean = False);overload;
Procedure DoLog(Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload; Procedure DoLog(Const Fmt : String; Args : Array of const;SkipSourceInfo : Boolean = False);overload;
function GetProcTypeFromToken(tk: TToken; IsClass: Boolean=False ): TProcType; function GetProcTypeFromToken(tk: TToken; IsClass: Boolean=False ): TProcType;
procedure ParseRecordFieldList(ARec: TPasRecordType; AEndToken: TToken); procedure ParseRecordFieldList(ARec: TPasRecordType; AEndToken: TToken; AllowMethods : Boolean);
procedure ParseRecordVariantParts(ARec: TPasRecordType; AEndToken: TToken); procedure ParseRecordVariantParts(ARec: TPasRecordType; AEndToken: TToken);
function GetProcedureClass(ProcType : TProcType): TPTreeElement; function GetProcedureClass(ProcType : TProcType): TPTreeElement;
procedure ParseClassFields(AType: TPasClassType; const AVisibility: TPasMemberVisibility; IsClassField : Boolean); procedure ParseClassFields(AType: TPasClassType; const AVisibility: TPasMemberVisibility; IsClassField : Boolean);
@ -3587,7 +3587,7 @@ begin
NextToken; NextToken;
M:=TPasRecordType(CreateElement(TPasRecordType,'',V)); M:=TPasRecordType(CreateElement(TPasRecordType,'',V));
V.Members:=M; V.Members:=M;
ParseRecordFieldList(M,tkBraceClose); ParseRecordFieldList(M,tkBraceClose,False);
// Current token is closing ), so we eat that // Current token is closing ), so we eat that
NextToken; NextToken;
// If there is a semicolon, we eat that too. // If there is a semicolon, we eat that too.
@ -3612,16 +3612,31 @@ begin
end; end;
// Starts on first token after Record or (. Ends on AEndToken // Starts on first token after Record or (. Ends on AEndToken
Procedure TPasParser.ParseRecordFieldList(ARec : TPasRecordType; AEndToken : TToken); Procedure TPasParser.ParseRecordFieldList(ARec : TPasRecordType; AEndToken : TToken; AllowMethods : Boolean);
Var Var
VN : String; VN : String;
v : TPasmemberVisibility; v : TPasmemberVisibility;
Proc: TPasProcedure;
ProcType: TProcType;
begin begin
v:=visPublic;
while CurToken<>AEndToken do while CurToken<>AEndToken do
begin begin
Case CurToken of Case CurToken of
tkProcedure,
tkFunction :
begin
if Not AllowMethods then
ParseExc(SErrRecordMethodsNotAllowed);
ProcType:=GetProcTypeFromtoken(CurToken,False);
Proc:=ParseProcedureOrFunctionDecl(ARec,ProcType,v);
if Proc.Parent is TPasOverloadedProc then
TPasOverloadedProc(Proc.Parent).Overloads.Add(Proc)
else
ARec.Members.Add(Proc);
end;
tkIdentifier : tkIdentifier :
begin begin
v:=visDefault; v:=visDefault;
@ -3669,7 +3684,7 @@ begin
try try
Result.PackMode:=PackMode; Result.PackMode:=PackMode;
NextToken; NextToken;
ParseRecordFieldList(Result,tkEnd); ParseRecordFieldList(Result,tkEnd,true);
except except
FreeAndNil(Result); FreeAndNil(Result);
Raise; Raise;

View File

@ -160,12 +160,14 @@ type
procedure AssertVariantSelector(AName, AType: string); procedure AssertVariantSelector(AName, AType: string);
procedure AssertField1(Hints: TPasMemberHints); procedure AssertField1(Hints: TPasMemberHints);
procedure AssertField2(Hints: TPasMemberHints); procedure AssertField2(Hints: TPasMemberHints);
procedure AssertMethod2(Hints: TPasMemberHints);
procedure AssertVariant1(Hints: TPasMemberHints); procedure AssertVariant1(Hints: TPasMemberHints);
procedure AssertVariant1(Hints: TPasMemberHints; VariantLabels : Array of string); procedure AssertVariant1(Hints: TPasMemberHints; VariantLabels : Array of string);
procedure AssertVariant2(Hints: TPasMemberHints); procedure AssertVariant2(Hints: TPasMemberHints);
procedure AssertVariant2(Hints: TPasMemberHints; VariantLabels : Array of string); procedure AssertVariant2(Hints: TPasMemberHints; VariantLabels : Array of string);
procedure AssertOneIntegerField(Hints: TPasMemberHints); procedure AssertOneIntegerField(Hints: TPasMemberHints);
procedure AssertTwoIntegerFields(Hints1, Hints2: TPasMemberHints); procedure AssertTwoIntegerFields(Hints1, Hints2: TPasMemberHints);
procedure AssertIntegerFieldAndMethod(Hints1, Hints2: TPasMemberHints);
procedure AssertRecordField(AIndex: Integer;Hints: TPasMemberHints); procedure AssertRecordField(AIndex: Integer;Hints: TPasMemberHints);
procedure AssertRecordVariant(AIndex: Integer;Hints: TPasMemberHints; VariantLabels : Array of string); procedure AssertRecordVariant(AIndex: Integer;Hints: TPasMemberHints; VariantLabels : Array of string);
Procedure AssertRecordVariantVariant(AIndex: Integer;Const AFieldName,ATypeName: string;Hints: TPasMemberHints; VariantLabels : Array of string); Procedure AssertRecordVariantVariant(AIndex: Integer;Const AFieldName,ATypeName: string;Hints: TPasMemberHints; VariantLabels : Array of string);
@ -228,6 +230,8 @@ type
Procedure TestTwoDeprecatedFieldsCombined; Procedure TestTwoDeprecatedFieldsCombined;
Procedure TestTwoDeprecatedFieldsCombinedDeprecated; Procedure TestTwoDeprecatedFieldsCombinedDeprecated;
Procedure TestTwoDeprecatedFieldsCombinedPlatform; Procedure TestTwoDeprecatedFieldsCombinedPlatform;
Procedure TestFieldAndMethod;
Procedure TestFieldAnd2Methods;
Procedure TestNested; Procedure TestNested;
Procedure TestNestedDeprecated; Procedure TestNestedDeprecated;
Procedure TestNestedPlatform; Procedure TestNestedPlatform;
@ -1434,6 +1438,18 @@ begin
AssertTrue('Field 2 hints match',Field2.Hints=Hints) AssertTrue('Field 2 hints match',Field2.Hints=Hints)
end; end;
procedure TTestRecordTypeParser.AssertMethod2(Hints: TPasMemberHints);
Var
P : TPasProcedure;
begin
AssertEquals('Member 2 type',TPasProcedure,TObject(TheRecord.Members[1]).ClassType);
P:=TPasProcedure(TheRecord.Members[1]);
AssertEquals('Method name','dosomething2',P.Name);
AssertTrue('Method hints match',P.Hints=Hints)
end;
procedure TTestRecordTypeParser.AssertOneIntegerField(Hints : TPasMemberHints); procedure TTestRecordTypeParser.AssertOneIntegerField(Hints : TPasMemberHints);
begin begin
@ -1449,6 +1465,14 @@ begin
AssertField2(Hints2); AssertField2(Hints2);
end; end;
procedure TTestRecordTypeParser.AssertIntegerFieldAndMethod(Hints1,
Hints2: TPasMemberHints);
begin
AssertEquals('Two members',2,TheRecord.Members.Count);
AssertField1(Hints1);
AssertMethod2(Hints2);
end;
procedure TTestRecordTypeParser.AssertRecordField(AIndex: Integer; procedure TTestRecordTypeParser.AssertRecordField(AIndex: Integer;
Hints: TPasMemberHints); Hints: TPasMemberHints);
@ -1771,6 +1795,29 @@ begin
AssertTwoIntegerFields([hdeprecated],[hdeprecated]); AssertTwoIntegerFields([hdeprecated],[hdeprecated]);
end; end;
procedure TTestRecordTypeParser.TestFieldAndMethod;
begin
TestFields(['x : integer;','procedure dosomething2;'],'',False);
AssertIntegerFieldAndMethod([],[]);
end;
procedure TTestRecordTypeParser.TestFieldAnd2Methods;
Var
P : TPasFunction;
begin
TestFields(['x : integer;','procedure dosomething2;','function dosomething3 : Integer;'],'',False);
AssertEquals('Member count',3,TheRecord.Members.Count);
AssertField1([]);
AssertMethod2([]);
AssertEquals('Member 3 type',TPasFunction,TObject(TheRecord.Members[2]).ClassType);
P:=TPasFunction(TheRecord.Members[2]);
AssertEquals('Method 2 name','dosomething3',P.Name);
AssertTrue('Method 2 hints match',[]=P.Hints);
// Standard type
AssertEquals('Method 2 result type','Integer', P.FuncType.ResultEl.ResultType.Name);
end;
procedure TTestRecordTypeParser.TestNested; procedure TTestRecordTypeParser.TestNested;
begin begin
TestFields(['x : integer;','y : record',' z : integer;','end'],'',False); TestFields(['x : integer;','y : record',' z : integer;','end'],'',False);

View File

@ -34,13 +34,10 @@
<LaunchingApplication Use="True"/> <LaunchingApplication Use="True"/>
</local> </local>
</RunParams> </RunParams>
<RequiredPackages Count="2"> <RequiredPackages Count="1">
<Item1> <Item1>
<PackageName Value="FPCUnitConsoleRunner"/>
</Item1>
<Item2>
<PackageName Value="FCL"/> <PackageName Value="FCL"/>
</Item2> </Item1>
</RequiredPackages> </RequiredPackages>
<Units Count="12"> <Units Count="12">
<Unit0> <Unit0>
@ -109,6 +106,7 @@
<Version Value="11"/> <Version Value="11"/>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../src"/>
</SearchPaths> </SearchPaths>
<Other> <Other>
<CompilerMessages> <CompilerMessages>