mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-14 22:09:16 +02:00
pastojs: record helper constructor
git-svn-id: trunk@41259 -
This commit is contained in:
parent
b0ca862f32
commit
c617546fcd
@ -15882,6 +15882,8 @@ begin
|
|||||||
else if ((C=TPasVariable) or (C=TPasProperty))
|
else if ((C=TPasVariable) or (C=TPasProperty))
|
||||||
and (not (vmClass in TPasVariable(FindData.Found).VarModifiers)) then
|
and (not (vmClass in TPasVariable(FindData.Found).VarModifiers)) then
|
||||||
// ok
|
// ok
|
||||||
|
else if IsHelper(FindData.Found.Parent) then
|
||||||
|
// ok
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
RaiseMsg(20170331184224,nExternalClassInstanceCannotAccessStaticX,
|
RaiseMsg(20170331184224,nExternalClassInstanceCannotAccessStaticX,
|
||||||
|
@ -1621,6 +1621,7 @@ type
|
|||||||
procedure SetUseSwitchStatement(const AValue: boolean);
|
procedure SetUseSwitchStatement(const AValue: boolean);
|
||||||
protected
|
protected
|
||||||
type
|
type
|
||||||
|
TMemberFunc = (mfInit, mfFinalize);
|
||||||
TConvertJSEvent = function(El: TPasElement; AContext: TConvertContext; Data: Pointer): TJSElement of object;
|
TConvertJSEvent = function(El: TPasElement; AContext: TConvertContext; Data: Pointer): TJSElement of object;
|
||||||
TCreateRefPathData = record
|
TCreateRefPathData = record
|
||||||
El: TPasElement;
|
El: TPasElement;
|
||||||
@ -1757,6 +1758,12 @@ type
|
|||||||
OpCode: TExprOpCode): TJSElement; virtual;
|
OpCode: TExprOpCode): TJSElement; virtual;
|
||||||
Function CreateCloneStaticArray(El: TPasElement; ArrTypeEl: TPasArrayType;
|
Function CreateCloneStaticArray(El: TPasElement; ArrTypeEl: TPasArrayType;
|
||||||
ArrayExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
|
ArrayExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
|
||||||
|
// class
|
||||||
|
Procedure AddInstanceMemberFunction(El: TPasClassType; Src: TJSSourceElements;
|
||||||
|
ClassContext: TConvertContext; IsTObject: boolean; Ancestor: TPasType;
|
||||||
|
Kind: TMemberFunc);
|
||||||
|
Procedure AddClassRTTI(El: TPasClassType; Src: TJSSourceElements;
|
||||||
|
FuncContext: TFunctionContext);
|
||||||
// misc
|
// misc
|
||||||
Function CreateCallback(Expr: TPasExpr; ResolvedEl: TPasResolverResult;
|
Function CreateCallback(Expr: TPasExpr; ResolvedEl: TPasResolverResult;
|
||||||
AContext: TConvertContext): TJSElement; virtual;
|
AContext: TConvertContext): TJSElement; virtual;
|
||||||
@ -1804,9 +1811,13 @@ type
|
|||||||
FuncContext: TFunctionContext);
|
FuncContext: TFunctionContext);
|
||||||
Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement);
|
Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement);
|
||||||
Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
|
Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
|
||||||
|
Procedure AddClassSupportedInterfaces(El: TPasClassType; Src: TJSSourceElements;
|
||||||
|
FuncContext: TFunctionContext);
|
||||||
// create elements for helpers
|
// create elements for helpers
|
||||||
Function CreateCallHelperMethod(Proc: TPasProcedure; Expr: TPasExpr;
|
Function CreateCallHelperMethod(Proc: TPasProcedure; Expr: TPasExpr;
|
||||||
AContext: TConvertContext; Implicit: boolean = false): TJSCallExpression; virtual;
|
AContext: TConvertContext; Implicit: boolean = false): TJSCallExpression; virtual;
|
||||||
|
Procedure AddHelperConstructor(El: TPasClassType; Src: TJSSourceElements;
|
||||||
|
AContext: TConvertContext); virtual;
|
||||||
// Statements
|
// Statements
|
||||||
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
|
Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
|
||||||
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
|
Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
|
||||||
@ -3799,7 +3810,7 @@ begin
|
|||||||
if TPasClassType(HelperForType).IsExternal then
|
if TPasClassType(HelperForType).IsExternal then
|
||||||
begin
|
begin
|
||||||
// method of a class helper for external class
|
// method of a class helper for external class
|
||||||
if not (ptmStatic in El.Modifiers) then
|
if IsClassMethod(El) and not (ptmStatic in El.Modifiers) then
|
||||||
RaiseMsg(20190201165259,nHelperClassMethodForExtClassMustBeStatic,
|
RaiseMsg(20190201165259,nHelperClassMethodForExtClassMustBeStatic,
|
||||||
sHelperClassMethodForExtClassMustBeStatic,[],El);
|
sHelperClassMethodForExtClassMustBeStatic,[],El);
|
||||||
if El.ClassType=TPasConstructor then
|
if El.ClassType=TPasConstructor then
|
||||||
@ -12451,13 +12462,6 @@ function TPasToJSConverter.ConvertClassType(El: TPasClassType;
|
|||||||
this.i = 0;
|
this.i = 0;
|
||||||
});
|
});
|
||||||
*)
|
*)
|
||||||
type
|
|
||||||
TMemberFunc = (mfInit, mfFinalize);
|
|
||||||
const
|
|
||||||
MemberFuncName: array[TMemberFunc] of string = (
|
|
||||||
'$init',
|
|
||||||
'$final'
|
|
||||||
);
|
|
||||||
var
|
var
|
||||||
IsTObject, AncestorIsExternal: boolean;
|
IsTObject, AncestorIsExternal: boolean;
|
||||||
|
|
||||||
@ -12466,7 +12470,7 @@ var
|
|||||||
if IsElementUsed(aMember) then exit(true);
|
if IsElementUsed(aMember) then exit(true);
|
||||||
if IsTObject then
|
if IsTObject then
|
||||||
begin
|
begin
|
||||||
if aMember is TPasProcedure then
|
if aMember.ClassType=TPasProcedure then
|
||||||
begin
|
begin
|
||||||
if (CompareText(aMember.Name,'AfterConstruction')=0)
|
if (CompareText(aMember.Name,'AfterConstruction')=0)
|
||||||
or (CompareText(aMember.Name,'BeforeDestruction')=0) then
|
or (CompareText(aMember.Name,'BeforeDestruction')=0) then
|
||||||
@ -12476,109 +12480,6 @@ var
|
|||||||
Result:=false;
|
Result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure AddCallAncestorMemberFunction(ClassContext: TConvertContext;
|
|
||||||
Ancestor: TPasType; Src: TJSSourceElements; Kind: TMemberFunc);
|
|
||||||
var
|
|
||||||
Call: TJSCallExpression;
|
|
||||||
AncestorPath: String;
|
|
||||||
begin
|
|
||||||
if (Ancestor=nil) or AncestorIsExternal then
|
|
||||||
exit;
|
|
||||||
Call:=CreateCallExpression(El);
|
|
||||||
AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
|
|
||||||
Call.Expr:=CreatePrimitiveDotExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call',El);
|
|
||||||
Call.AddArg(CreatePrimitiveDotExpr('this',El));
|
|
||||||
AddToSourceElements(Src,Call);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AddInstanceMemberFunction(Src: TJSSourceElements;
|
|
||||||
ClassContext: TConvertContext; Ancestor: TPasType; Kind: TMemberFunc);
|
|
||||||
// add instance initialization function:
|
|
||||||
// this.$init = function(){
|
|
||||||
// ancestor.$init();
|
|
||||||
// ... init variables ...
|
|
||||||
// }
|
|
||||||
// or add instance finalization function:
|
|
||||||
// this.$final = function(){
|
|
||||||
// ... clear references ...
|
|
||||||
// ancestor.$final();
|
|
||||||
// }
|
|
||||||
var
|
|
||||||
FuncVD: TJSVarDeclaration;
|
|
||||||
New_Src: TJSSourceElements;
|
|
||||||
New_FuncContext: TFunctionContext;
|
|
||||||
I: Integer;
|
|
||||||
P: TPasElement;
|
|
||||||
NewEl: TJSElement;
|
|
||||||
Func: TJSFunctionDeclarationStatement;
|
|
||||||
VarType: TPasType;
|
|
||||||
AssignSt: TJSSimpleAssignStatement;
|
|
||||||
begin
|
|
||||||
// add instance members
|
|
||||||
New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
|
|
||||||
New_FuncContext:=TFunctionContext.Create(El,New_Src,ClassContext);
|
|
||||||
try
|
|
||||||
New_FuncContext.ThisPas:=El;
|
|
||||||
New_FuncContext.IsGlobal:=true;
|
|
||||||
|
|
||||||
// add class members
|
|
||||||
For I:=0 to El.Members.Count-1 do
|
|
||||||
begin
|
|
||||||
P:=TPasElement(El.Members[i]);
|
|
||||||
if not IsMemberNeeded(P) then continue;
|
|
||||||
NewEl:=nil;
|
|
||||||
if (P.ClassType=TPasVariable)
|
|
||||||
and (ClassVarModifiersType*TPasVariable(P).VarModifiers=[]) then
|
|
||||||
begin
|
|
||||||
if Kind=mfInit then
|
|
||||||
// mfInit: init var
|
|
||||||
NewEl:=CreateVarDecl(TPasVariable(P),New_FuncContext) // can be nil
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
// mfFinalize: clear reference
|
|
||||||
if vmExternal in TPasVariable(P).VarModifiers then continue;
|
|
||||||
VarType:=ClassContext.Resolver.ResolveAliasType(TPasVariable(P).VarType);
|
|
||||||
if (VarType.ClassType=TPasRecordType)
|
|
||||||
or (VarType.ClassType=TPasClassType)
|
|
||||||
or (VarType.ClassType=TPasClassOfType)
|
|
||||||
or (VarType.ClassType=TPasSetType)
|
|
||||||
or (VarType.ClassType=TPasProcedureType)
|
|
||||||
or (VarType.ClassType=TPasFunctionType)
|
|
||||||
or (VarType.ClassType=TPasArrayType) then
|
|
||||||
begin
|
|
||||||
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
|
||||||
NewEl:=AssignSt;
|
|
||||||
AssignSt.LHS:=CreateSubDeclNameExpr(P,New_FuncContext);
|
|
||||||
AssignSt.Expr:=CreateLiteralUndefined(El);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if NewEl=nil then continue;
|
|
||||||
if (Kind=mfInit) and (New_Src.Statements.Count=0) then
|
|
||||||
// add call ancestor.$init.call(this)
|
|
||||||
AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
|
|
||||||
AddToSourceElements(New_Src,NewEl);
|
|
||||||
end;
|
|
||||||
if (Kind=mfFinalize) and (New_Src.Statements.Count>0) then
|
|
||||||
// call ancestor.$final.call(this)
|
|
||||||
AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
|
|
||||||
if (Ancestor<>nil) and (not AncestorIsExternal)
|
|
||||||
and (New_Src.Statements.Count=0) then
|
|
||||||
exit; // descendent does not need $init/$final
|
|
||||||
|
|
||||||
FuncVD:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
|
|
||||||
AddToSourceElements(Src,FuncVD);
|
|
||||||
FuncVD.Name:='this.'+MemberFuncName[Kind];
|
|
||||||
Func:=CreateFunctionSt(El);
|
|
||||||
FuncVD.Init:=Func;
|
|
||||||
Func.AFunction.Body.A:=New_Src;
|
|
||||||
New_Src:=nil;
|
|
||||||
finally
|
|
||||||
New_Src.Free;
|
|
||||||
New_FuncContext.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AddInterfaceProcNames(Call: TJSCallExpression);
|
procedure AddInterfaceProcNames(Call: TJSCallExpression);
|
||||||
var
|
var
|
||||||
Arr: TJSArrayLiteral;
|
Arr: TJSArrayLiteral;
|
||||||
@ -12596,180 +12497,6 @@ var
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure AddMapProcs(Map: TPasClassIntfMap; Call: TJSCallExpression;
|
|
||||||
var ObjLit: TJSObjectLiteral; FuncContext: TConvertContext);
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
MapItem: TObject;
|
|
||||||
Proc, IntfProc: TPasProcedure;
|
|
||||||
ProcName, IntfProcName: String;
|
|
||||||
Intf: TPasClassType;
|
|
||||||
Lit: TJSObjectLiteralElement;
|
|
||||||
begin
|
|
||||||
Intf:=Map.Intf;
|
|
||||||
if Map.Procs<>nil then
|
|
||||||
for i:=0 to Map.Procs.Count-1 do
|
|
||||||
begin
|
|
||||||
MapItem:=TObject(Map.Procs[i]);
|
|
||||||
if not (MapItem is TPasProcedure) then continue;
|
|
||||||
Proc:=TPasProcedure(MapItem);
|
|
||||||
ProcName:=TransformVariableName(Proc,FuncContext);
|
|
||||||
IntfProc:=TObject(Intf.Members[i]) as TPasProcedure;
|
|
||||||
IntfProcName:=TransformVariableName(IntfProc,FuncContext);
|
|
||||||
if IntfProcName=ProcName then continue;
|
|
||||||
if ObjLit=nil then
|
|
||||||
begin
|
|
||||||
ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
|
||||||
Call.AddArg(ObjLit);
|
|
||||||
end;
|
|
||||||
Lit:=ObjLit.Elements.AddElement;
|
|
||||||
Lit.Name:=TJSString(IntfProcName);
|
|
||||||
Lit.Expr:=CreateLiteralString(El,ProcName);
|
|
||||||
end;
|
|
||||||
if Map.AncestorMap<>nil then
|
|
||||||
AddMapProcs(Map.AncestorMap,Call,ObjLit,FuncContext);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AddInterfaces(Src: TJSSourceElements; FuncContext: TFunctionContext);
|
|
||||||
var
|
|
||||||
Call: TJSCallExpression;
|
|
||||||
ObjLit: TJSObjectLiteral;
|
|
||||||
i: Integer;
|
|
||||||
Scope, CurScope: TPas2JSClassScope;
|
|
||||||
o: TObject;
|
|
||||||
IntfMaps: TJSSimpleAssignStatement;
|
|
||||||
MapsObj: TJSObjectLiteral;
|
|
||||||
Map: TPasClassIntfMap;
|
|
||||||
FinishedGUIDs: TStringList;
|
|
||||||
Intf: TPasType;
|
|
||||||
CurEl: TPasClassType;
|
|
||||||
NeedIntfMap, HasInterfaces: Boolean;
|
|
||||||
begin
|
|
||||||
HasInterfaces:=false;
|
|
||||||
NeedIntfMap:=false;
|
|
||||||
Scope:=TPas2JSClassScope(El.CustomData);
|
|
||||||
repeat
|
|
||||||
if Scope.Interfaces<>nil then
|
|
||||||
begin
|
|
||||||
for i:=0 to Scope.Interfaces.Count-1 do
|
|
||||||
begin
|
|
||||||
CurEl:=TPasClassType(Scope.Element);
|
|
||||||
if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
|
|
||||||
HasInterfaces:=true;
|
|
||||||
o:=TObject(Scope.Interfaces[i]);
|
|
||||||
if o is TPasProperty then
|
|
||||||
// interface delegation -> needs $intfmaps={}
|
|
||||||
NeedIntfMap:=true;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
Scope:=TPas2JSClassScope(Scope.AncestorScope);
|
|
||||||
until Scope=nil;
|
|
||||||
if not HasInterfaces then exit;
|
|
||||||
|
|
||||||
IntfMaps:=nil;
|
|
||||||
FinishedGUIDs:=TStringList.Create;
|
|
||||||
try
|
|
||||||
ObjLit:=nil;
|
|
||||||
Scope:=TPas2JSClassScope(El.CustomData);
|
|
||||||
repeat
|
|
||||||
if Scope.Interfaces<>nil then
|
|
||||||
begin
|
|
||||||
for i:=0 to Scope.Interfaces.Count-1 do
|
|
||||||
begin
|
|
||||||
CurEl:=TPasClassType(Scope.Element);
|
|
||||||
if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
|
|
||||||
if NeedIntfMap then
|
|
||||||
begin
|
|
||||||
// add "this.$intfmaps = {};"
|
|
||||||
IntfMaps:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
|
||||||
AddToSourceElements(Src,IntfMaps);
|
|
||||||
IntfMaps.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbivnIntfMaps),El);
|
|
||||||
MapsObj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
|
||||||
IntfMaps.Expr:=MapsObj;
|
|
||||||
NeedIntfMap:=false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
o:=TObject(Scope.Interfaces[i]);
|
|
||||||
if o is TPasClassIntfMap then
|
|
||||||
begin
|
|
||||||
// add rtl.addIntf(this,intftype,{ intfprocname: "procname", ...});
|
|
||||||
Map:=TPasClassIntfMap(o);
|
|
||||||
Intf:=Map.Intf;
|
|
||||||
CurScope:=TPas2JSClassScope(Intf.CustomData);
|
|
||||||
if FinishedGUIDs.IndexOf(CurScope.GUID)>=0 then continue;
|
|
||||||
FinishedGUIDs.Add(CurScope.GUID);
|
|
||||||
Call:=CreateCallExpression(El);
|
|
||||||
AddToSourceElements(Src,Call);
|
|
||||||
Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfAddMap),El);
|
|
||||||
Call.AddArg(CreatePrimitiveDotExpr('this',El));
|
|
||||||
Call.AddArg(CreateReferencePathExpr(Map.Intf,FuncContext));
|
|
||||||
AddMapProcs(Map,Call,ObjLit,FuncContext);
|
|
||||||
end
|
|
||||||
else if o is TPasProperty then
|
|
||||||
AddIntfDelegations(El,TPasProperty(o),FinishedGUIDs,MapsObj,FuncContext)
|
|
||||||
else
|
|
||||||
RaiseNotSupported(El,FuncContext,20180326234026,GetObjName(o));
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
Scope:=TPas2JSClassScope(Scope.AncestorScope);
|
|
||||||
until Scope=nil;
|
|
||||||
finally
|
|
||||||
FinishedGUIDs.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure AddRTTI(Src: TJSSourceElements; FuncContext: TFunctionContext);
|
|
||||||
var
|
|
||||||
HasRTTIMembers: Boolean;
|
|
||||||
i: Integer;
|
|
||||||
P: TPasElement;
|
|
||||||
NewEl: TJSElement;
|
|
||||||
VarSt: TJSVariableStatement;
|
|
||||||
C: TClass;
|
|
||||||
begin
|
|
||||||
// add $r to local vars, to avoid name clashes and for nicer debugging
|
|
||||||
FuncContext.AddLocalVar(GetBIName(pbivnRTTILocal),nil);
|
|
||||||
|
|
||||||
HasRTTIMembers:=false;
|
|
||||||
For i:=0 to El.Members.Count-1 do
|
|
||||||
begin
|
|
||||||
P:=TPasElement(El.Members[i]);
|
|
||||||
//writeln('TPasToJSConverter.ConvertClassType RTTI El[',i,']=',GetObjName(P));
|
|
||||||
if El.ObjKind=okInterface then
|
|
||||||
// all interface methods are published
|
|
||||||
else if P.Visibility<>visPublished then
|
|
||||||
continue;
|
|
||||||
if not IsMemberNeeded(P) then continue;
|
|
||||||
NewEl:=nil;
|
|
||||||
C:=P.ClassType;
|
|
||||||
if C=TPasVariable then
|
|
||||||
NewEl:=CreateRTTIMemberField(TPasVariable(P),FuncContext)
|
|
||||||
else if C.InheritsFrom(TPasProcedure) then
|
|
||||||
NewEl:=CreateRTTIMemberMethod(TPasProcedure(P),FuncContext)
|
|
||||||
else if C=TPasProperty then
|
|
||||||
NewEl:=CreateRTTIMemberProperty(TPasProperty(P),FuncContext)
|
|
||||||
else if C.InheritsFrom(TPasType) then
|
|
||||||
continue
|
|
||||||
else if C=TPasMethodResolution then
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
DoError(20170409202315,nSymbolCannotBePublished,sSymbolCannotBePublished,[],P);
|
|
||||||
if NewEl=nil then
|
|
||||||
continue; // e.g. abstract or external proc
|
|
||||||
// add RTTI element
|
|
||||||
if not HasRTTIMembers then
|
|
||||||
begin
|
|
||||||
// add "var $r = this.$rtti"
|
|
||||||
VarSt:=CreateVarStatement(GetBIName(pbivnRTTILocal),
|
|
||||||
CreateMemberExpression(['this',GetBIName(pbivnRTTI)]),El);
|
|
||||||
AddToSourceElements(Src,VarSt);
|
|
||||||
|
|
||||||
HasRTTIMembers:=true;
|
|
||||||
end;
|
|
||||||
AddToSourceElements(Src,NewEl);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
Call: TJSCallExpression;
|
Call: TJSCallExpression;
|
||||||
FunDecl: TJSFunctionDeclarationStatement;
|
FunDecl: TJSFunctionDeclarationStatement;
|
||||||
@ -12784,7 +12511,7 @@ var
|
|||||||
AncestorPath, OwnerName, DestructorName, FnName, IntfKind: String;
|
AncestorPath, OwnerName, DestructorName, FnName, IntfKind: String;
|
||||||
C: TClass;
|
C: TClass;
|
||||||
AssignSt: TJSSimpleAssignStatement;
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
NeedInitFunction: Boolean;
|
NeedInitFunction, HasConstructor: Boolean;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
{$IFDEF VerbosePas2JS}
|
{$IFDEF VerbosePas2JS}
|
||||||
@ -12954,13 +12681,14 @@ begin
|
|||||||
if El.ObjKind in [okClass] then
|
if El.ObjKind in [okClass] then
|
||||||
begin
|
begin
|
||||||
// instance initialization function
|
// instance initialization function
|
||||||
AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfInit);
|
AddInstanceMemberFunction(El,Src,FuncContext,IsTObject,Ancestor,mfInit);
|
||||||
// instance finalization function
|
// instance finalization function
|
||||||
AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfFinalize);
|
AddInstanceMemberFunction(El,Src,FuncContext,IsTObject,Ancestor,mfFinalize);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if El.ObjKind in ([okClass]+okAllHelpers) then
|
if El.ObjKind in ([okClass]+okAllHelpers) then
|
||||||
begin
|
begin
|
||||||
|
HasConstructor:=false;
|
||||||
// add method implementations
|
// add method implementations
|
||||||
For i:=0 to El.Members.Count-1 do
|
For i:=0 to El.Members.Count-1 do
|
||||||
begin
|
begin
|
||||||
@ -12980,7 +12708,9 @@ begin
|
|||||||
AssignSt.Expr:=CreateLiteralString(P,DestructorName);
|
AssignSt.Expr:=CreateLiteralString(P,DestructorName);
|
||||||
AddToSourceElements(Src,AssignSt);
|
AddToSourceElements(Src,AssignSt);
|
||||||
end;
|
end;
|
||||||
end;
|
end
|
||||||
|
else if C.ClassType=TPasConstructor then
|
||||||
|
HasConstructor:=true;
|
||||||
NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext);
|
NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -12989,15 +12719,17 @@ begin
|
|||||||
continue; // e.g. abstract or external proc
|
continue; // e.g. abstract or external proc
|
||||||
AddToSourceElements(Src,NewEl);
|
AddToSourceElements(Src,NewEl);
|
||||||
end;
|
end;
|
||||||
|
if HasConstructor and (El.HelperForType<>nil) then
|
||||||
|
AddHelperConstructor(El,Src,FuncContext);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// add interfaces
|
// add interfaces
|
||||||
if (El.ObjKind=okClass) and (AContext.Resolver<>nil) then
|
if (El.ObjKind=okClass) and (AContext.Resolver<>nil) then
|
||||||
AddInterfaces(Src,FuncContext);
|
AddClassSupportedInterfaces(El,Src,FuncContext);
|
||||||
|
|
||||||
// add RTTI init function
|
// add RTTI init function
|
||||||
if AContext.Resolver<>nil then
|
if AContext.Resolver<>nil then
|
||||||
AddRTTI(Src,FuncContext);
|
AddClassRTTI(El,Src,FuncContext);
|
||||||
|
|
||||||
end;// end of init function
|
end;// end of init function
|
||||||
|
|
||||||
@ -15431,6 +15163,193 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPasToJSConverter.AddInstanceMemberFunction(El: TPasClassType;
|
||||||
|
Src: TJSSourceElements; ClassContext: TConvertContext; IsTObject: boolean;
|
||||||
|
Ancestor: TPasType; Kind: TMemberFunc);
|
||||||
|
const
|
||||||
|
MemberFuncName: array[TMemberFunc] of string = (
|
||||||
|
'$init',
|
||||||
|
'$final'
|
||||||
|
);
|
||||||
|
var
|
||||||
|
AncestorIsExternal: boolean;
|
||||||
|
|
||||||
|
function IsMemberNeeded(aMember: TPasElement): boolean;
|
||||||
|
begin
|
||||||
|
if IsElementUsed(aMember) then exit(true);
|
||||||
|
if IsTObject then
|
||||||
|
begin
|
||||||
|
if aMember.ClassType=TPasProcedure then
|
||||||
|
begin
|
||||||
|
if (CompareText(aMember.Name,'AfterConstruction')=0)
|
||||||
|
or (CompareText(aMember.Name,'BeforeDestruction')=0) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AddCallAncestorMemberFunction(ClassContext: TConvertContext;
|
||||||
|
Ancestor: TPasType; Src: TJSSourceElements; Kind: TMemberFunc);
|
||||||
|
var
|
||||||
|
Call: TJSCallExpression;
|
||||||
|
AncestorPath: String;
|
||||||
|
begin
|
||||||
|
if (Ancestor=nil) or AncestorIsExternal then
|
||||||
|
exit;
|
||||||
|
Call:=CreateCallExpression(El);
|
||||||
|
AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
|
||||||
|
Call.Expr:=CreatePrimitiveDotExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call',El);
|
||||||
|
Call.AddArg(CreatePrimitiveDotExpr('this',El));
|
||||||
|
AddToSourceElements(Src,Call);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// add instance initialization function:
|
||||||
|
// this.$init = function(){
|
||||||
|
// ancestor.$init();
|
||||||
|
// ... init variables ...
|
||||||
|
// }
|
||||||
|
// or add instance finalization function:
|
||||||
|
// this.$final = function(){
|
||||||
|
// ... clear references ...
|
||||||
|
// ancestor.$final();
|
||||||
|
// }
|
||||||
|
var
|
||||||
|
FuncVD: TJSVarDeclaration;
|
||||||
|
New_Src: TJSSourceElements;
|
||||||
|
New_FuncContext: TFunctionContext;
|
||||||
|
I: Integer;
|
||||||
|
P: TPasElement;
|
||||||
|
NewEl: TJSElement;
|
||||||
|
Func: TJSFunctionDeclarationStatement;
|
||||||
|
VarType: TPasType;
|
||||||
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
|
begin
|
||||||
|
// add instance members
|
||||||
|
AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
|
||||||
|
New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
|
||||||
|
New_FuncContext:=TFunctionContext.Create(El,New_Src,ClassContext);
|
||||||
|
try
|
||||||
|
New_FuncContext.ThisPas:=El;
|
||||||
|
New_FuncContext.IsGlobal:=true;
|
||||||
|
|
||||||
|
// add class members
|
||||||
|
For I:=0 to El.Members.Count-1 do
|
||||||
|
begin
|
||||||
|
P:=TPasElement(El.Members[i]);
|
||||||
|
if not IsMemberNeeded(P) then continue;
|
||||||
|
NewEl:=nil;
|
||||||
|
if (P.ClassType=TPasVariable)
|
||||||
|
and (ClassVarModifiersType*TPasVariable(P).VarModifiers=[]) then
|
||||||
|
begin
|
||||||
|
if Kind=mfInit then
|
||||||
|
// mfInit: init var
|
||||||
|
NewEl:=CreateVarDecl(TPasVariable(P),New_FuncContext) // can be nil
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// mfFinalize: clear reference
|
||||||
|
if vmExternal in TPasVariable(P).VarModifiers then continue;
|
||||||
|
VarType:=ClassContext.Resolver.ResolveAliasType(TPasVariable(P).VarType);
|
||||||
|
if (VarType.ClassType=TPasRecordType)
|
||||||
|
or (VarType.ClassType=TPasClassType)
|
||||||
|
or (VarType.ClassType=TPasClassOfType)
|
||||||
|
or (VarType.ClassType=TPasSetType)
|
||||||
|
or (VarType.ClassType=TPasProcedureType)
|
||||||
|
or (VarType.ClassType=TPasFunctionType)
|
||||||
|
or (VarType.ClassType=TPasArrayType) then
|
||||||
|
begin
|
||||||
|
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
||||||
|
NewEl:=AssignSt;
|
||||||
|
AssignSt.LHS:=CreateSubDeclNameExpr(P,New_FuncContext);
|
||||||
|
AssignSt.Expr:=CreateLiteralUndefined(El);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if NewEl=nil then continue;
|
||||||
|
if (Kind=mfInit) and (New_Src.Statements.Count=0) then
|
||||||
|
// add call ancestor.$init.call(this)
|
||||||
|
AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
|
||||||
|
AddToSourceElements(New_Src,NewEl);
|
||||||
|
end;
|
||||||
|
if (Kind=mfFinalize) and (New_Src.Statements.Count>0) then
|
||||||
|
// call ancestor.$final.call(this)
|
||||||
|
AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
|
||||||
|
if (Ancestor<>nil) and (not AncestorIsExternal)
|
||||||
|
and (New_Src.Statements.Count=0) then
|
||||||
|
exit; // descendent does not need $init/$final
|
||||||
|
|
||||||
|
FuncVD:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
|
||||||
|
AddToSourceElements(Src,FuncVD);
|
||||||
|
FuncVD.Name:='this.'+MemberFuncName[Kind];
|
||||||
|
Func:=CreateFunctionSt(El);
|
||||||
|
FuncVD.Init:=Func;
|
||||||
|
Func.AFunction.Body.A:=New_Src;
|
||||||
|
New_Src:=nil;
|
||||||
|
finally
|
||||||
|
New_Src.Free;
|
||||||
|
New_FuncContext.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPasToJSConverter.AddClassRTTI(El: TPasClassType;
|
||||||
|
Src: TJSSourceElements; FuncContext: TFunctionContext);
|
||||||
|
|
||||||
|
function IsMemberNeeded(aMember: TPasElement): boolean;
|
||||||
|
begin
|
||||||
|
Result:=IsElementUsed(aMember);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
HasRTTIMembers: Boolean;
|
||||||
|
i: Integer;
|
||||||
|
P: TPasElement;
|
||||||
|
NewEl: TJSElement;
|
||||||
|
VarSt: TJSVariableStatement;
|
||||||
|
C: TClass;
|
||||||
|
begin
|
||||||
|
// add $r to local vars, to avoid name clashes and for nicer debugging
|
||||||
|
FuncContext.AddLocalVar(GetBIName(pbivnRTTILocal),nil);
|
||||||
|
|
||||||
|
HasRTTIMembers:=false;
|
||||||
|
For i:=0 to El.Members.Count-1 do
|
||||||
|
begin
|
||||||
|
P:=TPasElement(El.Members[i]);
|
||||||
|
//writeln('TPasToJSConverter.ConvertClassType RTTI El[',i,']=',GetObjName(P));
|
||||||
|
if El.ObjKind=okInterface then
|
||||||
|
// all interface methods are published
|
||||||
|
else if P.Visibility<>visPublished then
|
||||||
|
continue;
|
||||||
|
if not IsMemberNeeded(P) then continue;
|
||||||
|
NewEl:=nil;
|
||||||
|
C:=P.ClassType;
|
||||||
|
if C=TPasVariable then
|
||||||
|
NewEl:=CreateRTTIMemberField(TPasVariable(P),FuncContext)
|
||||||
|
else if C.InheritsFrom(TPasProcedure) then
|
||||||
|
NewEl:=CreateRTTIMemberMethod(TPasProcedure(P),FuncContext)
|
||||||
|
else if C=TPasProperty then
|
||||||
|
NewEl:=CreateRTTIMemberProperty(TPasProperty(P),FuncContext)
|
||||||
|
else if C.InheritsFrom(TPasType) then
|
||||||
|
continue
|
||||||
|
else if C=TPasMethodResolution then
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
DoError(20170409202315,nSymbolCannotBePublished,sSymbolCannotBePublished,[],P);
|
||||||
|
if NewEl=nil then
|
||||||
|
continue; // e.g. abstract or external proc
|
||||||
|
// add RTTI element
|
||||||
|
if not HasRTTIMembers then
|
||||||
|
begin
|
||||||
|
// add "var $r = this.$rtti"
|
||||||
|
VarSt:=CreateVarStatement(GetBIName(pbivnRTTILocal),
|
||||||
|
CreateMemberExpression(['this',GetBIName(pbivnRTTI)]),El);
|
||||||
|
AddToSourceElements(Src,VarSt);
|
||||||
|
|
||||||
|
HasRTTIMembers:=true;
|
||||||
|
end;
|
||||||
|
AddToSourceElements(Src,NewEl);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateCallback(Expr: TPasExpr;
|
function TPasToJSConverter.CreateCallback(Expr: TPasExpr;
|
||||||
ResolvedEl: TPasResolverResult; AContext: TConvertContext): TJSElement;
|
ResolvedEl: TPasResolverResult; AContext: TConvertContext): TJSElement;
|
||||||
// El is a reference to a proc
|
// El is a reference to a proc
|
||||||
@ -16934,6 +16853,136 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPasToJSConverter.AddClassSupportedInterfaces(El: TPasClassType;
|
||||||
|
Src: TJSSourceElements; FuncContext: TFunctionContext);
|
||||||
|
|
||||||
|
function IsMemberNeeded(aMember: TPasElement): boolean;
|
||||||
|
begin
|
||||||
|
if IsElementUsed(aMember) then exit(true);
|
||||||
|
Result:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure AddMapProcs(Map: TPasClassIntfMap; Call: TJSCallExpression;
|
||||||
|
var ObjLit: TJSObjectLiteral; FuncContext: TConvertContext);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
MapItem: TObject;
|
||||||
|
Proc, IntfProc: TPasProcedure;
|
||||||
|
ProcName, IntfProcName: String;
|
||||||
|
Intf: TPasClassType;
|
||||||
|
Lit: TJSObjectLiteralElement;
|
||||||
|
begin
|
||||||
|
Intf:=Map.Intf;
|
||||||
|
if Map.Procs<>nil then
|
||||||
|
for i:=0 to Map.Procs.Count-1 do
|
||||||
|
begin
|
||||||
|
MapItem:=TObject(Map.Procs[i]);
|
||||||
|
if not (MapItem is TPasProcedure) then continue;
|
||||||
|
Proc:=TPasProcedure(MapItem);
|
||||||
|
ProcName:=TransformVariableName(Proc,FuncContext);
|
||||||
|
IntfProc:=TObject(Intf.Members[i]) as TPasProcedure;
|
||||||
|
IntfProcName:=TransformVariableName(IntfProc,FuncContext);
|
||||||
|
if IntfProcName=ProcName then continue;
|
||||||
|
if ObjLit=nil then
|
||||||
|
begin
|
||||||
|
ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
||||||
|
Call.AddArg(ObjLit);
|
||||||
|
end;
|
||||||
|
Lit:=ObjLit.Elements.AddElement;
|
||||||
|
Lit.Name:=TJSString(IntfProcName);
|
||||||
|
Lit.Expr:=CreateLiteralString(El,ProcName);
|
||||||
|
end;
|
||||||
|
if Map.AncestorMap<>nil then
|
||||||
|
AddMapProcs(Map.AncestorMap,Call,ObjLit,FuncContext);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
Call: TJSCallExpression;
|
||||||
|
ObjLit: TJSObjectLiteral;
|
||||||
|
i: Integer;
|
||||||
|
Scope, CurScope: TPas2JSClassScope;
|
||||||
|
o: TObject;
|
||||||
|
IntfMaps: TJSSimpleAssignStatement;
|
||||||
|
MapsObj: TJSObjectLiteral;
|
||||||
|
Map: TPasClassIntfMap;
|
||||||
|
FinishedGUIDs: TStringList;
|
||||||
|
Intf: TPasType;
|
||||||
|
CurEl: TPasClassType;
|
||||||
|
NeedIntfMap, HasInterfaces: Boolean;
|
||||||
|
begin
|
||||||
|
HasInterfaces:=false;
|
||||||
|
NeedIntfMap:=false;
|
||||||
|
Scope:=TPas2JSClassScope(El.CustomData);
|
||||||
|
repeat
|
||||||
|
if Scope.Interfaces<>nil then
|
||||||
|
begin
|
||||||
|
for i:=0 to Scope.Interfaces.Count-1 do
|
||||||
|
begin
|
||||||
|
CurEl:=TPasClassType(Scope.Element);
|
||||||
|
if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
|
||||||
|
HasInterfaces:=true;
|
||||||
|
o:=TObject(Scope.Interfaces[i]);
|
||||||
|
if o is TPasProperty then
|
||||||
|
// interface delegation -> needs $intfmaps={}
|
||||||
|
NeedIntfMap:=true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Scope:=TPas2JSClassScope(Scope.AncestorScope);
|
||||||
|
until Scope=nil;
|
||||||
|
if not HasInterfaces then exit;
|
||||||
|
|
||||||
|
IntfMaps:=nil;
|
||||||
|
FinishedGUIDs:=TStringList.Create;
|
||||||
|
try
|
||||||
|
ObjLit:=nil;
|
||||||
|
Scope:=TPas2JSClassScope(El.CustomData);
|
||||||
|
repeat
|
||||||
|
if Scope.Interfaces<>nil then
|
||||||
|
begin
|
||||||
|
for i:=0 to Scope.Interfaces.Count-1 do
|
||||||
|
begin
|
||||||
|
CurEl:=TPasClassType(Scope.Element);
|
||||||
|
if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
|
||||||
|
if NeedIntfMap then
|
||||||
|
begin
|
||||||
|
// add "this.$intfmaps = {};"
|
||||||
|
IntfMaps:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
||||||
|
AddToSourceElements(Src,IntfMaps);
|
||||||
|
IntfMaps.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbivnIntfMaps),El);
|
||||||
|
MapsObj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
|
||||||
|
IntfMaps.Expr:=MapsObj;
|
||||||
|
NeedIntfMap:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
o:=TObject(Scope.Interfaces[i]);
|
||||||
|
if o is TPasClassIntfMap then
|
||||||
|
begin
|
||||||
|
// add rtl.addIntf(this,intftype,{ intfprocname: "procname", ...});
|
||||||
|
Map:=TPasClassIntfMap(o);
|
||||||
|
Intf:=Map.Intf;
|
||||||
|
CurScope:=TPas2JSClassScope(Intf.CustomData);
|
||||||
|
if FinishedGUIDs.IndexOf(CurScope.GUID)>=0 then continue;
|
||||||
|
FinishedGUIDs.Add(CurScope.GUID);
|
||||||
|
Call:=CreateCallExpression(El);
|
||||||
|
AddToSourceElements(Src,Call);
|
||||||
|
Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfAddMap),El);
|
||||||
|
Call.AddArg(CreatePrimitiveDotExpr('this',El));
|
||||||
|
Call.AddArg(CreateReferencePathExpr(Map.Intf,FuncContext));
|
||||||
|
AddMapProcs(Map,Call,ObjLit,FuncContext);
|
||||||
|
end
|
||||||
|
else if o is TPasProperty then
|
||||||
|
AddIntfDelegations(El,TPasProperty(o),FinishedGUIDs,MapsObj,FuncContext)
|
||||||
|
else
|
||||||
|
RaiseNotSupported(El,FuncContext,20180326234026,GetObjName(o));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Scope:=TPas2JSClassScope(Scope.AncestorScope);
|
||||||
|
until Scope=nil;
|
||||||
|
finally
|
||||||
|
FinishedGUIDs.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateCallHelperMethod(Proc: TPasProcedure;
|
function TPasToJSConverter.CreateCallHelperMethod(Proc: TPasProcedure;
|
||||||
Expr: TPasExpr; AContext: TConvertContext; Implicit: boolean
|
Expr: TPasExpr; AContext: TConvertContext; Implicit: boolean
|
||||||
): TJSCallExpression;
|
): TJSCallExpression;
|
||||||
@ -17287,6 +17336,77 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPasToJSConverter.AddHelperConstructor(El: TPasClassType;
|
||||||
|
Src: TJSSourceElements; AContext: TConvertContext);
|
||||||
|
const
|
||||||
|
FunName = 'fn';
|
||||||
|
ArgsName = 'args';
|
||||||
|
var
|
||||||
|
aResolver: TPas2JSResolver;
|
||||||
|
HelperForType: TPasType;
|
||||||
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
|
Func: TJSFunctionDeclarationStatement;
|
||||||
|
New_Src: TJSSourceElements;
|
||||||
|
Call: TJSCallExpression;
|
||||||
|
DotExpr: TJSDotMemberExpression;
|
||||||
|
BracketExpr: TJSBracketMemberExpression;
|
||||||
|
New_FuncContext: TFunctionContext;
|
||||||
|
Init: TJSElement;
|
||||||
|
ReturnSt: TJSReturnStatement;
|
||||||
|
begin
|
||||||
|
if El.HelperForType=nil then exit;
|
||||||
|
aResolver:=AContext.Resolver;
|
||||||
|
HelperForType:=aResolver.ResolveAliasType(El.HelperForType);
|
||||||
|
if HelperForType.ClassType=TPasClassType then
|
||||||
|
exit; // a class helper does not need a special sub function
|
||||||
|
|
||||||
|
New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
|
||||||
|
New_FuncContext:=TFunctionContext.Create(El,New_Src,AContext);
|
||||||
|
try
|
||||||
|
New_FuncContext.ThisPas:=El;
|
||||||
|
New_FuncContext.IsGlobal:=true;
|
||||||
|
|
||||||
|
if HelperForType.ClassType=TPasRecordType then
|
||||||
|
begin
|
||||||
|
// record helper
|
||||||
|
// Note: a newinstance call looks like this: THelper.$new("NewHlp", [3]);
|
||||||
|
// The $new function:
|
||||||
|
// this.$new = function(fnname,args){
|
||||||
|
// return this[fnname].call(TRecType.$new(),args);
|
||||||
|
// }
|
||||||
|
ReturnSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
|
||||||
|
AddToSourceElements(New_Src,ReturnSt);
|
||||||
|
Call:=CreateCallExpression(El);
|
||||||
|
ReturnSt.Expr:=Call;
|
||||||
|
DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
|
||||||
|
Call.Expr:=DotExpr;
|
||||||
|
BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
|
||||||
|
DotExpr.MExpr:=BracketExpr;
|
||||||
|
DotExpr.Name:='call';
|
||||||
|
BracketExpr.MExpr:=CreatePrimitiveDotExpr('this',El);
|
||||||
|
BracketExpr.Name:=CreatePrimitiveDotExpr(FunName,El);
|
||||||
|
Init:=CreateValInit(HelperForType,nil,El,New_FuncContext);
|
||||||
|
Call.AddArg(Init);
|
||||||
|
Call.AddArg(CreatePrimitiveDotExpr(ArgsName,El));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseNotSupported(El,AContext,20190208181800);
|
||||||
|
// this.$new = function(fnname,args){
|
||||||
|
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
||||||
|
AddToSourceElements(Src,AssignSt);
|
||||||
|
AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbifnHelperNew),El);
|
||||||
|
Func:=CreateFunctionSt(El);
|
||||||
|
AssignSt.Expr:=Func;
|
||||||
|
Func.AFunction.Params.Add(FunName);
|
||||||
|
Func.AFunction.Params.Add(ArgsName);
|
||||||
|
Func.AFunction.Body.A:=New_Src;
|
||||||
|
New_Src:=nil;
|
||||||
|
finally
|
||||||
|
New_Src.Free;
|
||||||
|
New_FuncContext.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
|
function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
|
||||||
AContext: TConvertContext): TJSElement;
|
AContext: TConvertContext): TJSElement;
|
||||||
begin
|
begin
|
||||||
|
@ -645,11 +645,11 @@ type
|
|||||||
Procedure TestClassHelper_ClassPropertyStatic;
|
Procedure TestClassHelper_ClassPropertyStatic;
|
||||||
Procedure TestClassHelper_ClassProperty_Array;
|
Procedure TestClassHelper_ClassProperty_Array;
|
||||||
Procedure TestClassHelper_ForIn;
|
Procedure TestClassHelper_ForIn;
|
||||||
// todo: TestRecordHelper_ClassVar
|
Procedure TestExtClassHelper_ClassVar;
|
||||||
// todo: TestRecordHelper_Method
|
Procedure TestExtClassHelper_Method_Call;
|
||||||
// todo: TestRecordHelper_ClassMethod
|
Procedure TestRecordHelper_ClassVar;
|
||||||
// todo: TestRecordHelper_NestedMethod
|
Procedure TestRecordHelper_Method_Call;
|
||||||
// todo: TestRecorHelper_Constructor;
|
Procedure TestRecorHelper_Constructor;
|
||||||
// todo: TestRecordHelper_Args
|
// todo: TestRecordHelper_Args
|
||||||
// todo: TestRecordHelper_Property
|
// todo: TestRecordHelper_Property
|
||||||
// todo: TestRecordHelper_Property_Array
|
// todo: TestRecordHelper_Property_Array
|
||||||
@ -18643,7 +18643,7 @@ begin
|
|||||||
' end;',
|
' end;',
|
||||||
'']);
|
'']);
|
||||||
ConvertProgram;
|
ConvertProgram;
|
||||||
CheckSource('TestClassHelper',
|
CheckSource('TestClassHelper_ClassVar',
|
||||||
LinesToStr([ // statements
|
LinesToStr([ // statements
|
||||||
'rtl.createClass($mod, "TObject", null, function () {',
|
'rtl.createClass($mod, "TObject", null, function () {',
|
||||||
' this.$init = function () {',
|
' this.$init = function () {',
|
||||||
@ -20337,6 +20337,441 @@ begin
|
|||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestExtClassHelper_ClassVar;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$modeswitch externalclass}',
|
||||||
|
'type',
|
||||||
|
' TExtA = class external name ''ExtObj''',
|
||||||
|
' end;',
|
||||||
|
' THelper = class helper for TExtA',
|
||||||
|
' const',
|
||||||
|
' One = 1;',
|
||||||
|
' Two: word = 2;',
|
||||||
|
' class var',
|
||||||
|
' Glob: word;',
|
||||||
|
' function Foo(w: word): word;',
|
||||||
|
' class function Bar(w: word): word; static;',
|
||||||
|
' end;',
|
||||||
|
'function THelper.foo(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Result:=w;',
|
||||||
|
' Two:=One+w;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' Result:=Self.Glob;',
|
||||||
|
' Self.Glob:=Self.Glob;',
|
||||||
|
' with Self do Glob:=Glob;',
|
||||||
|
'end;',
|
||||||
|
'class function THelper.bar(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Result:=w;',
|
||||||
|
' Two:=One;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
'end;',
|
||||||
|
'var o: TExtA;',
|
||||||
|
'begin',
|
||||||
|
' texta.two:=texta.one;',
|
||||||
|
' texta.Glob:=texta.Glob;',
|
||||||
|
' with texta do begin',
|
||||||
|
' two:=one;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' end;',
|
||||||
|
' o.two:=o.one;',
|
||||||
|
' o.Glob:=o.Glob;',
|
||||||
|
' with o do begin',
|
||||||
|
' two:=one;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' end;',
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestExtClassHelper_ClassVar',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||||
|
' this.One = 1;',
|
||||||
|
' this.Two = 2;',
|
||||||
|
' this.Glob = 0;',
|
||||||
|
' this.Foo = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' Result = w;',
|
||||||
|
' $mod.THelper.Two = 1 + w;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' Result = $mod.THelper.Glob;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
' this.Bar = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' Result = w;',
|
||||||
|
' $mod.THelper.Two = 1;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.o = null;',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'var $with1 = $mod.o;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestExtClassHelper_Method_Call;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$modeswitch externalclass}',
|
||||||
|
'type',
|
||||||
|
' TExtA = class external name ''ExtObj''',
|
||||||
|
' procedure Run(w: word = 10);',
|
||||||
|
' end;',
|
||||||
|
' THelper = class helper for TExtA',
|
||||||
|
' function Foo(w: word = 1): word;',
|
||||||
|
' end;',
|
||||||
|
'function THelper.foo(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Run;',
|
||||||
|
' Run();',
|
||||||
|
' Run(11);',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(12);',
|
||||||
|
' Self.Foo;',
|
||||||
|
' Self.Foo();',
|
||||||
|
' Self.Foo(13);',
|
||||||
|
' with Self do begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(14);',
|
||||||
|
' end;',
|
||||||
|
'end;',
|
||||||
|
'var Obj: TExtA;',
|
||||||
|
'begin',
|
||||||
|
' obj.Foo;',
|
||||||
|
' obj.Foo();',
|
||||||
|
' obj.Foo(21);',
|
||||||
|
' with obj do begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(22);',
|
||||||
|
' end;',
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestExtClassHelper_Method_Call',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||||
|
' this.Foo = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' this.Run(10);',
|
||||||
|
' this.Run(10);',
|
||||||
|
' this.Run(11);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 12);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 13);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 14);',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.Obj = null;',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'$mod.THelper.Foo.apply($mod.Obj, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($mod.Obj, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($mod.Obj, 21);',
|
||||||
|
'var $with1 = $mod.Obj;',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 22);',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestRecordHelper_ClassVar;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TRec = record',
|
||||||
|
' end;',
|
||||||
|
' THelper = record helper for TRec',
|
||||||
|
' const',
|
||||||
|
' One = 1;',
|
||||||
|
' Two: word = 2;',
|
||||||
|
' class var',
|
||||||
|
' Glob: word;',
|
||||||
|
' function Foo(w: word): word;',
|
||||||
|
' class function Bar(w: word): word; static;',
|
||||||
|
' end;',
|
||||||
|
'function THelper.foo(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Result:=w;',
|
||||||
|
' Two:=One+w;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' Result:=Self.Glob;',
|
||||||
|
' Self.Glob:=Self.Glob;',
|
||||||
|
' with Self do Glob:=Glob;',
|
||||||
|
'end;',
|
||||||
|
'class function THelper.bar(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Result:=w;',
|
||||||
|
' Two:=One;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
'end;',
|
||||||
|
'var r: TRec;',
|
||||||
|
'begin',
|
||||||
|
' trec.two:=trec.one;',
|
||||||
|
' trec.Glob:=trec.Glob;',
|
||||||
|
' with trec do begin',
|
||||||
|
' two:=one;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' end;',
|
||||||
|
' r.two:=r.one;',
|
||||||
|
' r.Glob:=r.Glob;',
|
||||||
|
' with r do begin',
|
||||||
|
' two:=one;',
|
||||||
|
' Glob:=Glob;',
|
||||||
|
' end;',
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestRecordHelper_ClassVar',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.recNewT($mod, "TRec", function () {',
|
||||||
|
' this.$eq = function (b) {',
|
||||||
|
' return true;',
|
||||||
|
' };',
|
||||||
|
' this.$assign = function (s) {',
|
||||||
|
' return this;',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||||
|
' this.One = 1;',
|
||||||
|
' this.Two = 2;',
|
||||||
|
' this.Glob = 0;',
|
||||||
|
' this.Foo = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' Result = w;',
|
||||||
|
' $mod.THelper.Two = 1 + w;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' Result = $mod.THelper.Glob;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
' this.Bar = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' Result = w;',
|
||||||
|
' $mod.THelper.Two = 1;',
|
||||||
|
' $mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.r = $mod.TRec.$new();',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'var $with1 = $mod.TRec;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'var $with2 = $mod.r;',
|
||||||
|
'$mod.THelper.Two = 1;',
|
||||||
|
'$mod.THelper.Glob = $mod.THelper.Glob;',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestRecordHelper_Method_Call;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$modeswitch AdvancedRecords}',
|
||||||
|
'type',
|
||||||
|
' TRec = record',
|
||||||
|
' procedure Run(w: word = 10);',
|
||||||
|
' end;',
|
||||||
|
' THelper = record helper for TRec',
|
||||||
|
' function Foo(w: word = 1): word;',
|
||||||
|
' end;',
|
||||||
|
'procedure TRec.Run(w: word);',
|
||||||
|
'begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(2);',
|
||||||
|
' Self.Foo;',
|
||||||
|
' Self.Foo();',
|
||||||
|
' Self.Foo(3);',
|
||||||
|
' with Self do begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(4);',
|
||||||
|
' end;',
|
||||||
|
'end;',
|
||||||
|
'function THelper.foo(w: word): word;',
|
||||||
|
'begin',
|
||||||
|
' Run;',
|
||||||
|
' Run();',
|
||||||
|
' Run(11);',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(12);',
|
||||||
|
' Self.Foo;',
|
||||||
|
' Self.Foo();',
|
||||||
|
' Self.Foo(13);',
|
||||||
|
' with Self do begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(14);',
|
||||||
|
' end;',
|
||||||
|
'end;',
|
||||||
|
'var Rec: TRec;',
|
||||||
|
'begin',
|
||||||
|
' Rec.Foo;',
|
||||||
|
' Rec.Foo();',
|
||||||
|
' Rec.Foo(21);',
|
||||||
|
' with Rec do begin',
|
||||||
|
' Foo;',
|
||||||
|
' Foo();',
|
||||||
|
' Foo(22);',
|
||||||
|
' end;',
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestRecordHelper_Method_Call',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.recNewT($mod, "TRec", function () {',
|
||||||
|
' this.$eq = function (b) {',
|
||||||
|
' return true;',
|
||||||
|
' };',
|
||||||
|
' this.$assign = function (s) {',
|
||||||
|
' return this;',
|
||||||
|
' };',
|
||||||
|
' this.Run = function (w) {',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 2);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 3);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 4);',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||||
|
' this.Foo = function (w) {',
|
||||||
|
' var Result = 0;',
|
||||||
|
' this.Run(10);',
|
||||||
|
' this.Run(10);',
|
||||||
|
' this.Run(11);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 12);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 13);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 1);',
|
||||||
|
' $mod.THelper.Foo.apply(this, 14);',
|
||||||
|
' return Result;',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.Rec = $mod.TRec.$new();',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'$mod.THelper.Foo.apply($mod.Rec, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($mod.Rec, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($mod.Rec, 21);',
|
||||||
|
'var $with1 = $mod.Rec;',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 1);',
|
||||||
|
'$mod.THelper.Foo.apply($with1, 22);',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestRecorHelper_Constructor;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$modeswitch AdvancedRecords}',
|
||||||
|
'type',
|
||||||
|
' TRec = record',
|
||||||
|
' constructor Create(w: word);',
|
||||||
|
' end;',
|
||||||
|
' THelper = record helper for TRec',
|
||||||
|
' constructor NewHlp(w: word);',
|
||||||
|
' end;',
|
||||||
|
'var',
|
||||||
|
' Rec: TRec;',
|
||||||
|
'constructor TRec.Create(w: word);',
|
||||||
|
'begin',
|
||||||
|
' NewHlp(2);', // normal call
|
||||||
|
' trec.NewHlp(3);', // new instance
|
||||||
|
'end;',
|
||||||
|
'constructor THelper.NewHlp(w: word);',
|
||||||
|
'begin',
|
||||||
|
' create(2);', // normal call
|
||||||
|
' trec.create(3);', // new instance
|
||||||
|
' NewHlp(4);', // normal call
|
||||||
|
' trec.NewHlp(5);', // new instance
|
||||||
|
'end;',
|
||||||
|
'begin',
|
||||||
|
' rec.newhlp(2);', // normal call
|
||||||
|
' with rec do newhlp(12);', // normal call
|
||||||
|
' trec.newhlp(3);', // new instance
|
||||||
|
' with trec do newhlp(13);', // new instance
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestRecordHelper_Constructor',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.recNewT($mod, "TRec", function () {',
|
||||||
|
' this.$eq = function (b) {',
|
||||||
|
' return true;',
|
||||||
|
' };',
|
||||||
|
' this.$assign = function (s) {',
|
||||||
|
' return this;',
|
||||||
|
' };',
|
||||||
|
' this.Create = function (w) {',
|
||||||
|
' $mod.THelper.NewHlp.apply(this, 2);',
|
||||||
|
' $mod.THelper.$new("NewHlp", [3]);',
|
||||||
|
' return this;',
|
||||||
|
' };',
|
||||||
|
'}, true);',
|
||||||
|
'rtl.createHelper($mod, "THelper", null, function () {',
|
||||||
|
' this.NewHlp = function (w) {',
|
||||||
|
' this.Create(2);',
|
||||||
|
' $mod.TRec.$create("Create", [3]);',
|
||||||
|
' $mod.THelper.NewHlp.apply(this, 4);',
|
||||||
|
' $mod.THelper.$new("NewHlp", [5]);',
|
||||||
|
' return this;',
|
||||||
|
' };',
|
||||||
|
' this.$new = function (fn, args) {',
|
||||||
|
' return this[fn].call($mod.TRec.$new(), args);',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.Rec = $mod.TRec.$new();',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'$mod.THelper.NewHlp.apply($mod.Rec, 2);',
|
||||||
|
'var $with1 = $mod.Rec;',
|
||||||
|
'$mod.THelper.NewHlp.apply($with1, 12);',
|
||||||
|
'$mod.THelper.$new("NewHlp", [3]);',
|
||||||
|
'var $with2 = $mod.TRec;',
|
||||||
|
'$mod.THelper.$new("NewHlp", [13]);',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestModule.TestProcType;
|
procedure TTestModule.TestProcType;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user