mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-17 05:39:19 +02:00
pastojs: helpers: external method apply to helped type
git-svn-id: trunk@41707 -
This commit is contained in:
parent
19e1336043
commit
1ea55d0a74
@ -2024,7 +2024,7 @@ type
|
|||||||
function GetFunctionType(El: TPasElement): TPasFunctionType;
|
function GetFunctionType(El: TPasElement): TPasFunctionType;
|
||||||
function MethodIsStatic(El: TPasProcedure): boolean;
|
function MethodIsStatic(El: TPasProcedure): boolean;
|
||||||
function IsMethod(El: TPasProcedure): boolean;
|
function IsMethod(El: TPasProcedure): boolean;
|
||||||
function IsHelperMethod(El: TPasElement): boolean;
|
function IsHelperMethod(El: TPasElement): boolean; virtual;
|
||||||
function IsHelper(El: TPasElement): boolean;
|
function IsHelper(El: TPasElement): boolean;
|
||||||
function IsExternalClass_Name(aClass: TPasClassType; const ExtName: string): boolean;
|
function IsExternalClass_Name(aClass: TPasClassType; const ExtName: string): boolean;
|
||||||
function IsProcedureType(const ResolvedEl: TPasResolverResult; HasValue: boolean): boolean;
|
function IsProcedureType(const ResolvedEl: TPasResolverResult; HasValue: boolean): boolean;
|
||||||
|
@ -1455,6 +1455,8 @@ type
|
|||||||
function IsForInExtArray(Loop: TPasImplForLoop; const VarResolved,
|
function IsForInExtArray(Loop: TPasImplForLoop; const VarResolved,
|
||||||
InResolved: TPasResolverResult; out ArgResolved, LengthResolved,
|
InResolved: TPasResolverResult; out ArgResolved, LengthResolved,
|
||||||
PropResultResolved: TPasResolverResult): boolean;
|
PropResultResolved: TPasResolverResult): boolean;
|
||||||
|
function IsHelperMethod(El: TPasElement): boolean; override;
|
||||||
|
function IsHelperForMember(El: TPasElement): boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -3987,19 +3989,25 @@ begin
|
|||||||
RaiseMsg(20180329141108,nInvalidXModifierY,
|
RaiseMsg(20180329141108,nInvalidXModifierY,
|
||||||
sInvalidXModifierY,[Proc.ElementTypeName,ModifierNames[pm]],Proc);
|
sInvalidXModifierY,[Proc.ElementTypeName,ModifierNames[pm]],Proc);
|
||||||
end;
|
end;
|
||||||
okClassHelper:
|
okClassHelper,okRecordHelper,okTypeHelper:
|
||||||
begin
|
begin
|
||||||
HelperForType:=ResolveAliasType(AClass.HelperForType);
|
HelperForType:=ResolveAliasType(AClass.HelperForType);
|
||||||
if HelperForType.ClassType<>TPasClassType then
|
if HelperForType.ClassType=TPasClassType then
|
||||||
RaiseNotYetImplemented(20190201165157,El);
|
|
||||||
if TPasClassType(HelperForType).IsExternal then
|
|
||||||
begin
|
begin
|
||||||
// method of a class helper for external class
|
if TPasClassType(HelperForType).IsExternal then
|
||||||
if IsClassMethod(El) and not (ptmStatic in El.Modifiers) then
|
begin
|
||||||
RaiseMsg(20190201165259,nHelperClassMethodForExtClassMustBeStatic,
|
// method of a class helper for external class
|
||||||
sHelperClassMethodForExtClassMustBeStatic,[],El);
|
if IsClassMethod(El) and not (ptmStatic in El.Modifiers) then
|
||||||
if El.ClassType=TPasConstructor then
|
RaiseMsg(20190201165259,nHelperClassMethodForExtClassMustBeStatic,
|
||||||
RaiseNotYetImplemented(20190206153655,El);
|
sHelperClassMethodForExtClassMustBeStatic,[],El);
|
||||||
|
if El.ClassType=TPasConstructor then
|
||||||
|
RaiseNotYetImplemented(20190206153655,El);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if Proc.IsExternal then
|
||||||
|
begin
|
||||||
|
if not (HelperForType is TPasMembersType) then
|
||||||
|
RaiseMsg(20190314225457,nNotSupportedX,sNotSupportedX,['external method in type helper'],El);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -5886,6 +5894,26 @@ begin
|
|||||||
CheckAssignResCompatibility(VarResolved,PropResultResolved,Loop.VariableName,true);
|
CheckAssignResCompatibility(VarResolved,PropResultResolved,Loop.VariableName,true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPas2JSResolver.IsHelperMethod(El: TPasElement): boolean;
|
||||||
|
begin
|
||||||
|
Result:=inherited IsHelperMethod(El);
|
||||||
|
if not Result then exit;
|
||||||
|
Result:=not TPasProcedure(El).IsExternal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPas2JSResolver.IsHelperForMember(El: TPasElement): boolean;
|
||||||
|
begin
|
||||||
|
if (El=nil) or (El.Parent=nil) or (El.Parent.ClassType<>TPasClassType)
|
||||||
|
or (TPasClassType(El.Parent).HelperForType=nil) then
|
||||||
|
exit(false);
|
||||||
|
if El is TPasProcedure then
|
||||||
|
Result:=TPasProcedure(El).IsExternal
|
||||||
|
else if El is TPasVariable then
|
||||||
|
Result:=vmExternal in TPasVariable(El).VarModifiers
|
||||||
|
else
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TParamContext }
|
{ TParamContext }
|
||||||
|
|
||||||
constructor TParamContext.Create(PasEl: TPasElement; JSEl: TJSElement;
|
constructor TParamContext.Create(PasEl: TPasElement; JSEl: TJSElement;
|
||||||
@ -7896,7 +7924,8 @@ begin
|
|||||||
if aResolver.IsHelper(RightRefDecl.Parent) then
|
if aResolver.IsHelper(RightRefDecl.Parent) then
|
||||||
begin
|
begin
|
||||||
// LeftJS.HelperMember
|
// LeftJS.HelperMember
|
||||||
if RightRefDecl is TPasVariable then
|
if (RightRefDecl is TPasVariable)
|
||||||
|
and not (vmExternal in TPasVariable(RightRefDecl).VarModifiers) then
|
||||||
begin
|
begin
|
||||||
// LeftJS.HelperField -> HelperType.HelperField
|
// LeftJS.HelperField -> HelperType.HelperField
|
||||||
if Assigned(OnConvertRight) then
|
if Assigned(OnConvertRight) then
|
||||||
@ -7907,7 +7936,10 @@ begin
|
|||||||
end
|
end
|
||||||
else if RightRefDecl is TPasProcedure then
|
else if RightRefDecl is TPasProcedure then
|
||||||
begin
|
begin
|
||||||
if rrfNoImplicitCallWithoutParams in RightRef.Flags then
|
Proc:=TPasProcedure(RightRefDecl);
|
||||||
|
if Proc.IsExternal then
|
||||||
|
// normal call
|
||||||
|
else if rrfNoImplicitCallWithoutParams in RightRef.Flags then
|
||||||
begin
|
begin
|
||||||
Result:=CreateReferencePathExpr(RightRefDecl,AContext);
|
Result:=CreateReferencePathExpr(RightRefDecl,AContext);
|
||||||
exit;
|
exit;
|
||||||
@ -7915,7 +7947,6 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// call helper method
|
// call helper method
|
||||||
Proc:=TPasProcedure(RightRefDecl);
|
|
||||||
Result:=CreateCallHelperMethod(Proc,El,AContext);
|
Result:=CreateCallHelperMethod(Proc,El,AContext);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -8295,7 +8326,7 @@ begin
|
|||||||
Decl:=aResolver.GetPasPropertySetter(Prop);
|
Decl:=aResolver.GetPasPropertySetter(Prop);
|
||||||
if Decl is TPasProcedure then
|
if Decl is TPasProcedure then
|
||||||
begin
|
begin
|
||||||
if aResolver.IsHelper(Decl.Parent) then
|
if aResolver.IsHelperMethod(Decl) then
|
||||||
begin
|
begin
|
||||||
Result:=CreateCallHelperMethod(TPasProcedure(Decl),El,AContext);
|
Result:=CreateCallHelperMethod(TPasProcedure(Decl),El,AContext);
|
||||||
exit;
|
exit;
|
||||||
@ -9768,7 +9799,7 @@ begin
|
|||||||
end
|
end
|
||||||
else if C.InheritsFrom(TPasProcedure) then
|
else if C.InheritsFrom(TPasProcedure) then
|
||||||
begin
|
begin
|
||||||
if aResolver.IsHelper(Decl.Parent) then
|
if aResolver.IsHelperMethod(Decl) then
|
||||||
begin
|
begin
|
||||||
// calling a helper method
|
// calling a helper method
|
||||||
Result:=CreateCallHelperMethod(TPasProcedure(Decl),El.Value,AContext);
|
Result:=CreateCallHelperMethod(TPasProcedure(Decl),El.Value,AContext);
|
||||||
@ -16187,7 +16218,7 @@ begin
|
|||||||
Result:=CreateReferencePathExpr(Proc,AContext);
|
Result:=CreateReferencePathExpr(Proc,AContext);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
IsHelper:=aResolver.IsHelper(Proc.Parent);
|
IsHelper:=aResolver.IsHelperMethod(Proc);
|
||||||
NeedClass:=aResolver.IsClassMethod(Proc) and not aResolver.MethodIsStatic(Proc);
|
NeedClass:=aResolver.IsClassMethod(Proc) and not aResolver.MethodIsStatic(Proc);
|
||||||
|
|
||||||
// an of-object method -> create "rtl.createCallback(Target,func)"
|
// an of-object method -> create "rtl.createCallback(Target,func)"
|
||||||
@ -16599,7 +16630,7 @@ begin
|
|||||||
if Decl is TPasFunction then
|
if Decl is TPasFunction then
|
||||||
begin
|
begin
|
||||||
// call function
|
// call function
|
||||||
if aResolver.IsHelper(Decl.Parent) then
|
if aResolver.IsHelperMethod(Decl) then
|
||||||
begin
|
begin
|
||||||
if (Expr=nil) then
|
if (Expr=nil) then
|
||||||
// implicit property read, e.g. enumerator property Current
|
// implicit property read, e.g. enumerator property Current
|
||||||
@ -21304,9 +21335,16 @@ var
|
|||||||
begin
|
begin
|
||||||
if (Ref=nil) or (Ref.WithExprScope=nil) then exit(false);
|
if (Ref=nil) or (Ref.WithExprScope=nil) then exit(false);
|
||||||
Parent:=El.Parent;
|
Parent:=El.Parent;
|
||||||
if (Parent<>nil) and (Parent.ClassType=TPasClassType)
|
if (Parent.ClassType=TPasClassType)
|
||||||
and (TPasClassType(Parent).HelperForType<>nil) then
|
and (TPasClassType(Parent).HelperForType<>nil) then
|
||||||
exit(false);
|
begin
|
||||||
|
// e.g. with Obj do HelperMethod
|
||||||
|
if aResolver.IsHelperForMember(El) then
|
||||||
|
// e.g. with Obj do HelperExternalMethod -> Obj.HelperCall
|
||||||
|
else
|
||||||
|
// e.g. with Obj do HelperMethod -> THelper.HelperCall
|
||||||
|
exit(false);
|
||||||
|
end;
|
||||||
Result:=true;
|
Result:=true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -21403,6 +21441,8 @@ var
|
|||||||
begin
|
begin
|
||||||
Result:='';
|
Result:='';
|
||||||
{$IFDEF VerbosePas2JS}
|
{$IFDEF VerbosePas2JS}
|
||||||
|
if SameText(El.Name,'Fly') then
|
||||||
|
writeln('AAA1 TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
|
||||||
//writeln('TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
|
//writeln('TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
|
||||||
//AContext.WriteStack;
|
//AContext.WriteStack;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -21484,6 +21524,7 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// need full path
|
// need full path
|
||||||
|
writeln('AAA2 TPasToJSConverter.CreateReferencePath ');
|
||||||
if El.Parent=nil then
|
if El.Parent=nil then
|
||||||
RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
|
RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
|
||||||
El:=ImplToDecl(El);
|
El:=ImplToDecl(El);
|
||||||
@ -21493,38 +21534,26 @@ begin
|
|||||||
begin
|
begin
|
||||||
ParentEl:=ImplToDecl(ParentEl);
|
ParentEl:=ImplToDecl(ParentEl);
|
||||||
|
|
||||||
|
IsClassRec:=(ParentEl.ClassType=TPasClassType)
|
||||||
|
or (ParentEl.ClassType=TPasRecordType);
|
||||||
|
|
||||||
// check if ParentEl has a JS var
|
// check if ParentEl has a JS var
|
||||||
ShortName:=AContext.GetLocalName(ParentEl);
|
ShortName:=AContext.GetLocalName(ParentEl);
|
||||||
//writeln('TPasToJSConverter.CreateReferencePath El=',GetObjName(El),' ParentEl=',GetObjName(ParentEl),' ShortName=',ShortName);
|
//writeln('TPasToJSConverter.CreateReferencePath El=',GetObjName(El),' ParentEl=',GetObjName(ParentEl),' ShortName=',ShortName);
|
||||||
|
|
||||||
IsClassRec:=(ParentEl.ClassType=TPasClassType)
|
if IsClassRec then
|
||||||
or (ParentEl.ClassType=TPasRecordType);
|
|
||||||
|
|
||||||
if (ShortName<>'') and not IsClassRec then
|
|
||||||
begin
|
|
||||||
Prepend(Result,ShortName);
|
|
||||||
break;
|
|
||||||
end
|
|
||||||
else if ParentEl.ClassType=TImplementationSection then
|
|
||||||
begin
|
|
||||||
// element is in an implementation section (not program/library section)
|
|
||||||
// in other unit -> use pas.unitname.$impl
|
|
||||||
FoundModule:=El.GetModule;
|
|
||||||
if FoundModule=nil then
|
|
||||||
RaiseInconsistency(20161024192755,El);
|
|
||||||
Prepend(Result,TransformModuleName(FoundModule,true,AContext)
|
|
||||||
+'.'+GetBIName(pbivnImplementation));
|
|
||||||
break;
|
|
||||||
end
|
|
||||||
else if ParentEl is TPasModule then
|
|
||||||
begin
|
|
||||||
// element is in an unit interface or program/library section
|
|
||||||
Prepend(Result,TransformModuleName(TPasModule(ParentEl),true,AContext));
|
|
||||||
break;
|
|
||||||
end
|
|
||||||
else if IsClassRec then
|
|
||||||
begin
|
begin
|
||||||
// parent is a class or record declaration
|
// parent is a class or record declaration
|
||||||
|
writeln('AAA3 TPasToJSConverter.CreateReferencePath ',GetObjName(ParentEl));
|
||||||
|
if (ParentEl.ClassType=TPasClassType)
|
||||||
|
and (TPasClassType(ParentEl).HelperForType<>nil)
|
||||||
|
and aResolver.IsHelperForMember(El) then
|
||||||
|
begin
|
||||||
|
// redirect to helper-for-type
|
||||||
|
ParentEl:=aResolver.ResolveAliasType(TPasClassType(ParentEl).HelperForType);
|
||||||
|
ShortName:=AContext.GetLocalName(ParentEl);
|
||||||
|
end;
|
||||||
|
|
||||||
if Full then
|
if Full then
|
||||||
Prepend(Result,ParentEl.Name)
|
Prepend(Result,ParentEl.Name)
|
||||||
else
|
else
|
||||||
@ -21541,8 +21570,10 @@ begin
|
|||||||
Prepend(Result,ParentEl.Name)
|
Prepend(Result,ParentEl.Name)
|
||||||
else if (ParentEl.ClassType=TPasClassType)
|
else if (ParentEl.ClassType=TPasClassType)
|
||||||
and (TPasClassType(ParentEl).HelperForType<>nil) then
|
and (TPasClassType(ParentEl).HelperForType<>nil) then
|
||||||
|
begin
|
||||||
// helpers have no self
|
// helpers have no self
|
||||||
Prepend(Result,ParentEl.Name)
|
Prepend(Result,ParentEl.Name);
|
||||||
|
end
|
||||||
else if (SelfContext<>nil)
|
else if (SelfContext<>nil)
|
||||||
and IsA(TPasType(SelfContext.ThisPas),TPasMembersType(ParentEl)) then
|
and IsA(TPasType(SelfContext.ThisPas),TPasMembersType(ParentEl)) then
|
||||||
begin
|
begin
|
||||||
@ -21575,6 +21606,28 @@ begin
|
|||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
else if (ShortName<>'') then
|
||||||
|
begin
|
||||||
|
Prepend(Result,ShortName);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
else if ParentEl.ClassType=TImplementationSection then
|
||||||
|
begin
|
||||||
|
// element is in an implementation section (not program/library section)
|
||||||
|
// in other unit -> use pas.unitname.$impl
|
||||||
|
FoundModule:=El.GetModule;
|
||||||
|
if FoundModule=nil then
|
||||||
|
RaiseInconsistency(20161024192755,El);
|
||||||
|
Prepend(Result,TransformModuleName(FoundModule,true,AContext)
|
||||||
|
+'.'+GetBIName(pbivnImplementation));
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
else if ParentEl is TPasModule then
|
||||||
|
begin
|
||||||
|
// element is in an unit interface or program/library section
|
||||||
|
Prepend(Result,TransformModuleName(TPasModule(ParentEl),true,AContext));
|
||||||
|
break;
|
||||||
|
end
|
||||||
else if ParentEl.ClassType=TPasEnumType then
|
else if ParentEl.ClassType=TPasEnumType then
|
||||||
begin
|
begin
|
||||||
if (ShortName<>'') and not Full then
|
if (ShortName<>'') and not Full then
|
||||||
|
@ -680,6 +680,7 @@ type
|
|||||||
Procedure TestTypeHelper_ClassProperty;
|
Procedure TestTypeHelper_ClassProperty;
|
||||||
Procedure TestTypeHelper_ClassProperty_Array;
|
Procedure TestTypeHelper_ClassProperty_Array;
|
||||||
Procedure TestTypeHelper_ClassMethod;
|
Procedure TestTypeHelper_ClassMethod;
|
||||||
|
Procedure TestTypeHelper_ExtClassMethodFail;
|
||||||
Procedure TestTypeHelper_Constructor;
|
Procedure TestTypeHelper_Constructor;
|
||||||
Procedure TestTypeHelper_Word;
|
Procedure TestTypeHelper_Word;
|
||||||
Procedure TestTypeHelper_Double;
|
Procedure TestTypeHelper_Double;
|
||||||
@ -21197,12 +21198,15 @@ begin
|
|||||||
Add([
|
Add([
|
||||||
'{$modeswitch externalclass}',
|
'{$modeswitch externalclass}',
|
||||||
'type',
|
'type',
|
||||||
|
' TFly = function(w: word): word of object;',
|
||||||
' TExtA = class external name ''ExtObj''',
|
' TExtA = class external name ''ExtObj''',
|
||||||
' procedure Run(w: word = 10);',
|
' procedure Run(w: word = 10);',
|
||||||
' end;',
|
' end;',
|
||||||
' THelper = class helper for TExtA',
|
' THelper = class helper for TExtA',
|
||||||
' function Foo(w: word = 1): word;',
|
' function Foo(w: word = 1): word;',
|
||||||
|
' function Fly(w: word = 2): word; external name ''Fly'';',
|
||||||
' end;',
|
' end;',
|
||||||
|
'var p: TFly;',
|
||||||
'function THelper.foo(w: word): word;',
|
'function THelper.foo(w: word): word;',
|
||||||
'begin',
|
'begin',
|
||||||
' Run;',
|
' Run;',
|
||||||
@ -21214,22 +21218,32 @@ begin
|
|||||||
' Self.Foo;',
|
' Self.Foo;',
|
||||||
' Self.Foo();',
|
' Self.Foo();',
|
||||||
' Self.Foo(13);',
|
' Self.Foo(13);',
|
||||||
|
' Fly;',
|
||||||
|
' Fly();',
|
||||||
' with Self do begin',
|
' with Self do begin',
|
||||||
' Foo;',
|
' Foo;',
|
||||||
' Foo();',
|
' Foo();',
|
||||||
' Foo(14);',
|
' Foo(14);',
|
||||||
|
' Fly;',
|
||||||
|
' Fly();',
|
||||||
' end;',
|
' end;',
|
||||||
|
' p:=@Fly;',
|
||||||
'end;',
|
'end;',
|
||||||
'var Obj: TExtA;',
|
'var Obj: TExtA;',
|
||||||
'begin',
|
'begin',
|
||||||
' obj.Foo;',
|
' obj.Foo;',
|
||||||
' obj.Foo();',
|
' obj.Foo();',
|
||||||
' obj.Foo(21);',
|
' obj.Foo(21);',
|
||||||
|
' obj.Fly;',
|
||||||
|
' obj.Fly();',
|
||||||
' with obj do begin',
|
' with obj do begin',
|
||||||
' Foo;',
|
' Foo;',
|
||||||
' Foo();',
|
' Foo();',
|
||||||
' Foo(22);',
|
' Foo(22);',
|
||||||
|
' Fly;',
|
||||||
|
' Fly();',
|
||||||
' end;',
|
' end;',
|
||||||
|
' p:=@obj.Fly;',
|
||||||
'']);
|
'']);
|
||||||
ConvertProgram;
|
ConvertProgram;
|
||||||
CheckSource('TestExtClassHelper_Method_Call',
|
CheckSource('TestExtClassHelper_Method_Call',
|
||||||
@ -21246,22 +21260,33 @@ begin
|
|||||||
' $mod.THelper.Foo.call(this, 1);',
|
' $mod.THelper.Foo.call(this, 1);',
|
||||||
' $mod.THelper.Foo.call(this, 1);',
|
' $mod.THelper.Foo.call(this, 1);',
|
||||||
' $mod.THelper.Foo.call(this, 13);',
|
' $mod.THelper.Foo.call(this, 13);',
|
||||||
|
' this.Fly(2);',
|
||||||
|
' this.Fly(2);',
|
||||||
' $mod.THelper.Foo.call(this, 1);',
|
' $mod.THelper.Foo.call(this, 1);',
|
||||||
' $mod.THelper.Foo.call(this, 1);',
|
' $mod.THelper.Foo.call(this, 1);',
|
||||||
' $mod.THelper.Foo.call(this, 14);',
|
' $mod.THelper.Foo.call(this, 14);',
|
||||||
|
' this.Fly(2);',
|
||||||
|
' this.Fly(2);',
|
||||||
|
' $mod.p = rtl.createCallback(this, "Fly");',
|
||||||
' return Result;',
|
' return Result;',
|
||||||
' };',
|
' };',
|
||||||
'});',
|
'});',
|
||||||
|
'this.p = null;',
|
||||||
'this.Obj = null;',
|
'this.Obj = null;',
|
||||||
'']),
|
'']),
|
||||||
LinesToStr([ // $mod.$main
|
LinesToStr([ // $mod.$main
|
||||||
'$mod.THelper.Foo.call($mod.Obj, 1);',
|
'$mod.THelper.Foo.call($mod.Obj, 1);',
|
||||||
'$mod.THelper.Foo.call($mod.Obj, 1);',
|
'$mod.THelper.Foo.call($mod.Obj, 1);',
|
||||||
'$mod.THelper.Foo.call($mod.Obj, 21);',
|
'$mod.THelper.Foo.call($mod.Obj, 21);',
|
||||||
|
'$mod.Obj.Fly(2);',
|
||||||
|
'$mod.Obj.Fly(2);',
|
||||||
'var $with1 = $mod.Obj;',
|
'var $with1 = $mod.Obj;',
|
||||||
'$mod.THelper.Foo.call($with1, 1);',
|
'$mod.THelper.Foo.call($with1, 1);',
|
||||||
'$mod.THelper.Foo.call($with1, 1);',
|
'$mod.THelper.Foo.call($with1, 1);',
|
||||||
'$mod.THelper.Foo.call($with1, 22);',
|
'$mod.THelper.Foo.call($with1, 22);',
|
||||||
|
'$with1.Fly(2);',
|
||||||
|
'$with1.Fly(2);',
|
||||||
|
'$mod.p = rtl.createCallback($mod.Obj, "Fly");',
|
||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -23022,6 +23047,23 @@ begin
|
|||||||
'']));
|
'']));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestModule.TestTypeHelper_ExtClassMethodFail;
|
||||||
|
begin
|
||||||
|
StartProgram(false);
|
||||||
|
Add([
|
||||||
|
'{$modeswitch typehelpers}',
|
||||||
|
'type',
|
||||||
|
' THelper = type helper for word',
|
||||||
|
' procedure Run; external name ''Run'';',
|
||||||
|
' end;',
|
||||||
|
'var w: word;',
|
||||||
|
'begin',
|
||||||
|
' w.Run;',
|
||||||
|
'']);
|
||||||
|
SetExpectedPasResolverError('Not supported: external method in type helper',nNotSupportedX);
|
||||||
|
ConvertProgram;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestModule.TestTypeHelper_Constructor;
|
procedure TTestModule.TestTypeHelper_Constructor;
|
||||||
begin
|
begin
|
||||||
StartProgram(false);
|
StartProgram(false);
|
||||||
|
@ -1867,8 +1867,9 @@ function(){
|
|||||||
<li>A <b>record helper</b> can "extend" a record type. In $mode delphi a
|
<li>A <b>record helper</b> can "extend" a record type. In $mode delphi a
|
||||||
record helper can extend other types as well, see <i>type helper</i></li>
|
record helper can extend other types as well, see <i>type helper</i></li>
|
||||||
<li>A <b>type helper</b> can extend all base types like integer, string,
|
<li>A <b>type helper</b> can extend all base types like integer, string,
|
||||||
char, boolean, double, currency, and some user types like enumeration,
|
char, boolean, double, currency, and user types like enumeration,
|
||||||
set, range and array types. It cannot extend interfaces or helpers.<br>
|
set, range, array, class, record and interface types.
|
||||||
|
It cannot extend helpers and procedural types.<br>
|
||||||
Type helpers are enabled by default in <i>$mode delphi</i> and disabled in <i>$mode objfpc</i>.
|
Type helpers are enabled by default in <i>$mode delphi</i> and disabled in <i>$mode objfpc</i>.
|
||||||
You can enable them with <b>{$modeswitch typehelpers}</b>.
|
You can enable them with <b>{$modeswitch typehelpers}</b>.
|
||||||
</li>
|
</li>
|
||||||
@ -1929,6 +1930,8 @@ function(){
|
|||||||
<li><i>with value do ;</i> : uses a temporary variable. Delphi/FPC do not support it.</li>
|
<li><i>with value do ;</i> : uses a temporary variable. Delphi/FPC do not support it.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>A method with <i>external name</i> modifier is treated as an external
|
||||||
|
method of the helped type.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user