Browse Source

pastojs: fixed renaming duplicate local const

git-svn-id: trunk@38797 -
Mattias Gaertner 7 years ago
parent
commit
20a3df1fd6

+ 154 - 3
packages/pastojs/src/fppas2js.pp

@@ -922,6 +922,21 @@ type
   public
   end;
 
+  { TPas2JSSectionScope }
+
+  TPas2JSSectionScope = class(TPasSectionScope)
+  private
+    FElevatedLocals: TFPHashList;
+    procedure InternalAddElevatedLocal(Item: TPasIdentifier);
+    procedure OnClearElevatedLocal(Item, Dummy: pointer);
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    function FindElevatedLocal(const Identifier: String): TPasIdentifier; inline;
+    function AddElevatedLocal(const Identifier: String; El: TPasElement): TPasIdentifier; virtual;
+    procedure WriteElevatedLocals(Prefix: string); virtual;
+  end;
+
   { TPas2JSInitialFinalizationScope }
 
   TPas2JSInitialFinalizationScope = class(TPasInitialFinalizationScope)
@@ -1709,6 +1724,100 @@ begin
   while (Result>0) and (s[Result]<>c) do dec(Result);
 end;
 
+{ TPas2JSSectionScope }
+
+procedure TPas2JSSectionScope.InternalAddElevatedLocal(Item: TPasIdentifier);
+var
+  Index: Integer;
+  OldItem: TPasIdentifier;
+  LoName: string;
+begin
+  LoName:=lowercase(Item.Identifier);
+  Index:=FElevatedLocals.FindIndexOf(LoName);
+  {$IFDEF VerbosePasResolver}
+  if Item.Owner<>nil then
+    raise Exception.Create('20160925184110');
+  Item.Owner:=Self;
+  {$ENDIF}
+  //writeln('  Index=',Index);
+  if Index>=0 then
+    begin
+    // insert LIFO - last in, first out
+    OldItem:=TPasIdentifier(FElevatedLocals.List^[Index].Data);
+    {$IFDEF VerbosePasResolver}
+    if lowercase(OldItem.Identifier)<>LoName then
+      raise Exception.Create('20160925183438');
+    {$ENDIF}
+    Item.NextSameIdentifier:=OldItem;
+    FElevatedLocals.List^[Index].Data:=Item;
+    end
+  else
+    begin
+    FElevatedLocals.Add(LoName, Item);
+    {$IFDEF VerbosePasResolver}
+    if FindIdentifier(Item.Identifier)<>Item then
+      raise Exception.Create('20160925183849');
+    {$ENDIF}
+    end;
+end;
+
+procedure TPas2JSSectionScope.OnClearElevatedLocal(Item, Dummy: pointer);
+var
+  PasIdentifier: TPasIdentifier absolute Item;
+  Ident: TPasIdentifier;
+begin
+  if Dummy=nil then ;
+  //writeln('TPasIdentifierScope.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
+  while PasIdentifier<>nil do
+    begin
+    Ident:=PasIdentifier;
+    PasIdentifier:=PasIdentifier.NextSameIdentifier;
+    Ident.Free;
+    end;
+end;
+
+constructor TPas2JSSectionScope.Create;
+begin
+  inherited Create;
+  FElevatedLocals:=TFPHashList.Create;
+end;
+
+destructor TPas2JSSectionScope.Destroy;
+begin
+  FElevatedLocals.ForEachCall(@OnClearElevatedLocal,nil);
+  FElevatedLocals.Clear;
+  FreeAndNil(FElevatedLocals);
+  inherited Destroy;
+end;
+
+// inline
+function TPas2JSSectionScope.FindElevatedLocal(const Identifier: String
+  ): TPasIdentifier;
+begin
+  Result:=TPasIdentifier(FElevatedLocals.Find(lowercase(Identifier)));
+end;
+
+function TPas2JSSectionScope.AddElevatedLocal(const Identifier: String;
+  El: TPasElement): TPasIdentifier;
+var
+  Item: TPasIdentifier;
+begin
+  //writeln('TPasIdentifierScope.AddIdentifier Identifier="',Identifier,'" El=',GetObjName(El));
+  Item:=TPasIdentifier.Create;
+  Item.Identifier:=Identifier;
+  Item.Element:=El;
+
+  InternalAddElevatedLocal(Item);
+  //writeln('TPasIdentifierScope.AddIdentifier END');
+  Result:=Item;
+end;
+
+procedure TPas2JSSectionScope.WriteElevatedLocals(Prefix: string);
+begin
+  Prefix:=Prefix+'  ';
+  FElevatedLocals.ForEachCall(@OnWriteItem,Pointer(Prefix));
+end;
+
 { TPas2JSProcedureScope }
 
 procedure TPas2JSProcedureScope.AddGlobalJS(const JS: string);
