Jedi code format: Improved error messages. Issue #41144

This commit is contained in:
DomingoGP 2024-09-15 18:48:06 +02:00
parent f8ef2a93e6
commit ec16b7c23b
4 changed files with 94 additions and 12 deletions

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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.