mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-20 17:40:40 +02:00
Jedi Code Format: Support generic types with const. Issue #38088, patch from Domingo Galmés.
git-svn-id: trunk@64149 -
This commit is contained in:
parent
2f371ac685
commit
b6078f53b5
@ -65,6 +65,7 @@ type
|
|||||||
fiTokenCount: integer;
|
fiTokenCount: integer;
|
||||||
procedure RecogniseTypeHelper;
|
procedure RecogniseTypeHelper;
|
||||||
procedure SplitGreaterThanOrEqual;
|
procedure SplitGreaterThanOrEqual;
|
||||||
|
procedure SplitShr_gg;
|
||||||
|
|
||||||
procedure RecogniseGoal;
|
procedure RecogniseGoal;
|
||||||
procedure RecogniseUnit;
|
procedure RecogniseUnit;
|
||||||
@ -1260,6 +1261,9 @@ begin
|
|||||||
PopNode;
|
PopNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
CONST_GENERIC_TOKENS = [ttAt, ttOpenBracket, ttOpenSquareBracket, ttIdentifier, ttPlus, ttMinus,
|
||||||
|
ttNot, ttNumber, ttQuotedLiteralString, ttNil, ttTrue, ttFalse];
|
||||||
|
|
||||||
function TBuildParseTree.GenericAhead: boolean;
|
function TBuildParseTree.GenericAhead: boolean;
|
||||||
var
|
var
|
||||||
@ -1287,7 +1291,7 @@ begin
|
|||||||
if liTokenIndex mod 2 = 0 then
|
if liTokenIndex mod 2 = 0 then
|
||||||
begin
|
begin
|
||||||
// should be id
|
// should be id
|
||||||
if (lcToken.WordType <> wtBuiltInType) and (not IsIdentifierToken(lcToken, idAny)) then
|
if (lcToken.WordType <> wtBuiltInType) and (not IsIdentifierToken(lcToken, idAny)) and (not (lcToken.TokenType in CONST_GENERIC_TOKENS)) then
|
||||||
begin
|
begin
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
@ -1320,26 +1324,85 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
ConstraintTokens = [ttClass, ttRecord, ttConstructor];
|
ConstraintTokens = [ttClass, ttRecord, ttConstructor, ttInterface, ttObject];
|
||||||
|
|
||||||
procedure TBuildParseTree.RecogniseGenericType;
|
procedure TBuildParseTree.RecogniseGenericType;
|
||||||
|
var
|
||||||
|
lbHasConst: boolean;
|
||||||
|
lbIsGenericType:boolean;
|
||||||
|
|
||||||
|
procedure RecogniseP;
|
||||||
|
var
|
||||||
|
liNestLevel: integer;
|
||||||
|
begin
|
||||||
|
if fcTokenList.FirstSolidTokenType = ttConst then
|
||||||
|
begin
|
||||||
|
Recognise(ttConst);
|
||||||
|
lbHasConst := True;
|
||||||
|
end;
|
||||||
|
if lbHasConst = False then //can be a expresion like h: specialize TNames<[Blaise,Pascal]>;
|
||||||
|
begin
|
||||||
|
lbisGenericType:=(fcTokenList.FirstSolidTokenType=ttIdentifier) and (fcTokenList.SolidTokenType(2)=ttLessThan); //is generic type
|
||||||
|
if fcTokenList.FirstSolidTokenType=ttSpecialize then
|
||||||
|
lbIsGenericType:=true;
|
||||||
|
if (fcTokenList.FirstSolidTokenType in CONST_GENERIC_TOKENS) and (not lbIsGenericType) then
|
||||||
|
begin //hack. recognise tokens until ; , or >
|
||||||
|
liNestLevel := 0;
|
||||||
|
while (liNestLevel > 0) or (not (fcTokenList.FirstTokenType in [ttComma, ttGreaterThan, ttSemiColon, ttGreaterThanOrEqual, ttShr_gg])) do
|
||||||
|
begin
|
||||||
|
if fcTokenList.FirstTokenType in [ttOpenSquareBracket, ttOpenBracket] then
|
||||||
|
Inc(liNestLevel);
|
||||||
|
if fcTokenList.FirstTokenType in [ttCloseSquareBracket, ttCloseBracket] then
|
||||||
|
Dec(liNestLevel);
|
||||||
|
Recognise(fcTokenList.FirstTokenType);
|
||||||
|
if fcTokenList.EOF then
|
||||||
|
begin
|
||||||
|
raise TEParseError.Create('Unexpected EOF. ',nil);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RecogniseType;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RecogniseType;
|
||||||
|
|
||||||
|
if lbHasConst then
|
||||||
|
begin
|
||||||
|
if fcTokenList.FirstSolidTokenType = ttColon then
|
||||||
|
RecogniseGenericConstraints;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
PushNode(nGeneric);
|
PushNode(nGeneric);
|
||||||
|
|
||||||
// angle brackets
|
// angle brackets
|
||||||
Recognise(ttLessThan);
|
Recognise(ttLessThan);
|
||||||
RecogniseType;
|
|
||||||
|
while True do
|
||||||
|
begin
|
||||||
|
lbHasConst := False;
|
||||||
|
PushNode(nType);
|
||||||
|
RecogniseP;
|
||||||
|
// more types after commas
|
||||||
|
while fcTokenList.FirstSolidTokenType = ttComma do
|
||||||
|
begin
|
||||||
|
Recognise(ttComma);
|
||||||
|
RecogniseP;
|
||||||
|
end;
|
||||||
|
|
||||||
if fcTokenList.FirstSolidTokenType = ttColon then
|
if fcTokenList.FirstSolidTokenType = ttColon then
|
||||||
begin
|
begin
|
||||||
RecogniseGenericConstraints;
|
RecogniseGenericConstraints;
|
||||||
end;
|
end;
|
||||||
|
if fcTokenList.FirstSolidTokenType <> ttSemiColon then
|
||||||
// more types after commas
|
|
||||||
while fcTokenList.FirstSolidTokenType = ttComma do
|
|
||||||
begin
|
begin
|
||||||
Recognise(ttComma);
|
PopNode;
|
||||||
RecogniseType;
|
break;
|
||||||
|
end;
|
||||||
|
Recognise(ttSemiColon);
|
||||||
|
PopNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if fcTokenList.FirstSolidTokenType = ttGreaterThanOrEqual then
|
if fcTokenList.FirstSolidTokenType = ttGreaterThanOrEqual then
|
||||||
@ -1347,10 +1410,17 @@ begin
|
|||||||
// the tokenizer got it wrong - e.g "TTestNullable<T:Record>=Class"
|
// the tokenizer got it wrong - e.g "TTestNullable<T:Record>=Class"
|
||||||
// this is the same as TTestNullable<T:Record> =Class
|
// this is the same as TTestNullable<T:Record> =Class
|
||||||
RecogniseWhiteSpace;
|
RecogniseWhiteSpace;
|
||||||
|
|
||||||
SplitGreaterThanOrEqual;
|
SplitGreaterThanOrEqual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if fcTokenList.FirstSolidTokenType = ttShr_gg then
|
||||||
|
begin
|
||||||
|
// >> operator
|
||||||
|
RecogniseWhiteSpace;
|
||||||
|
SplitShr_gg;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
Recognise(ttGreaterThan);
|
Recognise(ttGreaterThan);
|
||||||
|
|
||||||
PopNode;
|
PopNode;
|
||||||
@ -1421,6 +1491,35 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TBuildParseTree.SplitShr_gg;
|
||||||
|
var
|
||||||
|
liIndex: integer;
|
||||||
|
lcNewToken: TSourceToken;
|
||||||
|
fsFileName: string;
|
||||||
|
begin
|
||||||
|
if fcTokenList.FirstTokenType = ttShr_gg then
|
||||||
|
begin
|
||||||
|
liIndex := fcTokenList.CurrentTokenIndex;
|
||||||
|
fsFileName := fcTokenList.SourceTokens[liIndex].FileName;
|
||||||
|
|
||||||
|
fcTokenList.Delete(liIndex);
|
||||||
|
|
||||||
|
lcNewToken := TSourceToken.Create();
|
||||||
|
lcNewToken.FileName := fsFileName;
|
||||||
|
lcNewToken.SourceCode := '>';
|
||||||
|
lcNewToken.TokenType := ttGreaterThan;
|
||||||
|
|
||||||
|
fcTokenList.Insert(liIndex, lcNewToken);
|
||||||
|
|
||||||
|
lcNewToken := TSourceToken.Create();
|
||||||
|
lcNewToken.FileName := fsFileName;
|
||||||
|
lcNewToken.SourceCode := '>';
|
||||||
|
lcNewToken.TokenType := ttGreaterThan;
|
||||||
|
|
||||||
|
fcTokenList.Insert(liIndex + 1 , lcNewToken);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ helper proc for RecogniseTypedConstant
|
{ helper proc for RecogniseTypedConstant
|
||||||
need to distinguish
|
need to distinguish
|
||||||
|
@ -63,6 +63,7 @@ type
|
|||||||
function ForwardChar(const piOffset: integer): Char;
|
function ForwardChar(const piOffset: integer): Char;
|
||||||
function ForwardChars(const piOffset, piCount: integer): String;
|
function ForwardChars(const piOffset, piCount: integer): String;
|
||||||
procedure Consume(const piCount: integer = 1);
|
procedure Consume(const piCount: integer = 1);
|
||||||
|
procedure UndoConsume(const piCount: integer = 1);
|
||||||
function EndOfFile: boolean;
|
function EndOfFile: boolean;
|
||||||
function EndOfFileAfter(const piChars: integer): boolean;
|
function EndOfFileAfter(const piChars: integer): boolean;
|
||||||
|
|
||||||
@ -820,10 +821,15 @@ function TBuildTokenList.TryPunctuation(const pcToken: TSourceToken): boolean;
|
|||||||
// "<<" is the start of two nested generics,
|
// "<<" is the start of two nested generics,
|
||||||
// likewise '>>' is not an operator, it is two "end-of-generic" signs in sucession
|
// likewise '>>' is not an operator, it is two "end-of-generic" signs in sucession
|
||||||
if (chLast = '<') and (ch = '<') then
|
if (chLast = '<') and (ch = '<') then
|
||||||
|
begin
|
||||||
|
Result := True; // <<
|
||||||
exit;
|
exit;
|
||||||
|
end;
|
||||||
if (chLast = '>') and (ch = '>') then
|
if (chLast = '>') and (ch = '>') then
|
||||||
|
begin
|
||||||
|
Result := True; // >>
|
||||||
exit;
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
Result := CharIsPuncChar(ch);
|
Result := CharIsPuncChar(ch);
|
||||||
end;
|
end;
|
||||||
@ -851,6 +857,12 @@ begin
|
|||||||
Consume;
|
Consume;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if length(pcToken.SourceCode) > 2 then // nested generic specialize TC1<TC2<TC3<integer>>>=record end;
|
||||||
|
begin
|
||||||
|
// only consume the first >
|
||||||
|
UndoConsume(Length(pcToken.SourceCode) - 1);
|
||||||
|
pcToken.SourceCode := pcToken.SourceCode[1];
|
||||||
|
end;
|
||||||
{ try to recognise the punctuation as an operator }
|
{ try to recognise the punctuation as an operator }
|
||||||
TypeOfToken(pcToken.SourceCode, leWordType, leTokenType);
|
TypeOfToken(pcToken.SourceCode, leWordType, leTokenType);
|
||||||
if leTokenType <> ttUnknown then
|
if leTokenType <> ttUnknown then
|
||||||
@ -932,6 +944,11 @@ begin
|
|||||||
inc(fiCurrentIndex, piCount);
|
inc(fiCurrentIndex, piCount);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TBuildTokenList.UndoConsume(const piCount: integer);
|
||||||
|
begin
|
||||||
|
dec(fiCurrentIndex, piCount);
|
||||||
|
end;
|
||||||
|
|
||||||
function TBuildTokenList.EndOfFile: boolean;
|
function TBuildTokenList.EndOfFile: boolean;
|
||||||
begin
|
begin
|
||||||
Result := fiCurrentIndex > Length(fsSourceCode);
|
Result := fiCurrentIndex > Length(fsSourceCode);
|
||||||
|
@ -640,9 +640,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function IsDfmIncludeDirective(const pt: TSourceToken): boolean;
|
function IsDfmIncludeDirective(const pt: TSourceToken): boolean;
|
||||||
|
var
|
||||||
|
lsToken:string;
|
||||||
begin
|
begin
|
||||||
// form dfm comment
|
// form dfm comment
|
||||||
Result := (pt.TokenType = ttComment) and AnsiSameText(pt.SourceCode, '{$R *.dfm}') and
|
lsToken:=UpperCase(pt.SourceCode);
|
||||||
|
Result := (pt.TokenType = ttComment) and ((lsToken = '{$R *.DFM}') or (lsToken = '[$R *.LFM}')) and
|
||||||
pt.HasParentNode(nImplementationSection, 4);
|
pt.HasParentNode(nImplementationSection, 4);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -295,7 +295,9 @@ type
|
|||||||
ttPlusAssign, // +=
|
ttPlusAssign, // +=
|
||||||
ttMinusAssign, // -=
|
ttMinusAssign, // -=
|
||||||
ttTimesAssign, // *=
|
ttTimesAssign, // *=
|
||||||
ttFloatDivAssign // /=
|
ttFloatDivAssign, // /=
|
||||||
|
ttShl_ll, // <<
|
||||||
|
ttShr_gg // >>
|
||||||
);
|
);
|
||||||
|
|
||||||
TTokenTypeSet = set of TTokenType;
|
TTokenTypeSet = set of TTokenType;
|
||||||
@ -419,7 +421,7 @@ const
|
|||||||
|
|
||||||
AddOperators: TTokenTypeSet = [ttPlus, ttMinus, ttOr, ttXor];
|
AddOperators: TTokenTypeSet = [ttPlus, ttMinus, ttOr, ttXor];
|
||||||
|
|
||||||
MulOperators: TTokenTypeSet = [ttTimes, ttFloatDiv, ttDiv, ttMod, ttAnd, ttShl, ttShr, ttExponent];
|
MulOperators: TTokenTypeSet = [ttTimes, ttFloatDiv, ttDiv, ttMod, ttAnd, ttShl, ttShr, ttExponent, ttShl_ll,ttShr_gg];
|
||||||
|
|
||||||
SingleSpaceOperators = [
|
SingleSpaceOperators = [
|
||||||
// some unary operators
|
// some unary operators
|
||||||
@ -427,7 +429,7 @@ const
|
|||||||
// all operators that are always binary
|
// all operators that are always binary
|
||||||
ttAnd, ttAs, ttDiv, ttIn, ttIs, ttMod, ttOr, ttShl, ttShr, ttXor,
|
ttAnd, ttAs, ttDiv, ttIn, ttIs, ttMod, ttOr, ttShl, ttShr, ttXor,
|
||||||
ttTimes, ttFloatDiv, ttExponent, ttEquals, ttGreaterThan, ttLessThan,
|
ttTimes, ttFloatDiv, ttExponent, ttEquals, ttGreaterThan, ttLessThan,
|
||||||
ttGreaterThanOrEqual, ttLessThanOrEqual, ttNotEqual, ttSetSymDif];
|
ttGreaterThanOrEqual, ttLessThanOrEqual, ttNotEqual, ttSetSymDif, ttShl_ll, ttShr_gg];
|
||||||
|
|
||||||
StringWords: TTokenTypeSet = [ttString, ttAnsiString, ttWideString];
|
StringWords: TTokenTypeSet = [ttString, ttAnsiString, ttWideString];
|
||||||
|
|
||||||
@ -789,6 +791,8 @@ begin
|
|||||||
AddKeyword('<=', wtOperator, ttLessThanOrEqual);
|
AddKeyword('<=', wtOperator, ttLessThanOrEqual);
|
||||||
AddKeyword('<>', wtOperator, ttNotEqual);
|
AddKeyword('<>', wtOperator, ttNotEqual);
|
||||||
AddKeyword('><', wtOperator, ttSetSymDif);
|
AddKeyword('><', wtOperator, ttSetSymDif);
|
||||||
|
AddKeyword('<<', wtOperator, ttShl_ll); // in FreePascal
|
||||||
|
AddKeyword('>>', wtOperator, ttShr_gg); // in FreePascal
|
||||||
// these must come after the above as they are shorter
|
// these must come after the above as they are shorter
|
||||||
AddKeyword('>', wtOperator, ttGreaterThan);
|
AddKeyword('>', wtOperator, ttGreaterThan);
|
||||||
AddKeyword('<', wtOperator, ttLessThan);
|
AddKeyword('<', wtOperator, ttLessThan);
|
||||||
|
@ -128,6 +128,13 @@ begin
|
|||||||
Result := True;
|
Result := True;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
{ in generic definition}
|
||||||
|
if pt.HasParentNode(nGeneric,2) then
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,6 +71,12 @@ begin
|
|||||||
if ptNext.TokenType = ttComment then
|
if ptNext.TokenType = ttComment then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
if (pt.TokenType in [ttLessThan,ttGreaterThan]) and pt.HasParentNode(nGeneric,1) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if pt.TokenType in NoSpaceAnywhere then
|
if pt.TokenType in NoSpaceAnywhere then
|
||||||
begin
|
begin
|
||||||
Result := True;
|
Result := True;
|
||||||
|
@ -78,6 +78,11 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (pt.TokenType in [ttLessThan,ttGreaterThan]) and pt.HasParentNode(nGeneric,1) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
// '@@' in asm, e.g. "JE @@initTls" needs the space
|
// '@@' in asm, e.g. "JE @@initTls" needs the space
|
||||||
if pt.HasParentNode(nAsm) then
|
if pt.HasParentNode(nAsm) then
|
||||||
|
@ -80,9 +80,9 @@ begin
|
|||||||
if pt.HasParentNode(nAsm) then
|
if pt.HasParentNode(nAsm) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
if pt.HasParentNode(nGeneric, 1) then
|
if pt.HasParentNode(nGeneric, 2) then
|
||||||
begin
|
begin
|
||||||
if pt.TokenType in [ttComma, ttColon] then
|
if pt.TokenType in [ttComma, ttColon, ttSemiColon] then
|
||||||
begin
|
begin
|
||||||
Result := true;
|
Result := true;
|
||||||
end;
|
end;
|
||||||
|
@ -1150,7 +1150,7 @@ object Form1: TForm1
|
|||||||
Left = 18
|
Left = 18
|
||||||
Height = 15
|
Height = 15
|
||||||
Top = 465
|
Top = 465
|
||||||
Width = 80
|
Width = 152
|
||||||
Anchors = [akLeft, akBottom]
|
Anchors = [akLeft, akBottom]
|
||||||
AutoSize = False
|
AutoSize = False
|
||||||
ParentColor = False
|
ParentColor = False
|
||||||
|
Loading…
Reference in New Issue
Block a user