* Support for type helpers, low()..High() ranges, static fields

git-svn-id: trunk@34668 -
This commit is contained in:
michael 2016-10-08 15:51:25 +00:00
parent f4bbb229fa
commit 0437bc4c8e
6 changed files with 114 additions and 18 deletions

View File

@ -705,7 +705,7 @@ type
end; end;
{ TPasVariable } { TPasVariable }
TVariableModifier = (vmCVar, vmExternal, vmPublic, vmExport, vmClass); TVariableModifier = (vmCVar, vmExternal, vmPublic, vmExport, vmClass,vmStatic);
TVariableModifiers = set of TVariableModifier; TVariableModifiers = set of TVariableModifier;
TPasVariable = class(TPasElement) TPasVariable = class(TPasElement)
@ -4138,7 +4138,11 @@ begin
If Kind=pekRange then If Kind=pekRange then
Result:='..' Result:='..'
else else
Result:=' '+OpcodeStrings[Opcode]+' '; begin
Result:=OpcodeStrings[Opcode];
if Not (OpCode in [eopAddress,eopDeref,eopSubIdent]) then
Result:=' '+Result+' ';
end;
If Assigned(Left) then If Assigned(Left) then
begin begin
op := Left.GetDeclaration(Full); op := Left.GetDeclaration(Full);

View File

