View Issue Details

IDProjectCategoryView StatusLast Update
0038932LazarusIDEpublic2021-06-13 14:18
ReporterOkobaPatino Assigned ToJuha Manninen  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version2.1 (SVN) 
Summary0038932: JCF can not format Enumerator word
DescriptionIf you have a variant or a parameter with the Enumerator name, JCF can not format it.
Steps To Reproduceprogram Project1;
function Enumerator:integer;
begin

end;

procedure Test(Enumerator:integer);
begin

end;

var
  Enumerator:Integer;
begin
end.
                          
TagsNo tags attached.
Fixed in Revisionr65219
LazTarget-
Widgetset
Attached Files

Activities

Domingo Galmés

2021-05-30 16:40

reporter   ~0131093

This patch solves the issue with 'enumerator' token used as identifier.


Sample code used for testing.


// Buggy sample.
// only for testing JCF.
program project1;

uses
  SysUtils;

var
  pIntArr: Pointer;
  IntArr: array of integer;

  function Enumerator: integer;
  begin
    Result := 1;
  end;

  procedure Test(Enumerator: integer);
  begin
    exit;
  end;

  // Error: duplicate identifier
  //var
  // Enumerator: integer;

type

  TNode = class
    none: integer;
  end;


type
  { TMyListEnumerator }

  TMyListEnumerator = object
  private
    FCurrent: integer;
  public
    constructor Create;
    destructor Destroy;
    function StepNext: boolean; enumerator MoveNext;
    property Value: integer read FCurrent; enumerator Current;
  end;

  TMyList = class
  end;

  { TMyListEnumerator }

  constructor TMyListEnumerator.Create;
  begin
    FCurrent := 0;
  end;

  destructor TMyListEnumerator.Destroy;
  begin
    inherited;
  end;

  function TMyListEnumerator.StepNext: boolean;
  begin
    Inc(FCurrent);
    Result := FCurrent <= 3;
  end;

  operator enumerator(AList: TMyList): TMyListEnumerator;
  begin
    Result.Create;
  end;


type
  { TMyListEnumerator }

  TMyListEnumerator2 = class
  private
    FCurrent: integer;
  public
    constructor Create;
    destructor Destroy;
    function StepNext: boolean; enumerator MoveNext;
    property Value: integer read FCurrent; enumerator Current;
  end;


  { TMyListEnumerator }

  constructor TMyListEnumerator2.Create;
  begin
    FCurrent := 0;
  end;

  destructor TMyListEnumerator2.Destroy;
  begin
    inherited;
  end;

  function TMyListEnumerator2.StepNext: boolean;
  begin
    Inc(FCurrent);
    Result := FCurrent <= 3;
  end;

  operator enumerator(AList: TMyList): TMyListEnumerator2;
  begin
    Result.Create;
  end;

var
  List: TMyList;
  i: integer;
begin
  List := TMyList.Create;
  for i in List do
    WriteLn(i);
  List.Free;
end.
JCF_Issue_38932_Enumerator.patch (4,659 bytes)   
From fce4990c3b6f45f2a44ed9e24aee665a72b7c446 Mon Sep 17 00:00:00 2001
From: DomingoGP <dgalmesp@gmail.com>
Date: Sun, 30 May 2021 18:34:18 +0200
Subject: [PATCH] Solves 	0038932: JCF can not format Enumerator word

---
 components/jcf2/Parse/BuildParseTree.pas | 38 ++++++++++++++++++------
 components/jcf2/Parse/Tokens.pas         |  3 +-
 2 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/components/jcf2/Parse/BuildParseTree.pas b/components/jcf2/Parse/BuildParseTree.pas
index 7af848a079..959f56fc32 100644
--- a/components/jcf2/Parse/BuildParseTree.pas
+++ b/components/jcf2/Parse/BuildParseTree.pas
@@ -272,7 +272,7 @@ type
 
     procedure RecogniseAnonymousMethod;
     function AnonymousMethodNext: boolean;
-
+    procedure CheckEnumeratorToken;
   Protected
 
   Public
@@ -2526,6 +2526,7 @@ begin
   PushNode(nFunctionHeading);
   Recognise(ttOperator);
 
+  CheckEnumeratorToken();
   RecogniseOperatorSymbol();
 
   if fcTokenList.FirstSolidTokenType = ttOpenBracket then
@@ -3962,6 +3963,7 @@ begin
     Recognise(ttSemicolon);
 
   //opt
+  CheckEnumeratorToken();
   if fcTokenList.FirstSolidTokenType in ProcedureDirectives then
     RecogniseProcedureDirectives;
 
@@ -3989,7 +3991,7 @@ begin
 
   RecogniseConstructorHeading(False);
   Recognise(ttSemicolon);
-
+  CheckEnumeratorToken();
   if fcTokenList.FirstSolidTokenType in ProcedureDirectives then
     RecogniseProcedureDirectives;
   RecogniseBlock;
@@ -4006,7 +4008,7 @@ begin
 
   RecogniseDestructorHeading(False);
   Recognise(ttSemicolon);
