pas2js: function await(atype; p:TJSPromise):atype

git-svn-id: trunk@45443 -
This commit is contained in:
Mattias Gaertner 2020-05-20 07:28:42 +00:00
parent b92ffac29a
commit 18fdc0675e
3 changed files with 96 additions and 18 deletions

View File

@ -1753,7 +1753,7 @@ type
function CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc; Expr: TPasExpr; function CheckBuiltInMinParamCount(Proc: TResElDataBuiltInProc; Expr: TPasExpr;
MinCount: integer; RaiseOnError: boolean): boolean; MinCount: integer; RaiseOnError: boolean): boolean;
function CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc; Params: TParamsExpr; function CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc; Params: TParamsExpr;
MaxCount: integer; RaiseOnError: boolean): integer; MaxCount: integer; RaiseOnError: boolean; Signature: string = ''): integer;
function CheckRaiseTypeArgNo(id: TMaxPrecInt; ArgNo: integer; Param: TPasExpr; function CheckRaiseTypeArgNo(id: TMaxPrecInt; ArgNo: integer; Param: TPasExpr;
const ParamResolved: TPasResolverResult; Expected: string; RaiseOnError: boolean): integer; const ParamResolved: TPasResolverResult; Expected: string; RaiseOnError: boolean): integer;
function FindUsedUnitInSection(const aName: string; Section: TPasSection): TPasModule; function FindUsedUnitInSection(const aName: string; Section: TPasSection): TPasModule;
@ -14705,13 +14705,17 @@ begin
end; end;
function TPasResolver.CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc; function TPasResolver.CheckBuiltInMaxParamCount(Proc: TResElDataBuiltInProc;
Params: TParamsExpr; MaxCount: integer; RaiseOnError: boolean): integer; Params: TParamsExpr; MaxCount: integer; RaiseOnError: boolean;
Signature: string): integer;
begin begin
if length(Params.Params)>MaxCount then if length(Params.Params)>MaxCount then
begin begin
if RaiseOnError then if RaiseOnError then
begin
if Signature='' then Signature:=Proc.Signature;
RaiseMsg(20170329154348,nWrongNumberOfParametersForCallTo, RaiseMsg(20170329154348,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[Proc.Signature],Params.Params[MaxCount]); sWrongNumberOfParametersForCallTo,[Signature],Params.Params[MaxCount]);
end;
exit(cIncompatible); exit(cIncompatible);
end; end;

View File

