codetools: parse delphi generic inside generic

git-svn-id: trunk@56510 -
This commit is contained in:
mattias 2017-11-27 16:15:57 +00:00
parent c1d0ee32a3
commit 60dce6d601

View File

@ -146,7 +146,7 @@ type
function GetExtraction(InUpperCase: boolean): string; function GetExtraction(InUpperCase: boolean): string;
function ExtractStreamEndIsIdentChar: boolean; function ExtractStreamEndIsIdentChar: boolean;
procedure ExtractNextAtom(AddAtom: boolean; Attr: TProcHeadAttributes); procedure ExtractNextAtom(AddAtom: boolean; Attr: TProcHeadAttributes);
procedure CheckOperatorProc(IsOperator: boolean; var IsFunction: boolean); inline; procedure CheckOperatorProc(var ParseAttr: TParseProcHeadAttributes); inline;
protected protected
// parsing // parsing
FLastCompilerMode: TCompilerMode; FLastCompilerMode: TCompilerMode;
@ -172,7 +172,7 @@ type
procedure ReadConstExpr; procedure ReadConstExpr;
// types // types
procedure ReadTypeNameAndDefinition; procedure ReadTypeNameAndDefinition;
procedure ReadGenericParamList(Must: boolean); procedure ReadGenericParamList(Must, AllowConstraints: boolean);
procedure ReadAttribute; procedure ReadAttribute;
procedure FixLastAttributes; procedure FixLastAttributes;
procedure ReadTypeReference(CreateNodes: boolean); procedure ReadTypeReference(CreateNodes: boolean);
@ -345,13 +345,16 @@ end;
{ TPascalParserTool } { TPascalParserTool }
// inline // inline
procedure TPascalParserTool.CheckOperatorProc(IsOperator: boolean; procedure TPascalParserTool.CheckOperatorProc(
var IsFunction: boolean); var ParseAttr: TParseProcHeadAttributes);
begin begin
if IsOperator then begin if pphIsOperator in ParseAttr then begin
AtomIsCustomOperator(true,true,true); AtomIsCustomOperator(true,true,true);
IsFunction:=not (UpAtomIs('INITIALIZE') or UpAtomIs('FINALIZE') if (UpAtomIs('INITIALIZE') or UpAtomIs('FINALIZE')
or UpAtomIs('ADDREF') or UpAtomIs('COPY')); or UpAtomIs('ADDREF') or UpAtomIs('COPY')) then
Exclude(ParseAttr,pphIsFunction)
else
Include(ParseAttr,pphIsFunction);
end else end else
AtomIsIdentifierSaveE; AtomIsIdentifierSaveE;
end; end;
@ -1283,9 +1286,9 @@ function TPascalParserTool.KeyWordFuncClassMethod: boolean;
enumerator <id> enumerator <id>
compilerproc[:name] compilerproc[:name]
} }
var IsFunction, HasForwardModifier: boolean; var
HasForwardModifier: boolean;
ParseAttr: TParseProcHeadAttributes; ParseAttr: TParseProcHeadAttributes;
IsOperator: Boolean;
begin begin
if (CurNode.Desc in AllClassSubSections) if (CurNode.Desc in AllClassSubSections)
and (CurNode.Parent.Desc in (AllClassBaseSections+AllClassInterfaces)) then begin and (CurNode.Parent.Desc in (AllClassBaseSections+AllClassInterfaces)) then begin
@ -1298,6 +1301,7 @@ begin
end; end;
HasForwardModifier:=false; HasForwardModifier:=false;
ParseAttr:=[pphIsMethodDecl,pphCreateNodes];
// create class method node // create class method node
CreateChildNode; CreateChildNode;
CurNode.Desc:=ctnProcedure; CurNode.Desc:=ctnProcedure;
@ -1312,21 +1316,21 @@ begin
end; end;
end; end;
// read procedure head // read procedure head
IsFunction:=UpAtomIs('FUNCTION'); if UpAtomIs('FUNCTION') then
IsOperator:=(not IsFunction) and UpAtomIs('OPERATOR'); Include(ParseAttr,pphIsFunction)
else if UpAtomIs('OPERATOR') then
Include(ParseAttr,pphIsOperator);
// read name // read name
ReadNextAtom; ReadNextAtom;
CheckOperatorProc(IsOperator,IsFunction);
// create node for procedure head // create node for procedure head
CreateChildNode; CreateChildNode;
CurNode.Desc:=ctnProcedureHead; CurNode.Desc:=ctnProcedureHead;
CheckOperatorProc(ParseAttr);
ReadNextAtom; ReadNextAtom;
if Scanner.CompilerMode=cmDELPHI then
ReadGenericParamList(false,true);
if (CurPos.Flag<>cafPoint) then begin if (CurPos.Flag<>cafPoint) then begin
// read rest // read rest
CurNode.SubDesc:=ctnsNeedJITParsing;
ParseAttr:=[pphIsMethodDecl];
if IsFunction then Include(ParseAttr,pphIsFunction);
if IsOperator then Include(ParseAttr,pphIsOperator);
ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier); ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier);
end else begin end else begin
// Method resolution clause (e.g. function Intf.Method = Method_Name) // Method resolution clause (e.g. function Intf.Method = Method_Name)
@ -1742,8 +1746,6 @@ begin
Result:=true; Result:=true;
HasForwardModifier:=false; HasForwardModifier:=false;
ReadGenericParamList(pphIsGeneric in ParseAttr);
if CurPos.Flag=cafRoundBracketOpen then begin if CurPos.Flag=cafRoundBracketOpen then begin
Attr:=[]; Attr:=[];
if pphCreateNodes in ParseAttr then if pphCreateNodes in ParseAttr then
@ -2719,17 +2721,15 @@ function TPascalParserTool.KeyWordFuncProc: boolean;
// class function/procedure // class function/procedure
// generic function/procedure // generic function/procedure
var var
ChildCreated: boolean; HasForwardModifier, IsClassProc: boolean;
IsFunction, HasForwardModifier, IsClassProc, IsOperator, IsMethod,
IsGeneric: boolean;
ProcNode: TCodeTreeNode; ProcNode: TCodeTreeNode;
ParseAttr: TParseProcHeadAttributes; ParseAttr: TParseProcHeadAttributes;
begin begin
ParseAttr:=[pphCreateNodes];
if UpAtomIs('GENERIC') then begin if UpAtomIs('GENERIC') then begin
IsGeneric:=true; Include(ParseAttr,pphIsGeneric);
ReadNextAtom; ReadNextAtom;
end else end;
IsGeneric:=false;
if UpAtomIs('CLASS') then begin if UpAtomIs('CLASS') then begin
if not (CurSection in [ctnImplementation]+AllSourceTypes) then if not (CurSection in [ctnImplementation]+AllSourceTypes) then
SaveRaiseStringExpectedButAtomFound(20170421195603,ctsIdentifier); SaveRaiseStringExpectedButAtomFound(20170421195603,ctsIdentifier);
@ -2742,54 +2742,44 @@ begin
ctsProcedureOrFunctionOrConstructorOrDestructor); ctsProcedureOrFunctionOrConstructorOrDestructor);
end else end else
IsClassProc:=false; IsClassProc:=false;
ChildCreated:=true; // create node for procedure
if ChildCreated then begin CreateChildNode;
// create node for procedure if IsClassProc then
CreateChildNode; CurNode.StartPos:=LastAtoms.GetPriorAtom.StartPos;
if IsClassProc then ProcNode:=CurNode;
CurNode.StartPos:=LastAtoms.GetPriorAtom.StartPos; ProcNode.Desc:=ctnProcedure;
ProcNode:=CurNode; if CurSection=ctnInterface then
ProcNode.Desc:=ctnProcedure; ProcNode.SubDesc:=ctnsForwardDeclaration;
if CurSection=ctnInterface then if UpAtomIs('FUNCTION') then
ProcNode.SubDesc:=ctnsForwardDeclaration; Include(ParseAttr,pphIsFunction)
end; else if UpAtomIs('OPERATOR') then
IsFunction:=UpAtomIs('FUNCTION'); Include(ParseAttr,pphIsOperator);
IsOperator:=(not IsFunction) and UpAtomIs('OPERATOR');
IsMethod:=False;
ReadNextAtom;// read first atom of head (= name/operator + parameterlist + resulttype;) ReadNextAtom;// read first atom of head (= name/operator + parameterlist + resulttype;)
CheckOperatorProc(IsOperator,IsFunction); // create node for procedure head
if ChildCreated then begin CreateChildNode;
// create node for procedure head CurNode.Desc:=ctnProcedureHead;
CreateChildNode; CheckOperatorProc(ParseAttr);
CurNode.Desc:=ctnProcedureHead;
CurNode.SubDesc:=ctnsNeedJITParsing;
end;
ReadNextAtom; ReadNextAtom;
ReadGenericParamList(false,true);
if (CurSection<>ctnInterface) then begin if (CurSection<>ctnInterface) then begin
while (CurPos.Flag=cafPoint) do begin while (CurPos.Flag=cafPoint) do begin
// read procedure name of a class method (the name after the . ) // read procedure name of a class method (the name after the . )
IsMethod:=True; Include(ParseAttr,pphIsMethodBody);
ReadNextAtom; ReadNextAtom;
CheckOperatorProc(IsOperator,IsFunction); CheckOperatorProc(ParseAttr);
ReadNextAtom; ReadNextAtom;
ReadGenericParamList(false,true);
end; end;
end; end;
// read rest of procedure head // read rest of procedure head
HasForwardModifier:=false; HasForwardModifier:=false;
ParseAttr:=[];
if IsFunction then Include(ParseAttr,pphIsFunction);
if IsOperator then Include(ParseAttr,pphIsOperator);
if IsMethod then Include(ParseAttr,pphIsMethodBody);
if IsGeneric then Include(ParseAttr,pphIsGeneric);
ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier); ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier);
if ChildCreated then begin if HasForwardModifier then
if HasForwardModifier then ProcNode.SubDesc:=ctnsForwardDeclaration;
ProcNode.SubDesc:=ctnsForwardDeclaration; // close head
// close head CurNode.EndPos:=CurPos.EndPos;
CurNode.EndPos:=CurPos.EndPos; EndChildNode;
EndChildNode; if ((ProcNode.SubDesc and ctnsForwardDeclaration)>0) then
end;
if ChildCreated and ((ProcNode.SubDesc and ctnsForwardDeclaration)>0) then
begin begin
// close method // close method
CurNode.EndPos:=CurPos.EndPos; CurNode.EndPos:=CurPos.EndPos;
@ -4081,7 +4071,7 @@ begin
//debugln(['TPascalParserTool.ReadTypeNameAndDefinition Name="',copy(Src,NamePos.StartPos,NamePos.EndPos-NamePos.StartPos),'"']); //debugln(['TPascalParserTool.ReadTypeNameAndDefinition Name="',copy(Src,NamePos.StartPos,NamePos.EndPos-NamePos.StartPos),'"']);
EndChildNode; EndChildNode;
// read generic parameter list // read generic parameter list
ReadGenericParamList(IsGeneric); ReadGenericParamList(IsGeneric,true);
end; end;
// read = // read =
if (CurPos.Flag<>cafEqual) then if (CurPos.Flag<>cafEqual) then
@ -4100,7 +4090,7 @@ begin
EndChildNode; EndChildNode;
end; end;
procedure TPascalParserTool.ReadGenericParamList(Must: boolean); procedure TPascalParserTool.ReadGenericParamList(Must, AllowConstraints: boolean);
{ At start cursor is on < { At start cursor is on <
At end cursor is on atom after > At end cursor is on atom after >
@ -4144,7 +4134,7 @@ begin
ReadNextAtom; ReadNextAtom;
end else if AtomIsChar('>') then begin end else if AtomIsChar('>') then begin
break; break;
end else if CurPos.Flag=cafColon then begin end else if AllowConstraints and (CurPos.Flag=cafColon) then begin
// read constraints // read constraints
ReadNextAtom; ReadNextAtom;
if CurPos.Flag<>cafNone then begin if CurPos.Flag<>cafNone then begin
@ -4183,9 +4173,11 @@ begin
// close ctnGenericParameter // close ctnGenericParameter
EndChildNode; EndChildNode;
end else begin end else begin
if AtomIs('>=') then if AtomIs('>=') then begin
// this is the rare case where >= are two separate atoms // this is the rare case where >= are two separate atoms
dec(CurPos.EndPos); dec(CurPos.EndPos);
LastAtoms.SetCurrent(CurPos);
end;
if not AtomIsChar('>') then if not AtomIsChar('>') then
SaveRaiseCharExpectedButAtomFound(20170421195745,'>'); SaveRaiseCharExpectedButAtomFound(20170421195745,'>');
end; end;
@ -6020,9 +6012,8 @@ end;
procedure TPascalParserTool.BuildSubTreeForProcHead(ProcNode: TCodeTreeNode); procedure TPascalParserTool.BuildSubTreeForProcHead(ProcNode: TCodeTreeNode);
var var
HasForwardModifier, IsFunction, IsOperator, IsMethod: boolean; HasForwardModifier, IsFunction: boolean;
ParseAttr: TParseProcHeadAttributes; ParseAttr: TParseProcHeadAttributes;
IsProcType, IsGeneric: Boolean;
ProcHeadNode: TCodeTreeNode; ProcHeadNode: TCodeTreeNode;
begin begin
if ProcNode.Desc=ctnProcedureHead then ProcNode:=ProcNode.Parent; if ProcNode.Desc=ctnProcedureHead then ProcNode:=ProcNode.Parent;
@ -6053,48 +6044,49 @@ begin
RaiseNodeParserError(ProcHeadNode); RaiseNodeParserError(ProcHeadNode);
exit; exit;
end; end;
ParseAttr:=[pphCreateNodes];
try try
IsMethod:=(ProcNode.Parent<>nil) and (ProcNode.Parent.Desc in (AllClasses+AllClassSections)); if (ProcNode.Parent<>nil) and (ProcNode.Parent.Desc in (AllClasses+AllClassSections)) then
Include(ParseAttr,pphIsMethodDecl);
MoveCursorToNodeStart(ProcNode); MoveCursorToNodeStart(ProcNode);
ReadNextAtom; ReadNextAtom;
if (Scanner.CompilerMode in [cmOBJFPC,cmFPC]) and UpAtomIs('GENERIC') then begin if (Scanner.CompilerMode in [cmOBJFPC,cmFPC]) and UpAtomIs('GENERIC') then begin
IsGeneric:=true; Include(ParseAttr,pphIsGeneric);
CurNode.Desc:=ctnGenericType; CurNode.Desc:=ctnGenericType;
ReadNextAtom; ReadNextAtom;
end else end;
IsGeneric:=false;
if UpAtomIs('CLASS') then if UpAtomIs('CLASS') then
ReadNextAtom; ReadNextAtom;
IsFunction:=UpAtomIs('FUNCTION'); if UpAtomIs('FUNCTION') then begin
IsOperator:=(not IsFunction) and UpAtomIs('OPERATOR'); IsFunction:=true;
IsProcType:=ProcNode.Desc=ctnProcedureType; Include(ParseAttr,pphIsFunction);
end else
IsFunction:=false;
if (not IsFunction) and UpAtomIs('OPERATOR') then
Include(ParseAttr,pphIsOperator);
if ProcNode.Desc=ctnProcedureType then
Include(ParseAttr,pphIsType);
// read procedure head (= [name[<parameters>]] + parameterlist + resulttype;) // read procedure head (= [name[<parameters>]] + parameterlist + resulttype;)
ReadNextAtom;// read first atom of head ReadNextAtom;// read first atom of head
CurNode:=ProcHeadNode; CurNode:=ProcHeadNode;
if CurNode=nil then if CurNode=nil then
if IsProcType then if pphIsType in ParseAttr then
SaveRaiseCharExpectedButAtomFound(20170421195925,';') SaveRaiseCharExpectedButAtomFound(20170421195925,';')
else else
SaveRaiseStringExpectedButAtomFound(20170421195928,'identifier'); SaveRaiseStringExpectedButAtomFound(20170421195928,'identifier');
ProcHeadNode.SubDesc:=ProcHeadNode.SubDesc and (not ctnsNeedJITParsing); ProcHeadNode.SubDesc:=ProcHeadNode.SubDesc and (not ctnsNeedJITParsing);
if not IsProcType then begin if not (pphIsType in ParseAttr) then begin
// read procedure name of a class method (the name after the . ) // read procedure name of a class method (the name after the . )
repeat repeat
CheckOperatorProc(IsOperator,IsFunction); CheckOperatorProc(ParseAttr);
ReadNextAtom; ReadGenericParamList(false,false);
if CurPos.Flag<>cafPoint then break; if CurPos.Flag<>cafPoint then break;
ReadNextAtom; ReadNextAtom;
until false; until false;
end; end;
// read rest of procedure head and build nodes // read rest of procedure head and build nodes
HasForwardModifier:=false; HasForwardModifier:=false;
ParseAttr:=[pphCreateNodes];
if IsMethod then Include(ParseAttr,pphIsMethodDecl);
if IsFunction then Include(ParseAttr,pphIsFunction);
if IsOperator then Include(ParseAttr,pphIsOperator);
if IsProcType then Include(ParseAttr,pphIsType);
if IsGeneric then Include(ParseAttr,pphIsGeneric);
ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier); ReadTilProcedureHeadEnd(ParseAttr,HasForwardModifier);
except except
{$IFDEF ShowIgnoreErrorAfter} {$IFDEF ShowIgnoreErrorAfter}