diff options
author | mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2020-03-28 16:32:32 +0000 |
---|---|---|
committer | mattias <mattias@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2020-03-28 16:32:32 +0000 |
commit | 6cbb5fd4da861defe4c2240f63b0241812763874 (patch) | |
tree | 68a784a1dcc892c68a21147c86c8278e421463bb /packages/pastojs | |
parent | c8f1a20b5ad8e81db27dcf38b326baa0e077abc8 (diff) | |
download | fpc-6cbb5fd4da861defe4c2240f63b0241812763874.tar.gz |
pastojs: filer: started pending specialize
git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@44388 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/pastojs')
-rw-r--r-- | packages/pastojs/src/pas2jsfiler.pp | 305 | ||||
-rw-r--r-- | packages/pastojs/tests/tcfiler.pas | 25 | ||||
-rw-r--r-- | packages/pastojs/tests/testpas2js.lpi | 1 |
3 files changed, 295 insertions, 36 deletions
diff --git a/packages/pastojs/src/pas2jsfiler.pp b/packages/pastojs/src/pas2jsfiler.pp index b63331a2be..ce7d901f3b 100644 --- a/packages/pastojs/src/pas2jsfiler.pp +++ b/packages/pastojs/src/pas2jsfiler.pp @@ -774,6 +774,7 @@ type procedure WriteScopeReferences(Obj: TJSONObject; References: TPasScopeReferences; const PropName: string; aContext: TPCUWriterContext); virtual; // extern references + function IsExternalEl(El: TPasElement): boolean; virtual; procedure WriteExtRefSignature(Ref: TPCUFilerElementRef; aContext: TPCUWriterContext); virtual; function WriteExternalReference(El: TPasElement; aContext: TPCUWriterContext): TPCUFilerElementRef; virtual; procedure WriteExternalReferences(aContext: TPCUWriterContext); virtual; @@ -903,6 +904,28 @@ type Arr: TJSONArray; end; + TPCUReaderPendingSpecialized = class; + + { TPCUReaderPendingSpecializedParam } + + TPCUReaderPendingSpecializedParam = class + public + Spec: TPCUReaderPendingSpecialized; + Index: integer; // index in Spec.Params + Element: TPasElement; + end; + + { TPCUReaderPendingSpecialized } + + TPCUReaderPendingSpecialized = class + public + Obj: TJSONObject; + GenericEl: TPasGenericType; + Params: TFPList; // list of PCUReaderPendingSpecializedParams + Prev, Next: TPCUReaderPendingSpecialized; + destructor Destroy; override; + end; + { TPCUReader } TPCUReader = class(TPCUCustomReader) @@ -910,6 +933,9 @@ type FElementRefsArray: TPCUFilerElementRefArray; // TPCUFilerElementRef by Id FJSON: TJSONObject; FPendingIdentifierScopes: TObjectList; // list of TPCUReaderPendingIdentifierScope + FPendingSpecialize: TPCUReaderPendingSpecialized; // chain of TPCUReaderPendingSpecialized + function AddPendingSpecialize(GenEl: TPasGenericType; ParamCount: integer): TPCUReaderPendingSpecialized; + procedure DeletePendingSpecialize(PendSpec: TPCUReaderPendingSpecialized); procedure Set_Variable_VarType(RefEl: TPasElement; Data: TObject); procedure Set_AliasType_DestType(RefEl: TPasElement; Data: TObject); procedure Set_PointerType_DestType(RefEl: TPasElement; Data: TObject); @@ -943,6 +969,7 @@ type procedure Set_ResolvedReference_Declaration(RefEl: TPasElement; Data: TObject); procedure Set_ResolvedReference_CtxConstructor(RefEl: TPasElement; Data: TObject); procedure Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement; Data: TObject); + procedure Set_SpecializeParam(RefEl: TPasElement; Data: TObject); protected // json procedure RaiseMsg(Id: int64; const Msg: string = ''); overload; override; @@ -988,6 +1015,7 @@ type procedure ReadPasElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUReaderContext); virtual; procedure ReadExternalMembers(El: TPasElement; Arr: TJSONArray; Members: TFPList); virtual; procedure ReadExternalReferences(Obj: TJSONObject; El: TPasElement); virtual; + procedure ReadExternalSpecialized(Obj: TJSONObject; GenEl: TPasGenericType; ParamIDs: TJSONArray); virtual; procedure ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual; procedure ReadUsedUnitsFinish(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); virtual; procedure ReadSectionScope(Obj: TJSONObject; Scope: TPas2JSSectionScope; aContext: TPCUReaderContext); virtual; @@ -1734,6 +1762,23 @@ begin AddLine(Line); end; +{ TPCUReaderPendingSpecialized } + +destructor TPCUReaderPendingSpecialized.Destroy; +var + i: Integer; +begin + Obj:=nil; + GenericEl:=nil; + if Params<>nil then + begin + for i:=0 to Params.Count-1 do + TObject(Params[i]).Free; + FreeAndNil(Params); + end; + inherited Destroy; +end; + { TPCUCustomReader } function TPCUCustomReader.ReadCanContinue: boolean; @@ -2192,7 +2237,7 @@ end; function TPCUWriter.CreateElementRef(El: TPasElement): TPCUFilerElementRef; begin Result:=inherited CreateElementRef(El); - if El.GetModule<>Resolver.RootElement then + if IsExternalEl(El) then begin if FFirstNewExt=nil then FFirstNewExt:=Result @@ -3119,22 +3164,81 @@ begin if aContext=nil then ; end; +function TPCUWriter.IsExternalEl(El: TPasElement): boolean; +var + C: TClass; +begin + while El<>nil do + begin + C:=El.ClassType; + if C.InheritsFrom(TPasModule) then + exit(El<>Resolver.RootElement) + else if C.InheritsFrom(TPasGenericType) then + begin + if Resolver.IsSpecialized(TPasGenericType(El)) then + exit(true); + end; + El:=El.Parent; + end; +end; + procedure TPCUWriter.WriteExtRefSignature(Ref: TPCUFilerElementRef; aContext: TPCUWriterContext); procedure WriteMemberIndex(Members: TFPList; Member: TPasElement; Obj: TJSONObject); var - i, Index: Integer; + i, Index, j: Integer; + CurEl: TPasElement; + SpecItem: TPRSpecializedItem; + Arr: TJSONArray; + Param: TPasType; begin + j:=0; + Index:=-1; + SpecItem:=nil; + + if (Member.CustomData is TPasGenericScope) then + begin + SpecItem:=TPasGenericScope(Member.CustomData).SpecializedFromItem; + if SpecItem<>nil then + begin + // member is specialized -> write generic index + Member:=SpecItem.GenericEl; + end; + end; + for i:=0 to Members.Count-1 do - if TPasElement(Members[i])=Member then + begin + CurEl:=TPasElement(Members[i]); + if CurEl=Member then begin - Index:=i; + Index:=j; break; - end; + end + else if (CurEl is TPasGenericType) + and Resolver.IsSpecialized(TPasGenericType(CurEl)) then + // skip specialized type + else + inc(j); + end; if Index<0 then RaiseMsg(20180309184111,Member); Obj.Add('MId',Index); + + if SpecItem<>nil then + begin + // write specialize params + Obj.Add('SpecName',SpecItem.SpecializedEl.Name); + Arr:=TJSONArray.Create; + Obj.Add('Spec',Arr); + for i:=0 to length(SpecItem.Params)-1 do + begin + Param:=SpecItem.Params[i]; + if Param=nil then + RaiseMsg(20200222110205,Member); + AddReferenceToArray(Arr,Param); + end; + end; end; var @@ -3169,24 +3273,44 @@ function TPCUWriter.WriteExternalReference(El: TPasElement; aContext: TPCUWriterContext): TPCUFilerElementRef; var ParentRef, Ref: TPCUFilerElementRef; - Parent: TPasElement; + Parent, NameEl: TPasElement; Name: String; + SpecItem: TPRSpecializedItem; begin Result:=nil; if El=nil then exit; // check if already written Ref:=GetElementReference(El); if Ref.Obj<>nil then - exit(Ref); + exit(Ref);// already written + if not IsExternalEl(El) then + RaiseMsg(20200323121033,El,GetObjName(El)); + //writeln('TPCUWriter.WriteExternalReference ',GetObjName(El)); - // check that is written + // write Parent first Parent:=El.Parent; - ParentRef:=WriteExternalReference(Parent,aContext); - if ParentRef=nil then - if not (El is TPasModule) then - RaiseMsg(20180308174440,El,GetObjName(El)); + if IsExternalEl(Parent) then + begin + ParentRef:=WriteExternalReference(Parent,aContext); + if ParentRef=nil then + if not (El is TPasModule) then + RaiseMsg(20180308174440,El,GetObjName(El)); + end + else + begin + // El is external, Parent is not -> e.g. El is a specialization + RaiseMsg(20200328173009,El,GetObjName(El)); // ToDo + end; + // check name - Name:=Resolver.GetOverloadName(El); + NameEl:=El; + if (El.CustomData is TPasGenericScope) then + begin + SpecItem:=TPasGenericScope(El.CustomData).SpecializedFromItem; + if SpecItem<>nil then + NameEl:=SpecItem.GenericEl; // specialized -> use generic name + end; + Name:=Resolver.GetOverloadName(NameEl); if Name='' then begin Name:=GetDefaultRefName(El); @@ -3243,7 +3367,7 @@ begin FLastNewExt:=nil; if Ref.Pending=nil then continue; // not used, e.g. when a child is written, its parents are - // written too, which might still be in the queue + // written too, who might still be in the queue El:=Ref.Element; //writeln('TPCUWriter.WriteExternalReferences ',GetObjName(El),' ',GetElementFullPath(El)); {$IF defined(VerbosePJUFiler) or defined(VerbosePCUFiler) or defined(VerboseUnitQueue)} @@ -3265,13 +3389,6 @@ end; procedure TPCUWriter.WriteElement(Obj: TJSONObject; El: TPasElement; aContext: TPCUWriterContext); - - function IsSpecialized(GenEl: TPasGenericType): boolean; - begin - Result:=(GenEl.CustomData is TPasGenericScope) - and (TPasGenericScope(GenEl.CustomData).SpecializedFromItem<>nil); - end; - var C: TClass; Kind: TPasExprKind; @@ -3391,7 +3508,7 @@ begin end else if C=TPasArrayType then begin - if IsSpecialized(TPasGenericType(El)) then exit; + if Resolver.IsSpecialized(TPasGenericType(El)) then exit; Obj.Add('Type','ArrType'); WriteArrayType(Obj,TPasArrayType(El),aContext); end @@ -3422,13 +3539,14 @@ begin end else if C=TPasRecordType then begin - if IsSpecialized(TPasGenericType(El)) then exit; + if Resolver.IsSpecialized(TPasGenericType(El)) then exit; Obj.Add('Type','Record'); WriteRecordType(Obj,TPasRecordType(El),aContext); end else if C=TPasClassType then begin - if IsSpecialized(TPasGenericType(El)) then exit; + if Resolver.IsSpecialized(TPasGenericType(El)) then + exit; // Note: only referenced specializations are stored Obj.Add('Type',PCUObjKindNames[TPasClassType(El).ObjKind]); WriteClassType(Obj,TPasClassType(El),aContext); end @@ -3439,7 +3557,7 @@ begin end else if C=TPasProcedureType then begin - if IsSpecialized(TPasGenericType(El)) then exit; + if Resolver.IsSpecialized(TPasGenericType(El)) then exit; Obj.Add('Type','ProcType'); WriteProcedureType(Obj,TPasProcedureType(El),aContext); end @@ -4763,6 +4881,43 @@ end; { TPCUReader } +function TPCUReader.AddPendingSpecialize(GenEl: TPasGenericType; + ParamCount: integer): TPCUReaderPendingSpecialized; +var + Param: TPCUReaderPendingSpecializedParam; + i: Integer; +begin + Result:=TPCUReaderPendingSpecialized.Create; + Result.GenericEl:=GenEl; + if FPendingSpecialize<>nil then + begin + Result.Next:=FPendingSpecialize; + FPendingSpecialize.Prev:=Result; + end; + FPendingSpecialize:=Result; + + Result.Params:=TFPList.Create; + for i:=0 to ParamCount-1 do + begin + Param:=TPCUReaderPendingSpecializedParam.Create; + Result.Params.Add(Param); + Param.Spec:=Result; + Param.Index:=i; + end; +end; + +procedure TPCUReader.DeletePendingSpecialize( + PendSpec: TPCUReaderPendingSpecialized); +begin + if FPendingSpecialize=PendSpec then + FPendingSpecialize:=PendSpec.Next; + if PendSpec.Prev<>nil then PendSpec.Prev.Next:=PendSpec.Next; + if PendSpec.Next<>nil then PendSpec.Next.Prev:=PendSpec.Prev; + PendSpec.Prev:=nil; + PendSpec.Next:=nil; + PendSpec.Free; +end; + procedure TPCUReader.Set_Variable_VarType(RefEl: TPasElement; Data: TObject); var El: TPasVariable absolute Data; @@ -5166,7 +5321,7 @@ begin if RefEl is TPasType then TResolvedRefCtxConstructor(Ref.Context).Typ:=TPasType(RefEl) // no AddRef else - RaiseMsg(20190222010314,Ref.Element,GetObjName(RefEl)); + RaiseMsg(20190222010314,Ref.Element,GetObjPath(RefEl)); end; procedure TPCUReader.Set_ResolvedReference_CtxAttrProc(RefEl: TPasElement; @@ -5177,7 +5332,37 @@ begin if RefEl is TPasConstructor then TResolvedRefCtxAttrProc(Ref.Context).Proc:=TPasConstructor(RefEl) // no AddRef else - RaiseMsg(20190222010821,Ref.Element,GetObjName(RefEl)); + RaiseMsg(20190222010821,Ref.Element,GetObjPath(RefEl)); +end; + +procedure TPCUReader.Set_SpecializeParam(RefEl: TPasElement; Data: TObject); +var + Param: TPCUReaderPendingSpecializedParam absolute Data; + PendSpec: TPCUReaderPendingSpecialized; + i: Integer; + RefParams, ElParams: TFPList; + SpecEl: TPasElement; +begin + PendSpec:=Param.Spec; + if not (RefEl is TPasType) then + RaiseMsg(20200222195932,PendSpec.GenericEl,GetObjPath(RefEl)); + Param.Element:=RefEl; + RefParams:=PendSpec.Params; + i:=RefParams.Count-1; + while (i>=0) and (TPCUReaderPendingSpecializedParam(RefParams[i]).Element<>nil) do + dec(i); + if i>=0 then exit; + // all RefParams resolved -> specialize + ElParams:=TFPList.Create; + try + for i:=0 to RefParams.Count-1 do + ElParams.Add(TPCUReaderPendingSpecializedParam(RefParams[i]).Element); + SpecEl:=Resolver.GetSpecializedEl(Resolver.RootElement,PendSpec.GenericEl,ElParams); + finally + ElParams.Free; + end; + // read child declarations + ReadExternalReferences(PendSpec.Obj,SpecEl); end; procedure TPCUReader.RaiseMsg(Id: int64; const Msg: string); @@ -6056,11 +6241,12 @@ end; procedure TPCUReader.ReadExternalMembers(El: TPasElement; Arr: TJSONArray; Members: TFPList); var - i, Index: Integer; + i, Index, j, k: Integer; Data: TJSONData; SubObj: TJSONObject; Name: string; ChildEl: TPasElement; + SpecArr: TJSONArray; begin for i:=0 to Arr.Count-1 do begin @@ -6076,12 +6262,33 @@ begin RaiseMsg(20180309184629,El,IntToStr(i)); if (Index<0) or (Index>=Members.Count) then RaiseMsg(20180309184718,El,IntToStr(Index)+' out of bounds 0-'+IntToStr(Members.Count)); - ChildEl:=TPasElement(Members[Index]); + ChildEl:=nil; + j:=0; + for k:=0 to Members.Count-1 do + begin + ChildEl:=TPasElement(Members[k]); + if (ChildEl is TPasGenericType) + and Resolver.IsSpecialized(TPasGenericType(ChildEl)) then + // skip specialized type + else if Index=j then + break + else + inc(j); + end; + if Index>j then + RaiseMsg(20200222102600,El,IntToStr(Index)+' out of bounds'); if Resolver.GetOverloadName(ChildEl)<>Name then RaiseMsg(20180309200800,El,'Expected="'+Name+'", but found "'+Resolver.GetOverloadName(ChildEl)+'" ('+ChildEl.Name+')'); // read child declarations - ReadExternalReferences(SubObj,ChildEl); + if ReadArray(SubObj,'Spec',SpecArr,ChildEl) then + begin + if not (ChildEl is TPasGenericType) then + RaiseMsg(20200222163616,El,GetObjPath(ChildEl)); + ReadExternalSpecialized(SubObj,TPasGenericType(ChildEl),SpecArr); + end + else + ReadExternalReferences(SubObj,ChildEl); end; end; @@ -6134,6 +6341,31 @@ begin end; end; +procedure TPCUReader.ReadExternalSpecialized(Obj: TJSONObject; + GenEl: TPasGenericType; ParamIDs: TJSONArray); +var + i, Id: Integer; + ErrorEl: TPasElement; + PendSpec: TPCUReaderPendingSpecialized; + PendParam: TPCUReaderPendingSpecializedParam; +begin + ErrorEl:=GenEl; + if ParamIDs.Count=0 then + RaiseMsg(20200222190934,ErrorEl); + PendSpec:=AddPendingSpecialize(GenEl,ParamIDs.Count); + PendSpec.Obj:=Obj; + for i:=0 to ParamIDs.Count-1 do + begin + if ParamIDs.Types[i]<>jtNumber then + RaiseMsg(20200222164327,GenEl,'i='+IntToStr(i)+' '+IntToStr(ord(ParamIDs.Types[i]))); + Id:=ParamIDs[i].AsInteger; + if Id<=0 then + RaiseMsg(20200222191724,ErrorEl,IntToStr(i)); + PendParam:=TPCUReaderPendingSpecializedParam(PendSpec.Params[i]); + PromiseSetElReference(Id,@Set_SpecializeParam,PendParam,ErrorEl); + end; +end; + procedure TPCUReader.ReadUsedUnitsInit(Obj: TJSONObject; Section: TPasSection; aContext: TPCUReaderContext); // Note: can be called twice for each section if there are pending used interfaces @@ -8082,6 +8314,9 @@ begin El.PackMode:=ReadPackedMode(Obj,'Packed',El); // ObjKind is the 'Type' + if El.IsForward then + exit; + El.InterfaceType:=ReadClassInterfaceType(Obj,'IntfType',El,citCom); ReadElType(Obj,'Ancestor',El,@Set_ClassType_AncestorType,aContext); @@ -8140,6 +8375,13 @@ begin Resolver.FinishSpecializedClassOrRecIntf(Scope); Resolver.FinishSpecializations(Scope); end; + + if (El.GenericTemplateTypes<>nil) and (El.GenericTemplateTypes.Count>0) + and ReadArray(Obj,'El',Arr,El) then + begin + // has specializations used by the module itself + ReadExternalMembers(El,Arr,El.Members); + end; end; procedure TPCUReader.ReadArgument(Obj: TJSONObject; El: TPasArgument; @@ -9008,6 +9250,9 @@ begin FElementRefsArray[i].Free; FElementRefsArray:=nil; FPendingIdentifierScopes.Clear; + while FPendingSpecialize<>nil do + DeletePendingSpecialize(FPendingSpecialize); + inherited Clear; FInitialFlags.Clear; end; diff --git a/packages/pastojs/tests/tcfiler.pas b/packages/pastojs/tests/tcfiler.pas index a535c259d8..277f4b3d93 100644 --- a/packages/pastojs/tests/tcfiler.pas +++ b/packages/pastojs/tests/tcfiler.pas @@ -16,7 +16,7 @@ Examples: ./testpas2js --suite=TTestPrecompile.TestPC_EmptyUnit } -unit tcfiler; +unit TCFiler; {$mode objfpc}{$H+} @@ -212,11 +212,24 @@ type procedure TestPC_GenericClass; procedure TestPC_GenericMethod; procedure TestPC_SpecializeClassSameUnit; // ToDo - // ToDo: specialize - // ToDo: inline specialize in unit interface - // ToDo: inline specialize in unit implementation - // ToDo: inline specialize in proc decl - // ToDo: inline specialize in proc body + // ToDo: specialize local generic type in unit interface + // ToDo: specialize local generic type in unit implementation + // ToDo: specialize local generic type in proc decl + // ToDo: specialize local generic type in proc body + // ToDo: inline specialize local generic type in unit interface + // ToDo: inline specialize local generic type in unit implementation + // ToDo: inline specialize local generic type in proc decl + // ToDo: inline specialize local generic type in proc body + // ToDo: specialize extern generic type in unit interface + // ToDo: specialize extern generic type in unit implementation + // ToDo: specialize extern generic type in proc decl + // ToDo: specialize extern generic type in proc body + // ToDo: inline specialize extern generic type in unit interface + // ToDo: inline specialize extern generic type in unit implementation + // ToDo: inline specialize extern generic type in proc decl + // ToDo: inline specialize extern generic type in proc body + // ToDo: half specialize TBird<T> = class a: TAnt<word,T>; end; + // ToDo: no specialize: TBird<T> = class a: TBird<T>; end; // ToDo: constraints procedure TestPC_UseUnit; diff --git a/packages/pastojs/tests/testpas2js.lpi b/packages/pastojs/tests/testpas2js.lpi index c879885290..05dc286e13 100644 --- a/packages/pastojs/tests/testpas2js.lpi +++ b/packages/pastojs/tests/testpas2js.lpi @@ -72,6 +72,7 @@ <Unit7> <Filename Value="tcfiler.pas"/> <IsPartOfProject Value="True"/> + <UnitName Value="TCFiler"/> </Unit7> <Unit8> <Filename Value="../src/pas2jsfiler.pp"/> |