codetools: fixed parsing sub proc of anonymous proc

This commit is contained in:
mattias 2021-11-18 22:38:59 +01:00
parent cab7a17b80
commit f84b6b1c5a
4 changed files with 57 additions and 42 deletions

View File

@ -0,0 +1 @@
sourcecloser

View File

@ -252,7 +252,7 @@ type
Copying: boolean = false; const Attr: TProcHeadAttributes = []); Copying: boolean = false; const Attr: TProcHeadAttributes = []);
procedure ReadAnsiStringParams(Extract: boolean = false; procedure ReadAnsiStringParams(Extract: boolean = false;
Copying: boolean = false; const Attr: TProcHeadAttributes = []); Copying: boolean = false; const Attr: TProcHeadAttributes = []);
function ReadClosure(ExceptionOnError, CreateNodes: boolean): boolean; function ReadClosure(ExceptionOnError: boolean): boolean;
function SkipTypeReference(ExceptionOnError: boolean): boolean; function SkipTypeReference(ExceptionOnError: boolean): boolean;
function SkipSpecializeParams(ExceptionOnError: boolean): boolean; function SkipSpecializeParams(ExceptionOnError: boolean): boolean;
function WordIsPropertyEnd: boolean; function WordIsPropertyEnd: boolean;
@ -1095,7 +1095,7 @@ begin
end else if UpAtomIs('WITH') then end else if UpAtomIs('WITH') then
ReadWithStatement(true,true) ReadWithStatement(true,true)
else if (UpAtomIs('PROCEDURE') or UpAtomIs('FUNCTION')) and AllowClosures then else if (UpAtomIs('PROCEDURE') or UpAtomIs('FUNCTION')) and AllowClosures then
ReadClosure(true,true); ReadClosure(true);
until false; until false;
except except
{$IFDEF ShowIgnoreErrorAfter} {$IFDEF ShowIgnoreErrorAfter}
@ -3040,7 +3040,7 @@ begin
ReadOnStatement(true,CreateNodes); ReadOnStatement(true,CreateNodes);
end else if (UpAtomIs('PROCEDURE') or UpAtomIs('FUNCTION')) end else if (UpAtomIs('PROCEDURE') or UpAtomIs('FUNCTION'))
and AllowClosures then begin and AllowClosures then begin
ReadClosure(true,CreateNodes); ReadClosure(true);
end else begin end else begin
// check for unexpected keywords // check for unexpected keywords
case BlockType of case BlockType of
@ -6111,8 +6111,7 @@ begin
until false; until false;
end; end;
function TPascalParserTool.ReadClosure(ExceptionOnError, CreateNodes: boolean function TPascalParserTool.ReadClosure(ExceptionOnError: boolean): boolean;
): boolean;
{ parse parameter list, result type, calling convention, begin..end { parse parameter list, result type, calling convention, begin..end
examples: examples:
@ -6126,6 +6125,7 @@ var
Attr: TProcHeadAttributes; Attr: TProcHeadAttributes;
IsFunction: boolean; IsFunction: boolean;
Last: TAtomPosition; Last: TAtomPosition;
ProcNode: TCodeTreeNode;
begin begin
Result:=false; Result:=false;
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
@ -6139,29 +6139,25 @@ begin
else else
exit; exit;
end; end;
// create node for procedure // create node for procedure
if CreateNodes then begin CreateChildNode;
CreateChildNode; CurNode.Desc:=ctnProcedure;
CurNode.Desc:=ctnProcedure; ProcNode:=CurNode;
end;
IsFunction:=UpAtomIs('FUNCTION'); IsFunction:=UpAtomIs('FUNCTION');
ReadNextAtom;// read first atom of head ReadNextAtom;// read first atom of head
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure head start ',GetAtom); writeln('TPascalParserTool.ReadClosure head start ',GetAtom);
{$ENDIF} {$ENDIF}
if CreateNodes then begin CreateChildNode;
CreateChildNode; CurNode.Desc:=ctnProcedureHead;
CurNode.Desc:=ctnProcedureHead;
end;
// read parameter list // read parameter list
if CurPos.Flag=cafRoundBracketOpen then begin if CurPos.Flag=cafRoundBracketOpen then begin
Attr:=[]; Attr:=[phpCreateNodes];
if CreateNodes then
Include(Attr,phpCreateNodes);
ReadParamList(true,false,Attr); ReadParamList(true,false,Attr);
end; end;
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure head end ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc)); writeln('TPascalParserTool.ReadClosure head end "',GetAtom,'" CurNode=',NodeDescToStr(CurNode.Desc));
{$ENDIF} {$ENDIF}
// read function result // read function result
if IsFunction then begin if IsFunction then begin
@ -6172,7 +6168,7 @@ begin
exit; exit;
end; end;
ReadNextAtom; ReadNextAtom;
ReadTypeReference(CreateNodes); ReadTypeReference(true);
end; end;
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure modifiers ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc)); writeln('TPascalParserTool.ReadClosure modifiers ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc));
@ -6181,22 +6177,17 @@ begin
while (CurPos.StartPos<=SrcLen) while (CurPos.StartPos<=SrcLen)
and IsKeyWordProcedureAnonymousSpecifier.DoIdentifier(@Src[CurPos.StartPos]) do and IsKeyWordProcedureAnonymousSpecifier.DoIdentifier(@Src[CurPos.StartPos]) do
ReadNextAtom; ReadNextAtom;
// close head // close ctnProcedureHead
if CreateNodes then begin CurNode.EndPos:=CurPos.StartPos;
// close ctnProcedureHead EndChildNode;
CurNode.EndPos:=CurPos.StartPos;
EndChildNode;
end;
repeat repeat
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure body ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc)); writeln('TPascalParserTool.ReadClosure body ',GetAtom,' CurNode=',NodePathAsString(CurNode));
{$ENDIF} {$ENDIF}
if CurPos.Flag=cafSemicolon then begin if CurPos.Flag=cafSemicolon then begin
ReadNextAtom; end else if UpAtomIs('BEGIN') or UpAtomIs('ASM') then begin
end else if UpAtomIs('BEGIN') then begin if not KeyWordFuncBeginEnd then exit;
break; if CurNode=ProcNode.Parent then break;
end else if UpAtomIs('ASM') then begin
break;
end else if UpAtomIs('TYPE') then begin end else if UpAtomIs('TYPE') then begin
if not KeyWordFuncType then exit; if not KeyWordFuncType then exit;
end else if UpAtomIs('VAR') then begin end else if UpAtomIs('VAR') then begin
@ -6217,20 +6208,8 @@ begin
until false; until false;
// read begin block // read begin block
{$IFDEF VerboseReadClosure} {$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure begin/asm ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc));
{$ENDIF}
// search "end"
ReadTilBlockEnd(false,CreateNodes);
{$IFDEF VerboseReadClosure}
writeln('TPascalParserTool.ReadClosure END ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc),' ',CurPos.EndPos); writeln('TPascalParserTool.ReadClosure END ',GetAtom,' CurNode=',NodeDescToStr(CurNode.Desc),' ',CurPos.EndPos);
{$ENDIF} {$ENDIF}
if CreateNodes then begin
// close procedure node
if CurNode.Desc<>ctnProcedure then
RaiseUnexpectedKeyWord(20181218125659);
CurNode.EndPos:=CurPos.EndPos;
EndChildNode;
end;
end; end;
function TPascalParserTool.SkipTypeReference(ExceptionOnError: boolean): boolean; function TPascalParserTool.SkipTypeReference(ExceptionOnError: boolean): boolean;

2
components/codetools/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
codetools.config
runtestscodetools

View File

@ -54,6 +54,7 @@ type
procedure TestParseIFOpt; procedure TestParseIFOpt;
procedure TestParseProcAnoAssign; procedure TestParseProcAnoAssign;
procedure TestParseProcAnoArg; procedure TestParseProcAnoArg;
procedure TestParseProcAnoArgSubFunc;
procedure TestParseThreadVar; procedure TestParseThreadVar;
end; end;
@ -566,6 +567,38 @@ begin
ParseModule; ParseModule;
end; end;
procedure TTestPascalParser.TestParseProcAnoArgSubFunc;
begin
Add([
'program test1;',
'{$mode objfpc}',
'{$modeswitch closures}',
'procedure DoIt;',
'begin',
' DoIt(',
' procedure',
' function Fly: word;',
' begin InFly; end;',
' begin InAno1;',
' end);',
' DoIt(',
' procedure(v: word)',
' function Run: word;',
' begin InRun end;',
' begin InAno2;',
' end);',
'end;',
'begin',
' DoIt(',
' procedure',
' function Say: word;',
' begin InSay; end;',
' begin InAno3;',
' end);',
'']);
ParseModule;
end;
procedure TTestPascalParser.TestParseThreadVar; procedure TTestPascalParser.TestParseThreadVar;
begin begin
Add([ Add([