mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-15 14:29:31 +02:00
Jedi code format: Improved error messages. Issue #41144
This commit is contained in:
parent
f8ef2a93e6
commit
ec16b7c23b
@ -331,7 +331,7 @@ begin
|
||||
fcConverter.GuiMessages := true;
|
||||
fcConverter.FileName := SourceEditorManagerIntf.ActiveEditor.FileName;
|
||||
fcConverter.OnIncludeFile := OnIncludeFile;
|
||||
fcConverter.ConvertUsingFakeUnit;
|
||||
fcConverter.ConvertUsingFakeUnit(BlockBegin.Y);
|
||||
if not fcConverter.ConvertError then
|
||||
begin
|
||||
outputstr:=StrTrimLastEndOfLine(fcConverter.OutputCode);
|
||||
|
@ -44,7 +44,7 @@ uses
|
||||
|
||||
type
|
||||
|
||||
EBuildTokenListWarning=Exception;
|
||||
EBuildTokenListWarning= type Exception;
|
||||
|
||||
TBuildTokenListFlag=(btlOnlyDirectives);
|
||||
TBuildTokenListFlags = set of TBuildTokenListFlag;
|
||||
@ -245,6 +245,7 @@ function TBuildTokenList.TryBracketStarComment(const pcToken: TSourceToken): boo
|
||||
var
|
||||
liCommentLength, lNestedDepth: integer;
|
||||
bPossiblyImbalanced: Boolean;
|
||||
liCommentStart, liLine, liCol:integer;
|
||||
|
||||
procedure MoveToCommentEnd;
|
||||
var
|
||||
@ -260,6 +261,9 @@ var
|
||||
// $ (US): 2021-06-28 15:48:59 $
|
||||
// Although it is not a parse error, but I do not want to introduce
|
||||
// another exception class.
|
||||
FindLineCol(fsSourceCode, liCommentStart, liLine, liCol);
|
||||
pcToken.XPosition := liCol;
|
||||
pcToken.YPosition := liLine;
|
||||
raise TEParseError.Create(lisMsgUnableToRecoverImbalancedBracketStarComment, pcToken);
|
||||
end else
|
||||
begin
|
||||
@ -305,6 +309,7 @@ begin
|
||||
if CurrentChars(2) <> '(*' then
|
||||
exit;
|
||||
|
||||
liCommentStart := fiCurrentIndex;
|
||||
lNestedDepth := 1;
|
||||
{ if the comment starts with (*) that is not the end of the comment }
|
||||
liCommentLength := 2;
|
||||
@ -329,6 +334,7 @@ function TBuildTokenList.TryCurlyComment(const pcToken: TSourceToken): boolean;
|
||||
var
|
||||
liCommentLength, lNestedDepth: integer;
|
||||
bPossiblyImbalanced: Boolean;
|
||||
liCommentStart, liLine, liCol:integer;
|
||||
|
||||
procedure MoveToCommentEnd;
|
||||
var
|
||||
@ -344,6 +350,9 @@ var
|
||||
// $ (US): 2021-06-28 15:48:59 $
|
||||
// Although it is not a parse error, but I do not want to introduce
|
||||
// another exception class.
|
||||
FindLineCol(fsSourceCode, liCommentStart, liLine, liCol);
|
||||
pcToken.XPosition := liCol;
|
||||
pcToken.YPosition := liLine;
|
||||
raise TEParseError.Create(lisMsgUnableToRecoverImbalancedCurlyComment, pcToken);
|
||||
end else
|
||||
begin
|
||||
@ -375,6 +384,7 @@ begin
|
||||
if Current <> '{' then
|
||||
exit;
|
||||
|
||||
liCommentStart := fiCurrentIndex;
|
||||
bPossiblyImbalanced := False;
|
||||
|
||||
pcToken.TokenType := ttComment;
|
||||
@ -500,8 +510,10 @@ function TBuildTokenList.TryMultiLineLiteralString(const pcToken: TSourceToken):
|
||||
var
|
||||
liCount,liAux:integer;
|
||||
liCountEnd:integer;
|
||||
liLiteralStart, liLine, liCol, liPos:integer;
|
||||
begin
|
||||
Result := False;
|
||||
liLiteralStart := fiCurrentIndex;
|
||||
liCount:=0;
|
||||
while ForwardChar(liCount)=NativeSingleQuote do
|
||||
Inc(liCount);
|
||||
@ -520,7 +532,13 @@ begin
|
||||
{ read until the close ''' }
|
||||
repeat
|
||||
if Current = #0 then
|
||||
raise TEParseError.Create(Format(lisMsgUnterminatedString,[pcToken.SourceCode]),pcToken);
|
||||
begin
|
||||
FindLineCol(fsSourceCode, liLiteralStart, liLine, liCol);
|
||||
pcToken.XPosition := liCol;
|
||||
pcToken.YPosition := liLine;
|
||||
liPos := 1;
|
||||
raise TEParseError.Create(Format(lisMsgUnterminatedString,[ExtractSubStr(pcToken.SourceCode,liPos,[#13,#10])]),pcToken);
|
||||
end;
|
||||
|
||||
if (Current = NativeSingleQuote) then
|
||||
begin
|
||||
@ -549,9 +567,12 @@ end;
|
||||
{ complexities like 'Hello'#32'World' and #$12'Foo' are assemlbed in the parser }
|
||||
function TBuildTokenList.TryLiteralString(const pcToken: TSourceToken;
|
||||
const pcDelimiter: Char): boolean;
|
||||
var
|
||||
liLiteralStart, liLine, liCol: integer;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
liLiteralStart := fiCurrentIndex;
|
||||
if Current = pcDelimiter then
|
||||
begin
|
||||
Result := True;
|
||||
@ -564,8 +585,12 @@ begin
|
||||
if Current = #0 then
|
||||
break;
|
||||
if CharIsReturn(Current) then
|
||||
begin
|
||||
FindLineCol(fsSourceCode, liLiteralStart, liLine, liCol);
|
||||
pcToken.XPosition := liCol;
|
||||
pcToken.YPosition := liLine;
|
||||
raise TEParseError.Create(Format(lisMsgUnterminatedString,[pcToken.SourceCode]),pcToken);
|
||||
|
||||
end;
|
||||
{ two quotes in a row are still part of the string }
|
||||
if (Current = pcDelimiter) then
|
||||
begin
|
||||
|
@ -50,6 +50,7 @@ type
|
||||
{ the strings for the in and out code }
|
||||
fsInputCode, fsOutputCode: String;
|
||||
fsFileName: String;
|
||||
fiFirstLineNumber: integer; //used by ConvertUsingFakeUnit
|
||||
|
||||
{ classes to lex and parse the source }
|
||||
fcTokeniser: TBuildTokenList;
|
||||
@ -88,7 +89,7 @@ type
|
||||
procedure Convert;
|
||||
procedure ConvertPart(const piStartIndex, piEndIndex: Integer;
|
||||
aOnlyOutputSelection: boolean=false);
|
||||
procedure ConvertUsingFakeUnit;
|
||||
procedure ConvertUsingFakeUnit(AFirstLineNumber:integer = 1);
|
||||
|
||||
procedure CollectOutput(const pcRoot: TParseTreeNode);
|
||||
{ call this to report the current state of the proceedings }
|
||||
@ -137,6 +138,7 @@ begin
|
||||
fcBuildParseTree := TBuildParseTree.Create;
|
||||
fcSingleProcess := nil;
|
||||
fbGuiMessages := True; // use Ui to show parse errors by default
|
||||
fiFirstLineNumber := 1;
|
||||
end;
|
||||
|
||||
destructor TConverter.Destroy;
|
||||
@ -171,9 +173,15 @@ begin
|
||||
try
|
||||
fcTokeniser.BuildTokenList(lcTokenList);
|
||||
except
|
||||
on E: EBuildTokenListWarning do
|
||||
on ETW: EBuildTokenListWarning do
|
||||
begin
|
||||
SendStatusMessage('', Format(lisMsgWarningClassMsg, ['', E.Message]), mtCodeWarning, -1, -1);
|
||||
SendStatusMessage('', Format(lisMsgWarningClassMsg, ['', ETW.Message]), mtCodeWarning, -1, -1);
|
||||
end;
|
||||
on EPR:TEParseError do
|
||||
begin
|
||||
fbConvertError := True;
|
||||
SendStatusMessage('', Format(lisMsgExceptionClassMsg, ['', EPR.Message]), mtException, EPR.YPosition, EPR.XPosition);
|
||||
Exit;
|
||||
end;
|
||||
on E: Exception do
|
||||
begin
|
||||
@ -369,7 +377,7 @@ end;
|
||||
procedure TConverter.SendStatusMessage(const psUnit, psMessage: String; const peMessageType: TStatusMessageType; const piY, piX: Integer);
|
||||
begin
|
||||
if Assigned(fOnStatusMessage) then
|
||||
fOnStatusMessage(psUnit, psMessage, peMessageType, piY, piX);
|
||||
fOnStatusMessage(psUnit, psMessage, peMessageType, piY + fiFirstLineNumber - 1, piX);
|
||||
end;
|
||||
|
||||
procedure TConverter.ShowParseTree;
|
||||
@ -390,6 +398,7 @@ begin
|
||||
Assert(piStartIndex >= 0);
|
||||
Assert(piEndIndex >= piStartIndex);
|
||||
Assert(piEndIndex <= Length(InputCode));
|
||||
fiFirstLineNumber := 100;
|
||||
|
||||
{ round to nearest end of line }
|
||||
liRealInputStart := piStartIndex;
|
||||
@ -448,7 +457,7 @@ hasImplemen. F T F T
|
||||
// Needed for formating include files or part of a file with tokens not supported by
|
||||
// the jedi code format parser.
|
||||
// {$I %DATE%} for example.
|
||||
procedure TConverter.ConvertUsingFakeUnit;
|
||||
procedure TConverter.ConvertUsingFakeUnit(AFirstLineNumber:integer);
|
||||
const
|
||||
END_MARK_INTERFACE = 'tfaketjcf_intfc_end_mark;'; //<lower case required
|
||||
END_MARK_IMPLEMENTATION = 'tfaketjcf_implm_end_mark;'; //<lower case required
|
||||
@ -463,6 +472,7 @@ var
|
||||
procedure AddFakeUnit;
|
||||
begin
|
||||
sourceCode := sourceCode + 'unit ' + FAKE_UNIT_NAME + #10;
|
||||
Dec(fiFirstLineNumber);
|
||||
end;
|
||||
|
||||
procedure AddFakeInterface;
|
||||
@ -470,34 +480,43 @@ var
|
||||
liUsesPos:integer;
|
||||
begin
|
||||
sourceCode := sourceCode + 'interface{:*_*:}' + #10;
|
||||
Dec(fiFirstLineNumber);
|
||||
liUsesPos:=PosEx('uses',sourceCodeLowerCase,1);
|
||||
if (liUsesPos>0) and (liImplementationPos>0) and (liUsesPos<liImplementationPos)
|
||||
and (length(sourceCodeLowerCase)>=liUsesPos+4) and CharIsWhiteSpace(sourceCodeLowerCase[liUsesPos+4]) then
|
||||
begin
|
||||
sourceCode := sourceCode + '// ' + END_MARK_INTERFACE + #10;
|
||||
Dec(fiFirstLineNumber);
|
||||
end
|
||||
else
|
||||
begin
|
||||
sourceCode := sourceCode + 'type' + #10; // if there is only a class selected this is required
|
||||
sourceCode := sourceCode + 'faketjcfifc=' + END_MARK_INTERFACE + #10;
|
||||
Dec(fiFirstLineNumber, 2);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure AddFakeImplementation;
|
||||
procedure AddFakeImplementation(AAdjustFirstLineNumber: boolean);
|
||||
var
|
||||
liUsesPos:integer;
|
||||
begin
|
||||
sourceCode := sourceCode + 'implementation{:*_*:}' + #10;
|
||||
if AAdjustFirstLineNumber then
|
||||
Dec(fiFirstLineNumber);
|
||||
liUsesPos:=PosEx('uses',sourceCodeLowerCase,1);
|
||||
if ((not hasInterface) and (not hasImplementation)) and (liUsesPos>0)
|
||||
and (length(sourceCodeLowerCase)>=liUsesPos+4) and CharIsWhiteSpace(sourceCodeLowerCase[liUsesPos+4]) then
|
||||
begin
|
||||
sourceCode := sourceCode + '// ' + END_MARK_IMPLEMENTATION + #10;
|
||||
if AAdjustFirstLineNumber then
|
||||
Dec(fiFirstLineNumber);
|
||||
end
|
||||
else
|
||||
begin
|
||||
sourceCode := sourceCode + 'type' + #10;
|
||||
sourceCode := sourceCode + 'faketjcfimpl=' + END_MARK_IMPLEMENTATION + #10;
|
||||
if AAdjustFirstLineNumber then
|
||||
Dec(fiFirstLineNumber, 2);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -508,6 +527,7 @@ var
|
||||
|
||||
begin
|
||||
//WRAPPING the inputCode in a fake unit
|
||||
fiFirstLineNumber := AFirstLineNumber;
|
||||
sourceCodeLowerCase := LowerCase(fsInputCode);
|
||||
{$push}{$warn 5057 off}
|
||||
hasInterface := HasStringAtLineStart(sourceCodeLowerCase, 'interface', liInterfacePos);
|
||||
@ -519,11 +539,11 @@ begin
|
||||
begin
|
||||
AddFakeInterface;
|
||||
if hasImplementation = False then
|
||||
AddFakeImplementation;
|
||||
AddFakeImplementation(True);
|
||||
end;
|
||||
sourceCode := sourceCode + fsInputCode;
|
||||
if (hasInterface = True) and (hasImplementation = False) then
|
||||
AddFakeImplementation;
|
||||
AddFakeImplementation(False);
|
||||
AddFakeEnd;
|
||||
fsInputCode:=sourceCode;
|
||||
Convert;
|
||||
|
@ -161,6 +161,8 @@ function StrStartsWithLineEnd(const aStr:string):boolean;
|
||||
// string ends with LF, CR, ignores trailing spaces
|
||||
function StrEndsWithLineEnd(const aStr:string):boolean;
|
||||
|
||||
procedure FindLineCol(ASource:string; APosition:integer; out ALine:integer; out ACol:integer);
|
||||
|
||||
type
|
||||
EJcfConversionError = class(Exception)
|
||||
end;
|
||||
@ -766,4 +768,39 @@ begin
|
||||
Result := (i>0) and CharIsReturn(aStr[i]);
|
||||
end;
|
||||
|
||||
procedure FindLineCol(ASource:string; APosition:integer; out ALine:integer; out ACol:integer);
|
||||
var
|
||||
liIndex:integer;
|
||||
liLast:integer;
|
||||
liLine:integer;
|
||||
liLineStart:integer;
|
||||
begin
|
||||
liLast:=aPosition;
|
||||
if length(ASource) < liLast then
|
||||
liLast:=length(ASource);
|
||||
liIndex:=1;
|
||||
liLine:=1;
|
||||
liLineStart:=1;
|
||||
while liIndex < liLast do
|
||||
begin
|
||||
if ASource[liIndex]=#13 then
|
||||
begin
|
||||
Inc(liLine);
|
||||
if ASource[liIndex + 1] = #10 then
|
||||
Inc(liIndex);
|
||||
liLineStart:= liIndex + 1;
|
||||
end
|
||||
else if ASource[liIndex] = #10 then
|
||||
begin
|
||||
Inc(liLine);
|
||||
liLineStart := liIndex + 1;
|
||||
end;
|
||||
Inc(liIndex);
|
||||
end;
|
||||
ALine := liLine;
|
||||
ACol:= liLast - liLineStart + 1;
|
||||
if ACol < 1 then
|
||||
ACol := 1;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user