mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 07:13:32 +02:00
pas2js: calling async function returns promise, await(async proc);
git-svn-id: trunk@45506 -
This commit is contained in:
parent
996bd416e0
commit
c305689305
@ -1094,11 +1094,22 @@ type
|
||||
end;
|
||||
TPas2JsElementDataClass = class of TPas2JsElementData;
|
||||
|
||||
TPas2JSModuleScopeFlag = (
|
||||
p2msfPromiseSearched // TJSPromise searched
|
||||
);
|
||||
TPas2JSModuleScopeFlags = set of TPas2JSModuleScopeFlag;
|
||||
|
||||
{ TPas2JSModuleScope }
|
||||
|
||||
TPas2JSModuleScope = class(TPasModuleScope)
|
||||
private
|
||||
FJSPromiseClass: TPasClassType;
|
||||
procedure SetJSPromiseClass(const AValue: TPasClassType);
|
||||
public
|
||||
FlagsJS: TPas2JSModuleScopeFlags;
|
||||
SystemVarRecs: TPasFunction;
|
||||
destructor Destroy; override;
|
||||
property JSPromiseClass: TPasClassType read FJSPromiseClass write SetJSPromiseClass;
|
||||
end;
|
||||
|
||||
{ TPas2jsElevatedLocals }
|
||||
@ -1334,6 +1345,18 @@ type
|
||||
end;
|
||||
PHasAnoFuncData = ^THasAnoFuncData;
|
||||
procedure OnHasAnonymousEl(El: TPasElement; arg: pointer);
|
||||
protected
|
||||
type
|
||||
TPRFindExtSystemClass = record
|
||||
JSName: string;
|
||||
ErrorPosEl: TPasElement;
|
||||
Found: TPasClassType;
|
||||
ElScope: TPasScope; // Where Found was found
|
||||
StartScope: TPasScope; // where the search started
|
||||
end;
|
||||
PPRFindExtSystemClass = ^TPRFindExtSystemClass;
|
||||
procedure OnFindExtSystemClass(El: TPasElement; ElScope, StartScope: TPasScope;
|
||||
FindExtSystemClassData: Pointer; var Abort: boolean); virtual;
|
||||
protected
|
||||
// overloads: fix name clashes in JS
|
||||
FOverloadScopes: TFPList; // list of TPasIdentifierScope
|
||||
@ -1381,6 +1404,9 @@ type
|
||||
); override;
|
||||
procedure FindCreatorArrayOfConst(Args: TFPList; ErrorEl: TPasElement);
|
||||
function FindProc_ArrLitToArrayOfConst(ErrorEl: TPasElement): TPasFunction; virtual;
|
||||
function FindSystemExternalClassType(const aClassName, JSName: string;
|
||||
ErrorEl: TPasElement): TPasClassType; virtual;
|
||||
function FindTJSPromise(ErrorEl: TPasElement): TPasClassType; virtual;
|
||||
procedure CheckExternalClassConstructor(Ref: TResolvedReference); virtual;
|
||||
procedure CheckConditionExpr(El: TPasExpr;
|
||||
const ResolvedEl: TPasResolverResult); override;
|
||||
@ -1425,6 +1451,8 @@ type
|
||||
Params: TParamsExpr; out ResolvedEl: TPasResolverResult); virtual;
|
||||
procedure BI_AWait_OnEval(Proc: TResElDataBuiltInProc;
|
||||
Params: TParamsExpr; Flags: TResEvalFlags; out Evaluated: TResEvalValue); virtual;
|
||||
procedure BI_AWait_OnFinishParamsExpr(Proc: TResElDataBuiltInProc;
|
||||
Params: TParamsExpr); virtual;
|
||||
public
|
||||
constructor Create; reintroduce;
|
||||
destructor Destroy; override;
|
||||
@ -1456,6 +1484,9 @@ type
|
||||
procedure CheckDispatchField(Proc: TPasProcedure; Switch: TValueSwitch);
|
||||
procedure AddMessageStr(var MsgToProc: TMessageIdToProc_List; const S: string; Proc: TPasProcedure);
|
||||
procedure AddMessageIdToClassScope(Proc: TPasProcedure; EmitHints: boolean); virtual;
|
||||
procedure ComputeResultElement(El: TPasResultElement; out
|
||||
ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
|
||||
StartEl: TPasElement = nil); override;
|
||||
// CustomData
|
||||
function GetElementData(El: TPasElementBase;
|
||||
DataClass: TPas2JsElementDataClass): TPas2JsElementData; virtual;
|
||||
@ -2223,6 +2254,24 @@ begin
|
||||
Result:='['+Result+']';
|
||||
end;
|
||||
|
||||
{ TPas2JSModuleScope }
|
||||
|
||||
procedure TPas2JSModuleScope.SetJSPromiseClass(const AValue: TPasClassType);
|
||||
begin
|
||||
if FJSPromiseClass=AValue then Exit;
|
||||
if FJSPromiseClass<>nil then
|
||||
FJSPromiseClass.Release{$IFDEF CheckPasTreeRefCount}('TPas2JSModuleScope.SetJSPromiseClass'){$ENDIF};
|
||||
FJSPromiseClass:=AValue;
|
||||
if FJSPromiseClass<>nil then
|
||||
FJSPromiseClass.AddRef{$IFDEF CheckPasTreeRefCount}('TPas2JSModuleScope.SetJSPromiseClass'){$ENDIF};
|
||||
end;
|
||||
|
||||
destructor TPas2JSModuleScope.Destroy;
|
||||
begin
|
||||
JSPromiseClass:=nil;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TPas2JSClassScope }
|
||||
|
||||
constructor TPas2JSClassScope.Create;
|
||||
@ -2846,6 +2895,25 @@ begin
|
||||
Data^.Expr:=TProcedureExpr(El);
|
||||
end;
|
||||
|
||||
procedure TPas2JSResolver.OnFindExtSystemClass(El: TPasElement; ElScope,
|
||||
StartScope: TPasScope; FindExtSystemClassData: Pointer; var Abort: boolean);
|
||||
var
|
||||
Data: PPRFindExtSystemClass absolute FindExtSystemClassData;
|
||||
aClass: TPasClassType;
|
||||
begin
|
||||
if Data^.Found<>nil then exit;
|
||||
if not (El is TPasClassType) then exit;
|
||||
aClass:=TPasClassType(El);
|
||||
if not aClass.IsExternal then exit;
|
||||
if aClass.Parent is TPasMembersType then
|
||||
exit; // nested class
|
||||
if not IsExternalClass_Name(aClass,Data^.JSName) then exit;
|
||||
Data^.Found:=aClass;
|
||||
Data^.ElScope:=ElScope;
|
||||
Data^.StartScope:=StartScope;
|
||||
Abort:=true;
|
||||
end;
|
||||
|
||||
function TPas2JSResolver.HasOverloadIndex(El: TPasElement;
|
||||
WithElevatedLocal: boolean): boolean;
|
||||
var
|
||||
@ -4098,11 +4166,10 @@ begin
|
||||
if (not (pm in [pmVirtual, pmAbstract, pmOverride,
|
||||
pmOverload, pmMessage, pmReintroduce,
|
||||
pmInline, pmAssembler, pmPublic,
|
||||
pmExternal, pmForward,
|
||||
pmAsync])) then
|
||||
pmExternal, pmForward])) then
|
||||
RaiseNotYetImplemented(20170208142159,El,'modifier '+ModifierNames[pm]);
|
||||
for ptm in Proc.ProcType.Modifiers do
|
||||
if (not (ptm in [ptmOfObject,ptmVarargs,ptmStatic])) then
|
||||
if (not (ptm in [ptmOfObject,ptmVarargs,ptmStatic,ptmAsync])) then
|
||||
RaiseNotYetImplemented(20170411171454,El,'modifier '+ProcTypeModifiers[ptm]);
|
||||
|
||||
// check pmPublic
|
||||
@ -4184,7 +4251,8 @@ begin
|
||||
and (Proc.ClassType=TPasClassFunction)
|
||||
and (Proc.Visibility in [visProtected,visPublic,visPublished])
|
||||
and (TPasClassFunction(Proc).FuncType.ResultEl.ResultType=AClassOrRec)
|
||||
and ([pmOverride,pmExternal]*Proc.Modifiers=[]) then
|
||||
and (Proc.Modifiers*[pmOverride,pmExternal]=[])
|
||||
and (Proc.ProcType.Modifiers*[ptmOfObject]=[ptmOfObject]) then
|
||||
begin
|
||||
// The first non private class function in a Pascal class descending
|
||||
// from an external class
|
||||
@ -4246,7 +4314,7 @@ begin
|
||||
RaiseMsg(20170227095454,nMissingExternalName,sMissingExternalName,
|
||||
['missing external name'],Proc);
|
||||
|
||||
for pm in [pmAssembler,pmForward,pmNoReturn,pmInline,pmAsync] do
|
||||
for pm in [pmAssembler,pmForward,pmNoReturn,pmInline] do
|
||||
if pm in Proc.Modifiers then
|
||||
RaiseMsg(20170323100842,nInvalidXModifierY,sInvalidXModifierY,
|
||||
[Proc.ElementTypeName,ModifierNames[pm]],Proc);
|
||||
@ -4429,6 +4497,37 @@ begin
|
||||
cCallingConventions[FuncType.CallingConvention],ErrorEl);
|
||||
end;
|
||||
|
||||
function TPas2JSResolver.FindSystemExternalClassType(const aClassName,
|
||||
JSName: string; ErrorEl: TPasElement): TPasClassType;
|
||||
var
|
||||
Data: TPRFindExtSystemClass;
|
||||
Abort: boolean;
|
||||
begin
|
||||
Data:=Default(TPRFindExtSystemClass);
|
||||
Data.ErrorPosEl:=ErrorEl;
|
||||
Data.JSName:=JSName;
|
||||
Abort:=false;
|
||||
IterateElements(aClassName,@OnFindExtSystemClass,@Data,Abort);
|
||||
Result:=Data.Found;
|
||||
if (ErrorEl<>nil) and (Result=nil) then
|
||||
RaiseIdentifierNotFound(20200526095647,aClassName+' = class external name '''+JSName+'''',ErrorEl);
|
||||
end;
|
||||
|
||||
function TPas2JSResolver.FindTJSPromise(ErrorEl: TPasElement): TPasClassType;
|
||||
var
|
||||
aMod: TPasModule;
|
||||
ModScope: TPas2JSModuleScope;
|
||||
begin
|
||||
aMod:=RootElement;
|
||||
ModScope:=aMod.CustomData as TPas2JSModuleScope;
|
||||
Result:=ModScope.JSPromiseClass;
|
||||
if p2msfPromiseSearched in ModScope.FlagsJS then
|
||||
exit; // use cache
|
||||
Result:=FindSystemExternalClassType('TJSPromise','Promise',ErrorEl);
|
||||
ModScope.JSPromiseClass:=Result;
|
||||
Include(ModScope.FlagsJS,p2msfPromiseSearched);
|
||||
end;
|
||||
|
||||
procedure TPas2JSResolver.CheckExternalClassConstructor(Ref: TResolvedReference
|
||||
);
|
||||
var
|
||||
@ -5013,6 +5112,7 @@ var
|
||||
TemplType: TPasGenericTemplateType;
|
||||
ConEl: TPasElement;
|
||||
ConToken: TToken;
|
||||
ResultEl: TPasResultElement;
|
||||
begin
|
||||
Param:=Params.Params[0];
|
||||
ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
|
||||
@ -5021,8 +5121,8 @@ begin
|
||||
if (ParamResolved.BaseType=btProc) and (ParamResolved.IdentEl is TPasFunction) then
|
||||
begin
|
||||
// typeinfo of function result -> resolve once
|
||||
TypeEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType;
|
||||
ComputeElement(TypeEl,ParamResolved,[rcNoImplicitProc]);
|
||||
ResultEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl;
|
||||
ComputeResultElement(ResultEl,ParamResolved,[]);
|
||||
Include(ParamResolved.Flags,rrfReadable);
|
||||
if ParamResolved.LoTypeEl=nil then
|
||||
RaiseInternalError(20170421124923);
|
||||
@ -5211,7 +5311,9 @@ end;
|
||||
|
||||
function TPas2JSResolver.BI_AWait_OnGetCallCompatibility(
|
||||
Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
|
||||
// function await(const Expr: T): T
|
||||
// await(const Expr: T): T
|
||||
// await(T; p: TJSPromise): T;
|
||||
// await(AsyncProc);
|
||||
const
|
||||
Signature2 = 'function await(aType,TJSPromise):aType';
|
||||
var
|
||||
@ -5242,6 +5344,18 @@ begin
|
||||
// function await(value)
|
||||
// must be the only parameter
|
||||
Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
|
||||
if Result=cIncompatible then exit;
|
||||
end
|
||||
else if ParamResolved.BaseType=btProc then
|
||||
begin
|
||||
// e.g. await(Proc)
|
||||
if Expr.Parent is TPasExpr then
|
||||
begin
|
||||
if RaiseOnError then
|
||||
RaiseMsg(20200523232827,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr);
|
||||
exit;
|
||||
end;
|
||||
Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -5284,10 +5398,40 @@ procedure TPas2JSResolver.BI_AWait_OnGetCallResult(Proc: TResElDataBuiltInProc;
|
||||
Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
|
||||
// function await(const Expr: T): T
|
||||
// function await(T; p: TJSPromise): T
|
||||
// await(Proc());
|
||||
var
|
||||
Param: TPasExpr;
|
||||
Param, PathEnd: TPasExpr;
|
||||
Ref: TResolvedReference;
|
||||
Decl: TPasElement;
|
||||
DeclFunc: TPasFunction;
|
||||
begin
|
||||
Param:=Params.Params[0];
|
||||
if length(Params.Params)=1 then
|
||||
begin
|
||||
// await(expr)
|
||||
PathEnd:=GetPathEndIdent(Param,true);
|
||||
if (PathEnd<>nil) and (PathEnd.CustomData is TResolvedReference) then
|
||||
begin
|
||||
Ref:=TResolvedReference(PathEnd.CustomData);
|
||||
Decl:=Ref.Declaration;
|
||||
if Decl is TPasFunction then
|
||||
begin
|
||||
DeclFunc:=TPasFunction(Decl);
|
||||
if DeclFunc.IsAsync then
|
||||
begin
|
||||
// await(CallAsyncFunction) -> use Pascal result type (not TJSPromise)
|
||||
// Note the missing rcCall flag
|
||||
ComputeResultElement(DeclFunc.FuncType.ResultEl,ResolvedEl,[],PathEnd);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
// await(expr:T):T
|
||||
end
|
||||
else
|
||||
begin
|
||||
// await(T;promise):T
|
||||
end;
|
||||
ComputeElement(Param,ResolvedEl,[]);
|
||||
Include(ResolvedEl.Flags,rrfReadable);
|
||||
if Proc=nil then ;
|
||||
@ -5309,6 +5453,42 @@ begin
|
||||
if Proc=nil then ;
|
||||
end;
|
||||
|
||||
procedure TPas2JSResolver.BI_AWait_OnFinishParamsExpr(
|
||||
Proc: TResElDataBuiltInProc; Params: TParamsExpr);
|
||||
var
|
||||
P: TPasExprArray;
|
||||
Param, PathEnd: TPasExpr;
|
||||
Ref: TResolvedReference;
|
||||
Decl: TPasElement;
|
||||
begin
|
||||
if Proc=nil then ;
|
||||
P:=Params.Params;
|
||||
if P=nil then ;
|
||||
Param:=P[0];
|
||||
FinishCallArgAccess(Param,rraRead);
|
||||
if length(P)=1 then
|
||||
begin
|
||||
// await(expr)
|
||||
PathEnd:=GetPathEndIdent(Param,false);
|
||||
if (PathEnd<>nil) and (PathEnd.CustomData is TResolvedReference) then
|
||||
begin
|
||||
Ref:=TResolvedReference(PathEnd.CustomData);
|
||||
Decl:=Ref.Declaration;
|
||||
if Decl is TPasProcedure then
|
||||
begin
|
||||
// implicit call
|
||||
Exclude(Ref.Flags,rrfNoImplicitCallWithoutParams);
|
||||
Include(Ref.Flags,rrfImplicitCallWithoutParams);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if length(P)>1 then
|
||||
FinishCallArgAccess(P[1],rraRead);
|
||||
if length(P)>2 then
|
||||
RaiseNotYetImplemented(20200525142451,Params);
|
||||
end;
|
||||
|
||||
constructor TPas2JSResolver.Create;
|
||||
var
|
||||
bt: TPas2jsBaseType;
|
||||
@ -5407,7 +5587,7 @@ begin
|
||||
// nil,nil,bfCustom,[bipfCanBeStatement]);
|
||||
AddBuiltInProc('AWait','function await(const Expr: T): T',
|
||||
@BI_AWait_OnGetCallCompatibility,@BI_AWait_OnGetCallResult,
|
||||
@BI_AWait_OnEval,nil,bfCustom,[bipfCanBeStatement]);
|
||||
@BI_AWait_OnEval,@BI_AWait_OnFinishParamsExpr,bfCustom,[bipfCanBeStatement]);
|
||||
end;
|
||||
|
||||
function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
|
||||
@ -6079,6 +6259,33 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPas2JSResolver.ComputeResultElement(El: TPasResultElement; out
|
||||
ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
|
||||
StartEl: TPasElement);
|
||||
var
|
||||
FuncType: TPasFunctionType;
|
||||
Proc: TPasProcedure;
|
||||
JSPromiseClass: TPasClassType;
|
||||
begin
|
||||
if (rcCall in Flags) and (El.Parent is TPasFunctionType) then
|
||||
begin
|
||||
FuncType:=TPasFunctionType(El.Parent);
|
||||
if FuncType.Parent is TPasProcedure then
|
||||
begin
|
||||
Proc:=TPasProcedure(FuncType.Parent);
|
||||
if Proc.IsAsync then
|
||||
begin
|
||||
// an async function call returns a TJSPromise
|
||||
JSPromiseClass:=FindTJSPromise(StartEl);
|
||||
SetResolverIdentifier(ResolvedEl,btContext,El,
|
||||
JSPromiseClass,JSPromiseClass,[rrfReadable,rrfWritable]);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
inherited ComputeResultElement(El, ResolvedEl, Flags, StartEl);
|
||||
end;
|
||||
|
||||
function TPas2JSResolver.GetElementData(El: TPasElementBase;
|
||||
DataClass: TPas2JsElementDataClass): TPas2JsElementData;
|
||||
begin
|
||||
@ -12875,10 +13082,12 @@ var
|
||||
Param: TPasExpr;
|
||||
ResultEl: TPasResultElement;
|
||||
TypeEl: TPasType;
|
||||
aResolver: TPas2JSResolver;
|
||||
begin
|
||||
Result:=nil;
|
||||
Param:=El.Params[0];
|
||||
AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
|
||||
aResolver:=AContext.Resolver;
|
||||
aResolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
|
||||
{$IFDEF VerbosePas2JS}
|
||||
writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo ',GetResolverResultDbg(ParamResolved));
|
||||
{$ENDIF}
|
||||
@ -12886,7 +13095,7 @@ begin
|
||||
begin
|
||||
// typeinfo(function) -> typeinfo(resulttype)
|
||||
ResultEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl;
|
||||
AContext.Resolver.ComputeElement(ResultEl.ResultType,ParamResolved,[rcNoImplicitProc]);
|
||||
aResolver.ComputeResultElement(ResultEl,ParamResolved,[]);
|
||||
{$IFDEF VerbosePas2JS}
|
||||
writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo FuncResult=',GetResolverResultDbg(ParamResolved));
|
||||
{$ENDIF}
|
||||
@ -17393,7 +17602,7 @@ begin
|
||||
RaiseNotSupported(El,AContext,20171225104212);
|
||||
if GetEnumeratorFunc.ClassType<>TPasFunction then
|
||||
RaiseNotSupported(El,AContext,20171225104237);
|
||||
aResolver.ComputeElement(GetEnumeratorFunc.FuncType.ResultEl,ResolvedEl,[rcType]);
|
||||
aResolver.ComputeResultElement(GetEnumeratorFunc.FuncType.ResultEl,ResolvedEl,[rcCall]);
|
||||
EnumeratorTypeEl:=ResolvedEl.LoTypeEl;
|
||||
|
||||
if EnumeratorTypeEl is TPasClassType then
|
||||
|
@ -431,7 +431,8 @@ const
|
||||
'IsNested',
|
||||
'Static',
|
||||
'Varargs',
|
||||
'ReferenceTo'
|
||||
'ReferenceTo',
|
||||
'Async'
|
||||
);
|
||||
|
||||
PCUProcedureMessageTypeNames: array[TProcedureMessageType] of string = (
|
||||
@ -494,8 +495,7 @@ const
|
||||
'DispId',
|
||||
'NoReturn',
|
||||
'Far',
|
||||
'Final',
|
||||
'Async'
|
||||
'Final'
|
||||
);
|
||||
PCUProcedureModifiersImplProc = [pmInline,pmAssembler,pmCompilerProc,pmNoReturn];
|
||||
|
||||
|
@ -340,10 +340,6 @@ type
|
||||
Procedure TestProc_LocalVarInit;
|
||||
Procedure TestProc_ReservedWords;
|
||||
Procedure TestProc_ConstRefWord;
|
||||
Procedure TestProc_Async;
|
||||
Procedure TestProc_AWaitOutsideAsyncFail;
|
||||
Procedure TestProc_AWait;
|
||||
Procedure TestProc_AWaitExternalClassPromise;
|
||||
|
||||
// anonymous functions
|
||||
Procedure TestAnonymousProc_Assign_ObjFPC;
|
||||
@ -356,7 +352,6 @@ type
|
||||
Procedure TestAnonymousProc_NestedAssignResult;
|
||||
Procedure TestAnonymousProc_Class;
|
||||
Procedure TestAnonymousProc_ForLoop;
|
||||
Procedure TestAnonymousProc_Async;
|
||||
|
||||
// enums, sets
|
||||
Procedure TestEnum_Name;
|
||||
@ -865,6 +860,23 @@ type
|
||||
procedure TestRangeChecks_StringIndex;
|
||||
procedure TestRangeChecks_TypecastInt;
|
||||
procedure TestRangeChecks_TypeHelperInt;
|
||||
|
||||
// Async/AWait
|
||||
Procedure TestAsync_Proc;
|
||||
Procedure TestAsync_CallResultIsPromise;
|
||||
Procedure TestAsync_ConstructorFail;
|
||||
Procedure TestAsync_PropertyGetterFail;
|
||||
Procedure TestAwait_NonPromiseWithTypeFail;
|
||||
Procedure TestAWait_OutsideAsyncFail;
|
||||
Procedure TestAWait_Result;
|
||||
Procedure TestAWait_ExternalClassPromise;
|
||||
Procedure TestAsync_AnonymousProc;
|
||||
// ToDo: proc type, implict call, explicit call, await()
|
||||
// ToDo: proc type assign async mismatch fail
|
||||
// ToDo: inherited;
|
||||
// ToDo: inherited asyncproc;
|
||||
// ToDo: await(inherited asyncproc);
|
||||
// ToDo: i:=await(inherited asyncfunc)
|
||||
end;
|
||||
|
||||
function LinesToStr(Args: array of const): string;
|
||||
@ -4609,115 +4621,6 @@ begin
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestProc_Async;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'procedure Fly(w: word); async; forward;',
|
||||
'procedure Run(w: word); async;',
|
||||
'begin',
|
||||
'end;',
|
||||
'procedure Fly(w: word); ',
|
||||
'begin',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestProc_Async',
|
||||
LinesToStr([ // statements
|
||||
'this.Run = async function (w) {',
|
||||
'};',
|
||||
'this.Fly = async function (w) {',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Run(1);'
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestProc_AWaitOutsideAsyncFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'function Crawl(w: double): word; ',
|
||||
'begin',
|
||||
'end;',
|
||||
'function Run(w: double): word;',
|
||||
'begin',
|
||||
' Result:=await(Crawl(w));',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
SetExpectedPasResolverError(sAWaitOnlyInAsyncProcedure,nAWaitOnlyInAsyncProcedure);
|
||||
ConvertProgram;
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestProc_AWait;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'function Crawl(d: double = 1.3): word; ',
|
||||
'begin',
|
||||
'end;',
|
||||
'function Run(d: double): word; async;',
|
||||
'begin',
|
||||
' Result:=await(1);',
|
||||
' Result:=await(Crawl);',
|
||||
' Result:=await(Crawl(4.5));',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestProc_AWait',
|
||||
LinesToStr([ // statements
|
||||
'this.Crawl = function (d) {',
|
||||
' var Result = 0;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Run = async function (d) {',
|
||||
' var Result = 0;',
|
||||
' Result = await 1;',
|
||||
' Result = await $mod.Crawl(1.3);',
|
||||
' Result = await $mod.Crawl(4.5);',
|
||||
' return Result;',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Run(1);'
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestProc_AWaitExternalClassPromise;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch externalclass}',
|
||||
'type',
|
||||
' TJSPromise = class external name ''Promise''',
|
||||
' end;',
|
||||
'function Run(d: double): word; async;',
|
||||
'var',
|
||||
' p: TJSPromise;',
|
||||
'begin',
|
||||
' Result:=await(word,p);',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestProc_AWaitExternalClassPromise',
|
||||
LinesToStr([ // statements
|
||||
'this.Run = async function (d) {',
|
||||
' var Result = 0;',
|
||||
' var p = null;',
|
||||
' Result = await p;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Run(1);'
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAnonymousProc_Assign_ObjFPC;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -5197,44 +5100,6 @@ begin
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAnonymousProc_Async;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$mode objfpc}',
|
||||
'type',
|
||||
' TFunc = reference to function(x: double): word;',
|
||||
'function Crawl(d: double = 1.3): word; ',
|
||||
'begin',
|
||||
'end;',
|
||||
'var Func: TFunc;',
|
||||
'begin',
|
||||
' Func:=function(c:double):word async begin',
|
||||
' Result:=await(Crawl(c));',
|
||||
' end;',
|
||||
' Func:=function(c:double):word async assembler asm',
|
||||
' end;',
|
||||
' ']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAnonymousProc_Async',
|
||||
LinesToStr([ // statements
|
||||
'this.Crawl = function (d) {',
|
||||
' var Result = 0;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Func = null;',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Func = async function (c) {',
|
||||
' var Result = 0;',
|
||||
' Result = await $mod.Crawl(c);',
|
||||
' return Result;',
|
||||
'};',
|
||||
'$mod.Func = async function (c) {',
|
||||
'};',
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestEnum_Name;
|
||||
begin
|
||||
StartProgram(false);
|
||||
@ -31748,6 +31613,336 @@ begin
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAsync_Proc;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'procedure Fly(w: word = 1); async; forward;',
|
||||
'procedure Run(w: word = 2); async;',
|
||||
'begin',
|
||||
' Fly(w);',
|
||||
' Fly;',
|
||||
' await(Fly(w));',
|
||||
' await(Fly);',
|
||||
'end;',
|
||||
'procedure Fly(w: word); ',
|
||||
'begin',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run;',
|
||||
' Run(3);',
|
||||
'']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAsync_Proc',
|
||||
LinesToStr([ // statements
|
||||
'this.Run = async function (w) {',
|
||||
' $mod.Fly(w);',
|
||||
' $mod.Fly(1);',
|
||||
' await $mod.Fly(w);',
|
||||
' await $mod.Fly(1);',
|
||||
'};',
|
||||
'this.Fly = async function (w) {',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Run(2);',
|
||||
'$mod.Run(3);',
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAsync_CallResultIsPromise;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch externalclass}',
|
||||
'type',
|
||||
' TObject = class',
|
||||
' end;',
|
||||
' TJSPromise = class external name ''Promise''',
|
||||
' end;',
|
||||
' TBird = class',
|
||||
' function Fly: word; async; ',
|
||||
' end;',
|
||||
'function TBird.Fly: word; async; ',
|
||||
'begin',
|
||||
' Result:=3;',
|
||||
' Fly:=4+Result;',
|
||||
' if Result=5 then ;',
|
||||
' exit(6);',
|
||||
'end;',
|
||||
'function Run: word; async;',
|
||||
'begin',
|
||||
' Result:=11+Result;',
|
||||
' inc(Result);',
|
||||
'end;',
|
||||
'var',
|
||||
' p: TJSPromise;',
|
||||
' o: TBird;',
|
||||
'begin',
|
||||
' p:=Run;',
|
||||
' p:=Run();',
|
||||
' if Run=p then ;',
|
||||
' if p=Run then ;',
|
||||
' if Run()=p then ;',
|
||||
' if p=Run() then ;',
|
||||
' p:=o.Fly;',
|
||||
' p:=o.Fly();',
|
||||
' if o.Fly=p then ;',
|
||||
' if o.Fly()=p then ;',
|
||||
' with o do begin',
|
||||
' p:=Fly;',
|
||||
' p:=Fly();',
|
||||
' if Fly=p then ;',
|
||||
' if Fly()=p then ;',
|
||||
' end;',
|
||||
'']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAsync_CallResultIsPromise',
|
||||
LinesToStr([ // statements
|
||||
'rtl.createClass($mod, "TObject", null, function () {',
|
||||
' this.$init = function () {',
|
||||
' };',
|
||||
' this.$final = function () {',
|
||||
' };',
|
||||
'});',
|
||||
'rtl.createClass($mod, "TBird", $mod.TObject, function () {',
|
||||
' this.Fly = async function () {',
|
||||
' var Result = 0;',
|
||||
' Result = 3;',
|
||||
' Result = 4 + Result;',
|
||||
' if (Result === 5) ;',
|
||||
' return 6;',
|
||||
' return Result;',
|
||||
' };',
|
||||
'});',
|
||||
'this.Run = async function () {',
|
||||
' var Result = 0;',
|
||||
' Result = 11 + Result;',
|
||||
' Result += 1;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.p = null;',
|
||||
'this.o = null;',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.p = $mod.Run();',
|
||||
'$mod.p = $mod.Run();',
|
||||
'if ($mod.Run() === $mod.p) ;',
|
||||
'if ($mod.p === $mod.Run()) ;',
|
||||
'if ($mod.Run() === $mod.p) ;',
|
||||
'if ($mod.p === $mod.Run()) ;',
|
||||
'$mod.p = $mod.o.Fly();',
|
||||
'$mod.p = $mod.o.Fly();',
|
||||
'if ($mod.o.Fly() === $mod.p) ;',
|
||||
'if ($mod.o.Fly() === $mod.p) ;',
|
||||
'var $with1 = $mod.o;',
|
||||
'$mod.p = $with1.Fly();',
|
||||
'$mod.p = $with1.Fly();',
|
||||
'if ($with1.Fly() === $mod.p) ;',
|
||||
'if ($with1.Fly() === $mod.p) ;',
|
||||
'']));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAsync_ConstructorFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'type',
|
||||
' TObject = class',
|
||||
' end;',
|
||||
' TBird = class',
|
||||
' constructor Create; async;',
|
||||
' end;',
|
||||
'constructor TBird.Create; async;',
|
||||
'begin',
|
||||
'end;',
|
||||
'begin',
|
||||
'']);
|
||||
SetExpectedPasResolverError('Invalid constructor modifier async',nInvalidXModifierY);
|
||||
ConvertProgram;
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAsync_PropertyGetterFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'type',
|
||||
' TObject = class',
|
||||
' end;',
|
||||
' TBird = class',
|
||||
' function GetSize: word; async;',
|
||||
' property Size: word read GetSize;',
|
||||
' end;',
|
||||
'function TBird.GetSize: word; async;',
|
||||
'begin',
|
||||
'end;',
|
||||
'begin',
|
||||
'']);
|
||||
SetExpectedPasResolverError('Invalid property getter modifier async',nInvalidXModifierY);
|
||||
ConvertProgram;
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAwait_NonPromiseWithTypeFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'procedure Run; async;',
|
||||
'begin',
|
||||
' await(word,1);',
|
||||
'end;',
|
||||
'begin',
|
||||
'']);
|
||||
SetExpectedPasResolverError('Incompatible type arg no. 2: Got "Longint", expected "TJSPromise"',nIncompatibleTypeArgNo);
|
||||
ConvertProgram;
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAWait_OutsideAsyncFail;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'procedure Crawl(w: double); ',
|
||||
'begin',
|
||||
'end;',
|
||||
'procedure Run(w: double);',
|
||||
'begin',
|
||||
' await(Crawl(w));',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
SetExpectedPasResolverError(sAWaitOnlyInAsyncProcedure,nAWaitOnlyInAsyncProcedure);
|
||||
ConvertProgram;
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAWait_Result;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch externalclass}',
|
||||
'type',
|
||||
' TJSPromise = class external name ''Promise''',
|
||||
' end;',
|
||||
'function Crawl(d: double = 1.3): word; ',
|
||||
'begin',
|
||||
'end;',
|
||||
'function Run(d: double = 1.6): word; async;',
|
||||
'begin',
|
||||
' Result:=await(1);',
|
||||
' Result:=await(Crawl);',
|
||||
' Result:=await(Crawl(4.5));',
|
||||
' Result:=await(Run);',
|
||||
' Result:=await(Run(6.7));',
|
||||
'end;',
|
||||
'begin',
|
||||
' Run(1);']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAWait_Result',
|
||||
LinesToStr([ // statements
|
||||
'this.Crawl = function (d) {',
|
||||
' var Result = 0;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Run = async function (d) {',
|
||||
' var Result = 0;',
|
||||
' Result = await 1;',
|
||||
' Result = await $mod.Crawl(1.3);',
|
||||
' Result = await $mod.Crawl(4.5);',
|
||||
' Result = await $mod.Run(1.6);',
|
||||
' Result = await $mod.Run(6.7);',
|
||||
' return Result;',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Run(1);'
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAWait_ExternalClassPromise;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$modeswitch externalclass}',
|
||||
'type',
|
||||
' TJSPromise = class external name ''Promise''',
|
||||
' end;',
|
||||
'function Fly(w: word): TJSPromise; async;',
|
||||
'begin',
|
||||
'end;',
|
||||
'function Jump(w: word): word; async;',
|
||||
'begin',
|
||||
'end;',
|
||||
'function Run(d: double): word; async;',
|
||||
'var',
|
||||
' p: TJSPromise;',
|
||||
'begin',
|
||||
' Result:=await(word,p);', // promise needs type
|
||||
' Result:=await(word,Fly(3));', // promise needs type
|
||||
' Result:=await(Jump(4));', // async non promise must omit the type
|
||||
'end;',
|
||||
'begin',
|
||||
'']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAWait_ExternalClassPromise',
|
||||
LinesToStr([ // statements
|
||||
'this.Fly = async function (w) {',
|
||||
' var Result = null;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Jump = async function (w) {',
|
||||
' var Result = 0;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Run = async function (d) {',
|
||||
' var Result = 0;',
|
||||
' var p = null;',
|
||||
' Result = await p;',
|
||||
' Result = await $mod.Fly(3);',
|
||||
' Result = await $mod.Jump(4);',
|
||||
' return Result;',
|
||||
'};',
|
||||
'']),
|
||||
LinesToStr([
|
||||
]));
|
||||
end;
|
||||
|
||||
procedure TTestModule.TestAsync_AnonymousProc;
|
||||
begin
|
||||
StartProgram(false);
|
||||
Add([
|
||||
'{$mode objfpc}',
|
||||
'type',
|
||||
' TFunc = reference to function(x: double): word; async;',
|
||||
'function Crawl(d: double = 1.3): word; ',
|
||||
'begin',
|
||||
'end;',
|
||||
'var Func: TFunc;',
|
||||
'begin',
|
||||
' Func:=function(c:double):word async begin',
|
||||
' Result:=await(Crawl(c));',
|
||||
' end;',
|
||||
' Func:=function(c:double):word async assembler asm',
|
||||
' end;',
|
||||
' ']);
|
||||
ConvertProgram;
|
||||
CheckSource('TestAsync_AnonymousProc',
|
||||
LinesToStr([ // statements
|
||||
'this.Crawl = function (d) {',
|
||||
' var Result = 0;',
|
||||
' return Result;',
|
||||
'};',
|
||||
'this.Func = null;',
|
||||
'']),
|
||||
LinesToStr([
|
||||
'$mod.Func = async function (c) {',
|
||||
' var Result = 0;',
|
||||
' Result = await $mod.Crawl(c);',
|
||||
' return Result;',
|
||||
'};',
|
||||
'$mod.Func = async function (c) {',
|
||||
'};',
|
||||
'']));
|
||||
end;
|
||||
|
||||
|
||||
Initialization
|
||||
RegisterTests([TTestModule]);
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user