@ -1063,7 +1063,7 @@ begin
ParseExcTokenError(';'); ParseExcTokenError(';');
UnGetToken; UnGetToken;
end end
else if (CurToken=tkDotDot) then // A: B..C; else if (CurToken in [tkBraceOpen,tkDotDot]) then // A: B..C;
begin begin
K:=stkRange; K:=stkRange;
UnGetToken; UnGetToken;
@ -1225,7 +1225,7 @@ Const
NoHintTokens = [tkProcedure,tkFunction]; NoHintTokens = [tkProcedure,tkFunction];
var var
PM : TPackMode; PM : TPackMode;
CH , ok: Boolean; // Check hint ? CH , isHelper,ok: Boolean; // Check hint ?
begin begin
Result := nil; Result := nil;
// NextToken and check pack mode // NextToken and check pack mode
@ -1246,7 +1246,16 @@ begin
tkInterface: Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface); tkInterface: Result := ParseClassDecl(Parent, NamePos, TypeName, okInterface);
tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName); tkSpecialize: Result:=ParseSpecializeType(Parent,TypeName);
tkClass: Result := ParseClassDecl(Parent, NamePos, TypeName, okClass, PM); tkClass: Result := ParseClassDecl(Parent, NamePos, TypeName, okClass, PM);
tkType: Result:=ParseAliasType(Parent,NamePos,TypeName); tkType:
begin
NextToken;
isHelper:=Curtoken=tkHelper;
UnGetToken;
if isHelper then
Result:=ParseClassDecl(Parent,NamePos,TypeName,okTypeHelper,PM)
else
Result:=ParseAliasType(Parent,NamePos,TypeName);
end;
// Always allowed // Always allowed
tkIdentifier: Result:=ParseSimpleType(Parent,NamePos,TypeName,Full); tkIdentifier: Result:=ParseSimpleType(Parent,NamePos,TypeName,Full);
tkCaret: Result:=ParsePointerType(Parent,NamePos,TypeName); tkCaret: Result:=ParsePointerType(Parent,NamePos,TypeName);
@ -1552,7 +1561,7 @@ begin
while CurToken in [tkDot] do while CurToken in [tkDot] do
begin begin
NextToken; NextToken;
if CurToken=tkIdentifier then if CurToken in [tkIdentifier,tktrue,tkfalse] then // true and false are also identifiers
begin begin
AddToBinaryExprChain(Result,Last, AddToBinaryExprChain(Result,Last,
CreatePrimitiveExpr(AParent,pekIdent,CurTokenString), eopSubIdent); CreatePrimitiveExpr(AParent,pekIdent,CurTokenString), eopSubIdent);
@ -4498,17 +4507,32 @@ Var
VarList: TFPList; VarList: TFPList;
Element: TPasElement; Element: TPasElement;
I : Integer; I : Integer;
isStatic : Boolean;
begin begin
VarList := TFPList.Create; VarList := TFPList.Create;
try try
ParseInlineVarDecl(AType, VarList, AVisibility, False); ParseInlineVarDecl(AType, VarList, AVisibility, False);
if CurToken=tkSemicolon then
begin
NextToken;
isStatic:=CurTokenIsIdentifier('static');
if isStatic then
ExpectToken(tkSemicolon)
else
UngetToken;
end;
for i := 0 to VarList.Count - 1 do for i := 0 to VarList.Count - 1 do
begin begin
Element := TPasElement(VarList[i]); Element := TPasElement(VarList[i]);
Element.Visibility := AVisibility; Element.Visibility := AVisibility;
if IsClassField and (Element is TPasVariable) then if (Element is TPasVariable) then
begin
if IsClassField then
TPasVariable(Element).VarModifiers:=TPasVariable(Element).VarModifiers+[vmClass]; TPasVariable(Element).VarModifiers:=TPasVariable(Element).VarModifiers+[vmClass];
if isStatic then
TPasVariable(Element).VarModifiers:=TPasVariable(Element).VarModifiers+[vmStatic];
end;
AType.Members.Add(Element); AType.Members.Add(Element);
end; end;
finally finally
@ -4689,10 +4713,11 @@ function TPasParser.ParseClassDecl(Parent: TPasElement;
Var Var
ok: Boolean; ok: Boolean;
FT : TPasType;
begin begin
NextToken; NextToken;
FT:=Nil;
if (AObjKind = okClass) and (CurToken = tkOf) then if (AObjKind = okClass) and (CurToken = tkOf) then
begin begin
Result := TPasClassOfType(CreateElement(TPasClassOfType, AClassName, Result := TPasClassOfType(CreateElement(TPasClassOfType, AClassName,
@ -4704,15 +4729,22 @@ begin
end; end;
if (CurToken = tkHelper) then if (CurToken = tkHelper) then
begin begin
if Not (AObjKind in [okClass,okRecordHelper]) then if Not (AObjKind in [okClass,okTypeHelper,okRecordHelper]) then
ParseExc(nParserHelperNotAllowed,SParserHelperNotAllowed,[ObjKindNames[AObjKind]]); ParseExc(nParserHelperNotAllowed,SParserHelperNotAllowed,[ObjKindNames[AObjKind]]);
if (AObjKind = okClass) then Case AObjKind of
okClass:
AObjKind:=okClassHelper; AObjKind:=okClassHelper;
okTypeHelper:
begin
ExpectToken(tkFor);
FT:=ParseType(Parent,Scanner.CurSourcePos,'',False);
end
end;
NextToken; NextToken;
end; end;
Result := TPasClassType(CreateElement(TPasClassType, AClassName, Result := TPasClassType(CreateElement(TPasClassType, AClassName,
Parent, NamePos)); Parent, NamePos));
TPasClassType(Result).HelperForType:=FT;
ok:=false; ok:=false;
try try
TPasClassType(Result).ObjKind := AObjKind; TPasClassType(Result).ObjKind := AObjKind;

View File

@ -72,6 +72,7 @@ type
procedure TestOneSpecializedClassInterface; procedure TestOneSpecializedClassInterface;
Procedure TestOneField; Procedure TestOneField;
Procedure TestOneFieldComment; Procedure TestOneFieldComment;
procedure TestOneFieldStatic;
Procedure TestOneVarField; Procedure TestOneVarField;
Procedure TestOneClassField; Procedure TestOneClassField;
Procedure TestOneFieldVisibility; Procedure TestOneFieldVisibility;
@ -513,6 +514,16 @@ begin
AssertVisibility; AssertVisibility;
end; end;
procedure TTestClassType.TestOneFieldStatic;
begin
AddMember('a : integer; static');
ParseClass;
AssertNotNull('Have 1 field',Field1);
AssertMemberName('a');
AssertVisibility;
AssertTrue('Have static field',vmStatic in TPasVariable(Field1).VarModifiers);
end;
procedure TTestClassType.TestOneFieldComment; procedure TTestClassType.TestOneFieldComment;
begin begin
AddComment:=true; AddComment:=true;

View File

@ -80,6 +80,7 @@ type
Procedure TestFunctionOneArgDefaultExpr; Procedure TestFunctionOneArgDefaultExpr;
procedure TestProcedureTwoArgsDefault; procedure TestProcedureTwoArgsDefault;
Procedure TestFunctionTwoArgsDefault; Procedure TestFunctionTwoArgsDefault;
procedure TestFunctionOneArgEnumeratedExplicit;
procedure TestProcedureOneUntypedVarArg; procedure TestProcedureOneUntypedVarArg;
Procedure TestFunctionOneUntypedVarArg; Procedure TestFunctionOneUntypedVarArg;
procedure TestProcedureTwoUntypedVarArgs; procedure TestProcedureTwoUntypedVarArgs;
@ -562,6 +563,13 @@ begin
AssertArg(FuncType,0,'B',argDefault,'Integer','1'); AssertArg(FuncType,0,'B',argDefault,'Integer','1');
end; end;
procedure TTestProcedureFunction.TestFunctionOneArgEnumeratedExplicit;
begin
ParseFunction('(B : TSomeEnum = TSomeEnum.False)');
AssertFunc([],ccDefault,1);
AssertArg(FuncType,0,'B',argDefault,'TSomeEnum','TSomeEnum.False');
end;
procedure TTestProcedureFunction.TestProcedureOneArgDefaultSet; procedure TTestProcedureFunction.TestProcedureOneArgDefaultSet;
begin begin
ParseProcedure('(B : MySet = [1,2])'); ParseProcedure('(B : MySet = [1,2])');

View File

@ -33,6 +33,7 @@ type
TTestTypeParser = Class(TBaseTestTypeParser) TTestTypeParser = Class(TBaseTestTypeParser)
private private
Protected Protected
procedure StartTypeHelper(ForType: String; AParent: String);
Procedure DoTestAliasType(Const AnAliasType : String; Const AHint : String); Procedure DoTestAliasType(Const AnAliasType : String; Const AHint : String);
procedure DoTestStringType(const AnAliasType: String; const AHint: String); procedure DoTestStringType(const AnAliasType: String; const AHint: String);
procedure DoTypeError(Const AMsg,ASource : string); procedure DoTypeError(Const AMsg,ASource : string);
@ -139,6 +140,7 @@ type
Procedure TestComplexSet; Procedure TestComplexSet;
Procedure TestComplexSetDeprecated; Procedure TestComplexSetDeprecated;
Procedure TestComplexSetPlatform; Procedure TestComplexSetPlatform;
procedure TestRangeLowHigh;
Procedure TestRangeSet; Procedure TestRangeSet;
Procedure TestSubRangeSet; Procedure TestSubRangeSet;
Procedure TestRangeSetDeprecated; Procedure TestRangeSetDeprecated;
@ -155,6 +157,7 @@ type
Procedure TestReferenceArray; Procedure TestReferenceArray;
Procedure TestReferencePointer; Procedure TestReferencePointer;
Procedure TestInvalidColon; Procedure TestInvalidColon;
Procedure TestTypeHelper;
end; end;
{ TTestRecordTypeParser } { TTestRecordTypeParser }
@ -2326,6 +2329,7 @@ Function TBaseTestTypeParser.ParseType(ASource: String; ATypeClass: TClass;
Var Var
D : String; D : String;
begin begin
Hint:=AHint; Hint:=AHint;
Add('Type'); Add('Type');
@ -2340,11 +2344,19 @@ begin
Add(' '+D+';'); Add(' '+D+';');
// Writeln(source.text); // Writeln(source.text);
ParseDeclarations; ParseDeclarations;
if ATypeClass.InHeritsFrom(TPasClassType) then
AssertEquals('One type definition',1,Declarations.Classes.Count)
else
AssertEquals('One type definition',1,Declarations.Types.Count); AssertEquals('One type definition',1,Declarations.Types.Count);
If (AtypeClass<>Nil) then If (AtypeClass<>Nil) then
AssertEquals('First declaration is type definition.',ATypeClass,TObject(Declarations.Types[0]).ClassType); begin
AssertEquals('First declaration has correct name.','A',TPasType(Declarations.Types[0]).Name); if ATypeClass.InHeritsFrom(TPasClassType) then
Result:=TPasType(Declarations.Classes[0])
else
Result:=TPasType(Declarations.Types[0]); Result:=TPasType(Declarations.Types[0]);
AssertEquals('First declaration is type definition.',ATypeClass,Result.ClassType);
end;
AssertEquals('First declaration has correct name.','A',Result.Name);
FType:=Result; FType:=Result;
Definition:=Result; Definition:=Result;
if (Hint<>'') then if (Hint<>'') then
@ -3044,6 +3056,13 @@ begin
DoTestComplexSet; DoTestComplexSet;
end; end;
procedure TTestTypeParser.TestRangeLowHigh;
begin
DoParseRangeSet('low(TRange)..high(TRange)','');
end;
procedure TTestTypeParser.TestRangeSet; procedure TTestTypeParser.TestRangeSet;
begin begin
// TRange = (rLow, rMiddle, rHigh); // TRange = (rLow, rMiddle, rHigh);
@ -3198,6 +3217,28 @@ begin
AssertEquals('wrong colon in type raised an error',true,ok); AssertEquals('wrong colon in type raised an error',true,ok);
end; end;
procedure TTestTypeParser.StartTypeHelper(ForType: String; AParent: String);
Var
S : String;
begin
S:='TMyClass = Type Helper';
if (AParent<>'') then
begin
S:=S+'('+AParent;
S:=S+')';
end;
S:=S+' for '+ForType;
Add(S);
end;
procedure TTestTypeParser.TestTypeHelper;
begin
ParseType('Type Helper for AnsiString end',TPasClassType,'');
end;
initialization initialization
RegisterTests([TTestTypeParser,TTestRecordTypeParser,TTestProcedureTypeParser]); RegisterTests([TTestTypeParser,TTestRecordTypeParser,TTestProcedureTypeParser]);
end. end.

View File

@ -30,7 +30,7 @@
<RunParams> <RunParams>
<local> <local>
<FormatVersion Value="1"/> <FormatVersion Value="1"/>
<CommandLineParams Value="--suite=TTestTypeParser.TestGenericArray"/> <CommandLineParams Value="--suite=TTestTypeParser.TestRangeLowHigh"/>
</local> </local>
</RunParams> </RunParams>
<RequiredPackages Count="1"> <RequiredPackages Count="1">