-
+  CheckEnumeratorToken();
   if fcTokenList.FirstSolidTokenType in ProcedureDirectives then
     RecogniseProcedureDirectives;
   RecogniseBlock;
@@ -4215,7 +4217,7 @@ begin
 
     external is more complex
   }
-
+  CheckEnumeratorToken();
   if (fcTokenList.FirstSolidTokenType in ProcedureDirectives) or
     ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
     (fcTokenList.SolidTokenType(2) in ProcedureDirectives)) then
@@ -4226,6 +4228,7 @@ begin
       Recognise(ttSemiColon);
     lbFirstPass := True;
 
+    CheckEnumeratorToken();
     while (fcTokenList.FirstSolidTokenType in ProcedureDirectives) or
       ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
         (fcTokenList.SolidTokenType(2) in ProcedureDirectives)) do
@@ -4270,6 +4273,7 @@ begin
       end;
 
       lbFirstPass := False;
+      CheckEnumeratorToken();
     end;
 
     PopNode;
@@ -5688,13 +5692,14 @@ const
   }
   PropertyDirectives = [ttDefault, ttNoDefault, ttStored, ttEnumerator];
 begin
+  CheckEnumeratorToken();
   if ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
     (fcTokenList.SolidTokenType(2) in PropertyDirectives)) or
     (fcTokenList.FirstSolidTokenType in PropertyDirectives) then
   begin
     if fcTokenList.FirstSolidTokenType = ttSemicolon then
       Recognise(ttSemicolon);
-
+    CheckEnumeratorToken();
     while fcTokenList.FirstSolidTokenType in PropertyDirectives do
     begin
       PushNode(nPropertyDirective);
@@ -5720,14 +5725,12 @@ begin
         begin
           Recognise(ttEnumerator);
           RecogniseIdentifier(False, idStrict);
+        end;
       end;
-      end;
-
       PopNode;
+      CheckEnumeratorToken();
     end;
-
   end;
-
 end;
 
 procedure TBuildParseTree.RecogniseExportsSection;
@@ -5924,6 +5927,23 @@ begin
   end;
 end;
 
+procedure TBuildParseTree.CheckEnumeratorToken;
+var
+  lc: TSourceToken;
+begin
+  lc := fcTokenList.FirstSolidToken;
+  if (lc.TokenType=ttIdentifier) and (length(lc.SourceCode)=10) and (lowercase(lc.SourceCode)='enumerator') then
+  begin
+    lc.TokenType:=ttEnumerator;
+    lc.WordType:=wtReservedWord;
+  end;
+  lc := fcTokenList.SolidToken(2);
+  if (lc.TokenType=ttIdentifier) and (length(lc.SourceCode)=10) and (lowercase(lc.SourceCode)='enumerator') then
+  begin
+    lc.TokenType:=ttEnumerator;
+    lc.WordType:=wtReservedWord;
+  end;
+end;
 
 procedure TBuildParseTree.RecogniseLiteralString;
 begin
diff --git a/components/jcf2/Parse/Tokens.pas b/components/jcf2/Parse/Tokens.pas
index 03b3491188..33b1643a02 100644
--- a/components/jcf2/Parse/Tokens.pas
+++ b/components/jcf2/Parse/Tokens.pas
@@ -624,7 +624,8 @@ begin
   AddKeyword('downto', wtReservedWord, ttDownTo);
   AddKeyword('else', wtReservedWord, ttElse);
   AddKeyword('end', wtReservedWord, ttEnd);
-  AddKeyword('enumerator', wtReservedWord, ttEnumerator);
+  // 'enumerator' can be a valid identifier.
+  //AddKeyword('enumerator', wtReservedWord, ttEnumerator);
   AddKeyword('except', wtReservedWord, ttExcept);
   AddKeyword('exports', wtReservedWord, ttExports);
   AddKeyword('file', wtReservedWord, ttFile);
-- 
2.31.1.windows.1

OkobaPatino

2021-05-31 14:23

reporter   ~0131101

Thank you @DomingoGP. Can you recheck 0038543 too please?
@JuhaManninen Can you please apply?

Juha Manninen

2021-06-01 05:21

developer   ~0131109

I can't yet. I am away from my development machine for a while. Either someone else applies it or I will do it later.

Juha Manninen

2021-06-11 07:37

developer   ~0131249

Applied, thanks.

OkobaPatino

2021-06-13 13:09

reporter   ~0131288

Thanks @JuhaManninen.
Although I found a a bug with a new test. The Function code will nor work but the Procedure will.
 @DomingoGP can you give this test a try?

program Project1;

type

  TTestEnumerator = record
    X: Integer;
  end;

  procedure Test1(var Enumerator: TTestEnumerator);
  begin
    Enumerator.X := 1;
  end;

  function Test(var Enumerator: TTestEnumerator): Boolean;
  begin
    Enumerator.X := 1;
    Result := True;
  end;

begin

end.

Domingo Galmés

2021-06-13 14:18

