pastojs: await with one param must be async function

git-svn-id: trunk@47895 -
This commit is contained in:
Mattias Gaertner 2020-12-29 23:18:41 +00:00
parent edfbf2ce30
commit 8eafcd9490
4 changed files with 187 additions and 50 deletions

View File

@ -3544,7 +3544,8 @@ begin
' s[9+1]:=''b'';', ' s[9+1]:=''b'';',
' s[10]:='''''''';', ' s[10]:='''''''';',
' s[11]:=^g;', ' s[11]:=^g;',
' s[12]:=^H;']); ' s[12]:=^H;',
'']);
ParseProgram; ParseProgram;
end; end;
@ -3622,6 +3623,7 @@ begin
' m=low(char)+high(char);', ' m=low(char)+high(char);',
' n = string(''A'');', ' n = string(''A'');',
' o = UnicodeString(''A'');', ' o = UnicodeString(''A'');',
//' p = ^C''bird'';',
'begin']); 'begin']);
ParseProgram; ParseProgram;
CheckResolverUnexpectedHints; CheckResolverUnexpectedHints;

View File

@ -2399,6 +2399,7 @@ const
TempRefSetPathName = 's'; TempRefSetPathName = 's';
TempRefParamName = 'a'; TempRefParamName = 'a';
IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_']; IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_'];
AwaitSignature2 = 'function await(aType,TJSPromise):aType';
function CodePointToJSString(u: longword): TJSString; function CodePointToJSString(u: longword): TJSString;
begin begin
@ -5956,12 +5957,10 @@ 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;
// await(T; p: TJSPromise): T; // await(T; p: TJSPromise): T
// await(T; jsvalue): T
// await(AsyncFuncWithResultT): T
// await(AsyncProc); // await(AsyncProc);
// await(Proc);
// await(const Expr: T): T
const
Signature2 = 'function await(aType,TJSPromise):aType';
var var
Params: TParamsExpr; Params: TParamsExpr;
Param: TPasExpr; Param: TPasExpr;
@ -5991,6 +5990,48 @@ begin
// must be the only parameter // must be the only parameter
Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError); Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
if Result=cIncompatible then exit; if Result=cIncompatible then exit;
TypeEl:=ParamResolved.LoTypeEl;
if (ParamResolved.IdentEl is TPasResultElement) then
begin
// await(AsyncFuncCall)
if not TPasFunctionType(ParamResolved.IdentEl.Parent).IsAsync then
begin
{$IFDEF VerbosePas2JS}
writeln('TPas2JSResolver.BI_AWait_OnGetCallCompatibility ',GetResolverResultDbg(ParamResolved));
{$ENDIF}
if RaiseOnError then
RaiseMsg(20201229232446,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr)
else
exit(cIncompatible);
end;
end
else if (ParamResolved.BaseType=btContext)
and (TypeEl is TPasProcedureType) then
begin
// await(AsyncFuncTypeVar)
if not TPasProcedureType(TypeEl).IsAsync then
begin
{$IFDEF VerbosePas2JS}
writeln('TPas2JSResolver.BI_AWait_OnGetCallCompatibility ',GetResolverResultDbg(ParamResolved));
{$ENDIF}
if RaiseOnError then
RaiseMsg(20201229232541,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr)
else
exit(cIncompatible);
end;
end
else
begin
{$IFDEF VerbosePas2JS}
writeln('TPas2JSResolver.BI_AWait_OnGetCallCompatibility ',GetResolverResultDbg(ParamResolved));
{$ENDIF}
if RaiseOnError then
RaiseMsg(20201229224920,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr)
else
exit(cIncompatible);
end;
end end
else if ParamResolved.BaseType=btProc then else if ParamResolved.BaseType=btProc then
begin begin
@ -6028,7 +6069,7 @@ begin
begin begin
if RaiseOnError then if RaiseOnError then
RaiseMsg(20200520090749,nWrongNumberOfParametersForCallTo, RaiseMsg(20200520090749,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[Signature2],Params); sWrongNumberOfParametersForCallTo,[AwaitSignature2],Params);
exit(cIncompatible); exit(cIncompatible);
end; end;
@ -6062,14 +6103,21 @@ begin
exit(CheckRaiseTypeArgNo(20200520091707,2,Param,Param2Resolved, exit(CheckRaiseTypeArgNo(20200520091707,2,Param,Param2Resolved,
'instance of TJSPromise',RaiseOnError)); 'instance of TJSPromise',RaiseOnError));
if (Param2Resolved.BaseType<>btContext) if (Param2Resolved.BaseType=btContext)
or not (Param2Resolved.LoTypeEl is TPasClassType) and (Param2Resolved.LoTypeEl is TPasClassType)
or not IsExternalClass_Name(TPasClassType(Param2Resolved.LoTypeEl),'Promise') then and IsExternalClass_Name(TPasClassType(Param2Resolved.LoTypeEl),'Promise') then
exit(CheckRaiseTypeArgNo(20200520091707,2,Param,Param2Resolved, // await(T,aPromise)
else if IsJSBaseType(Param2Resolved,pbtJSValue) then
// await(T,jsvalue)
else if (Param2Resolved.IdentEl is TPasArgument)
and (Param2Resolved.LoTypeEl=nil) then
// await(T,UntypedArg)
else
exit(CheckRaiseTypeArgNo(20200520091708,2,Param,Param2Resolved,
'TJSPromise',RaiseOnError)); 'TJSPromise',RaiseOnError));
end; end;
Result:=CheckBuiltInMaxParamCount(Proc,Params,2,RaiseOnError,Signature2); Result:=CheckBuiltInMaxParamCount(Proc,Params,2,RaiseOnError,AwaitSignature2);
end; end;
end; end;
@ -6084,11 +6132,18 @@ begin
Param:=Params.Params[0]; Param:=Params.Params[0];
if length(Params.Params)=1 then if length(Params.Params)=1 then
begin begin
// await(expr) // await(AsyncFuncCall)
if CheckCallAsyncFuncResult(Param,ResolvedEl) then if CheckCallAsyncFuncResult(Param,ResolvedEl) then
begin
// await(CallAsynFuncResultT): T // await(CallAsynFuncResultT): T
if (ResolvedEl.BaseType=btContext)
and (ResolvedEl.LoTypeEl is TPasClassType)
and IsExternalClass_Name(TPasClassType(ResolvedEl.LoTypeEl),'Promise') then
// async function returns a promise, await resolve all promises -> need final type as first param
RaiseMsg(20201229235932,nWrongNumberOfParametersForCallTo,
sWrongNumberOfParametersForCallTo,[AwaitSignature2],Param);
exit; exit;
// await(expr:T):T end;
end end
else else
begin begin