@ -406,6 +406,7 @@ Works:
- generics - generics
- async procedure modifier - async procedure modifier
- function await(const expr: T): T - function await(const expr: T): T
- function await(T; p: TJSPromise): T
ToDos: ToDos:
- range check: - range check:
@ -486,7 +487,7 @@ const
nVirtualMethodNameMustMatchExternal = 4013; nVirtualMethodNameMustMatchExternal = 4013;
nPublishedNameMustMatchExternal = 4014; nPublishedNameMustMatchExternal = 4014;
nInvalidVariableModifier = 4015; nInvalidVariableModifier = 4015;
// was nExternalObjectConstructorMustBeNamedNew = 4016; nAWaitOnlyInAsyncProcedure = 4016;
nNewInstanceFunctionMustBeVirtual = 4017; nNewInstanceFunctionMustBeVirtual = 4017;
nNewInstanceFunctionMustHaveTwoParameters = 4018; nNewInstanceFunctionMustHaveTwoParameters = 4018;
nNewInstanceFunctionMustNotHaveOverloadAtX = 4019; nNewInstanceFunctionMustNotHaveOverloadAtX = 4019;
@ -502,7 +503,6 @@ const
nDuplicateMessageIdXAtY = 4029; nDuplicateMessageIdXAtY = 4029;
nDispatchRequiresX = 4030; nDispatchRequiresX = 4030;
nConstRefNotForXAsConst = 4031; nConstRefNotForXAsConst = 4031;
nAWaitOnlyInAsyncProcedure = 3144;
// resourcestring patterns of messages // resourcestring patterns of messages
resourcestring resourcestring
sPasElementNotSupported = 'Pascal element not supported: %s'; sPasElementNotSupported = 'Pascal element not supported: %s';
@ -520,7 +520,7 @@ resourcestring
sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external'; sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external';
sInvalidVariableModifier = 'Invalid variable modifier "%s"'; sInvalidVariableModifier = 'Invalid variable modifier "%s"';
sPublishedNameMustMatchExternal = 'Published name must match external'; sPublishedNameMustMatchExternal = 'Published name must match external';
// was sExternalObjectConstructorMustBeNamedNew = 'external object constructor must be named "new"'; sAWaitOnlyInAsyncProcedure = 'await only available in async procedure';
sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual'; sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual';
sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters'; sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters';
sNewInstanceFunctionMustNotHaveOverloadAtX = 'NewInstance function must not have overload at %s'; sNewInstanceFunctionMustNotHaveOverloadAtX = 'NewInstance function must not have overload at %s';
@ -536,7 +536,6 @@ resourcestring
sDuplicateMessageIdXAtY = 'Duplicate message id "%s" at %s'; sDuplicateMessageIdXAtY = 'Duplicate message id "%s" at %s';
sDispatchRequiresX = 'Dispatch requires %s'; sDispatchRequiresX = 'Dispatch requires %s';
sConstRefNotForXAsConst = 'ConstRef not yet implemented for %s. Treating as Const'; sConstRefNotForXAsConst = 'ConstRef not yet implemented for %s. Treating as Const';
sAWaitOnlyInAsyncProcedure = 'await only available in async procedure';
const const
ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
@ -5213,11 +5212,14 @@ end;
function TPas2JSResolver.BI_AWait_OnGetCallCompatibility( function TPas2JSResolver.BI_AWait_OnGetCallCompatibility(
Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer; Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
// function await(const Expr: T): T // function await(const Expr: T): T
const
Signature2 = 'function await(aType,TJSPromise):aType';
var var
Params: TParamsExpr; Params: TParamsExpr;
Param: TPasExpr; Param: TPasExpr;
ParamResolved: TPasResolverResult; ParamResolved: TPasResolverResult;
ParentProc: TPasProcedure; ParentProc: TPasProcedure;
TypeEl: TPasType;
begin begin
Result:=cIncompatible; Result:=cIncompatible;
@ -5235,24 +5237,60 @@ begin
Params:=TParamsExpr(Expr); Params:=TParamsExpr(Expr);
Param:=Params.Params[0]; Param:=Params.Params[0];
ComputeElement(Param,ParamResolved,[]); ComputeElement(Param,ParamResolved,[]);
if not (rrfReadable in ParamResolved.Flags) then if (rrfReadable in ParamResolved.Flags) then
begin
// function await(value)
// must be the only parameter
Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
end
else
begin
TypeEl:=ParamResolved.LoTypeEl;
if (TypeEl is TPasUnresolvedSymbolRef)
and (TypeEl.CustomData is TResElDataBaseType) then
// base type
else if (TypeEl<>nil) and (ParamResolved.IdentEl is TPasType) then
// custom type
else
exit(CheckRaiseTypeArgNo(20200519151816,1,Param,ParamResolved,'jsvalue',RaiseOnError)); exit(CheckRaiseTypeArgNo(20200519151816,1,Param,ParamResolved,'jsvalue',RaiseOnError));
Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError); // function await(type,...)
if Proc=nil then ; if length(Params.Params)<2 then
begin
if RaiseOnError then
RaiseMsg(20200520090749,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[Signature2],Params);
exit(cIncompatible);
end;
// check second param TJSPromise
Param:=Params.Params[1];
ComputeElement(Param,ParamResolved,[]);
if not (rrfReadable in ParamResolved.Flags) then
exit(CheckRaiseTypeArgNo(20200520091707,2,Param,ParamResolved,
'instance of TJSPromise',RaiseOnError));
if (ParamResolved.BaseType<>btContext)
or not (ParamResolved.LoTypeEl is TPasClassType)
or not IsExternalClass_Name(TPasClassType(ParamResolved.LoTypeEl),'Promise') then
exit(CheckRaiseTypeArgNo(20200520091707,2,Param,ParamResolved,
'TJSPromise',RaiseOnError));
Result:=CheckBuiltInMaxParamCount(Proc,Params,2,RaiseOnError,Signature2);
end;
end; end;
procedure TPas2JSResolver.BI_AWait_OnGetCallResult(Proc: TResElDataBuiltInProc; procedure TPas2JSResolver.BI_AWait_OnGetCallResult(Proc: TResElDataBuiltInProc;
Params: TParamsExpr; out ResolvedEl: TPasResolverResult); Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
// function await(const Expr: T): T // function await(const Expr: T): T
// function await(T; p: TJSPromise): T
var var
Param: TPasExpr; Param: TPasExpr;
begin begin
if length(Params.Params)<>1 then
RaiseMsg(20200519233144,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[Proc.Signature],Params);
Param:=Params.Params[0]; Param:=Params.Params[0];
ComputeElement(Param,ResolvedEl,[]); ComputeElement(Param,ResolvedEl,[]);
Include(ResolvedEl.Flags,rrfReadable);
if Proc=nil then ;
end; end;
procedure TPas2JSResolver.BI_AWait_OnEval(Proc: TResElDataBuiltInProc; procedure TPas2JSResolver.BI_AWait_OnEval(Proc: TResElDataBuiltInProc;
@ -5263,11 +5301,12 @@ var
begin begin
Evaluated:=nil; Evaluated:=nil;
if length(Params.Params)<>1 then if length(Params.Params)<>1 then
RaiseMsg(20200519233220,nWrongNumberOfParametersForCallTo, exit;
sWrongNumberOfParametersForCallTo,[Proc.Signature],Params);
Param:=Params.Params[0]; Param:=Params.Params[0];
ComputeElement(Param,ParamResolved,[]); ComputeElement(Param,ParamResolved,[]);
Evaluated:=Eval(Param,Flags); Evaluated:=Eval(Param,Flags);
if Proc=nil then ;
end; end;
constructor TPas2JSResolver.Create; constructor TPas2JSResolver.Create;
@ -13217,9 +13256,12 @@ var
JS: TJSElement; JS: TJSElement;
AWaitJS: TJSAwaitExpression; AWaitJS: TJSAwaitExpression;
begin begin
if length(El.Params)<>1 then if length(El.Params)=1 then
Param:=El.Params[0]
else if length(El.Params)=2 then
Param:=El.Params[1]
else
RaiseNotSupported(El,AContext,20200519233919); RaiseNotSupported(El,AContext,20200519233919);
Param:=El.Params[0];
JS:=ConvertExpression(Param,AContext); JS:=ConvertExpression(Param,AContext);
AWaitJS:=TJSAwaitExpression(CreateElement(TJSAwaitExpression,El)); AWaitJS:=TJSAwaitExpression(CreateElement(TJSAwaitExpression,El));
AWaitJS.A:=JS; AWaitJS.A:=JS;

View File

@ -343,6 +343,7 @@ type
Procedure TestProc_Async; Procedure TestProc_Async;
Procedure TestProc_AWaitOutsideAsyncFail; Procedure TestProc_AWaitOutsideAsyncFail;
Procedure TestProc_AWait; Procedure TestProc_AWait;
Procedure TestProc_AWaitExternalClassPromise;
// anonymous functions // anonymous functions
Procedure TestAnonymousProc_Assign_ObjFPC; Procedure TestAnonymousProc_Assign_ObjFPC;
@ -4686,6 +4687,37 @@ begin
])); ]));
end; 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; procedure TTestModule.TestAnonymousProc_Assign_ObjFPC;
begin begin
StartProgram(false); StartProgram(false);