reporter   ~0131290

This patch solves the corner case when 'Enumerator' is the first word after begin in function.
JCF_Enumerator2.patch (2,850 bytes)   
From dc573e63f5b60f4f9ff02256db762542dabfc7e0 Mon Sep 17 00:00:00 2001
From: DomingoGP <dgalmesp@gmail.com>
Date: Sun, 13 Jun 2021 16:13:40 +0200
Subject: [PATCH] Solves corner case when enumerator is the first word in
 function after begin.

---
 components/jcf2/Parse/BuildParseTree.pas | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/components/jcf2/Parse/BuildParseTree.pas b/components/jcf2/Parse/BuildParseTree.pas
index 7371a037cd..ef0ac25f79 100644
--- a/components/jcf2/Parse/BuildParseTree.pas
+++ b/components/jcf2/Parse/BuildParseTree.pas
@@ -272,7 +272,7 @@ type
 
     procedure RecogniseAnonymousMethod;
     function AnonymousMethodNext: boolean;
-    procedure CheckEnumeratorToken;
+    procedure CheckEnumeratorToken(aCheckTwoTokens:boolean=false);
   Protected
 
   Public
@@ -4218,7 +4218,7 @@ begin
 
     external is more complex
   }
-  CheckEnumeratorToken();
+  CheckEnumeratorToken(fcTokenList.FirstSolidTokenType = ttSemicolon);
   if (fcTokenList.FirstSolidTokenType in ProcedureDirectives) or
     ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
     (fcTokenList.SolidTokenType(2) in ProcedureDirectives)) then
@@ -4229,7 +4229,7 @@ begin
       Recognise(ttSemiColon);
     lbFirstPass := True;
 
-    CheckEnumeratorToken();
+    CheckEnumeratorToken(fcTokenList.FirstSolidTokenType = ttSemicolon);
     while (fcTokenList.FirstSolidTokenType in ProcedureDirectives) or
       ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
         (fcTokenList.SolidTokenType(2) in ProcedureDirectives)) do
@@ -5704,7 +5704,7 @@ const
   }
   PropertyDirectives = [ttDefault, ttNoDefault, ttStored, ttEnumerator];
 begin
-  CheckEnumeratorToken();
+  CheckEnumeratorToken(fcTokenList.FirstSolidTokenType = ttSemicolon);
   if ((fcTokenList.FirstSolidTokenType = ttSemicolon) and
     (fcTokenList.SolidTokenType(2) in PropertyDirectives)) or
     (fcTokenList.FirstSolidTokenType in PropertyDirectives) then
@@ -5939,7 +5939,7 @@ begin
   end;
 end;
 
-procedure TBuildParseTree.CheckEnumeratorToken;
+procedure TBuildParseTree.CheckEnumeratorToken(aCheckTwoTokens:boolean);
 var
   lc: TSourceToken;
 begin
@@ -5949,11 +5949,14 @@ begin
     lc.TokenType:=ttEnumerator;
     lc.WordType:=wtReservedWord;
   end;
-  lc := fcTokenList.SolidToken(2);
-  if (lc<>nil) and (lc.TokenType=ttIdentifier) and (length(lc.SourceCode)=10) and (lowercase(lc.SourceCode)='enumerator') then
+  if aCheckTwoTokens then
   begin
-    lc.TokenType:=ttEnumerator;
-    lc.WordType:=wtReservedWord;
+    lc := fcTokenList.SolidToken(2);
+    if (lc<>nil) and (lc.TokenType=ttIdentifier) and (length(lc.SourceCode)=10) and (lowercase(lc.SourceCode)='enumerator') then
+    begin
+      lc.TokenType:=ttEnumerator;
+      lc.WordType:=wtReservedWord;
+    end;
   end;
 end;
 
-- 
2.31.1.windows.1

JCF_Enumerator2.patch (2,850 bytes)   

Issue History

Date Modified Username Field Change
2021-05-26 14:50 OkobaPatino New Issue
2021-05-30 16:40 Domingo Galmés Note Added: 0131093
2021-05-30 16:40 Domingo Galmés File Added: JCF_Issue_38932_Enumerator.patch
2021-05-31 14:23 OkobaPatino Note Added: 0131101
2021-06-01 05:21 Juha Manninen Note Added: 0131109
2021-06-11 07:30 Juha Manninen Assigned To => Juha Manninen
2021-06-11 07:30 Juha Manninen Status new => assigned
2021-06-11 07:37 Juha Manninen Status assigned => resolved
2021-06-11 07:37 Juha Manninen Resolution open => fixed
2021-06-11 07:37 Juha Manninen Fixed in Revision => r65219
2021-06-11 07:37 Juha Manninen LazTarget => -
2021-06-11 07:37 Juha Manninen Note Added: 0131249
2021-06-13 13:09 OkobaPatino Note Added: 0131288
2021-06-13 14:18 Domingo Galmés Note Added: 0131290
2021-06-13 14:18 Domingo Galmés File Added: JCF_Enumerator2.patch