View File

@ -883,8 +883,11 @@ type
Procedure TestAwait_NonPromiseWithTypeFail; Procedure TestAwait_NonPromiseWithTypeFail;
Procedure TestAwait_AsyncCallTypeMismatch; Procedure TestAwait_AsyncCallTypeMismatch;
Procedure TestAWait_OutsideAsyncFail; Procedure TestAWait_OutsideAsyncFail;
Procedure TestAWait_Result; Procedure TestAWait_IntegerFail;
Procedure TestAWait_ExternalClassPromise; Procedure TestAWait_ExternalClassPromise;
Procedure TestAWait_JSValue;
Procedure TestAWait_Result;
Procedure TestAWait_ResultPromiseMissingTypeFail;
Procedure TestAsync_AnonymousProc; Procedure TestAsync_AnonymousProc;
Procedure TestAsync_ProcType; Procedure TestAsync_ProcType;
Procedure TestAsync_ProcTypeAsyncModMismatchFail; Procedure TestAsync_ProcTypeAsyncModMismatchFail;
@ -32619,48 +32622,21 @@ begin
ConvertProgram; ConvertProgram;
end; end;
procedure TTestModule.TestAWait_Result; procedure TTestModule.TestAWait_IntegerFail;
begin begin
StartProgram(false); StartProgram(false);
Add([ Add([
'{$modeswitch externalclass}', 'function Run: word;',
'type',
' TJSPromise = class external name ''Promise''',
' end;',
'function Crawl(d: double = 1.3): word; ',
'begin', 'begin',
'end;', 'end;',
'function Run(d: double = 1.6): word; async;', 'procedure Fly(w: word); async;',
'begin', 'begin',
' Result:=await(1);', ' await(Run());',
' Result:=await(Crawl);',
' Result:=await(Crawl(4.5));',
' Result:=await(Run);',
' Result:=await(Run(6.7));',
'end;', 'end;',
'begin', 'begin',
' Run(1);']); ' Fly(1);']);
SetExpectedPasResolverError('async function expected, but Result:Word found',nXExpectedButYFound);
ConvertProgram; 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);'
]));
SetExpectedPasResolverError('Await without promise',nAwaitWithoutPromise);
end; end;
procedure TTestModule.TestAWait_ExternalClassPromise; procedure TTestModule.TestAWait_ExternalClassPromise;
@ -32723,6 +32699,110 @@ begin
CheckResolverUnexpectedHints(); CheckResolverUnexpectedHints();
end; end;
procedure TTestModule.TestAWait_JSValue;
begin
StartProgram(false);
Add([
'{$modeswitch externalclass}',
'type',
' TJSPromise = class external name ''Promise''',
' end;',
'function Fly(w: word): jsvalue; async;',
'begin',
'end;',
'function Run(d: jsvalue; var e): word; async;',
'begin',
' Result:=await(word,d);', // promise needs type
' d:=await(Fly(4));', // async non promise must omit the type
' Result:=await(word,e);', // promise needs type
'end;',
'begin',
'']);
ConvertProgram;
CheckSource('TestAWait_JSValue',
LinesToStr([ // statements
'this.Fly = async function (w) {',
' var Result = undefined;',
' return Result;',
'};',
'this.Run = async function (d, e) {',
' var Result = 0;',
' Result = await d;',
' d = await $mod.Fly(4);',
' Result = await e.get();',
' return Result;',
'};',
'']),
LinesToStr([
]));
CheckResolverUnexpectedHints();
end;
procedure TTestModule.TestAWait_Result;
begin
StartProgram(false);
Add([
'{$modeswitch externalclass}',
'type',
' TJSPromise = class external name ''Promise''',
' end;',
'function Crawl(d: double = 1.3): TJSPromise; ',
'begin',
'end;',
'function Run(d: double = 1.6): word; async;',
'begin',
' Result:=await(word,Crawl);',
' Result:=await(word,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 = null;',
' return Result;',
'};',
'this.Run = async function (d) {',
' var Result = 0;',
' 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);'
]));
CheckResolverUnexpectedHints();
end;
procedure TTestModule.TestAWait_ResultPromiseMissingTypeFail;
begin
StartProgram(false);
Add([
'{$mode objfpc}',
'{$modeswitch externalclass}',
'type',
' TJSPromise = class external name ''Promise''',
' end;',
'function Run: TJSPromise; async;',
'begin',
'end;',
'procedure Fly(w: word); async;',
'begin',
' await(Run());',
'end;',
'begin',
' Fly(1);']);
SetExpectedPasResolverError('Wrong number of parameters specified for call to "function await(aType,TJSPromise):aType"',
nWrongNumberOfParametersForCallTo);
ConvertProgram;
end;
procedure TTestModule.TestAsync_AnonymousProc; procedure TTestModule.TestAsync_AnonymousProc;
begin begin
StartProgram(false); StartProgram(false);

View File

@ -3060,9 +3060,9 @@ End.
Pas2js supports the JS operators async and await to simplify the use of Promise. Pas2js supports the JS operators async and await to simplify the use of Promise.
The await operator corresponds to three intrinsic Pas2js functions: The await operator corresponds to three intrinsic Pas2js functions:
<ul> <ul>
<li><i>function await(AsyncFunctionWithResultT): T;</i> // implicit promise</li> <li><i>function await(AsyncFunctionWithResultT()): T;</i> // implicit promise, the inner () can be omitted</li>
<li><i>function await(aType; p: TJSPromise): aType;</i> // explicit promise requires the resolved type</li> <li><i>function await(aType; p: TJSPromise): aType;</i> // explicit promise requires the resolved type</li>
<li><i>function await(const Expr: T): T;</i> // implicit promise</li> <li><i>function await(aType; j: jsvalue): aType;</i> // explicit promise requires the resolved type</li>
</ul> </ul>
The await function can only be used inside a procedure with the async modifier.<br> The await function can only be used inside a procedure with the async modifier.<br>
Example for the explicit promise: Example for the explicit promise: