mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 13:09:22 +02:00
pastojs: implemented TObject.Free
git-svn-id: trunk@36236 -
This commit is contained in:
parent
5006de1d40
commit
0464f1f68c
@ -109,6 +109,7 @@ Works:
|
|||||||
- external vars and methods
|
- external vars and methods
|
||||||
- const
|
- const
|
||||||
- bracket accessor, getter/setter has external name '[]'
|
- bracket accessor, getter/setter has external name '[]'
|
||||||
|
- TObject.Free sets variable to nil
|
||||||
- dynamic arrays
|
- dynamic arrays
|
||||||
- arrays can be null
|
- arrays can be null
|
||||||
- init as "arr = []" so typeof works
|
- init as "arr = []" so typeof works
|
||||||
@ -247,13 +248,6 @@ Works:
|
|||||||
- dotted unit names, namespaces
|
- dotted unit names, namespaces
|
||||||
|
|
||||||
ToDos:
|
ToDos:
|
||||||
- scanner: bark on unknown modeswitch
|
|
||||||
- scanner: bark on disabling fixed modeswitch
|
|
||||||
- scanner: bark on unknown mode
|
|
||||||
- $hint
|
|
||||||
- $note
|
|
||||||
- $warn
|
|
||||||
|
|
||||||
- constant evaluation
|
- constant evaluation
|
||||||
- integer ranges
|
- integer ranges
|
||||||
- static arrays
|
- static arrays
|
||||||
@ -266,7 +260,6 @@ ToDos:
|
|||||||
- documentation
|
- documentation
|
||||||
- move local types to unit scope
|
- move local types to unit scope
|
||||||
- local var absolute
|
- local var absolute
|
||||||
- make -Jirtl.js default for -Jc and -Tnodejs, needs #IFDEF in cfg
|
|
||||||
- FuncName:= (instead of Result:=)
|
- FuncName:= (instead of Result:=)
|
||||||
- check memleaks
|
- check memleaks
|
||||||
- @@ compare method in delphi mode
|
- @@ compare method in delphi mode
|
||||||
@ -360,6 +353,7 @@ const
|
|||||||
nTypeXCannotBePublished = 4021;
|
nTypeXCannotBePublished = 4021;
|
||||||
nNotSupportedX = 4022;
|
nNotSupportedX = 4022;
|
||||||
nNestedInheritedNeedsParameters = 4023;
|
nNestedInheritedNeedsParameters = 4023;
|
||||||
|
nFreeNeedsVar = 4024;
|
||||||
// resourcestring patterns of messages
|
// resourcestring patterns of messages
|
||||||
resourcestring
|
resourcestring
|
||||||
sPasElementNotSupported = 'Pascal element not supported: %s';
|
sPasElementNotSupported = 'Pascal element not supported: %s';
|
||||||
@ -385,6 +379,7 @@ resourcestring
|
|||||||
sTypeXCannotBePublished = 'Type "%s" cannot be published';
|
sTypeXCannotBePublished = 'Type "%s" cannot be published';
|
||||||
sNotSupportedX = 'Not supported: %s';
|
sNotSupportedX = 'Not supported: %s';
|
||||||
sNestedInheritedNeedsParameters = 'nested inherited needs parameters';
|
sNestedInheritedNeedsParameters = 'nested inherited needs parameters';
|
||||||
|
sFreeNeedsVar = 'Free needs a variable';
|
||||||
|
|
||||||
const
|
const
|
||||||
ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
|
ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
|
||||||
@ -407,6 +402,8 @@ type
|
|||||||
pbifnGetObject,
|
pbifnGetObject,
|
||||||
pbifnIs,
|
pbifnIs,
|
||||||
pbifnIsExt,
|
pbifnIsExt,
|
||||||
|
pbifnFreeLocalVar,
|
||||||
|
pbifnFreeVar,
|
||||||
pbifnProcType_Create,
|
pbifnProcType_Create,
|
||||||
pbifnProcType_Equal,
|
pbifnProcType_Equal,
|
||||||
pbifnProgramMain,
|
pbifnProgramMain,
|
||||||
@ -467,6 +464,7 @@ type
|
|||||||
pbivnRTTIPropStored,
|
pbivnRTTIPropStored,
|
||||||
pbivnRTTISet_CompType,
|
pbivnRTTISet_CompType,
|
||||||
pbivnSelf,
|
pbivnSelf,
|
||||||
|
pbivnTObjectDestroy,
|
||||||
pbivnWith,
|
pbivnWith,
|
||||||
pbitnAnonymousPostfix,
|
pbitnAnonymousPostfix,
|
||||||
pbitnIntDouble,
|
pbitnIntDouble,
|
||||||
@ -504,6 +502,8 @@ const
|
|||||||
'getObject', // rtl.getObject
|
'getObject', // rtl.getObject
|
||||||
'is', // rtl.is
|
'is', // rtl.is
|
||||||
'isExt', // rtl.isExt
|
'isExt', // rtl.isExt
|
||||||
|
'freeLoc', // rtl.freeLoc
|
||||||
|
'free', // rtl.free
|
||||||
'createCallback', // rtl.createCallback
|
'createCallback', // rtl.createCallback
|
||||||
'eqCallback', // rtl.eqCallback
|
'eqCallback', // rtl.eqCallback
|
||||||
'$main',
|
'$main',
|
||||||
@ -539,7 +539,7 @@ const
|
|||||||
'symDiffSet', // rtl.symDiffSet >< (symmetrical difference)
|
'symDiffSet', // rtl.symDiffSet >< (symmetrical difference)
|
||||||
'unionSet', // rtl.unionSet +
|
'unionSet', // rtl.unionSet +
|
||||||
'spaceLeft', // rtl.spaceLeft
|
'spaceLeft', // rtl.spaceLeft
|
||||||
'strSetLength',
|
'strSetLength', // rtl.
|
||||||
'$init',
|
'$init',
|
||||||
'$e',
|
'$e',
|
||||||
'$impl',
|
'$impl',
|
||||||
@ -564,22 +564,23 @@ const
|
|||||||
'stored',
|
'stored',
|
||||||
'comptype',
|
'comptype',
|
||||||
'Self',
|
'Self',
|
||||||
|
'tObjectDestroy', // rtl.tObjectDestroy
|
||||||
'$with',
|
'$with',
|
||||||
'$a',
|
'$a',
|
||||||
'NativeInt',
|
'NativeInt',
|
||||||
'tTypeInfo',
|
'tTypeInfo', // rtl.
|
||||||
'tTypeInfoClass',
|
'tTypeInfoClass', // rtl.
|
||||||
'tTypeInfoClassRef',
|
'tTypeInfoClassRef', // rtl.
|
||||||
'tTypeInfoDynArray',
|
'tTypeInfoDynArray', // rtl.
|
||||||
'tTypeInfoEnum',
|
'tTypeInfoEnum', // rtl.
|
||||||
'tTypeInfoInteger',
|
'tTypeInfoInteger', // rtl.
|
||||||
'tTypeInfoMethodVar',
|
'tTypeInfoMethodVar', // rtl.
|
||||||
'tTypeInfoPointer',
|
'tTypeInfoPointer', // rtl.
|
||||||
'tTypeInfoProcVar',
|
'tTypeInfoProcVar', // rtl.
|
||||||
'tTypeInfoRecord',
|
'tTypeInfoRecord', // rtl.
|
||||||
'tTypeInfoRefToProcVar',
|
'tTypeInfoRefToProcVar', // rtl.
|
||||||
'tTypeInfoSet',
|
'tTypeInfoSet', // rtl.
|
||||||
'tTypeInfoStaticArray',
|
'tTypeInfoStaticArray', // rtl.
|
||||||
'NativeUInt'
|
'NativeUInt'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -875,6 +876,8 @@ type
|
|||||||
procedure PushOverloadScope(Scope: TPasIdentifierScope);
|
procedure PushOverloadScope(Scope: TPasIdentifierScope);
|
||||||
procedure PopOverloadScope;
|
procedure PopOverloadScope;
|
||||||
procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
|
procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
|
||||||
|
procedure ResolveNameExpr(El: TPasExpr; const aName: string;
|
||||||
|
Access: TResolvedRefAccess); override;
|
||||||
procedure FinishModule(CurModule: TPasModule); override;
|
procedure FinishModule(CurModule: TPasModule); override;
|
||||||
procedure FinishSetType(El: TPasSetType); override;
|
procedure FinishSetType(El: TPasSetType); override;
|
||||||
procedure FinishClassType(El: TPasClassType); override;
|
procedure FinishClassType(El: TPasClassType); override;
|
||||||
@ -932,6 +935,7 @@ type
|
|||||||
function GetBaseDescription(const R: TPasResolverResult; AddPath: boolean=
|
function GetBaseDescription(const R: TPasResolverResult; AddPath: boolean=
|
||||||
false): string; override;
|
false): string; override;
|
||||||
function HasTypeInfo(El: TPasType): boolean; override;
|
function HasTypeInfo(El: TPasType): boolean; override;
|
||||||
|
function IsTObjectFreeMethod(El: TPasExpr): boolean; virtual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -1129,11 +1133,11 @@ type
|
|||||||
FPreservedWords: TJSReservedWordList; // sorted with CompareStr
|
FPreservedWords: TJSReservedWordList; // sorted with CompareStr
|
||||||
FTargetPlatform: TPasToJsPlatform;
|
FTargetPlatform: TPasToJsPlatform;
|
||||||
FTargetProcessor: TPasToJsProcessor;
|
FTargetProcessor: TPasToJsProcessor;
|
||||||
Function CreateBuiltInIdentifierExpr(AName: string): TJSPrimaryExpressionIdent;
|
Function CreatePrimitiveDotExpr(AName: string; Src: TPasElement = nil): TJSElement;
|
||||||
Function CreateSubDeclNameExpr(El: TPasElement; const Name: string;
|
Function CreateSubDeclNameExpr(El: TPasElement; const Name: string;
|
||||||
AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
AContext: TConvertContext): TJSElement;
|
||||||
Function CreateIdentifierExpr(El: TPasElement; AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
Function CreateIdentifierExpr(El: TPasElement; AContext: TConvertContext): TJSElement;
|
||||||
Function CreateIdentifierExpr(AName: string; El: TPasElement; AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
Function CreateIdentifierExpr(AName: string; El: TPasElement; AContext: TConvertContext): TJSElement;
|
||||||
Function CreateSwitchStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
|
Function CreateSwitchStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
|
||||||
Function CreateTypeDecl(El: TPasType; AContext: TConvertContext): TJSElement;
|
Function CreateTypeDecl(El: TPasType; AContext: TConvertContext): TJSElement;
|
||||||
Function CreateVarDecl(El: TPasVariable; AContext: TConvertContext): TJSElement;
|
Function CreateVarDecl(El: TPasVariable; AContext: TConvertContext): TJSElement;
|
||||||
@ -1204,6 +1208,7 @@ type
|
|||||||
Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
|
Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
|
||||||
Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
|
Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
|
||||||
Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
|
Function ClonePrimaryExpression(El: TJSPrimaryExpression; Src: TPasElement): TJSPrimaryExpression;
|
||||||
Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasElement;
|
Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasElement;
|
||||||
El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
|
El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasElement;
|
Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasElement;
|
||||||
@ -1213,7 +1218,7 @@ type
|
|||||||
Function CreateReferencePath(El: TPasElement; AContext : TConvertContext;
|
Function CreateReferencePath(El: TPasElement; AContext : TConvertContext;
|
||||||
Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
|
Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
|
||||||
Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext;
|
Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext;
|
||||||
Full: boolean = false; Ref: TResolvedReference = nil): TJSPrimaryExpressionIdent; virtual;
|
Full: boolean = false; Ref: TResolvedReference = nil): TJSElement; virtual;
|
||||||
Function CreateImplementationSection(El: TPasModule; AContext: TConvertContext): TJSFunctionDeclarationStatement;
|
Function CreateImplementationSection(El: TPasModule; AContext: TConvertContext): TJSFunctionDeclarationStatement;
|
||||||
Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext);
|
Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext);
|
||||||
Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement): TJSElement; virtual;
|
Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement): TJSElement; virtual;
|
||||||
@ -1259,9 +1264,9 @@ type
|
|||||||
Function ConvertParamsExpression(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertParamsExpression(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertExternalConstructor(Left: TPasElement;
|
Function ConvertExternalConstructor(Left: TPasElement; Ref: TResolvedReference;
|
||||||
Ref: TResolvedReference; ParamsExpr: TParamsExpr;
|
ParamsExpr: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
AContext : TConvertContext): TJSElement; virtual;
|
Function ConvertTObjectFree(Bin: TBinaryExpr; NameExpr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement; virtual;
|
Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement; virtual;
|
||||||
Function ConvertSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
Function ConvertOpenArrayParam(ElType: TPasType; El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
Function ConvertOpenArrayParam(ElType: TPasType; El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
|
||||||
@ -1829,6 +1834,78 @@ begin
|
|||||||
if Lines=nil then exit;
|
if Lines=nil then exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPas2JSResolver.ResolveNameExpr(El: TPasExpr; const aName: string;
|
||||||
|
Access: TResolvedRefAccess);
|
||||||
|
|
||||||
|
procedure CheckTObjectFree(Ref: TResolvedReference);
|
||||||
|
var
|
||||||
|
Bin: TBinaryExpr;
|
||||||
|
Left: TPasExpr;
|
||||||
|
LeftResolved: TPasResolverResult;
|
||||||
|
IdentEl: TPasElement;
|
||||||
|
begin
|
||||||
|
if not IsTObjectFreeMethod(El) then exit;
|
||||||
|
if Ref.WithExprScope<>nil then
|
||||||
|
begin
|
||||||
|
// with expr do free
|
||||||
|
if GetNewInstanceExpr(Ref.WithExprScope.Expr)<>nil then
|
||||||
|
exit; // with TSomeClass.Free do Free -> ok
|
||||||
|
RaiseMsg(20170517092407,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
end;
|
||||||
|
if (El.Parent.ClassType<>TBinaryExpr) then
|
||||||
|
RaiseMsg(20170516151916,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
Bin:=TBinaryExpr(El.Parent);
|
||||||
|
if (Bin.right<>El) or (Bin.OpCode<>eopSubIdent) then
|
||||||
|
RaiseMsg(20170516151950,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
if rrfImplicitCallWithoutParams in Ref.Flags then
|
||||||
|
// ".Free;" -> ok
|
||||||
|
else if Bin.Parent is TParamsExpr then
|
||||||
|
begin
|
||||||
|
if Bin.Parent.Parent is TPasExpr then
|
||||||
|
RaiseMsg(20170516161345,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
// ".Free();" -> ok
|
||||||
|
end
|
||||||
|
else if Bin.Parent is TPasImplElement then
|
||||||
|
// ok
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{$IFDEF VerbosePas2JS}
|
||||||
|
writeln('TPas2JSResolver.ResolveNameExpr.CheckTObjectFree Bin.Parent=',GetObjName(Bin.Parent));
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseMsg(20170516160347,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Left:=Bin.left;
|
||||||
|
ComputeElement(Left,LeftResolved,[]);
|
||||||
|
if not (rrfReadable in LeftResolved.Flags) then
|
||||||
|
RaiseMsg(20170516152300,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
if not (rrfWritable in LeftResolved.Flags) then
|
||||||
|
RaiseMsg(20170516152307,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
IdentEl:=LeftResolved.IdentEl;
|
||||||
|
if IdentEl=nil then
|
||||||
|
RaiseMsg(20170516152401,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
if IdentEl.ClassType=TPasArgument then
|
||||||
|
exit; // readable and writable argument -> ok
|
||||||
|
if (IdentEl.ClassType=TPasVariable)
|
||||||
|
or (IdentEl.ClassType=TPasConst) then
|
||||||
|
exit; // readable and writable variable -> ok
|
||||||
|
if IdentEl.ClassType=TPasResultElement then
|
||||||
|
exit; // readable and writable function result -> ok
|
||||||
|
RaiseMsg(20170516152455,nFreeNeedsVar,sFreeNeedsVar,[],El);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
Ref: TResolvedReference;
|
||||||
|
begin
|
||||||
|
inherited ResolveNameExpr(El, aName, Access);
|
||||||
|
if El.CustomData is TResolvedReference then
|
||||||
|
begin
|
||||||
|
Ref:=TResolvedReference(El.CustomData);
|
||||||
|
if (CompareText(aName,'free')=0) then
|
||||||
|
CheckTObjectFree(Ref);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPas2JSResolver.FinishModule(CurModule: TPasModule);
|
procedure TPas2JSResolver.FinishModule(CurModule: TPasModule);
|
||||||
var
|
var
|
||||||
ModuleClass: TClass;
|
ModuleClass: TClass;
|
||||||
@ -2995,6 +3072,27 @@ begin
|
|||||||
Result:=false;
|
Result:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPas2JSResolver.IsTObjectFreeMethod(El: TPasExpr): boolean;
|
||||||
|
var
|
||||||
|
Ref: TResolvedReference;
|
||||||
|
Decl: TPasElement;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
if El=nil then exit;
|
||||||
|
if El.ClassType<>TPrimitiveExpr then exit;
|
||||||
|
if not (El.CustomData is TResolvedReference) then exit;
|
||||||
|
Ref:=TResolvedReference(El.CustomData);
|
||||||
|
if CompareText(TPrimitiveExpr(El).Value,'free')<>0 then exit;
|
||||||
|
Decl:=Ref.Declaration;
|
||||||
|
if not (Decl.ClassType=TPasProcedure)
|
||||||
|
or (Decl.Parent.ClassType<>TPasClassType)
|
||||||
|
or (CompareText(Decl.Parent.Name,'tobject')<>0)
|
||||||
|
or (pmExternal in TPasProcedure(Decl).Modifiers)
|
||||||
|
or (TPasProcedure(Decl).ProcType.Args.Count>0) then
|
||||||
|
exit;
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TP2JConstExprData }
|
{ TP2JConstExprData }
|
||||||
|
|
||||||
destructor TP2JConstExprData.Destroy;
|
destructor TP2JConstExprData.Destroy;
|
||||||
@ -3481,7 +3579,7 @@ begin
|
|||||||
ModVarName:=FBuiltInNames[pbivnModule];
|
ModVarName:=FBuiltInNames[pbivnModule];
|
||||||
IntfContext.AddLocalVar(ModVarName,El);
|
IntfContext.AddLocalVar(ModVarName,El);
|
||||||
AddToSourceElements(Src,CreateVarStatement(ModVarName,
|
AddToSourceElements(Src,CreateVarStatement(ModVarName,
|
||||||
CreateBuiltInIdentifierExpr('this'),El));
|
CreatePrimitiveDotExpr('this'),El));
|
||||||
|
|
||||||
if (El is TPasProgram) then
|
if (El is TPasProgram) then
|
||||||
begin // program
|
begin // program
|
||||||
@ -3596,7 +3694,7 @@ begin
|
|||||||
else
|
else
|
||||||
FunName:=FBuiltInNames[pbifnClassInstanceFree];
|
FunName:=FBuiltInNames[pbifnClassInstanceFree];
|
||||||
FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+FunName;
|
FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+FunName;
|
||||||
C.Expr:=CreateBuiltInIdentifierExpr(FunName);
|
C.Expr:=CreatePrimitiveDotExpr(FunName);
|
||||||
ArgElems:=C.Args.Elements;
|
ArgElems:=C.Args.Elements;
|
||||||
// parameter: "funcname"
|
// parameter: "funcname"
|
||||||
ArgEx := CreateLiteralString(Ref.Element,TransformVariableName(Proc,AContext));
|
ArgEx := CreateLiteralString(Ref.Element,TransformVariableName(Proc,AContext));
|
||||||
@ -3975,10 +4073,10 @@ begin
|
|||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
if (RightResolved.TypeEl is TPasClassType) and TPasClassType(RightResolved.TypeEl).IsExternal then
|
if (RightResolved.TypeEl is TPasClassType) and TPasClassType(RightResolved.TypeEl).IsExternal then
|
||||||
// B is external class -> "rtl.asExt(A,B)"
|
// B is external class -> "rtl.asExt(A,B)"
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAsExt])
|
Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAsExt])
|
||||||
else
|
else
|
||||||
// otherwise -> "rtl.as(A,B)"
|
// otherwise -> "rtl.as(A,B)"
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs]);
|
Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs]);
|
||||||
Call.AddArg(A);
|
Call.AddArg(A);
|
||||||
Call.AddArg(B);
|
Call.AddArg(B);
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
@ -4011,7 +4109,7 @@ begin
|
|||||||
eopPower:
|
eopPower:
|
||||||
begin
|
begin
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr('Math.pow');
|
Call.Expr:=CreatePrimitiveDotExpr('Math.pow');
|
||||||
Call.AddArg(A);
|
Call.AddArg(A);
|
||||||
Call.AddArg(B);
|
Call.AddArg(B);
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
@ -4032,7 +4130,7 @@ begin
|
|||||||
// convert "a div b" to "Math.floor(a/b)"
|
// convert "a div b" to "Math.floor(a/b)"
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.AddArg(R);
|
Call.AddArg(R);
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr('Math.floor');
|
Call.Expr:=CreatePrimitiveDotExpr('Math.floor');
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -4176,7 +4274,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// convert "recordA = recordB" to "recordA.$equal(recordB)"
|
// convert "recordA = recordB" to "recordA.$equal(recordB)"
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,A,CreateBuiltInIdentifierExpr(FBuiltInNames[pbifnRecordEqual]));
|
Call.Expr:=CreateDotExpression(El,A,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual]));
|
||||||
A:=nil;
|
A:=nil;
|
||||||
Call.AddArg(B);
|
Call.AddArg(B);
|
||||||
B:=nil;
|
B:=nil;
|
||||||
@ -4230,7 +4328,7 @@ var
|
|||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
|
|
||||||
ParamsExpr:=nil;;
|
ParamsExpr:=nil;
|
||||||
RightEl:=El.right;
|
RightEl:=El.right;
|
||||||
while RightEl.ClassType=TParamsExpr do
|
while RightEl.ClassType=TParamsExpr do
|
||||||
begin
|
begin
|
||||||
@ -4252,6 +4350,11 @@ begin
|
|||||||
else
|
else
|
||||||
Result:=ConvertExternalConstructor(El.left,RightRef,nil,AContext);
|
Result:=ConvertExternalConstructor(El.left,RightRef,nil,AContext);
|
||||||
exit;
|
exit;
|
||||||
|
end
|
||||||
|
else if AContext.Resolver.IsTObjectFreeMethod(RightEl) then
|
||||||
|
begin
|
||||||
|
Result:=ConvertTObjectFree(El,RightEl,AContext);
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -4289,28 +4392,19 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateIdentifierExpr(El: TPasElement;
|
function TPasToJSConverter.CreateIdentifierExpr(El: TPasElement;
|
||||||
AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
AContext: TConvertContext): TJSElement;
|
||||||
var
|
|
||||||
I: TJSPrimaryExpressionIdent;
|
|
||||||
begin
|
begin
|
||||||
I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
|
Result:=CreatePrimitiveDotExpr(TransformVariableName(El,AContext),El);
|
||||||
I.Name:=TJSString(TransformVariableName(El,AContext));
|
|
||||||
Result:=I;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateIdentifierExpr(AName: string; El: TPasElement;
|
function TPasToJSConverter.CreateIdentifierExpr(AName: string; El: TPasElement;
|
||||||
AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
AContext: TConvertContext): TJSElement;
|
||||||
Var
|
|
||||||
I : TJSPrimaryExpressionIdent;
|
|
||||||
begin
|
begin
|
||||||
I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
|
Result:=CreatePrimitiveDotExpr(TransformVariableName(El,AName,AContext),El);
|
||||||
AName:=TransformVariableName(El,AName,AContext);
|
|
||||||
I.Name:=TJSString(AName);
|
|
||||||
Result:=I;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateSubDeclNameExpr(El: TPasElement;
|
function TPasToJSConverter.CreateSubDeclNameExpr(El: TPasElement;
|
||||||
const Name: string; AContext: TConvertContext): TJSPrimaryExpressionIdent;
|
const Name: string; AContext: TConvertContext): TJSElement;
|
||||||
var
|
var
|
||||||
CurName, ParentName: String;
|
CurName, ParentName: String;
|
||||||
begin
|
begin
|
||||||
@ -4319,8 +4413,7 @@ begin
|
|||||||
if ParentName='' then
|
if ParentName='' then
|
||||||
ParentName:='this';
|
ParentName:='this';
|
||||||
CurName:=ParentName+'.'+CurName;
|
CurName:=ParentName+'.'+CurName;
|
||||||
Result:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
|
Result:=CreatePrimitiveDotExpr(CurName,El);
|
||||||
Result.Name:=TJSString(CurName);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr;
|
function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr;
|
||||||
@ -4451,6 +4544,12 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (Ref.WithExprScope<>nil) and AContext.Resolver.IsTObjectFreeMethod(El) then
|
||||||
|
begin
|
||||||
|
Result:=ConvertTObjectFree(nil,El,AContext);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
Prop:=nil;
|
Prop:=nil;
|
||||||
AssignContext:=nil;
|
AssignContext:=nil;
|
||||||
ImplicitCall:=rrfImplicitCallWithoutParams in Ref.Flags;
|
ImplicitCall:=rrfImplicitCallWithoutParams in Ref.Flags;
|
||||||
@ -4503,7 +4602,7 @@ begin
|
|||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,
|
Call.Expr:=CreateDotExpression(El,
|
||||||
CreateIdentifierExpr(Arg.Name,Arg,AContext),
|
CreateIdentifierExpr(Arg.Name,Arg,AContext),
|
||||||
CreateBuiltInIdentifierExpr(TempRefObjGetterName));
|
CreatePrimitiveDotExpr(TempRefObjGetterName));
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -4517,7 +4616,7 @@ begin
|
|||||||
AssignContext.Call:=Call;
|
AssignContext.Call:=Call;
|
||||||
Call.Expr:=CreateDotExpression(El,
|
Call.Expr:=CreateDotExpression(El,
|
||||||
CreateIdentifierExpr(Arg.Name,Arg,AContext),
|
CreateIdentifierExpr(Arg.Name,Arg,AContext),
|
||||||
CreateBuiltInIdentifierExpr(TempRefObjSetterName));
|
CreatePrimitiveDotExpr(TempRefObjSetterName));
|
||||||
Call.AddArg(AssignContext.RightSide);
|
Call.AddArg(AssignContext.RightSide);
|
||||||
AssignContext.RightSide:=nil;
|
AssignContext.RightSide:=nil;
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
@ -4587,7 +4686,7 @@ begin
|
|||||||
else
|
else
|
||||||
Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
|
Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
|
||||||
if Result=nil then
|
if Result=nil then
|
||||||
Result:=CreateBuiltInIdentifierExpr(Name);
|
Result:=CreatePrimitiveDotExpr(Name);
|
||||||
|
|
||||||
if ImplicitCall then
|
if ImplicitCall then
|
||||||
begin
|
begin
|
||||||
@ -4681,11 +4780,11 @@ function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr;
|
|||||||
Call:=nil;
|
Call:=nil;
|
||||||
try
|
try
|
||||||
Call:=CreateCallExpression(ParentEl);
|
Call:=CreateCallExpression(ParentEl);
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr(FunName);
|
Call.Expr:=CreatePrimitiveDotExpr(FunName);
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr(SelfName));
|
Call.AddArg(CreatePrimitiveDotExpr(SelfName));
|
||||||
if Apply then
|
if Apply then
|
||||||
// "inherited;" -> pass the arguments
|
// "inherited;" -> pass the arguments
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr('arguments'))
|
Call.AddArg(CreatePrimitiveDotExpr('arguments'))
|
||||||
else
|
else
|
||||||
// "inherited Name(...)" -> pass the user arguments
|
// "inherited Name(...)" -> pass the user arguments
|
||||||
CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
|
CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
|
||||||
@ -4999,7 +5098,7 @@ var
|
|||||||
Ref:=TResolvedReference(PathEl.CustomData);
|
Ref:=TResolvedReference(PathEl.CustomData);
|
||||||
Path:=CreateReferencePath(Prop,AContext,rpkPath,false,Ref);
|
Path:=CreateReferencePath(Prop,AContext,rpkPath,false,Ref);
|
||||||
if Path<>'' then
|
if Path<>'' then
|
||||||
Bracket.MExpr:=CreateBuiltInIdentifierExpr(Path);
|
Bracket.MExpr:=CreatePrimitiveDotExpr(Path);
|
||||||
PathEl:=nil;
|
PathEl:=nil;
|
||||||
end
|
end
|
||||||
else if (PathEl is TBinaryExpr)
|
else if (PathEl is TBinaryExpr)
|
||||||
@ -5515,7 +5614,7 @@ begin
|
|||||||
else
|
else
|
||||||
// use external class name
|
// use external class name
|
||||||
ExtName:=(Proc.Parent as TPasClassType).ExternalName;
|
ExtName:=(Proc.Parent as TPasClassType).ExternalName;
|
||||||
ExtNameEl:=CreateBuiltInIdentifierExpr(ExtName);
|
ExtNameEl:=CreatePrimitiveDotExpr(ExtName);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if CompareText(Proc.Name,'new')=0 then
|
if CompareText(Proc.Name,'new')=0 then
|
||||||
@ -5539,6 +5638,112 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasToJSConverter.ConvertTObjectFree(Bin: TBinaryExpr;
|
||||||
|
NameExpr: TPasExpr; AContext: TConvertContext): TJSElement;
|
||||||
|
|
||||||
|
function CreateCallRTLFree(Obj, Prop: TJSElement): TJSElement;
|
||||||
|
// create "rtl.free(obj,prop)"
|
||||||
|
var
|
||||||
|
Call: TJSCallExpression;
|
||||||
|
begin
|
||||||
|
Call:=CreateCallExpression(Bin.right);
|
||||||
|
Call.Expr:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbifnFreeVar)]);
|
||||||
|
Call.Args.AddElement(Obj);
|
||||||
|
Call.Args.AddElement(Prop);
|
||||||
|
Result:=Call;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement;
|
||||||
|
// create "Setter=rtl.freeLoc(Getter)"
|
||||||
|
var
|
||||||
|
Call: TJSCallExpression;
|
||||||
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
|
begin
|
||||||
|
Call:=CreateCallExpression(Src);
|
||||||
|
Call.Expr:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbifnFreeLocalVar)]);
|
||||||
|
Call.Args.AddElement(Getter);
|
||||||
|
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,Src));
|
||||||
|
AssignSt.LHS:=Setter;
|
||||||
|
AssignSt.Expr:=Call;
|
||||||
|
Result:=AssignSt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
LeftJS, Obj, Prop, Getter, Setter: TJSElement;
|
||||||
|
DotExpr: TJSDotMemberExpression;
|
||||||
|
BracketJS: TJSBracketMemberExpression;
|
||||||
|
aName: TJSString;
|
||||||
|
WithExprScope: TPas2JSWithExprScope;
|
||||||
|
begin
|
||||||
|
Result:=nil;
|
||||||
|
|
||||||
|
LeftJS:=nil;
|
||||||
|
try
|
||||||
|
WithExprScope:=TResolvedReference(NameExpr.CustomData).WithExprScope as TPas2JSWithExprScope;
|
||||||
|
if WithExprScope<>nil then
|
||||||
|
begin
|
||||||
|
if AContext.Resolver.GetNewInstanceExpr(WithExprScope.Expr)<>nil then
|
||||||
|
begin
|
||||||
|
// "with TSomeClass.Create do Free"
|
||||||
|
// -> "$with1=rtl.freeLoc($with1);
|
||||||
|
Getter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
|
||||||
|
Setter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
|
||||||
|
Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{$IFDEF VerbosePas2JS}
|
||||||
|
writeln('TPasToJSConverter.ConvertTObjectFree With=',GetObjName(WithExprScope.Expr));
|
||||||
|
{$ENDIF}
|
||||||
|
RaiseInconsistency(20170517092248);
|
||||||
|
end;
|
||||||
|
|
||||||
|
LeftJS:=ConvertElement(Bin.left,AContext);
|
||||||
|
{$IFDEF VerbosePas2JS}
|
||||||
|
writeln('TPasToJSConverter.ConvertTObjectFree ',GetObjName(LeftJS));
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
if LeftJS is TJSPrimaryExpressionIdent then
|
||||||
|
begin
|
||||||
|
aName:=TJSPrimaryExpressionIdent(LeftJS).Name;
|
||||||
|
if Pos('.',aName)>0 then
|
||||||
|
RaiseInconsistency(20170516173832);
|
||||||
|
// v.free
|
||||||
|
// -> v=rtl.freeLoc(v);
|
||||||
|
Getter:=LeftJS;
|
||||||
|
Setter:=ClonePrimaryExpression(TJSPrimaryExpressionIdent(LeftJS),Bin.left);
|
||||||
|
Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
|
||||||
|
end
|
||||||
|
else if LeftJS is TJSDotMemberExpression then
|
||||||
|
begin
|
||||||
|
// obj.prop.free
|
||||||
|
// -> rtl.free(obj,"prop");
|
||||||
|
DotExpr:=TJSDotMemberExpression(LeftJS);
|
||||||
|
Obj:=DotExpr.MExpr;
|
||||||
|
DotExpr.MExpr:=nil;
|
||||||
|
Prop:=CreateLiteralJSString(Bin.right,DotExpr.Name);
|
||||||
|
FreeAndNil(LeftJS);
|
||||||
|
Result:=CreateCallRTLFree(Obj,Prop);
|
||||||
|
end
|
||||||
|
else if LeftJS is TJSBracketMemberExpression then
|
||||||
|
begin
|
||||||
|
// obj[prop].free
|
||||||
|
// -> rtl.free(obj,prop);
|
||||||
|
BracketJS:=TJSBracketMemberExpression(LeftJS);
|
||||||
|
Obj:=BracketJS.MExpr;
|
||||||
|
BracketJS.MExpr:=nil;
|
||||||
|
Prop:=BracketJS.Name;
|
||||||
|
BracketJS.Name:=nil;
|
||||||
|
FreeAndNil(LeftJS);
|
||||||
|
Result:=CreateCallRTLFree(Obj,Prop);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
RaiseNotSupported(Bin.left,AContext,20170516164659,'invalid scope for Free');
|
||||||
|
finally
|
||||||
|
if Result=nil then
|
||||||
|
LeftJS.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
|
function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
|
||||||
AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement;
|
AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement;
|
||||||
var
|
var
|
||||||
@ -5898,7 +6103,7 @@ begin
|
|||||||
|
|
||||||
// default: Param.length
|
// default: Param.length
|
||||||
Arg:=ConvertElement(Param,AContext);
|
Arg:=ConvertElement(Param,AContext);
|
||||||
Result:=CreateDotExpression(El,Arg,CreateBuiltInIdentifierExpr('length'));
|
Result:=CreateDotExpression(El,Arg,CreatePrimitiveDotExpr('length'));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
|
function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
|
||||||
@ -6056,7 +6261,7 @@ begin
|
|||||||
ProcEl:=ProcEl.Parent;
|
ProcEl:=ProcEl.Parent;
|
||||||
if ProcEl is TPasFunction then
|
if ProcEl is TPasFunction then
|
||||||
// in a function, "return result;"
|
// in a function, "return result;"
|
||||||
TJSReturnStatement(Result).Expr:=CreateBuiltInIdentifierExpr(ResolverResultVar)
|
TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(ResolverResultVar)
|
||||||
else
|
else
|
||||||
; // in a procedure, "return;" which means "return undefined;"
|
; // in a procedure, "return;" which means "return undefined;"
|
||||||
end;
|
end;
|
||||||
@ -6112,7 +6317,7 @@ begin
|
|||||||
// create "ref.set"
|
// create "ref.set"
|
||||||
Call.Expr:=CreateDotExpression(El,
|
Call.Expr:=CreateDotExpression(El,
|
||||||
CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
|
CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
|
||||||
CreateBuiltInIdentifierExpr(TempRefObjSetterName));
|
CreatePrimitiveDotExpr(TempRefObjSetterName));
|
||||||
// create "+"
|
// create "+"
|
||||||
if IsInc then
|
if IsInc then
|
||||||
AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El))
|
AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El))
|
||||||
@ -6123,7 +6328,7 @@ begin
|
|||||||
AddJS.A:=TJSCallExpression(CreateElement(TJSCallExpression,El));
|
AddJS.A:=TJSCallExpression(CreateElement(TJSCallExpression,El));
|
||||||
TJSCallExpression(AddJS.A).Expr:=CreateDotExpression(El,
|
TJSCallExpression(AddJS.A).Expr:=CreateDotExpression(El,
|
||||||
CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
|
CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
|
||||||
CreateBuiltInIdentifierExpr(TempRefObjGetterName));
|
CreatePrimitiveDotExpr(TempRefObjGetterName));
|
||||||
// add "b"
|
// add "b"
|
||||||
AddJS.B:=ValueJS;
|
AddJS.B:=ValueJS;
|
||||||
ValueJS:=nil;
|
ValueJS:=nil;
|
||||||
@ -6277,7 +6482,7 @@ begin
|
|||||||
Call:=nil;
|
Call:=nil;
|
||||||
try
|
try
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,SubParamJS,CreateBuiltInIdentifierExpr('charCodeAt'));
|
Call.Expr:=CreateDotExpression(El,SubParamJS,CreatePrimitiveDotExpr('charCodeAt'));
|
||||||
Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
|
Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
|
||||||
Call.AddArg(Minus);
|
Call.AddArg(Minus);
|
||||||
if length(SubParams.Params)<>1 then
|
if length(SubParams.Params)<>1 then
|
||||||
@ -6297,7 +6502,7 @@ begin
|
|||||||
Result:=ConvertElement(Param,AContext);
|
Result:=ConvertElement(Param,AContext);
|
||||||
// Note: convert Param first, as it might raise an exception
|
// Note: convert Param first, as it might raise an exception
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,Result,CreateBuiltInIdentifierExpr('charCodeAt'));
|
Call.Expr:=CreateDotExpression(El,Result,CreatePrimitiveDotExpr('charCodeAt'));
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
exit;
|
exit;
|
||||||
end
|
end
|
||||||
@ -6687,7 +6892,7 @@ begin
|
|||||||
// precision -> rtl El.toFixed(precision);
|
// precision -> rtl El.toFixed(precision);
|
||||||
NeedStrLit:=false;
|
NeedStrLit:=false;
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,Add,CreateBuiltInIdentifierExpr('toFixed'));
|
Call.Expr:=CreateDotExpression(El,Add,CreatePrimitiveDotExpr('toFixed'));
|
||||||
Call.AddArg(ConvertElement(El.format2,AContext));
|
Call.AddArg(ConvertElement(El.format2,AContext));
|
||||||
Add:=Call;
|
Add:=Call;
|
||||||
Call:=nil;
|
Call:=nil;
|
||||||
@ -6793,7 +6998,7 @@ begin
|
|||||||
if Call.Expr=nil then
|
if Call.Expr=nil then
|
||||||
// default: array1.concat(array2,...)
|
// default: array1.concat(array2,...)
|
||||||
Call.Expr:=CreateDotExpression(El,ConvertElement(Param0,AContext),
|
Call.Expr:=CreateDotExpression(El,ConvertElement(Param0,AContext),
|
||||||
CreateBuiltInIdentifierExpr('concat'));
|
CreatePrimitiveDotExpr('concat'));
|
||||||
for i:=1 to length(El.Params)-1 do
|
for i:=1 to length(El.Params)-1 do
|
||||||
Call.AddArg(ConvertElement(El.Params[i],AContext));
|
Call.AddArg(ConvertElement(El.Params[i],AContext));
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
@ -6875,7 +7080,7 @@ begin
|
|||||||
try
|
try
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
ArrEl:=ConvertElement(El.Params[1],AContext);
|
ArrEl:=ConvertElement(El.Params[1],AContext);
|
||||||
Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
|
Call.Expr:=CreateDotExpression(El,ArrEl,CreatePrimitiveDotExpr('splice'));
|
||||||
Call.AddArg(ConvertElement(El.Params[2],AContext));
|
Call.AddArg(ConvertElement(El.Params[2],AContext));
|
||||||
Call.AddArg(CreateLiteralNumber(El,1));
|
Call.AddArg(CreateLiteralNumber(El,1));
|
||||||
Call.AddArg(ConvertElement(El.Params[0],AContext));
|
Call.AddArg(ConvertElement(El.Params[0],AContext));
|
||||||
@ -6899,7 +7104,7 @@ begin
|
|||||||
try
|
try
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
ArrEl:=ConvertElement(El.Params[0],AContext);
|
ArrEl:=ConvertElement(El.Params[0],AContext);
|
||||||
Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
|
Call.Expr:=CreateDotExpression(El,ArrEl,CreatePrimitiveDotExpr('splice'));
|
||||||
Call.AddArg(ConvertElement(El.Params[1],AContext));
|
Call.AddArg(ConvertElement(El.Params[1],AContext));
|
||||||
Call.AddArg(ConvertElement(El.Params[2],AContext));
|
Call.AddArg(ConvertElement(El.Params[2],AContext));
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
@ -6949,7 +7154,7 @@ begin
|
|||||||
// typeinfo(classinstance) -> classinstance.$rtti
|
// typeinfo(classinstance) -> classinstance.$rtti
|
||||||
// typeinfo(classof) -> classof.$rtti
|
// typeinfo(classof) -> classof.$rtti
|
||||||
Result:=ConvertElement(Param,AContext);
|
Result:=ConvertElement(Param,AContext);
|
||||||
Result:=CreateDotExpression(El,Result,CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTTI]));
|
Result:=CreateDotExpression(El,Result,CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTTI]));
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Result:=CreateTypeInfoRef(TypeEl,AContext,Param);
|
Result:=CreateTypeInfoRef(TypeEl,AContext,Param);
|
||||||
@ -7025,17 +7230,35 @@ begin
|
|||||||
RaiseNotSupported(El,AContext,20161024191314);
|
RaiseNotSupported(El,AContext,20161024191314);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateBuiltInIdentifierExpr(AName: string
|
function TPasToJSConverter.CreatePrimitiveDotExpr(AName: string;
|
||||||
): TJSPrimaryExpressionIdent;
|
Src: TPasElement): TJSElement;
|
||||||
var
|
var
|
||||||
|
p: Integer;
|
||||||
|
DotExpr: TJSDotMemberExpression;
|
||||||
Ident: TJSPrimaryExpressionIdent;
|
Ident: TJSPrimaryExpressionIdent;
|
||||||
begin
|
begin
|
||||||
if AName='' then
|
if AName='' then
|
||||||
RaiseInconsistency(20170402230134);
|
RaiseInconsistency(20170402230134);
|
||||||
Ident:=TJSPrimaryExpressionIdent.Create(0,0);
|
p:=PosLast('.',AName);
|
||||||
// do not lowercase
|
if p>0 then
|
||||||
Ident.Name:=TJSString(AName);
|
begin
|
||||||
Result:=Ident;
|
if Src<>nil then
|
||||||
|
DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,Src))
|
||||||
|
else
|
||||||
|
DotExpr:=TJSDotMemberExpression.Create(0,0);
|
||||||
|
DotExpr.Name:=TJSString(copy(AName,p+1,length(AName))); // do not lowercase
|
||||||
|
DotExpr.MExpr:=CreatePrimitiveDotExpr(LeftStr(AName,p-1));
|
||||||
|
Result:=DotExpr;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if Src<>nil then
|
||||||
|
Ident:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,Src))
|
||||||
|
else
|
||||||
|
Ident:=TJSPrimaryExpressionIdent.Create(0,0);
|
||||||
|
Ident.Name:=TJSString(AName); // do not lowercase
|
||||||
|
Result:=Ident;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateTypeDecl(El: TPasType;
|
function TPasToJSConverter.CreateTypeDecl(El: TPasType;
|
||||||
@ -7236,7 +7459,7 @@ Var
|
|||||||
RetSt: TJSReturnStatement;
|
RetSt: TJSReturnStatement;
|
||||||
begin
|
begin
|
||||||
RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
|
RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
|
||||||
RetSt.Expr:=CreateBuiltInIdentifierExpr(ResolverResultVar);
|
RetSt.Expr:=CreatePrimitiveDotExpr(ResolverResultVar);
|
||||||
Add(RetSt);
|
Add(RetSt);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -7354,8 +7577,8 @@ var
|
|||||||
exit;
|
exit;
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
|
AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
|
||||||
Call.Expr:=CreateBuiltInIdentifierExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call');
|
Call.Expr:=CreatePrimitiveDotExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call');
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr('this'));
|
Call.AddArg(CreatePrimitiveDotExpr('this'));
|
||||||
AddToSourceElements(Src,Call);
|
AddToSourceElements(Src,Call);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -7503,8 +7726,9 @@ var
|
|||||||
P: TPasElement;
|
P: TPasElement;
|
||||||
Scope: TPas2JSClassScope;
|
Scope: TPas2JSClassScope;
|
||||||
Ancestor: TPasType;
|
Ancestor: TPasType;
|
||||||
AncestorPath, OwnerName: String;
|
AncestorPath, OwnerName, DestructorName: String;
|
||||||
C: TClass;
|
C: TClass;
|
||||||
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
if El.IsForward then
|
if El.IsForward then
|
||||||
@ -7544,7 +7768,7 @@ begin
|
|||||||
OwnerName:=AContext.GetLocalName(El.GetModule);
|
OwnerName:=AContext.GetLocalName(El.GetModule);
|
||||||
if OwnerName='' then
|
if OwnerName='' then
|
||||||
OwnerName:='this';
|
OwnerName:='this';
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr(OwnerName));
|
Call.AddArg(CreatePrimitiveDotExpr(OwnerName));
|
||||||
|
|
||||||
// add parameter: string constant '"classname"'
|
// add parameter: string constant '"classname"'
|
||||||
ArgEx := CreateLiteralString(El,TransformVariableName(El,AContext));
|
ArgEx := CreateLiteralString(El,TransformVariableName(El,AContext));
|
||||||
@ -7557,7 +7781,7 @@ begin
|
|||||||
AncestorPath:=TPasClassType(Ancestor).ExternalName
|
AncestorPath:=TPasClassType(Ancestor).ExternalName
|
||||||
else
|
else
|
||||||
AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
|
AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr(AncestorPath));
|
Call.AddArg(CreatePrimitiveDotExpr(AncestorPath));
|
||||||
|
|
||||||
if AncestorIsExternal then
|
if AncestorIsExternal then
|
||||||
begin
|
begin
|
||||||
@ -7626,7 +7850,21 @@ begin
|
|||||||
//writeln('TPasToJSConverter.ConvertClassType methods El[',i,']=',GetObjName(P));
|
//writeln('TPasToJSConverter.ConvertClassType methods El[',i,']=',GetObjName(P));
|
||||||
if not IsMemberNeeded(P) then continue;
|
if not IsMemberNeeded(P) then continue;
|
||||||
if P is TPasProcedure then
|
if P is TPasProcedure then
|
||||||
NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext)
|
begin
|
||||||
|
if IsTObject and (P.ClassType=TPasDestructor) then
|
||||||
|
begin
|
||||||
|
DestructorName:=TransformVariableName(P,AContext);
|
||||||
|
if DestructorName<>'Destroy' then
|
||||||
|
begin
|
||||||
|
// add 'rtl.tObjectDestroy="destroy";'
|
||||||
|
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,P));
|
||||||
|
AssignSt.LHS:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbivnTObjectDestroy)]);
|
||||||
|
AssignSt.Expr:=CreateLiteralString(P,DestructorName);
|
||||||
|
AddToSourceElements(Src,AssignSt);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext);
|
||||||
|
end
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
if NewEl=nil then
|
if NewEl=nil then
|
||||||
@ -8224,7 +8462,7 @@ begin
|
|||||||
// has nested procs -> add "var self = this;"
|
// has nested procs -> add "var self = this;"
|
||||||
FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
|
FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
|
||||||
SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
|
SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
|
||||||
CreateBuiltInIdentifierExpr('this'),El);
|
CreatePrimitiveDotExpr('this'),El);
|
||||||
AddBodyStatement(SelfSt,BodyPas);
|
AddBodyStatement(SelfSt,BodyPas);
|
||||||
if ImplProcScope.SelfArg<>nil then
|
if ImplProcScope.SelfArg<>nil then
|
||||||
begin
|
begin
|
||||||
@ -8400,7 +8638,7 @@ begin
|
|||||||
// default else: throw exceptobject
|
// default else: throw exceptobject
|
||||||
Last.BFalse:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
|
Last.BFalse:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
|
||||||
TJSThrowStatement(Last.BFalse).A:=
|
TJSThrowStatement(Last.BFalse).A:=
|
||||||
CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
|
CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject]);
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -8605,7 +8843,7 @@ begin
|
|||||||
ImplContext.ThisPas:=El;
|
ImplContext.ThisPas:=El;
|
||||||
ModVarName:=FBuiltInNames[pbivnModule];
|
ModVarName:=FBuiltInNames[pbivnModule];
|
||||||
AddToSourceElements(Src,CreateVarStatement(ModVarName,
|
AddToSourceElements(Src,CreateVarStatement(ModVarName,
|
||||||
CreateBuiltInIdentifierExpr('this'),El));
|
CreatePrimitiveDotExpr('this'),El));
|
||||||
ImplContext.AddLocalVar(ModVarName,El);
|
ImplContext.AddLocalVar(ModVarName,El);
|
||||||
|
|
||||||
// add var $impl = $mod.$impl
|
// add var $impl = $mod.$impl
|
||||||
@ -8927,7 +9165,7 @@ begin
|
|||||||
if El is TPasClassType then
|
if El is TPasClassType then
|
||||||
begin
|
begin
|
||||||
// use this
|
// use this
|
||||||
Result:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTTILocal]);
|
Result:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTTILocal]);
|
||||||
exit;
|
exit;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -9481,7 +9719,7 @@ begin
|
|||||||
if El.ExceptObject<>Nil then
|
if El.ExceptObject<>Nil then
|
||||||
E:=ConvertElement(El.ExceptObject,AContext)
|
E:=ConvertElement(El.ExceptObject,AContext)
|
||||||
else
|
else
|
||||||
E:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
|
E:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject]);
|
||||||
T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
|
T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
|
||||||
T.A:=E;
|
T.A:=E;
|
||||||
Result:=T;
|
Result:=T;
|
||||||
@ -9852,13 +10090,21 @@ function TPasToJSConverter.ConvertSimpleStatement(El: TPasImplSimple;
|
|||||||
|
|
||||||
Var
|
Var
|
||||||
E : TJSElement;
|
E : TJSElement;
|
||||||
|
C: TClass;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
E:=ConvertElement(EL.Expr,AContext);
|
E:=ConvertElement(EL.Expr,AContext);
|
||||||
if E=nil then
|
if E=nil then
|
||||||
exit(nil); // e.g. "inherited;" without ancestor proc
|
exit(nil); // e.g. "inherited;" without ancestor proc
|
||||||
Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
|
C:=E.ClassType;
|
||||||
TJSExpressionStatement(Result).A:=E;
|
if (C=TJSExpressionStatement)
|
||||||
|
or (C=TJSStatementList) then
|
||||||
|
Result:=E
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
|
||||||
|
TJSExpressionStatement(Result).A:=E;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo;
|
function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo;
|
||||||
@ -10403,7 +10649,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// aChar -> aChar.charCodeAt()
|
// aChar -> aChar.charCodeAt()
|
||||||
Call:=TJSCallExpression(CreateElement(TJSCallExpression,Expr));
|
Call:=TJSCallExpression(CreateElement(TJSCallExpression,Expr));
|
||||||
Call.Expr:=CreateDotExpression(Expr,Result,CreateBuiltInIdentifierExpr('charCodeAt'));
|
Call.Expr:=CreateDotExpression(Expr,Result,CreatePrimitiveDotExpr('charCodeAt'));
|
||||||
Result:=Call;
|
Result:=Call;
|
||||||
end
|
end
|
||||||
else if ExprResolved.BaseType=btContext then
|
else if ExprResolved.BaseType=btContext then
|
||||||
@ -10418,6 +10664,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasToJSConverter.ClonePrimaryExpression(El: TJSPrimaryExpression;
|
||||||
|
Src: TPasElement): TJSPrimaryExpression;
|
||||||
|
begin
|
||||||
|
Result:=TJSPrimaryExpression(CreateElement(TJSElementClass(El.ClassType),Src));
|
||||||
|
if Result.ClassType=TJSPrimaryExpressionIdent then
|
||||||
|
TJSPrimaryExpressionIdent(Result).Name:=TJSPrimaryExpressionIdent(El).Name;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
|
function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
|
||||||
Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement;
|
Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement;
|
||||||
// new recordtype()
|
// new recordtype()
|
||||||
@ -10780,7 +11034,7 @@ end;
|
|||||||
|
|
||||||
function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
|
function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
|
||||||
AContext: TConvertContext; Full: boolean; Ref: TResolvedReference
|
AContext: TConvertContext; Full: boolean; Ref: TResolvedReference
|
||||||
): TJSPrimaryExpressionIdent;
|
): TJSElement;
|
||||||
var
|
var
|
||||||
Name: String;
|
Name: String;
|
||||||
begin
|
begin
|
||||||
@ -10788,7 +11042,7 @@ begin
|
|||||||
writeln('TPasToJSConverter.CreateReferencePathExpr El="',GetObjName(El),'" El.Parent=',GetObjName(El.Parent));
|
writeln('TPasToJSConverter.CreateReferencePathExpr El="',GetObjName(El),'" El.Parent=',GetObjName(El.Parent));
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Name:=CreateReferencePath(El,AContext,rpkPathAndName,Full,Ref);
|
Name:=CreateReferencePath(El,AContext,rpkPathAndName,Full,Ref);
|
||||||
Result:=CreateBuiltInIdentifierExpr(Name);
|
Result:=CreatePrimitiveDotExpr(Name);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression;
|
procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression;
|
||||||
@ -11036,12 +11290,12 @@ begin
|
|||||||
// GetExpr: this.p.readvar
|
// GetExpr: this.p.readvar
|
||||||
// Will create "{p:GetPathExpr, get:function(){return GetExpr;},
|
// Will create "{p:GetPathExpr, get:function(){return GetExpr;},
|
||||||
// set:function(v){GetExpr = v;}}"
|
// set:function(v){GetExpr = v;}}"
|
||||||
GetPathExpr:=CreateBuiltInIdentifierExpr(LeftStr(GetPath,GetDotPos-1));
|
GetPathExpr:=CreatePrimitiveDotExpr(LeftStr(GetPath,GetDotPos-1));
|
||||||
GetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
|
GetExpr:=CreateDotExpression(El,CreatePrimitiveDotExpr('this.'+GetPathName),
|
||||||
CreateBuiltInIdentifierExpr(copy(GetPath,GetDotPos+1)));
|
CreatePrimitiveDotExpr(copy(GetPath,GetDotPos+1)));
|
||||||
if ParamContext.Setter=nil then
|
if ParamContext.Setter=nil then
|
||||||
SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
|
SetExpr:=CreateDotExpression(El,CreatePrimitiveDotExpr('this.'+GetPathName),
|
||||||
CreateBuiltInIdentifierExpr(copy(GetPath,GetDotPos+1)));
|
CreatePrimitiveDotExpr(copy(GetPath,GetDotPos+1)));
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -11049,7 +11303,7 @@ begin
|
|||||||
GetExpr:=FullGetter;
|
GetExpr:=FullGetter;
|
||||||
FullGetter:=nil;
|
FullGetter:=nil;
|
||||||
if ParamContext.Setter=nil then
|
if ParamContext.Setter=nil then
|
||||||
SetExpr:=CreateBuiltInIdentifierExpr(GetPath);
|
SetExpr:=CreatePrimitiveDotExpr(GetPath);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if ParamContext.Setter<>nil then
|
if ParamContext.Setter<>nil then
|
||||||
@ -11065,15 +11319,15 @@ begin
|
|||||||
if LeftStr(GetPath,GetDotPos)=LeftStr(SetPath,SetDotPos) then
|
if LeftStr(GetPath,GetDotPos)=LeftStr(SetPath,SetDotPos) then
|
||||||
begin
|
begin
|
||||||
// use GetPathExpr for setter
|
// use GetPathExpr for setter
|
||||||
SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
|
SetExpr:=CreateDotExpression(El,CreatePrimitiveDotExpr('this.'+GetPathName),
|
||||||
CreateBuiltInIdentifierExpr(copy(SetPath,GetDotPos+1)));
|
CreatePrimitiveDotExpr(copy(SetPath,GetDotPos+1)));
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// setter needs its own SetPathExpr
|
// setter needs its own SetPathExpr
|
||||||
SetPathExpr:=CreateBuiltInIdentifierExpr(LeftStr(SetPath,SetDotPos-1));
|
SetPathExpr:=CreatePrimitiveDotExpr(LeftStr(SetPath,SetDotPos-1));
|
||||||
SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+SetPathName),
|
SetExpr:=CreateDotExpression(El,CreatePrimitiveDotExpr('this.'+SetPathName),
|
||||||
CreateBuiltInIdentifierExpr(copy(SetPath,GetDotPos+1)));
|
CreatePrimitiveDotExpr(copy(SetPath,GetDotPos+1)));
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -11092,12 +11346,12 @@ begin
|
|||||||
// SetExpr: this.p.i
|
// SetExpr: this.p.i
|
||||||
DotExpr:=TJSDotMemberExpression(FullGetter);
|
DotExpr:=TJSDotMemberExpression(FullGetter);
|
||||||
GetPathExpr:=DotExpr.MExpr;
|
GetPathExpr:=DotExpr.MExpr;
|
||||||
DotExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
|
DotExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName);
|
||||||
GetExpr:=DotExpr;
|
GetExpr:=DotExpr;
|
||||||
FullGetter:=nil;
|
FullGetter:=nil;
|
||||||
SetExpr:=CreateDotExpression(El,
|
SetExpr:=CreateDotExpression(El,
|
||||||
CreateBuiltInIdentifierExpr('this.'+GetPathName),
|
CreatePrimitiveDotExpr('this.'+GetPathName),
|
||||||
CreateBuiltInIdentifierExpr(String(DotExpr.Name)));
|
CreatePrimitiveDotExpr(String(DotExpr.Name)));
|
||||||
end
|
end
|
||||||
else if FullGetter.ClassType=TJSBracketMemberExpression then
|
else if FullGetter.ClassType=TJSBracketMemberExpression then
|
||||||
begin
|
begin
|
||||||
@ -11113,12 +11367,12 @@ begin
|
|||||||
ParamExpr:=BracketExpr.Name;
|
ParamExpr:=BracketExpr.Name;
|
||||||
|
|
||||||
// create "a:value"
|
// create "a:value"
|
||||||
BracketExpr.Name:=CreateBuiltInIdentifierExpr('this.'+ParamName);
|
BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+ParamName);
|
||||||
AddVar(ParamName,ParamExpr);
|
AddVar(ParamName,ParamExpr);
|
||||||
|
|
||||||
// create GetPathExpr "this.arr"
|
// create GetPathExpr "this.arr"
|
||||||
GetPathExpr:=BracketExpr.MExpr;
|
GetPathExpr:=BracketExpr.MExpr;
|
||||||
BracketExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
|
BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName);
|
||||||
|
|
||||||
// GetExpr "this.p[this.a]"
|
// GetExpr "this.p[this.a]"
|
||||||
GetExpr:=BracketExpr;
|
GetExpr:=BracketExpr;
|
||||||
@ -11127,8 +11381,8 @@ begin
|
|||||||
// SetExpr "this.p[this.a]"
|
// SetExpr "this.p[this.a]"
|
||||||
BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
|
BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
|
||||||
SetExpr:=BracketExpr;
|
SetExpr:=BracketExpr;
|
||||||
BracketExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
|
BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName);
|
||||||
BracketExpr.Name:=CreateBuiltInIdentifierExpr('this.'+ParamName);
|
BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+ParamName);
|
||||||
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -11146,7 +11400,7 @@ begin
|
|||||||
// create SetExpr = v;
|
// create SetExpr = v;
|
||||||
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
|
||||||
AssignSt.LHS:=SetExpr;
|
AssignSt.LHS:=SetExpr;
|
||||||
AssignSt.Expr:=CreateBuiltInIdentifierExpr(TempRefObjSetterArgName);
|
AssignSt.Expr:=CreatePrimitiveDotExpr(TempRefObjSetterArgName);
|
||||||
SetExpr:=AssignSt;
|
SetExpr:=AssignSt;
|
||||||
end
|
end
|
||||||
else if (SetExpr.ClassType=TJSCallExpression) then
|
else if (SetExpr.ClassType=TJSCallExpression) then
|
||||||
@ -11217,7 +11471,7 @@ begin
|
|||||||
// create "T.isPrototypeOf(exceptObject)"
|
// create "T.isPrototypeOf(exceptObject)"
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=DotExpr;
|
Call.Expr:=DotExpr;
|
||||||
Call.AddArg(CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]));
|
Call.AddArg(CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject]));
|
||||||
IfSt.Cond:=Call;
|
IfSt.Cond:=Call;
|
||||||
|
|
||||||
if El.VarEl<>nil then
|
if El.VarEl<>nil then
|
||||||
@ -11227,7 +11481,7 @@ begin
|
|||||||
ListLast:=ListFirst;
|
ListLast:=ListFirst;
|
||||||
IfSt.BTrue:=ListFirst;
|
IfSt.BTrue:=ListFirst;
|
||||||
V:=CreateVarStatement(TransformVariableName(El,El.VariableName,AContext),
|
V:=CreateVarStatement(TransformVariableName(El,El.VariableName,AContext),
|
||||||
CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]),El);
|
CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject]),El);
|
||||||
ListFirst.A:=V;
|
ListFirst.A:=V;
|
||||||
// add statements
|
// add statements
|
||||||
AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
|
AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
|
||||||
@ -11449,7 +11703,7 @@ const
|
|||||||
VarAssignSt.LHS:=CreateSubDeclNameExpr(PasVar,PasVar.Name,FuncContext);
|
VarAssignSt.LHS:=CreateSubDeclNameExpr(PasVar,PasVar.Name,FuncContext);
|
||||||
VarDotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PasVar));
|
VarDotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PasVar));
|
||||||
VarAssignSt.Expr:=VarDotExpr;
|
VarAssignSt.Expr:=VarDotExpr;
|
||||||
VarDotExpr.MExpr:=CreateBuiltInIdentifierExpr(SrcParamName);
|
VarDotExpr.MExpr:=CreatePrimitiveDotExpr(SrcParamName);
|
||||||
VarDotExpr.Name:=TJSString(TransformVariableName(PasVar,FuncContext));
|
VarDotExpr.Name:=TJSString(TransformVariableName(PasVar,FuncContext));
|
||||||
if (AContext.Resolver<>nil) then
|
if (AContext.Resolver<>nil) then
|
||||||
begin
|
begin
|
||||||
@ -11666,7 +11920,7 @@ begin
|
|||||||
IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
|
IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
|
||||||
AddToStatementList(BodyFirst,BodyLast,IfSt,El);
|
AddToStatementList(BodyFirst,BodyLast,IfSt,El);
|
||||||
FD.Body.A:=BodyFirst;
|
FD.Body.A:=BodyFirst;
|
||||||
IfSt.Cond:=CreateBuiltInIdentifierExpr(SrcParamName);
|
IfSt.Cond:=CreatePrimitiveDotExpr(SrcParamName);
|
||||||
// add clone statements
|
// add clone statements
|
||||||
AddCloneStatements(IfSt,FuncContext);
|
AddCloneStatements(IfSt,FuncContext);
|
||||||
// add init default statements
|
// add init default statements
|
||||||
@ -11698,7 +11952,7 @@ begin
|
|||||||
// );
|
// );
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
Call.Expr:=CreateDotExpression(El,List.B,
|
Call.Expr:=CreateDotExpression(El,List.B,
|
||||||
CreateBuiltInIdentifierExpr(FBuiltInNames[pbifnRTTIAddFields]));
|
CreatePrimitiveDotExpr(FBuiltInNames[pbifnRTTIAddFields]));
|
||||||
List.B:=Call;
|
List.B:=Call;
|
||||||
AddRTTIFields(Call.Args);
|
AddRTTIFields(Call.Args);
|
||||||
end;
|
end;
|
||||||
|
@ -366,7 +366,11 @@ type
|
|||||||
Procedure TestClass_NestedSelf;
|
Procedure TestClass_NestedSelf;
|
||||||
Procedure TestClass_NestedClassSelf;
|
Procedure TestClass_NestedClassSelf;
|
||||||
Procedure TestClass_NestedCallInherited;
|
Procedure TestClass_NestedCallInherited;
|
||||||
Procedure TestClass_TObjectFree; // ToDO
|
Procedure TestClass_TObjectFree;
|
||||||
|
Procedure TestClass_TObjectFreeNewInstance;
|
||||||
|
Procedure TestClass_TObjectFreeLowerCase;
|
||||||
|
Procedure TestClass_TObjectFreeFunctionFail;
|
||||||
|
Procedure TestClass_TObjectFreePropertyFail;
|
||||||
|
|
||||||
// class of
|
// class of
|
||||||
Procedure TestClassOf_Create;
|
Procedure TestClassOf_Create;
|
||||||
@ -5787,13 +5791,13 @@ begin
|
|||||||
Add('function GetRec(vB: integer = 0): TRecord;');
|
Add('function GetRec(vB: integer = 0): TRecord;');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add('end;');
|
Add('end;');
|
||||||
Add('procedure DoIt(vG: integer; const vH: integer; var vI: integer);');
|
Add('procedure DoIt(vG: integer; const vH: integer);');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add('end;');
|
Add('end;');
|
||||||
Add('begin');
|
Add('begin');
|
||||||
Add(' doit(getrec.i,getrec.i,getrec.i);');
|
Add(' doit(getrec.i,getrec.i);');
|
||||||
Add(' doit(getrec().i,getrec().i,getrec().i);');
|
Add(' doit(getrec().i,getrec().i);');
|
||||||
Add(' doit(getrec(1).i,getrec(2).i,getrec(3).i);');
|
Add(' doit(getrec(1).i,getrec(2).i);');
|
||||||
ConvertProgram;
|
ConvertProgram;
|
||||||
CheckSource('TestRecordElementFromFuncResult_AsParams',
|
CheckSource('TestRecordElementFromFuncResult_AsParams',
|
||||||
LinesToStr([ // statements
|
LinesToStr([ // statements
|
||||||
@ -5811,37 +5815,13 @@ begin
|
|||||||
' var Result = new $mod.TRecord();',
|
' var Result = new $mod.TRecord();',
|
||||||
' return Result;',
|
' return Result;',
|
||||||
'};',
|
'};',
|
||||||
'this.DoIt = function (vG,vH,vI) {',
|
'this.DoIt = function (vG,vH) {',
|
||||||
'};'
|
'};'
|
||||||
]),
|
]),
|
||||||
LinesToStr([
|
LinesToStr([
|
||||||
'$mod.DoIt($mod.GetRec(0).i,$mod.GetRec(0).i,{',
|
'$mod.DoIt($mod.GetRec(0).i,$mod.GetRec(0).i);',
|
||||||
' p: $mod.GetRec(0),',
|
'$mod.DoIt($mod.GetRec(0).i,$mod.GetRec(0).i);',
|
||||||
' get: function () {',
|
'$mod.DoIt($mod.GetRec(1).i,$mod.GetRec(2).i);',
|
||||||
' return this.p.i;',
|
|
||||||
' },',
|
|
||||||
' set: function (v) {',
|
|
||||||
' this.p.i = v;',
|
|
||||||
' }',
|
|
||||||
'});',
|
|
||||||
'$mod.DoIt($mod.GetRec(0).i,$mod.GetRec(0).i,{',
|
|
||||||
' p: $mod.GetRec(0),',
|
|
||||||
' get: function () {',
|
|
||||||
' return this.p.i;',
|
|
||||||
' },',
|
|
||||||
' set: function (v) {',
|
|
||||||
' this.p.i = v;',
|
|
||||||
' }',
|
|
||||||
'});',
|
|
||||||
'$mod.DoIt($mod.GetRec(1).i,$mod.GetRec(2).i,{',
|
|
||||||
' p: $mod.GetRec(3),',
|
|
||||||
' get: function () {',
|
|
||||||
' return this.p.i;',
|
|
||||||
' },',
|
|
||||||
' set: function (v) {',
|
|
||||||
' this.p.i = v;',
|
|
||||||
' }',
|
|
||||||
'});',
|
|
||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -8196,8 +8176,6 @@ end;
|
|||||||
|
|
||||||
procedure TTestModule.TestClass_TObjectFree;
|
procedure TTestModule.TestClass_TObjectFree;
|
||||||
begin
|
begin
|
||||||
exit;
|
|
||||||
|
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
Add([
|
Add([
|
||||||
'type',
|
'type',
|
||||||
@ -8214,24 +8192,30 @@ begin
|
|||||||
' o.free;',
|
' o.free;',
|
||||||
' o.free();',
|
' o.free();',
|
||||||
' l.free;',
|
' l.free;',
|
||||||
|
' l.free();',
|
||||||
' o.obj.free;',
|
' o.obj.free;',
|
||||||
' o.obj.free();',
|
' o.obj.free();',
|
||||||
|
' with o do obj.free;',
|
||||||
|
' with o do obj.free();',
|
||||||
' result.Free;',
|
' result.Free;',
|
||||||
' result.Free();',
|
' result.Free();',
|
||||||
'end;',
|
'end;',
|
||||||
'var o: tobject;',
|
'var o: tobject;',
|
||||||
|
' a: array of tobject;',
|
||||||
'begin',
|
'begin',
|
||||||
' o.free;',
|
' o.free;',
|
||||||
' o.obj.free;',
|
' o.obj.free;',
|
||||||
|
' a[1+2].free;',
|
||||||
'']);
|
'']);
|
||||||
ConvertProgram;
|
ConvertProgram;
|
||||||
CheckSource('TestClass_NestedCallInherited',
|
CheckSource('TestClass_TObjectFree',
|
||||||
LinesToStr([ // statements
|
LinesToStr([ // statements
|
||||||
'rtl.createClass($mod, "TObject", null, function () {',
|
'rtl.createClass($mod, "TObject", null, function () {',
|
||||||
' this.$init = function () {',
|
' this.$init = function () {',
|
||||||
' this.Obj = null;',
|
' this.Obj = null;',
|
||||||
' };',
|
' };',
|
||||||
' this.$final = function () {',
|
' this.$final = function () {',
|
||||||
|
' this.Obj = undefined;',
|
||||||
' };',
|
' };',
|
||||||
' this.Free = function () {',
|
' this.Free = function () {',
|
||||||
' };',
|
' };',
|
||||||
@ -8239,14 +8223,142 @@ begin
|
|||||||
'this.DoIt = function (o) {',
|
'this.DoIt = function (o) {',
|
||||||
' var Result = null;',
|
' var Result = null;',
|
||||||
' var l = null;',
|
' var l = null;',
|
||||||
|
' o = rtl.freeLoc(o);',
|
||||||
|
' o = rtl.freeLoc(o);',
|
||||||
|
' l = rtl.freeLoc(l);',
|
||||||
|
' l = rtl.freeLoc(l);',
|
||||||
|
' rtl.free(o, "Obj");',
|
||||||
|
' rtl.free(o, "Obj");',
|
||||||
|
' var $with1 = o;',
|
||||||
|
' rtl.free($with1, "Obj");',
|
||||||
|
' var $with2 = o;',
|
||||||
|
' rtl.free($with2, "Obj");',
|
||||||
|
' Result = rtl.freeLoc(Result);',
|
||||||
|
' Result = rtl.freeLoc(Result);',
|
||||||
' return Result;',
|
' return Result;',
|
||||||
'};',
|
'};',
|
||||||
'this.o = null;',
|
'this.o = null;',
|
||||||
|
'this.a = [];',
|
||||||
'']),
|
'']),
|
||||||
LinesToStr([ // $mod.$main
|
LinesToStr([ // $mod.$main
|
||||||
|
'rtl.free($mod, "o");',
|
||||||
|
'rtl.free($mod.o, "Obj");',
|
||||||
|
'rtl.free($mod.a, 1 + 2);',
|
||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestClass_TObjectFreeNewInstance;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TObject = class',
|
||||||
|
' constructor Create;',
|
||||||
|
' procedure Free;',
|
||||||
|
' end;',
|
||||||
|
'constructor TObject.Create; begin end;',
|
||||||
|
'procedure tobject.free; begin end;',
|
||||||
|
'begin',
|
||||||
|
' with tobject.create do free;',
|
||||||
|
'']);
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestClass_TObjectFreeNewInstance',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.createClass($mod, "TObject", null, function () {',
|
||||||
|
' this.$init = function () {',
|
||||||
|
' };',
|
||||||
|
' this.$final = function () {',
|
||||||
|
' };',
|
||||||
|
' this.Create = function () {',
|
||||||
|
' };',
|
||||||
|
' this.Free = function () {',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'var $with1 = $mod.TObject.$create("Create");',
|
||||||
|
'$with1=rtl.freeLoc($with1);',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestClass_TObjectFreeLowerCase;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TObject = class',
|
||||||
|
' destructor Destroy;',
|
||||||
|
' procedure Free;',
|
||||||
|
' end;',
|
||||||
|
'destructor TObject.Destroy; begin end;',
|
||||||
|
'procedure tobject.free; begin end;',
|
||||||
|
'var o: tobject;',
|
||||||
|
'begin',
|
||||||
|
' o.free;',
|
||||||
|
'']);
|
||||||
|
Converter.UseLowerCase:=true;
|
||||||
|
ConvertProgram;
|
||||||
|
CheckSource('TestClass_TObjectFreeLowerCase',
|
||||||
|
LinesToStr([ // statements
|
||||||
|
'rtl.createClass($mod, "tobject", null, function () {',
|
||||||
|
' this.$init = function () {',
|
||||||
|
' };',
|
||||||
|
' this.$final = function () {',
|
||||||
|
' };',
|
||||||
|
' rtl.tObjectDestroy = "destroy";',
|
||||||
|
' this.destroy = function () {',
|
||||||
|
' };',
|
||||||
|
' this.free = function () {',
|
||||||
|
' };',
|
||||||
|
'});',
|
||||||
|
'this.o = null;',
|
||||||
|
'']),
|
||||||
|
LinesToStr([ // $mod.$main
|
||||||
|
'rtl.free($mod, "o");',
|
||||||
|
'']));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestClass_TObjectFreeFunctionFail;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TObject = class',
|
||||||
|
' procedure Free;',
|
||||||
|
' function GetObj: tobject; virtual; abstract;',
|
||||||
|
' end;',
|
||||||
|
'procedure tobject.free;',
|
||||||
|
'begin',
|
||||||
|
'end;',
|
||||||
|
'var o: tobject;',
|
||||||
|
'begin',
|
||||||
|
' o.getobj.free;',
|
||||||
|
'']);
|
||||||
|
SetExpectedPasResolverError(sFreeNeedsVar,nFreeNeedsVar);
|
||||||
|
ConvertProgram;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestClass_TObjectFreePropertyFail;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'type',
|
||||||
|
' TObject = class',
|
||||||
|
' procedure Free;',
|
||||||
|
' FObj: TObject;',
|
||||||
|
' property Obj: tobject read FObj write FObj;',
|
||||||
|
' end;',
|
||||||
|
'procedure tobject.free;',
|
||||||
|
'begin',
|
||||||
|
'end;',
|
||||||
|
'var o: tobject;',
|
||||||
|
'begin',
|
||||||
|
' o.obj.free;',
|
||||||
|
'']);
|
||||||
|
SetExpectedPasResolverError(sFreeNeedsVar,nFreeNeedsVar);
|
||||||
|
ConvertProgram;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestModule.TestClassOf_Create;
|
procedure TTestModule.TestClassOf_Create;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user