@@ -1799,6 +1908,11 @@ begin
   C:=El.ClassType;
   if C=TPasProperty then
     exit(false)
+  else if C=TPasConst then
+    begin
+    if El.Parent is TProcedureBody then
+      exit(false); // local const counted via TPas2JSSectionScope.FElevatedLocals
+    end
   else if C=TPasClassType then
     begin
     if TPasClassType(El).IsForward then
@@ -1888,14 +2002,36 @@ end;
 
 function TPas2JSResolver.GetOverloadIndex(El: TPasElement): integer;
 var
-  i: Integer;
+  i, j: Integer;
   Identifier: TPasIdentifier;
+  Scope: TPasIdentifierScope;
+  CurEl: TPasElement;
 begin
   Result:=0;
   for i:=FOverloadScopes.Count-1 downto 0 do
     begin
+    Scope:=TPasIdentifierScope(FOverloadScopes[i]);
+    if (Scope.ClassType=TPas2JSSectionScope) and (i<FOverloadScopes.Count-1) then
+      begin
+      // Note: the elevated locals are after the section scope and before the next deeper scope
+
+      // check elevated locals
+      Identifier:=TPas2JSSectionScope(Scope).FindElevatedLocal(El.Name);
+      j:=0;
+      // add count or index
+      while Identifier<>nil do
+        begin
+        CurEl:=Identifier.Element;
+        Identifier:=Identifier.NextSameIdentifier;
+        if CurEl=El then
+          j:=0
+        else
+          inc(j);
+        end;
+      inc(Result,j);
+      end;
     // find last added
-    Identifier:=TPasIdentifierScope(FOverloadScopes[i]).FindLocalIdentifier(El.Name);
+    Identifier:=Scope.FindLocalIdentifier(El.Name);
     // add count or index
     inc(Result,GetOverloadIndex(Identifier,El));
     end;
@@ -2514,6 +2650,8 @@ var
   AbsIdent: TPasElement;
   TypeEl: TPasType;
   GUID: TGUID;
+  i: Integer;
+  SectionScope: TPas2JSSectionScope;
 begin
   inherited FinishVariable(El);
 
@@ -2586,8 +2724,20 @@ begin
       RaiseMsg(20180404135105,nNotSupportedX,sNotSupportedX,['COM-interface as record member'],El);
     end
   else if ParentC=TProcedureBody then
+    begin
     // local var
-    RaiseVarModifierNotSupported(LocalVarModifiersAllowed)
+    RaiseVarModifierNotSupported(LocalVarModifiersAllowed);
+    if (El.ClassType=TPasConst) and TPasConst(El).IsConst then
+      begin
+      // local const
+      i:=ScopeCount-1;
+      while (i>=0) and not (Scopes[i] is TPas2JSSectionScope) do dec(i);
+      if i<0 then
+        RaiseNotYetImplemented(20180420131358,El);
+      SectionScope:=TPas2JSSectionScope(Scopes[i]);
+      SectionScope.AddElevatedLocal(El.Name,El);
+      end;
+    end
   else if ParentC=TImplementationSection then
     // implementation var
     RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
@@ -3431,6 +3581,7 @@ begin
   ScopeClass_InitialFinalization:=TPas2JSInitialFinalizationScope;
   ScopeClass_Module:=TPas2JSModuleScope;
   ScopeClass_Procedure:=TPas2JSProcedureScope;
+  ScopeClass_Section:=TPas2JSSectionScope;
   ScopeClass_WithExpr:=TPas2JSWithExprScope;
   for bt in [pbtJSValue] do
     AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);

+ 18 - 15
packages/pastojs/src/pas2jsfiler.pp

@@ -880,7 +880,7 @@ type
     procedure ReadExternalReferences(Obj: TJSONObject; El: TPasElement); virtual;
     procedure ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadUsedUnitsFinish(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
-    procedure ReadSectionScope(Obj: TJSONObject; Scope: TPasSectionScope; aContext: TPCUReaderContext); virtual;
+    procedure ReadSectionScope(Obj: TJSONObject; Scope: TPas2JSSectionScope; aContext: TPCUReaderContext); virtual;
     procedure ReadSection(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     procedure ReadDeclarations(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual;
     function ReadElement(Obj: TJSONObject; Parent: TPasElement; aContext: TPCUReaderContext): TPasElement; virtual;
@@ -1587,14 +1587,14 @@ function TPCUCustomReader.ReadCanContinue: boolean;
 var
   Module: TPasModule;
   Section: TPasSection;
-  Scope: TPasSectionScope;
+  Scope: TPas2JSSectionScope;
 begin
   Result:=false;
   Module:=Resolver.RootElement;
   if Module=nil then exit(true); // not yet started
   Section:=Resolver.GetLastSection;
   if Section=nil then exit(true); // only header
-  Scope:=Section.CustomData as TPasSectionScope;
+  Scope:=Section.CustomData as TPas2JSSectionScope;
   if Scope.Finished then exit(false); // finished
   Result:=Section.PendingUsedIntf=nil;
 end;
@@ -2501,7 +2501,7 @@ procedure TPCUWriter.WriteSection(ParentJSON: TJSONObject;
   Section: TPasSection; const PropName: string; aContext: TPCUWriterContext);
 var
   Obj, SubObj: TJSONObject;
-  Scope, UsesScope: TPasSectionScope;
+  Scope, UsesScope: TPas2JSSectionScope;
   i, j: Integer;
   Arr: TJSONArray;
   UsesUnit: TPasUsesUnit;
@@ -2515,7 +2515,7 @@ begin
   aContext.IndirectUsesArr:=nil;
   WritePasElement(Obj,Section,aContext);
 
-  Scope:=TPasSectionScope(CheckElScope(Section,20180206121825,TPasSectionScope));
+  Scope:=TPas2JSSectionScope(CheckElScope(Section,20180206121825,TPas2JSSectionScope));
   if not Scope.Finished then
     RaiseMsg(20180206130333,Section);
   if Scope.UsesScopes.Count<>length(Section.UsesClause) then
@@ -2524,7 +2524,7 @@ begin
   for i:=0 to Scope.UsesScopes.Count-1 do
     begin
     UsesUnit:=Section.UsesClause[i];
-    UsesScope:=TPasSectionScope(Scope.UsesScopes[i]);
+    UsesScope:=TPas2JSSectionScope(Scope.UsesScopes[i]);
     if UsesScope.Element<>TPasModule(UsesUnit.Module).InterfaceSection then
       RaiseMsg(20180206122459,Section,'usesscope '+IntToStr(i)+' UsesScope.Element='+GetObjName(UsesScope.Element)+' Module='+GetObjName(Section.UsesClause[i].Module));
     if Arr=nil then
@@ -2575,6 +2575,8 @@ begin
     end;
   WriteIdentifierScope(Obj,Scope,aContext);
 
+  // not needed: Scope ElevatedLocals
+
   WriteDeclarations(Obj,Section,aContext);
   if Section is TInterfaceSection then
     begin
@@ -5224,7 +5226,7 @@ procedure TPCUReader.ReadUsedUnitsFinish(Obj: TJSONObject;
   Section: TPasSection; aContext: TPCUReaderContext);
 var
   Arr: TJSONArray;
-  Scope, UsedScope: TPasSectionScope;
+  Scope, UsedScope: TPas2JSSectionScope;
   i: Integer;
   Use: TPasUsesUnit;
   Module: TPasModule;
@@ -5232,11 +5234,11 @@ var
   UsesObj, ModuleObj: TJSONObject;
   Name: string;
 begin
-  Scope:=Section.CustomData as TPasSectionScope;
+  Scope:=Section.CustomData as TPas2JSSectionScope;
   // read external refs from used units
   if ReadArray(Obj,'Uses',Arr,Section) then
     begin
-    Scope:=Section.CustomData as TPasSectionScope;
+    Scope:=Section.CustomData as TPas2JSSectionScope;
     if Scope.UsesFinished then
       RaiseMsg(20180313133931,Section);
     if Section.PendingUsedIntf<>nil then
@@ -5252,7 +5254,7 @@ begin
       Use:=Section.UsesClause[i];
 
       Module:=Use.Module as TPasModule;
-      UsedScope:=Module.InterfaceSection.CustomData as TPasSectionScope;
+      UsedScope:=Module.InterfaceSection.CustomData as TPas2JSSectionScope;
       Scope.UsesScopes.Add(UsedScope);
       if ReadObject(UsesObj,'Module',ModuleObj,Use) then
         ReadExternalReferences(ModuleObj,Module);
@@ -5277,7 +5279,7 @@ begin
         RaiseMsg(20180314155840,Section,Name);
       if Module.InterfaceSection=nil then
         RaiseMsg(20180314155953,Section,'indirect unit "'+Name+'"');
-      UsedScope:=Module.InterfaceSection.CustomData as TPasSectionScope;
+      UsedScope:=Module.InterfaceSection.CustomData as TPas2JSSectionScope;
       if not UsedScope.Finished then
         RaiseMsg(20180314155953,Section,'indirect unit "'+Name+'"');
       ReadExternalReferences(UsesObj,Module);
@@ -5290,16 +5292,17 @@ begin
 end;
 
 procedure TPCUReader.ReadSectionScope(Obj: TJSONObject;
-  Scope: TPasSectionScope; aContext: TPCUReaderContext);
+  Scope: TPas2JSSectionScope; aContext: TPCUReaderContext);
 begin
   ReadIdentifierScope(Obj,Scope,aContext);
+  // not needed: Scope ElevatedLocals
 end;
 
 procedure TPCUReader.ReadSection(Obj: TJSONObject; Section: TPasSection;
   aContext: TPCUReaderContext);
 // Note: can be called twice for each section if there are pending used interfaces
 var
-  Scope: TPasSectionScope;
+  Scope: TPas2JSSectionScope;
 begin
   {$IFDEF VerbosePCUFiler}
   writeln('TPCUReader.ReadSection ',GetObjName(Section));
@@ -5307,13 +5310,13 @@ begin
   if Section.CustomData=nil then
     begin
     ReadPasElement(Obj,Section,aContext);
-    Scope:=TPasSectionScope(Resolver.CreateScope(Section,TPasSectionScope));
+    Scope:=TPas2JSSectionScope(Resolver.CreateScope(Section,TPas2JSSectionScope));
     ReadUsedUnitsInit(Obj,Section,aContext);
     if Section.PendingUsedIntf<>nil then exit;
     end
   else
     begin
-    Scope:=Section.CustomData as TPasSectionScope;
+    Scope:=Section.CustomData as TPas2JSSectionScope;
     if Scope.Finished then
       RaiseMsg(20180308160336,Section);
     if Section.PendingUsedIntf<>nil then

+ 8 - 8
packages/pastojs/tests/tcfiler.pas

@@ -66,7 +66,7 @@ type
     procedure CheckRestoredPasScope(const Path: string; Orig, Rest: TPasScope); virtual;
     procedure CheckRestoredModuleScope(const Path: string; Orig, Rest: TPas2JSModuleScope); virtual;
     procedure CheckRestoredIdentifierScope(const Path: string; Orig, Rest: TPasIdentifierScope); virtual;
-    procedure CheckRestoredSectionScope(const Path: string; Orig, Rest: TPasSectionScope); virtual;
+    procedure CheckRestoredSectionScope(const Path: string; Orig, Rest: TPas2JSSectionScope); virtual;
     procedure CheckRestoredInitialFinalizationScope(const Path: string; Orig, Rest: TPas2JSInitialFinalizationScope); virtual;
     procedure CheckRestoredEnumTypeScope(const Path: string; Orig, Rest: TPasEnumTypeScope); virtual;
     procedure CheckRestoredRecordScope(const Path: string; Orig, Rest: TPasRecordScope); virtual;
@@ -649,18 +649,18 @@ begin
 end;
 
 procedure TCustomTestPrecompile.CheckRestoredSectionScope(const Path: string;
-  Orig, Rest: TPasSectionScope);
+  Orig, Rest: TPas2JSSectionScope);
 var
   i: Integer;
-  OrigUses, RestUses: TPasSectionScope;
+  OrigUses, RestUses: TPas2JSSectionScope;
 begin
   AssertEquals(Path+' UsesScopes.Count',Orig.UsesScopes.Count,Rest.UsesScopes.Count);
   for i:=0 to Orig.UsesScopes.Count-1 do
     begin
-    OrigUses:=TPasSectionScope(Orig.UsesScopes[i]);
-    if not (TObject(Rest.UsesScopes[i]) is TPasSectionScope) then
+    OrigUses:=TPas2JSSectionScope(Orig.UsesScopes[i]);
+    if not (TObject(Rest.UsesScopes[i]) is TPas2JSSectionScope) then
       Fail(Path+'.UsesScopes['+IntToStr(i)+'] Rest='+GetObjName(TObject(Rest.UsesScopes[i])));
-    RestUses:=TPasSectionScope(Rest.UsesScopes[i]);
+    RestUses:=TPas2JSSectionScope(Rest.UsesScopes[i]);
     if OrigUses.ClassType<>RestUses.ClassType then
       Fail(Path+'.UsesScopes['+IntToStr(i)+'] Orig='+GetObjName(OrigUses)+' Rest='+GetObjName(RestUses));
     CheckRestoredReference(Path+'.UsesScopes['+IntToStr(i)+']',OrigUses.Element,RestUses.Element);
@@ -949,8 +949,8 @@ begin
     CheckRestoredResolvedReference(Path+'[TResolvedReference]',TResolvedReference(Orig),TResolvedReference(Rest))
   else if C=TPas2JSModuleScope then
     CheckRestoredModuleScope(Path+'[TPas2JSModuleScope]',TPas2JSModuleScope(Orig),TPas2JSModuleScope(Rest))
-  else if C=TPasSectionScope then
-    CheckRestoredSectionScope(Path+'[TPasSectionScope]',TPasSectionScope(Orig),TPasSectionScope(Rest))
+  else if C=TPas2JSSectionScope then
+    CheckRestoredSectionScope(Path+'[TPas2JSSectionScope]',TPas2JSSectionScope(Orig),TPas2JSSectionScope(Rest))
   else if C=TPas2JSInitialFinalizationScope then
     CheckRestoredInitialFinalizationScope(Path+'[TPas2JSInitialFinalizationScope]',TPas2JSInitialFinalizationScope(Orig),TPas2JSInitialFinalizationScope(Rest))
   else if C=TPasEnumTypeScope then

+ 2 - 2
packages/pastojs/tests/tcmodules.pas

@@ -3445,8 +3445,6 @@ end;
 
 procedure TTestModule.TestProc_DuplicateConst;
 begin
-  exit;
-
   StartProgram(false);
   Add([
   'const A = 1;',
@@ -3471,6 +3469,8 @@ begin
     'var A$1 = 2;',
     'var A$2 = 21;',
     'this.DoIt = function () {',
+    '  function SubIt() {',
+    '  };',
     '};',
     'var A$3 = 3;',
     'this.DoSome = function () {',