* Parse async functions

This commit is contained in:
Michaël Van Canneyt 2021-09-05 14:10:12 +02:00
parent d1bbc99e48
commit a214682495
3 changed files with 58 additions and 13 deletions

View File

@ -24,8 +24,10 @@ uses
Const
SEmptyLabel = '';
MinAsyncVersion = ecma2021;
Type
TECMAVersion = jsScanner.TECMAVersion;
{ TJSParser }
@ -51,6 +53,7 @@ Type
procedure Expect(aToken: TJSToken);
procedure Consume(aToken: TJSToken; AllowSemicolonInsert : Boolean = False);
procedure FreeCurrentLabelSet;
function GetVersion: TECMAVersion;
procedure LeaveLabel;
function LookupLabel(ALabelName: String; Kind: TJSToken): TJSLabel;
function ParseAdditiveExpression: TJSElement;
@ -117,7 +120,8 @@ Type
Property NoIn : Boolean Read FNoIn Write FNoIn;
Property IsLHS : Boolean Read FIsLHS Write FIsLHS;
Public
Constructor Create(AInput: TStream);
Constructor Create(AInput: TStream; aVersion : TECMAVersion = ecma5);
// Scanner has version
Constructor Create(AScanner : TJSScanner);
Destructor Destroy; override;
Function Parse : TJSElement;
@ -127,6 +131,7 @@ Type
Function GetNextToken : TJSToken;
Function PeekNextToken : TJSToken;
Function IsEndOfLine : Boolean;
Property ECMAVersion : TECMAVersion Read GetVersion;
end;
implementation
@ -349,11 +354,11 @@ begin
Error(Format(Fmt,Args));
end;
Constructor TJSParser.Create(AInput: TStream);
Constructor TJSParser.Create(AInput: TStream; aVersion : TECMAVersion = ecma5);
begin
FInput:=AInput;
FCurrent:=TJSUnknown;
FScanner:=TJSScanner.Create(FInput);
FScanner:=TJSScanner.Create(FInput,aVersion);
FFreeScanner:=True;
end;
@ -1931,6 +1936,11 @@ begin
end;
end;
function TJSParser.GetVersion: TECMAVersion;
begin
Result:=FSCanner.ECMAVersion;
end;
function TJSParser.ParseExpressionStatement : TJSElement;
Var
@ -2034,21 +2044,27 @@ Var
E : TJSElement;
Done : Boolean;
VS : TJSElementNodes;
aSync : Boolean;
begin
{$ifdef debugparser} Writeln('>>> Entering source elements');{$endif}
Result:=TJSSourceElements(CreateElement(TJSSourceElements));
try
Done:=False;
aSync:=False;
VS:=FCurrentVars;
Try
FCurrentVars:=Result.Vars;
Repeat
{$ifdef debugparser} Writeln('Sourceelements start:',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
aSync:= (ECMAVersion>=MinAsyncVersion) and (CurrentToken=tjsIdentifier) and (CurrentTokenString='async');
if aSync then
GetNextToken;
If (CurrentToken=jstoken.tjsFunction) then
begin
If (PeekNextToken<>tjsBraceOpen) then
begin
F:=Self.ParseFunctionDeclaration;
F.AFunction.IsAsync:=aSync;
Result.Functions.AddNode.Node:=F;
end
else

View File

@ -113,8 +113,8 @@ Type
procedure Error(const Msg: string);overload;
procedure Error(const Msg: string; Args: array of Const);overload;
public
constructor Create(ALineReader: TLineReader; ECMAVersion : TECMAVersion = ecma5);
constructor Create(AStream : TStream; ECMAVersion : TECMAVersion = ecma5);
constructor Create(ALineReader: TLineReader; aECMAVersion : TECMAVersion = ecma5);
constructor Create(AStream : TStream; aECMAVersion : TECMAVersion = ecma5);
destructor Destroy; override;
procedure OpenFile(const AFilename: string);
Function FetchRegexprToken: TJSToken;
@ -162,18 +162,18 @@ begin
ReadLn(FTextFile, Result);
end;
constructor TJSScanner.Create(ALineReader: TLineReader; ECMAVersion: TECMAVersion);
constructor TJSScanner.Create(ALineReader: TLineReader; aECMAVersion: TECMAVersion);
begin
inherited Create;
FSourceFile := ALineReader;
FNonKeyWords:=NonJSKeywords[ECMAVersion];
ECMAVersion:=aECMAVersion;
end;
constructor TJSScanner.Create(AStream: TStream; ECMAVersion: TECMAVersion);
constructor TJSScanner.Create(AStream: TStream; aECMAVersion: TECMAVersion);
begin
FSourceStream:=ASTream;
FOwnSourceFile:=True;
Create(TStreamLineReader.Create(AStream));
Create(TStreamLineReader.Create(AStream),aECMAVersion);
end;
destructor TJSScanner.Destroy;

View File

@ -5,7 +5,7 @@ unit tcparser;
interface
uses
Classes, SysUtils, fpcunit, testregistry, jsParser, jstree, jsbase;
Classes, SysUtils, fpcunit, testregistry, jsParser, jstree, jsbase;
type
@ -20,7 +20,7 @@ type
protected
procedure SetUp; override;
procedure TearDown; override;
Procedure CreateParser(Const ASource : string);
Procedure CreateParser(Const ASource : string; aVersion : TECMAVersion = TECMAVersion.ecma5);
Procedure CheckClass(E : TJSElement; C : TJSElementClass);
Procedure AssertEquals(Const AMessage : String; Expected, Actual : TJSType); overload;
Procedure AssertIdentifier(Msg : String; El : TJSElement; Const AName : TJSString);
@ -106,6 +106,7 @@ type
procedure TestBlockEmptyStatement;
procedure TestBlockSimpleStatement;
procedure TestFunctionDeclarationEmpty;
procedure TestFunctionDeclarationAsync;
procedure TestFunctionDeclarationWithArgs;
procedure TestFunctionDeclarationWithBody;
procedure TestIfSimple;
@ -1691,6 +1692,7 @@ begin
CheckClass(N,TJSFunctionDeclarationStatement);
FD:=TJSFunctionDeclarationStatement(N);
AssertNotNull('Function definition assigned',FD.AFunction);
AssertFalse('Async function ',FD.AFunction.IsAsync);
AssertEquals('Function name OK','a',FD.AFunction.Name);
AssertNotNull('Function body assigned', FD.AFunction.Body);
AssertEquals('No parameters',0,FD.AFunction.Params.Count);
@ -1703,6 +1705,33 @@ begin
// TJSEmptyBlockStatement
end;
procedure TTestJSParser.TestFunctionDeclarationAsync;
Var
E : TJSSourceElements;
N : TJSElement;
FD : TJSFunctionDeclarationStatement;
begin
CreateParser('async function a () {}',MinAsyncVersion);
E:=GetSourceElements;
AssertEquals('1 function defined',1,E.functions.Count);
N:=E.Functions.Nodes[0].Node;
AssertNotNull('Function element defined ',N);
CheckClass(N,TJSFunctionDeclarationStatement);
FD:=TJSFunctionDeclarationStatement(N);
AssertNotNull('Function definition assigned',FD.AFunction);
AssertTrue('Async function ',FD.AFunction.IsAsync);
AssertEquals('Function name OK','a',FD.AFunction.Name);
AssertNotNull('Function body assigned', FD.AFunction.Body);
AssertEquals('No parameters',0,FD.AFunction.Params.Count);
N:=FD.AFunction.Body;
CheckClass(N,TJSFunctionBody);
AssertNotNull('Function body has element',TJSFunctionBody(N).A);
CheckClass(TJSFunctionBody(N).A, TJSSourceElements);
E:=TJSSourceElements(TJSFunctionBody(N).A);
AssertEquals('0 statement in functionbody elements',0,E.Statements.Count);
end;
procedure TTestJSParser.TestFunctionDeclarationWithArgs;
Var
@ -2521,10 +2550,10 @@ begin
FReeAndNil(FSource);
end;
Procedure TTestJSParser.CreateParser(Const ASource: string);
Procedure TTestJSParser.CreateParser(Const ASource: string; aVersion : TECMAVersion = TECMAVersion.ecma5);
begin
FSource:=TStringStream.Create(ASource);
FParser:=TJSParser.Create(FSource);
FParser:=TJSParser.Create(FSource,aVersion);
end;
Procedure TTestJSParser.CheckClass(E: TJSElement; C: TJSElementClass);