diff --git a/components/codetools/basiccodetools.pas b/components/codetools/basiccodetools.pas index 866a97a424..01880f8b53 100644 --- a/components/codetools/basiccodetools.pas +++ b/components/codetools/basiccodetools.pas @@ -2511,75 +2511,102 @@ function FindLineEndOrCodeInFrontOfPosition(const Source: string; 2: a:=1; 1: b:=1; | - 2: // comment - 3: // comment + 2: // comment for below + 3: // comment for below 4: a:=1; 1: | - 2: /* */ + 2: (* comment belongs to the following line *) 3: a:=1; - 1: end;| /* - 2: */ a:=1; + 1: end; (* comment belongs to the first line + 2: *)| a:=1; 1: b:=1; // comment | 2: a:=1; - 1: b:=1; /* - 2: comment */ | + 1: b:=1; (* + 2: comment *) | 3: a:=1; } var SrcStart: integer; - function ReadComment(var P: integer; SubComment: boolean): boolean; + function IsSpace(c: char): boolean; + begin + if SkipSemicolonComma then + Result:=c in [' ',#9,';',','] + else + Result:=c in [' ',#9]; + end; + + function ReadComment(var p: integer; SubComment: boolean): boolean; // true if comment was skipped - // false if not skipped, because comment is compiler directive + // false if not skipped, because comment is compiler directive or simple bracket var OldP: integer; IsDirective: Boolean; begin - //debugln(['ReadComment ',dbgstr(copy(Source,p-5,5))+'|'+Source[P]+dbgstr(copy(Source,p+1,5))]); - OldP:=P; - IsDirective:=false; - case Source[P] of - '}': - begin - dec(P); - while (P>=SrcStart) and (Source[P]<>'{') do begin - if NestedComments and (Source[P]='}') then - ReadComment(P,true) - else - dec(P); - end; - IsDirective:=(P>=SrcStart) and (Source[P+1]='$'); - dec(P); - end; - ')': - begin - dec(P); - if (P>=SrcStart) and (Source[P]='*') then begin - dec(P); - while (P>SrcStart) - and ((Source[P-1]<>'(') or (Source[P]<>'*')) do begin - if NestedComments and ((Source[P]=')') and (Source[P-1]='*')) then - ReadComment(P,true) + //debugln(['ReadComment ',dbgstr(copy(Source,p-5,5))+'|'+Source[p]+dbgstr(copy(Source,p+1,5))]); + OldP:=p+1; + repeat + IsDirective:=false; + case Source[p] of + '}': + begin + dec(p); + while (p>SrcStart) and (Source[p]<>'{') do begin + if NestedComments and (Source[p]='}') then + ReadComment(p,true) else - dec(P); + dec(p); end; - IsDirective:=(P>=SrcStart) and (Source[P+1]='$'); - dec(P,2); - end else begin - // normal bracket - // => position behind code - inc(p); - Result:=false; - exit; + IsDirective:=(p>=SrcStart) and (Source[p+1]='$'); + dec(p); end; - end; - else - exit(true); - end; - Result:=(not IsDirective) or (not StopAtDirectives) or SubComment; - if not Result then P:=OldP+1; + ')': + begin + dec(p); + if (p>SrcStart) and (Source[p]='*') then begin + dec(p); + while (p>SrcStart) + and ((Source[p-1]<>'(') or (Source[p]<>'*')) do begin + if NestedComments and ((Source[p]=')') and (Source[p-1]='*')) then + ReadComment(p,true) + else + dec(p); + end; + IsDirective:=(p>=SrcStart) and (Source[p+1]='$'); + dec(p,2); + end else begin + // normal bracket + // => position behind code + p:=OldP; + exit(false); + end; + end; + else + exit(true); + end; + if SubComment then exit(true); // always skip nested comments + if IsDirective and StopAtDirectives then begin + // directive can not be skipped + p:=OldP; + exit(false); + end; + // it is a normal comment + // check if it belongs to the code in front + while (p>=SrcStart) and IsSpace(Source[p]) do + dec(p); + if (p comment can be skipped + exit(true); + end; + if not (Source[p] in [')','}']) then begin + // code => comment belongs to code in front + p:=OldP; + exit(false); + end; + // read next comment + until false; end; var @@ -2587,46 +2614,47 @@ var LineStartPos: LongInt; IsEmpty: Boolean; LineEndPos: Integer; + p: LongInt; begin SrcStart:=MinPosition; if SrcStart<1 then SrcStart:=1; - if Position<=SrcStart then begin + if (Position<=SrcStart) then begin Result:=SrcStart; exit; end; // simple heuristic - // will fail on lines: // } - Result:=Position-1; - if Result>length(Source) then Result:=length(Source); - while (Result>=SrcStart) do begin - case Source[Result] of - '}',')': - if not ReadComment(Result,false) then exit; - + // will fail on lines: // } + Result:=-1; + p:=Position-1; + if p>length(Source) then p:=length(Source); + while (p>=SrcStart) do begin + case Source[p] of #10,#13: begin - // line end in code found - if (Result>SrcStart) and (Source[Result-1] in [#10,#13]) - and (Source[Result]<>Source[Result-1]) then - dec(Result); - LineEndPos:=Result; // start of line end + // line end found (outside comments) + if (p>SrcStart) and (Source[p-1] in [#10,#13]) + and (Source[p]<>Source[p-1]) then + dec(p); + LineEndPos:=p; // start of line end + Result:=LineEndPos; // test if in a // comment - LineStartPos:=Result; + LineStartPos:=p; IsEmpty:=true; while (LineStartPos>SrcStart) do begin case Source[LineStartPos-1] of #10,#13: break; ' ',#9: ; + ';',',': if not SkipSemicolonComma then IsEmpty:=false; else IsEmpty:=false; end; dec(LineStartPos); end; if IsEmpty then begin // the line is empty => return start of line end - Result:=LineEndPos; + p:=LineEndPos; if SkipEmptyLines then begin // skip all empty lines - LineStartPos:=Result; + LineStartPos:=p; while (LineStartPos>SrcStart) do begin case Source[LineStartPos-1] of #10,#13: @@ -2636,7 +2664,7 @@ begin if (LineEndPos>SrcStart) and (Source[LineEndPos-1] in [#10,#13]) and (Source[LineEndPos]<>Source[LineEndPos-1]) then dec(LineEndPos); - Result:=LineEndPos; + p:=LineEndPos; end; ' ',#9: ; else @@ -2646,37 +2674,41 @@ begin dec(LineStartPos); end; end; - exit; + break; end; + // line is not empty TestPos:=LineStartPos; while (Source[TestPos] in [' ',#9]) do inc(TestPos); if (Source[TestPos]='/') and (Source[TestPos+1]='/') then begin // the whole line is a // comment - // this comment belongs to the code + // this comment belongs to the code behind // => continue on next line - Result:=LineStartPos-1; + p:=LineStartPos-1; continue; end; - dec(Result); + dec(p); end; + '}',')': + if not ReadComment(p,false) then break; ' ',#9: - dec(Result); + dec(p); ';',',': begin - if StopAtDirectives then begin + if not SkipSemicolonComma then begin // code found - inc(Result); - exit; + inc(p); + break; end; - dec(Result); + dec(p); end; else // code found - inc(Result); - exit; + inc(p); + break; end; end; + if Result<1 then Result:=p; if Resultnil) and (Result.Desc<>Desc) do + Result:=Result.NextBrother; +end; + procedure TCodeTree.ConsistencyCheck; var RealNodeCount: integer; diff --git a/components/codetools/pascalparsertool.pas b/components/codetools/pascalparsertool.pas index adeb6f1f6a..35989d0d4a 100644 --- a/components/codetools/pascalparsertool.pas +++ b/components/codetools/pascalparsertool.pas @@ -246,6 +246,7 @@ type function FindPrevNodeOnSameLvl(StartNode: TCodeTreeNode): TCodeTreeNode; // sections + function FindRootNode(Desc: TCodeTreeNodeDesc): TCodeTreeNode; function FindInterfaceNode: TCodeTreeNode; function FindImplementationNode: TCodeTreeNode; function FindInitializationNode: TCodeTreeNode; @@ -4665,6 +4666,12 @@ begin end; end; +function TPascalParserTool.FindRootNode(Desc: TCodeTreeNodeDesc + ): TCodeTreeNode; +begin + Result:=Tree.FindRootNode(Desc); +end; + function TPascalParserTool.NodeHasParentOfType(ANode: TCodeTreeNode; NodeDesc: TCodeTreeNodeDesc): boolean; begin @@ -5119,30 +5126,22 @@ end; function TPascalParserTool.FindInterfaceNode: TCodeTreeNode; begin - Result:=Tree.Root; - while (Result<>nil) and (Result.Desc<>ctnInterface) do - Result:=Result.NextBrother; + Result:=FindRootNode(ctnInterface); end; function TPascalParserTool.FindImplementationNode: TCodeTreeNode; begin - Result:=Tree.Root; - while (Result<>nil) and (Result.Desc<>ctnImplementation) do - Result:=Result.NextBrother; + Result:=FindRootNode(ctnImplementation); end; function TPascalParserTool.FindInitializationNode: TCodeTreeNode; begin - Result:=Tree.Root; - while (Result<>nil) and (Result.Desc<>ctnInitialization) do - Result:=Result.NextBrother; + Result:=FindRootNode(ctnInitialization); end; function TPascalParserTool.FindFinalizationNode: TCodeTreeNode; begin - Result:=Tree.Root; - while (Result<>nil) and (Result.Desc<>ctnFinalization) do - Result:=Result.NextBrother; + Result:=FindRootNode(ctnFinalization); end; function TPascalParserTool.FindMainBeginEndNode: TCodeTreeNode;