1{ *********************************************************************
2    This file is part of the Free Component Library (FCL)
3    Copyright (c) 2016 Michael Van Canneyt.
4
5    Javascript parser
6
7    See the file COPYING.FPC, included in this distribution,
8    for details about the copyright.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14  **********************************************************************}
15unit jsparser;
16
17{ $define debugparser}
18{$mode objfpc}{$H+}
19
20interface
21
22uses
23  Classes, SysUtils, jsscanner, jstree, jstoken;
24
25Const
26   SEmptyLabel = '';
27
28Type
29
30  { TJSParser }
31
32  TJSParser = Class(TObject)
33  Private
34    FFunctionDepth: Integer;
35    FInput : TStream;
36    FIsLHS: Boolean;
37    FNoIn: Boolean;
38    FScanner : TJSScanner;
39    FPrevious,
40    FCurrent : TJSToken;
41    FCurrentString : String;
42    FFreeScanner : Boolean;
43    FCurrentVars : TJSElementNodes;
44    FPeekToken: TJSToken;
45    FPeekTokenString: String;
46    FLabelSets,
47    FCurrentLabelSet:TJSLabelSet;
48    FLabels : TJSLabel;
49    function CheckSemiColonInsert(aToken: TJSToken; Consume: Boolean): Boolean;
50    function EnterLabel(ALabelName: String): TJSLabel;
51    procedure Expect(aToken: TJSToken);
52    procedure Consume(aToken: TJSToken; AllowSemicolonInsert : Boolean = False);
53    procedure FreeCurrentLabelSet;
54    procedure LeaveLabel;
55    function LookupLabel(ALabelName: String; Kind: TJSToken): TJSLabel;
56    function ParseAdditiveExpression: TJSElement;
57    function ParseArguments: TJSarguments;
58    function ParseArrayLiteral: TJSElement;
59    function ParseAssignmentExpression: TJSElement;
60    function ParseBitwiseAndExpression: TJSElement;
61    function ParseBitwiseORExpression: TJSElement;
62    function ParseBitwiseXORExpression: TJSElement;
63    function ParseBlock: TJSElement;
64    function ParseBreakStatement: TJSElement;
65    function ParseConditionalExpression: TJSElement;
66    function ParseContinueStatement: TJSElement;
67    function ParseEmptyStatement: TJSElement;
68    function ParseEqualityExpression: TJSElement;
69    function ParseExpression: TJSElement;
70    function ParseExpressionStatement: TJSElement;
71    function ParseFormalParameterList: TStrings;
72    function ParseFunctionDeclaration: TJSFunctionDeclarationStatement;
73    function ParseFunctionExpression: TJSFunctionDeclarationStatement;
74    function ParseFunctionStatement: TJSElement;
75    function ParseFunctionBody: TJSFunctionBody;
76    function ParseIdentifier: String;
77    function ParseIfStatement: TJSElement;
78    function ParseIterationStatement: TJSElement;
79    function ParseLabeledStatement: TJSElement;
80    function ParseLeftHandSideExpression: TJSElement;
81    function ParseLiteral: TJSElement;
82    function ParseLogicalAndExpression: TJSElement;
83    function ParseLogicalORExpression: TJSElement;
84    function ParseMemberExpression: TJSElement;
85    function ParseMultiplicativeExpression: TJSElement;
86    function ParseNumericLiteral: TJSElement;
87    function ParseObjectLiteral: TJSElement;
88    function ParsePostFixExpression: TJSElement;
89    function ParsePrimaryExpression: TJSElement;
90    function ParseRegularExpressionLiteral: TJSElement;
91    function ParseRelationalExpression: TJSElement;
92    function ParseReturnStatement: TJSElement;
93    function ParseShiftExpression: TJSElement;
94    function ParseStatement: TJSElement;
95    function ParseStatementList: TJSElement;
96    function ParseStringLiteral: TJSElement;
97    function ParseSwitchStatement: TJSElement;
98    function ParseThrowStatement: TJSElement;
99    function ParseTryStatement: TJSElement;
100    function ParseUnaryExpression: TJSElement;
101    function ParseVariableDeclaration: TJSElement;
102    function ParseVariableDeclarationList: TJSElement;
103    function ParseVariableStatement: TJSElement;
104    function ParseWithStatement: TJSElement;
105  Protected
106    Procedure CheckParser;
107    Function CurrentLabelSet : TJSLabelSet;
108    function CurSource: String;
109    Function CurLine : Integer;
110    Function CurPos : Integer;
111    Function CreateElement(AElementClass : TJSElementClass)  : TJSElement;
112    Procedure Error(Msg : String);
113    Procedure Error(Fmt : String; Args : Array of const);
114    // Parse functions
115    function ParseSourceElements: TJSSourceElements;
116    Property FunctionDepth : Integer Read FFunctionDepth Write FFunctionDepth;
117    Property NoIn : Boolean Read FNoIn Write FNoIn;
118    Property IsLHS : Boolean Read FIsLHS Write FIsLHS;
119  Public
120    Constructor Create(AInput: TStream);
121    Constructor Create(AScanner : TJSScanner);
122    Destructor Destroy; override;
123    Function Parse : TJSElement;
124    Function ParseProgram : TJSFunctionDeclarationStatement;
125    Function CurrentToken : TJSToken;
126    Function CurrentTokenString : String;
127    Function GetNextToken : TJSToken;
128    Function PeekNextToken : TJSToken;
129    Function IsEndOfLine : Boolean;
130  end;
131
132implementation
133
134uses typinfo;
135
136Resourcestring
137  SErrUnmatchedCurlyBrace    = 'Unmatched }';
138  SErrUnmatchedSquareBrace   = 'Unmatched ]';
139  SErrUnmatchedBrace         = 'Unmatched )';
140  SErrUnexpectedToken        = 'Unexpected token: ''%s''';
141  SErrTokenMismatch          = 'Unexpected token: ''%s'', expected: ''%s''';
142  SErrSemicolonOrInExpected  = 'Unexpected token: ''%s'', expected ; or ''in''';
143  SErrSemicolonExpected      = 'Unexpected token: ''%s'', expected ;';
144  SErrDuplicateLabelName     = 'Duplicate label name: ''%s''';
145  SErrLabelNotContinuable    = 'Label ''%s'' is not suitable for continue.';
146  SErrLabelNOtDefinedOrReachable = 'Label ''%s'' is not defined or not reachable.';
147  SErrContinueNotInLoop      = 'Continue statement not in loop';
148  SErrBreakNotInLoop         = 'Break statement not in loop';
149  SErrReturnNotInFunction    = 'return statement not in a function body';
150  SErrCaseEndExpected        = 'Unexpected token: Expected }, case or default clause';
151  SErrDuplicateSwitchDefault = 'Duplicate default clause for switch statement';
152  SErrNewlineAfterThrow      = 'Newline after throw not allowed';
153  SErrCatchFinallyExpected   = 'Unexpected token: Expected ''catch'' or ''finally''';
154  SErrArgumentsExpected      = 'Unexpected token: Expected '','' or '')'', got %s';
155  SErrArrayEnd               = 'Unexpected token: Expected '','' or '']'', got %s';
156  //SErrObjectEnd              = 'Unexpected token: Expected '','' or ''}'', got %s';
157  SErrObjectElement          = 'Unexpected token: Expected string, identifier or number after '','' got: %s';
158  SErrLiteralExpected        = 'Unexpected token: Expected: null, true, false, number, string, or regex, got: %s';
159  SErrInvalidnumber          = 'Invalid numerical value: %s';
160  SErrInvalidRegularExpression = 'Invalid regular expression: %s';
161  SErrFunctionNotAllowedHere = 'function keyword not allowed here';
162
163{ TJSScanner }
164
165Function TJSParser.CurrentToken: TJSToken;
166
167begin
168  Result:=FCurrent;
169end;
170
171Function TJSParser.CurrentTokenString: String;
172begin
173  Result:=FCurrentString;
174end;
175
176Function TJSParser.GetNextToken: TJSToken;
177begin
178  FPrevious:=FCurrent;
179  If (FPeekToken<>tjsunknown) then
180     begin
181     FCurrent:=FPeekToken;
182     FCurrentString:=FPeekTokenString;
183     FPeekToken:=tjsUnknown;
184     FPeekTokenString:='';
185     end
186  else
187    begin
188    FCurrent:=FScanner.FetchToken;
189    FCurrentString:=FScanner.CurTokenString;
190    end;
191  Result:=FCurrent;
192  {$ifdef debugparser}Writeln('GetNextToken (',FScanner.CurLine,',',FScanner.CurColumn,'): ',GetEnumName(TypeInfo(TJSToken),Ord(FCurrent)), ' As string: ',FCurrentString);{$endif debugparser}
193end;
194
195Function TJSParser.PeekNextToken: TJSToken;
196begin
197  If (FPeekToken=tjsUnknown) then
198    begin
199    FPeekToken:=FScanner.FetchToken;
200    FPeekTokenString:=FScanner.CurTokenString;
201    end;
202  {$ifdef debugparser}Writeln('PeekNextToken : ',GetEnumName(TypeInfo(TJSToken),Ord(FPeekToken)), ' As string: ',FPeekTokenString);{$endif debugparser}
203  Result:=FPeekToken;
204end;
205
206Function TJSParser.IsEndOfLine: Boolean;
207begin
208  Result:=FScanner.IsEndOfLine;
209end;
210
211
212Function TJSParser.CurPos: Integer;
213begin
214  If Assigned(FScanner) then
215    Result:=FScanner.CurColumn
216  else
217    Result:=0;
218end;
219
220Function TJSParser.CurLine: Integer;
221begin
222  If Assigned(FScanner) then
223    Result:=FScanner.CurRow
224  else
225    Result:=0;
226end;
227
228function TJSParser.CurSource: String;
229begin
230  If Assigned(FScanner) then
231    Result:=FScanner.CurFileName
232  else
233    Result:='';
234end;
235
236Procedure TJSParser.CheckParser;
237begin
238
239end;
240
241procedure TJSParser.LeaveLabel;
242
243Var
244  L : TJSLabel;
245
246begin
247  L:=FLabels;
248  FLabels:=FLabels.Next;
249  L.Free; // ??
250end;
251
252function TJSParser.LookupLabel(ALabelName : String; Kind : TJSToken) :TJSLabel;
253
254Var
255  L : TJSLabel;
256
257begin
258  L:=FLabels;
259  Result:=Nil;
260  While (L<>Nil) and (Result=Nil) do
261    begin
262    If (L.Name=ALabelName) then
263      begin
264      if (kind=tjsContinue) and (Not L.LabelSet.Continuable) and (ALabelName<>SEmptyLabel) then
265        Error(SErrLabelNotContinuable,[ALabelName]);
266      Result:=L;
267      end;
268    L:=L.Next;
269    end;
270  If (Result=Nil) then
271    begin
272    If (ALabelName<>'') then
273      Error(SErrLabelNOtDefinedOrReachable,[ALabelName])
274    else if kind=tjsCOntinue then
275      Error(SErrContinueNotInLoop)
276    else
277      Error(SErrBreakNotInLoop);
278    end;
279end;
280
281function TJSParser.EnterLabel(ALabelName : String) :TJSLabel;
282
283Var
284  L : TJSLabel;
285
286begin
287  If (ALAbelName<>SEmptyLabel) then
288    begin
289    L:=FLabels;
290    While (L<>Nil) do
291      begin
292      If (L.Name=ALabelName) then
293        Error(SErrDuplicateLabelName,[ALabelName]);
294      L:=L.Next;
295      end;
296    end;
297  L:=TJSLabel.Create;
298  L.Name:=ALabelName;
299  L.LabelSet:=CurrentLabelSet;
300  L.LocationSource:=Self.CurSource;
301  L.LocationLine:=CurLine;
302  L.LocationPos:=CurPos;
303  L.Next:=FLabels;
304  FLabels:=L;
305  Result:=L;
306end;
307
308Function TJSParser.CurrentLabelSet: TJSLabelSet;
309
310Var
311  LS : TJSLabelSet;
312
313begin
314  If (FCurrentLabelSet=Nil) then
315    begin
316    LS:=TJSLabelSet.Create;
317    If (FLabelSets=Nil) then
318      LS.Target:=1
319    else
320      LS.Target:=FLabelSets.Target;
321    LS.Next:=FLabelSets;
322    FLabelSets:=LS;
323    FCurrentLabelSet:=LS;
324    end;
325  Result:=FCurrentLabelSet;
326end;
327
328Function TJSParser.CreateElement(AElementClass: TJSElementClass): TJSElement;
329begin
330  Result:=AElementClass.Create(CurLine,CurPos,CurSource);
331end;
332
333Procedure TJSParser.Error(Msg: String);
334
335Var
336  ErrAt : String;
337
338begin
339  If Assigned(FScanner) then
340    If FScanner.CurFilename<>'' then
341      ErrAt:=Format('Error: file "%s" line %d, pos %d: ',[FScanner.CurFileName,FScanner.CurRow,FScanner.CurColumn])
342    else
343      ErrAt:=Format('Error: line %d, pos %d: ',[FScanner.Currow,FScanner.CurColumn]);
344  Raise Exception.Create(ErrAt+Msg)
345end;
346
347Procedure TJSParser.Error(Fmt: String; Args: Array of const);
348begin
349  Error(Format(Fmt,Args));
350end;
351
352Constructor TJSParser.Create(AInput: TStream);
353begin
354  FInput:=AInput;
355  FCurrent:=TJSUnknown;
356  FScanner:=TJSScanner.Create(FInput);
357  FFreeScanner:=True;
358end;
359
360Constructor TJSParser.Create(AScanner: TJSScanner);
361begin
362  FCurrent:=TJSUnknown;
363  FScanner:=AScanner;
364  FFreeScanner:=False;
365end;
366
367Destructor TJSParser.Destroy;
368begin
369  if FFreeScanner then
370    FreeAndNil(FScanner);
371  inherited;
372end;
373
374
375
376procedure TJSParser.Expect(aToken: TJSToken);
377
378begin
379  {$ifdef debugparser}  Writeln('Expecting : ',GetEnumName(TypeInfo(TJSToken),Ord(AToken)), ' As string: ',TokenInfos[AToken]);{$endif debugparser}
380  If Not CheckSemiColonInsert(AToken,False) then
381    if (CurrentToken<>aToken) then
382      Error(SerrTokenMismatch,[CurrenttokenString,TokenInfos[aToken]]);
383end;
384
385function TJSParser.CheckSemiColonInsert(aToken : TJSToken; Consume : Boolean) : Boolean;
386
387begin
388  Result:=(AToken=tjsSemiColon);
389  If Result then
390    begin
391    Result:=(CurrentToken=tjsCurlyBraceClose) or (FScanner.WasEndOfLine) or (CurrentToken=tjsEOF);
392    If Result and Consume then
393      FPrevious:=tjsSemiColon;
394    end;
395end;
396
397procedure TJSParser.Consume(aToken: TJSToken; AllowSemicolonInsert: Boolean);
398begin
399  {$ifdef debugparser}  Writeln('Consuming : ',GetEnumName(TypeInfo(TJSToken),Ord(AToken)), ' As string: ',TokenInfos[AToken]);{$endif debugparser}
400  Expect(aToken);
401  If not (AllowSemiColonInsert and CheckSemiColonInsert(aToken,True)) then
402    GetNextToken;
403end;
404
405function TJSParser.ParseIdentifier : String;
406
407begin
408  Result:='';
409  Repeat
410    Expect(tjsIdentifier);
411    Result:=Result+CurrentTokenString;
412    GetNextToken;
413    If (CurrentToken=tjsDot) then
414      begin
415      If (Result<>'') then
416         Result:=Result+'.';
417      GetNextToken;
418      end;
419  until (CurrentToken<>tjsIdentifier);
420end;
421
422function TJSParser.ParseFormalParameterList : TStrings;
423
424begin
425  Result:=Nil;
426  While (CurrentToken=tjsIdentifier) do
427    begin
428    Expect(tjsIdentifier);
429    If (Result=Nil) then
430      Result:=TstringList.Create;
431    Result.Add(CurrentTokenString);
432    GetNextToken;
433    If (CurrentToken=tjsComma) then
434       GetNextToken;
435    end;
436end;
437
438
439function TJSParser.ParseFunctionDeclaration : TJSFunctionDeclarationStatement;
440
441Var
442  Id : String;
443  D : TJSFuncDef;
444  args : TStrings;
445  body : TJSFunctionBody;
446
447begin
448  {$ifdef debugparser}  Writeln('>>> Entering ParseFunctionDeclaration');{$endif debugparser}
449  Consume(tjsFunction);
450  ID:=ParseIdentifier;
451  Consume(tjsBraceOpen);
452  Args:=ParseFormalParameterList;
453  try
454    Consume(tjsBraceClose);
455    Consume(tjsCurlyBraceOpen);
456    Inc(FFunctionDepth);
457    try
458      Body:=ParseFunctionBody;
459      try
460        // GetNextToken; not sure
461        Consume(tjsCurlyBraceClose);
462        D:=TJSFuncDef.Create;
463        try
464          D.Name:=ID;
465          If Assigned(Args)then
466            D.Params.Assign(Args);
467          D.Body:=Body;
468          Result:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
469          Result.AFunction:=D;
470        except
471          FreeAndNil(D);
472          Raise;
473        end;
474      except
475        FreeAndNil(Body);
476        Raise;
477      end;
478    finally
479      Dec(FFunctionDepth);
480    end;
481  finally
482    FreeAndNil(Args);
483  end;
484  {$ifdef debugparser}  Writeln('>>> Exiting ParseFunctionDeclaration');{$endif debugparser}
485end;
486
487function TJSParser.ParseStatementList : TJSElement;
488
489Var
490  E : TJSElement;
491  SL : TJSSTatementList;
492
493begin
494  {$ifdef debugparser}  Writeln('>>> ParseStatementList');{$endif debugparser}
495  E:=ParseStatement;
496  try
497    if (CurrentToken in [tjsCurlyBraceClose,tjsEof,tjsCase,tjsDefault]) then
498      Result:=E
499    else
500      begin
501      SL:=TJSSTatementList(CreateElement(TJSStatementList));
502      try
503        SL.A:=E;
504        SL.B:=ParseStatementlist();
505        Result:=SL;
506      except
507        FreeAndNil(SL);
508        Raise;
509      end;
510      end;
511  except
512    FreeAndNil(E);
513    Raise;
514  end;
515  {$ifdef debugparser}  Writeln('<<< ParseStatementList');{$endif debugparser}
516end;
517
518function TJSParser.ParseBlock : TJSElement;
519
520begin
521  {$ifdef debugparser}  Writeln('>>> ParseBlock');{$endif debugparser}
522  Consume(tjsCurlyBraceOpen);
523  If (CurrentToken=tjsCurlyBraceClose) then
524    Result:=CreateElement(TJSEmptyBlockStatement)
525  else
526    result:=ParseStatementList;
527  Consume(tjsCurlyBraceClose);
528  {$ifdef debugparser}  Writeln('<<< ParseBlock');{$endif debugparser}
529end;
530
531function TJSParser.ParseArrayLiteral: TJSElement;
532
533Var
534  N : TJSArrayLiteral;
535  E : TJSArrayLiteralElement;
536  I : Integer;
537
538begin
539  Consume(tjsSquaredBraceOpen);
540  N:=TJSArrayLiteral(CreateElement(TJSArrayLiteral));
541  Result:=N;
542  try
543    I:=0;
544    While (CurrentToken<>tjsSquaredBraceClose) do
545      begin
546      If (CurrentToken=tjsComma) then
547         begin
548         GetNextToken;
549         Inc(I);
550         end
551      else
552         begin
553         E:=N.Elements.AddElement;
554         E.ElementIndex:=I;
555         Inc(I);
556         E.Expr:=ParseAssignmentExpression;
557         If Not (CurrentToken in [tjsComma,tjsSquaredBraceClose]) then
558           Error(SErrArrayEnd,[CurrentTokenString])
559         end;
560      end;
561    Consume(tjsSquaredBraceClose);
562  except
563    FreeAndNil(Result);
564    Raise;
565  end;
566end;
567
568function TJSParser.ParseObjectLiteral: TJSElement;
569
570Var
571  N : TJSObjectLiteral;
572  E : TJSObjectLiteralElement;
573begin
574  Consume(tjsCurlyBraceOpen);
575  N:=TJSObjectLiteral(CreateElement(TJSObjectLiteral));
576  Result:=N;
577  try
578    While (CurrentToken<>tjsCurlyBraceClose) do
579      begin
580      While CurrentToken=tjsComma do
581         GetNextToken;
582      If (CurrentToken in [tjsIdentifier,jstoken.tjsString,tjsnumber]) then
583         begin
584         E:=N.Elements.AddElement;
585         E.Name:=CurrenttokenString;
586         GetNextToken;
587         end
588      else
589         Error(SErrObjectElement,[CurrentTokenString]);
590      Consume(tjsColon);
591      E.Expr:=ParseAssignmentExpression;
592      While CurrentToken=tjsComma do
593         GetNextToken;
594{      If Not (CurrentToken in [tjsComma,tjsCurlyBraceClose]) then
595        Error(SErrObjectEnd,[CurrentTokenString])}
596      end;
597    Consume(tjsCurlyBraceClose);
598  except
599    FreeAndNil(Result);
600    Raise;
601  end;
602end;
603
604function TJSParser.ParseNumericLiteral: TJSElement;
605
606Var
607  L : TJSLiteral;
608  D : Double;
609  I : Integer;
610
611begin
612  {$ifdef debugparser}  Writeln('Parsing numerical literal');{$endif debugparser}
613  Result:=Nil;
614  try
615    Val(CurrentTokenString,D,I);
616    If (I>0) then
617      Error(SErrInvalidnumber,[CurrentTokenString]);
618    L:=TJSLiteral(CreateElement(TJSLiteral));
619    GetNextToken;
620    L.Value.AsNumber:=D;
621    Result:=L;
622  except
623    FreeAndNil(Result);
624    Raise;
625  end;
626end;
627
628function TJSParser.ParseStringLiteral: TJSElement;
629
630Var
631  L : TJSLiteral;
632begin
633    {$ifdef debugparser} Writeln('Parsing string literal');{$endif debugparser}
634  Result:=Nil;
635  try
636    L:=TJSLiteral(CreateElement(TJSLiteral));
637    L.Value.AsString:=CurrentTokenString;
638    GetNextToken;
639    Result:=L;
640  except
641    FreeAndNil(Result);
642    Raise;
643  end;
644end;
645
646function TJSParser.ParseRegularExpressionLiteral: TJSElement;
647
648Var
649  S,pa,fl : String;
650  P : integer;
651  R : TJSRegularExpressionLiteral;
652begin
653  Result:=Nil;
654  If (CurrentToken=tjsRegex) then
655    begin
656    S:=CurrentTokenString;
657    P:=Length(S);
658    While (P>=1) and (S[P]<>'/') do
659      Dec(P);
660    If (P<=1) then
661      Error(SErrInvalidRegularExpression,[CurrentTokenString]);
662    pa:=Copy(S,2,P-1);
663    fl:=Copy(S,P,Length(S)-P+1);
664    R:=TJSRegularExpressionLiteral(CreateElement(TJSRegularExpressionLiteral));
665    Result:=R;
666    R.Pattern.AsString:=Pa;
667    R.PatternFlags.AsString:=Fl;
668    R.Argv[0]:=R.Pattern;
669    R.Argv[1]:=R.PatternFlags;
670    end;
671  try
672    Consume(tjsRegEx);
673  except
674    FreeAndNil(Result);
675    Raise;
676  end;
677end;
678
679function TJSParser.ParseLiteral: TJSElement;
680
681Var
682  L : TJSLiteral;
683
684begin
685  {$ifdef debugparser}Writeln('Parsing literal: ',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
686  Result:=Nil;
687  Case CurrentToken of
688    tjsNull : begin
689              L:=TJSLiteral(CreateElement(TJSLiteral));
690              Result:=L;
691              L.Value.IsNull:=True;
692              GetNextToken;
693              end;
694    tjsTrue,
695    tjsFalse: begin
696              L:=TJSLiteral(CreateElement(TJSLiteral));
697              Result:=L;
698              L.Value.AsBoolean:=(CurrentToken=tjsTrue);
699              GetNextToken;
700              end;
701    tjsNumber : Result:=ParseNumericLiteral;
702    jstoken.tjsString : Result:=ParseStringLiteral;
703    tjsDiv,
704    tjsDivEq : Result:=ParseRegularExpressionLiteral
705  else
706    Error(SErrLiteralExpected,[CurrentTokenString]);
707  end;
708end;
709
710function TJSParser.ParsePrimaryExpression: TJSElement;
711
712Var
713  R : TJSPrimaryExpressionIdent;
714
715begin
716  {$ifdef debugparser}  Writeln('ParsePrimaryExpression');{$endif debugparser}
717  Result:=Nil;
718  try
719    Case CurrentToken of
720      tjsThis :
721        begin
722        Result:=TJSPrimaryExpressionThis(CreateElement(TJSPrimaryExpressionThis));
723        GetNextToken;
724        end;
725      tjsidentifier:
726        begin
727        R:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent));
728        Result:=R;
729        R.Name:=CurrentTokenString;
730        GetNextToken;
731        end;
732      tjsSquaredBraceOpen: Result:=ParseArrayLiteral;
733      tjsCurlyBraceOpen: Result:=ParseObjectLiteral;
734      tjsBraceOpen:
735        begin
736        Consume(tjsBraceOpen);
737        Result:=ParseExpression;
738        Consume(tjsBraceClose);
739        end;
740    else
741      Result:=ParseLiteral;
742    end; // Case;
743  except
744    FreeAndNil(Result);
745    Raise;
746  end;
747  {$ifdef debugparser}  Writeln('Exit ParsePrimaryExpression');{$endif debugparser}
748end;
749
750
751function TJSParser.ParseMemberExpression: TJSElement;
752
753Var
754  M  : TJSDotMemberExpression;
755  N  : TJSNewMemberExpression;
756  B  : TJSBracketMemberExpression;
757  Done : Boolean;
758
759begin
760  {$ifdef debugparser}  Writeln('ParseMemberExpression');{$endif debugparser}
761  Case CurrentToken of
762    tjsFunction : Result:=ParseFunctionExpression();
763    tjsNew      : begin
764                  GetNextToken;
765                  N:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression));
766                  try
767                    Result:=N;
768                    N.MExpr:=ParseMemberExpression();
769                    if (CurrentToken=tjsBraceOpen) then
770                      N.Args:=ParseArguments;
771                  except
772                    FreeAndNil(N);
773                    Raise;
774                  end;
775                  end;
776  else
777    Result:=ParsePrimaryExpression()
778  end;
779  try
780    Done:=False;
781    Repeat
782      Case CurrentToken of
783       tjsDot :
784         begin
785         M:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression));
786         M.MExpr:=Result;
787         Result:=M;
788         GetNextToken;
789         If (CurrentToken=tjsIdentifier) then
790           M.Name:=CurrentTokenString;
791         Consume(tjsIdentifier);
792         end;
793       tjsSquaredBraceOpen:
794         begin
795         B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression));
796         B.MExpr:=Result;
797         Result:=B;
798         GetNextToken;
799         B.Name:=ParseExpression();
800         Consume(tjsSquaredBraceClose);
801         end;
802      else
803        Done:=True;
804        isLHS:=True;
805      end;
806    Until Done;
807  except
808    FreeAndNil(Result);
809    Raise;
810  end;
811  {$ifdef debugparser}  Writeln('Exit ParseMemberExpression');{$endif debugparser}
812end;
813
814function TJSParser.ParseArguments: TJSarguments;
815
816Var
817  E : TJSArrayLiteralElement;
818
819begin
820  Consume(tjsBraceOpen);
821  Result:=TJSArguments(CreateElement(TJSArguments));
822  try
823    While (CurrentToken<>tjsBraceClose) do
824      begin
825      E:=Result.Elements.AddElement;
826      E.Expr:=ParseAssignmentExpression;
827      If (CurrentToken<>tjsBraceClose) then
828        If CurrentToken=tjsComma then
829          GetNextToken
830        else
831          Error(SErrArgumentsExpected,[CurrentTokenString]);
832      end;
833    Consume(tjsBraceClose);
834  except
835    FreeAndNil(Result);
836    Raise;
837  end;
838end;
839
840function TJSParser.ParseLeftHandSideExpression: TJSElement;
841
842Var
843  M  : TJSDotMemberExpression;
844  B  : TJSBracketMemberExpression;
845  C : TJSCallExpression;
846  Done : Boolean;
847
848begin
849  {$ifdef debugparser}  Writeln('ParseLeftHandSideExpression');{$endif debugparser}
850  Case CurrentToken of
851    tjsFunction : Result:=ParseFunctionExpression;
852    tjsNew      : Result:=ParseMemberExpression;
853  else
854    Result:=ParsePrimaryExpression
855  end;
856  try
857    Done:=False;
858    Repeat
859      Case CurrentToken of
860       tjsDot :
861         begin
862         M:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression));
863         M.MExpr:=Result;
864         Result:=M;
865         GetNextToken;
866         If (CurrentToken=tjsIdentifier) then
867           M.Name:=CurrentTokenString;
868         Consume(tjsIdentifier);
869         end;
870       tjsSquaredBraceOpen:
871         begin
872         B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression));
873         B.MExpr:=Result;
874         Result:=B;
875         GetNextToken;
876         B.Name:=ParseExpression;
877         Consume(tjsSquaredBraceClose);
878         end;
879       tjsBraceOpen:
880         begin
881         C:=TJSCallExpression(CreateElement(TJSCallExpression));
882         C.Expr:=Result;
883         Result:=C;
884         C.Args:=ParseArguments;
885         end;
886      else
887        {$ifdef debugparser}Writeln('Leaving LHS');{$endif debugparser}
888        Done:=True;
889        isLHS:=True;
890      end;
891    Until Done;
892  except
893    FreeAndNil(Result);
894    Raise;
895  end;
896  {$ifdef debugparser}  Writeln('Exit ParseLeftHandSideExpression');{$endif debugparser}
897end;
898
899function TJSParser.ParsePostFixExpression: TJSElement;
900Var
901  R : TJSUnaryExpression;
902
903begin
904  {$ifdef debugparser}  Writeln('ParsePostfixExpression');{$endif debugparser}
905  Result:=ParseLeftHandSideExpression;
906  Try
907  If (Not IsEndOfLine) and (CurrentToken in [tjsPlusPlus,tjsMinusMinus]) then
908    begin
909    If (CurrentToken=tjsPlusPLus) then
910      R:=TJSUnaryExpression(CreateElement(TJSUnaryPostPlusPlusExpression))
911    else
912      R:=TJSUnaryExpression(CreateElement(TJSUnaryPostMinusMinusExpression));
913    R.A:=Result;
914    Result:=R;
915    GetNextToken;
916    isLHS:=False;
917    end;
918  except
919    freeAndNil(Result);
920    Raise;
921  end;
922  {$ifdef debugparser}  Writeln('Exit ParsePostfixExpression');{$endif debugparser}
923end;
924
925function TJSParser.ParseUnaryExpression: TJSElement;
926
927Var
928  C : TJSElementClass;
929  R : TJSUnaryExpression;
930
931begin
932  {$ifdef debugparser} Writeln('ParseUnaryExpression');{$endif debugparser}
933  C:=Nil;
934  Result:=Nil;
935  try
936    Case CurrentToken of
937      tjsDelete     : C:=TJSUnaryDeleteExpression;
938      tjsVoid       : C:=TJSUnaryVoidExpression;
939      tjsTypeOf     : C:=TJSUnaryTypeOfExpression;
940      tjsPlusPlus   : C:=TJSUnaryPrePlusPlusExpression;
941      tjsMinusMinus : C:=TJSUnaryPreMinusMinusExpression;
942      tjsPlus       : C:=TJSUnaryPlusExpression;
943      tjsMinus      : C:=TJSUnaryMinusExpression;
944      tjsInv        : C:=TJSUnaryInvExpression;
945      tjsNot        : C:=TJSUnaryNotExpression;
946    else
947      Result:=ParsePostFixExpression;
948    end;
949    If (Result=Nil) then
950      begin
951      {$ifdef debugparser} Writeln('Found Unary Expression',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
952      R:=TJSUnaryExpression(CreateElement(C));
953      Result:=R;
954      GetNextToken;
955      R.A:=ParseUnaryExpression();
956      isLHS:=False;
957      end;
958  except
959    FreeAndNil(Result);
960    Raise;
961  end;
962  {$ifdef debugparser} Writeln('Exit ParseUnaryExpression');{$endif debugparser}
963end;
964
965function TJSParser.ParseMultiplicativeExpression: TJSElement;
966
967Var
968  C : TJSElementClass;
969  R : TJSMultiplicativeExpression;
970
971begin
972  {$ifdef debugparser}  Writeln('ParseMultiplicativeExpression');{$endif debugparser}
973  Result:=ParseUnaryExpression;
974  try
975    While (CurrentToken in [tjsMul,tjsDiv,tjsMod]) do
976      begin
977      if CurrentToken=tjsMul then
978        C:=TJSMultiplicativeExpressionMul
979      else if CurrentToken=tjsDiv then
980        C:=TJSMultiplicativeExpressionDiv
981      else
982        C:=TJSMultiplicativeExpressionMod;
983      R:=TJSMultiplicativeExpression(CreateElement(C));
984      GetNextToken;
985      R.A:=Result;
986      Result:=R;
987      R.B:=ParseUnaryExpression;
988      isLHS:=False;
989      end;
990  except
991    FreeAndNil(Result);
992    Raise;
993  end;
994  {$ifdef debugparser}  Writeln('Exit ParseMultiplicativeExpression');{$endif debugparser}
995end;
996
997function TJSParser.ParseAdditiveExpression: TJSElement;
998
999Var
1000  C : TJSElementClass;
1001  R : TJSAdditiveExpression;
1002
1003begin
1004  {$ifdef debugparser}  Writeln('ParseAdditiveExpression');{$endif debugparser}
1005  Result:=ParseMultiplicativeExpression;
1006  try
1007    While (CurrentToken in [tjsPlus,tjsMinus]) do
1008      begin
1009      if CurrentToken=tjsPlus then
1010        C:=TJSAdditiveExpressionPlus
1011      else
1012        C:=TJSAdditiveExpressionMinus;
1013      R:=TJSAdditiveExpression(CreateElement(C));
1014      GetNextToken;
1015      R.A:=Result;
1016      Result:=R;
1017      R.B:=ParseMultiplicativeExpression;
1018      isLHS:=False;
1019      end;
1020  except
1021    FreeAndNil(Result);
1022    Raise;
1023  end;
1024  {$ifdef debugparser}  Writeln('Exit ParseAdditiveExpression');{$endif debugparser}
1025end;
1026
1027function TJSParser.ParseShiftExpression: TJSElement;
1028
1029Var
1030  C : TJSElementClass;
1031  R : TJSShiftExpression;
1032
1033begin
1034  {$ifdef debugparser}  Writeln('ParseShiftExpression');{$endif debugparser}
1035  Result:=ParseAdditiveExpression;
1036  try
1037    While (CurrentToken in [tjsLshift,tjsRshift,tjsURShift]) do
1038      begin
1039      Case CurrentToken of
1040        tjsLshift : C:=TJSLShiftExpression;
1041        tjsRshift : C:=TJSRShiftExpression;
1042        tjsURshift : C:=TJSURShiftExpression;
1043      end;
1044      R:=TJSShiftExpression(CreateElement(C));
1045      R.A:=Result;
1046      Result:=R;
1047      GetNextToken;
1048      R.B:=ParseAdditiveExpression;
1049      IsLHS:=False;
1050      end;
1051  except
1052    FreeAndNil(Result);
1053    Raise;
1054  end;
1055  {$ifdef debugparser}  Writeln('Exit ParseShiftExpression');{$endif debugparser}
1056end;
1057
1058function TJSParser.ParseRelationalExpression: TJSElement;
1059
1060Var
1061  S : Set of TJSToken;
1062  C : TJSElementClass;
1063  R : TJSRelationalExpression;
1064
1065begin
1066  {$ifdef debugparser}  Writeln('ParseRelationalExpression');{$endif debugparser}
1067  Result:=ParseShiftExpression;
1068  try
1069    S:=[tjsLT,tjsGT,tjsLE,tjsGE,tjsInstanceOf];
1070    If Not Noin then
1071      Include(S,tjsIn);
1072    While (CurrentToken in S) do
1073      begin
1074      Case CurrentToken of
1075        tjsLT : C:=TJSRelationalExpressionLT;
1076        tjsGT : C:=TJSRelationalExpressionGT;
1077        tjsLE : C:=TJSRelationalExpressionLE;
1078        tjsGE : C:=TJSRelationalExpressionGE;
1079        tjsInstanceOf :C:=TJSRelationalExpressionInstanceOf;
1080        tjsIn : C:=TJSRelationalExpressionIn;
1081      end;
1082      R:=TJSRelationalExpression(CreateElement(C));
1083      R.A:=Result;
1084      Result:=R;
1085      GetNextToken;
1086      R.B:=ParseRelationalExpression();
1087      IsLHS:=False;
1088      end;
1089  except
1090    FreeAndNil(Result);
1091    Raise;
1092  end;
1093  {$ifdef debugparser}  Writeln('Exit ParseRelationalExpression');{$endif debugparser}
1094end;
1095
1096function TJSParser.ParseEqualityExpression: TJSElement;
1097
1098Var
1099  C : TJSElementClass;
1100  E : TJSEqualityExpression;
1101
1102begin
1103  {$ifdef debugparser}  Writeln('ParseEqualityExpression');{$endif debugparser}
1104  Result:=ParseRelationalExpression;
1105  try
1106     While (CurrentToken in [tjsEq,tjsNE,tjsSEQ,tjsSNE]) do
1107       begin
1108       Case CurrentToken of
1109         tjsEq : C:=TJSEqualityExpressionEQ;
1110         tjsNE : C:=TJSEqualityExpressionNE;
1111         tjsSEQ : C:=TJSEqualityExpressionSEQ;
1112         tjsSNE : C:=TJSEqualityExpressionSNE;
1113       end;
1114       GetNextToken;
1115       E:=TJSEqualityExpression(CreateElement(C));
1116       Result:=E;
1117       E.A:=Result;
1118       E.B:=ParseEqualityExpression();
1119       E:=Nil;
1120       IsLHS:=False;
1121       end;
1122  except
1123    FreeAndNil(Result);
1124    Raise;
1125  end;
1126  {$ifdef debugparser}  Writeln('Exit ParseEqualityExpression');{$endif debugparser}
1127end;
1128
1129function TJSParser.ParseBitwiseAndExpression: TJSElement;
1130
1131Var
1132  L : TJSBitwiseAndExpression;
1133
1134begin
1135  {$ifdef debugparser}  Writeln('ParseBitwiseAndExpression');{$endif debugparser}
1136  Result:=ParseEqualityExpression;
1137  try
1138    If (CurrentToken<>tjsAnd) then
1139      exit;
1140    GetNextToken;
1141    L:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression));
1142    L.A:=Result;
1143    Result:=L;
1144    L.B:=ParseBitwiseAndExpression();
1145    IsLHS:=False;
1146  except
1147    FreeAndNil(Result);
1148    Raise;
1149  end;
1150  {$ifdef debugparser}  Writeln('Exit ParseBitwiseAndExpression');{$endif debugparser}
1151end;
1152
1153function TJSParser.ParseBitwiseXORExpression: TJSElement;
1154
1155Var
1156  L : TJSBitwiseXOrExpression;
1157
1158begin
1159  {$ifdef debugparser}  Writeln('ParseBitwiseXorExpression');{$endif debugparser}
1160  Result:=ParseBitwiseAndExpression;
1161  try
1162    If (CurrentToken<>tjsXOr) then
1163      exit;
1164    GetNextToken;
1165    L:=TJSBitwiseXOrExpression(CreateElement(TJSBitwiseXOrExpression));
1166    L.A:=Result;
1167    Result:=L;
1168    L.B:=ParseBitwiseXORExpression();
1169    IsLHS:=False;
1170  except
1171    FreeAndNil(Result);
1172    Raise;
1173  end;
1174  {$ifdef debugparser}  Writeln('Exit ParseBitwiseXorExpression');{$endif debugparser}
1175end;
1176
1177function TJSParser.ParseBitwiseORExpression: TJSElement;
1178
1179Var
1180  L : TJSBitwiseOrExpression;
1181
1182begin
1183  {$ifdef debugparser}  Writeln('ParseBitWiseOrExpression');{$endif debugparser}
1184    Result:=ParseBitwiseXORExpression;
1185    try
1186      If (CurrentToken<>tjsOr) then
1187        exit;
1188      GetNextToken;
1189      L:=TJSBitwiseOrExpression(CreateElement(TJSBitwiseOrExpression));
1190      L.A:=Result;
1191      Result:=L;
1192      L.B:=ParseBitwiseORExpression();
1193      IsLHS:=False;
1194    except
1195      FreeAndNil(Result);
1196      Raise;
1197    end;
1198    {$ifdef debugparser}  Writeln('Exit ParseBitWiseOrExpression');{$endif debugparser}
1199end;
1200
1201function TJSParser.ParseLogicalAndExpression: TJSElement;
1202
1203Var
1204  L : TJSLogicalAndExpression;
1205
1206begin
1207  {$ifdef debugparser}  Writeln('ParseLogicalAndExpression');{$endif debugparser}
1208  Result:=ParseBitwiseORExpression;
1209  try
1210    If (CurrentToken<>tjsAndAnd) then
1211      exit;
1212    GetNextToken;
1213    L:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression));
1214    L.A:=Result;
1215    Result:=L;
1216    L.B:=ParseLogicalAndExpression();
1217    IsLHS:=False;
1218  except
1219    FreeAndNil(Result);
1220    Raise;
1221  end;
1222  {$ifdef debugparser}  Writeln('Exit ParseLogicalAndExpression');{$endif debugparser}
1223end;
1224
1225function TJSParser.ParseLogicalORExpression: TJSElement;
1226
1227Var
1228  L : TJSLogicalOrExpression;
1229
1230begin
1231  {$ifdef debugparser}  Writeln('ParseLogicalOrExpression');{$endif debugparser}
1232  Result:=ParseLogicalAndExpression;
1233  try
1234    If (CurrentToken<>tjsOROR) then
1235      exit;
1236    GetNextToken;
1237    L:=TJSLogicalOrExpression(CreateElement(TJSLogicalOrExpression));
1238    L.A:=Result;
1239    Result:=L;
1240    L.B:=ParseLogicalOrExpression();
1241    IsLHS:=False;
1242  except
1243    FreeAndNil(Result);
1244    Raise;
1245  end;
1246  {$ifdef debugparser}  Writeln('Exit ParseLogicalOrExpression');{$endif debugparser}
1247end;
1248
1249function TJSParser.ParseConditionalExpression: TJSElement;
1250
1251Var
1252  N : TJSConditionalExpression;
1253  L : TJSElement;
1254begin
1255  {$ifdef debugparser}  Writeln('ParseConditionalExpression');{$endif debugparser}
1256  Result:=Nil;
1257  Result:=ParseLogicalORExpression;
1258  try
1259    If (CurrentToken=tjsConditional) then
1260      begin
1261      {$ifdef debugparser}  Writeln('ParseConditionalExpression : Detected conditional ');{$endif debugparser}
1262      GetNextToken;
1263      L:=Result;
1264      N:=TJSConditionalExpression(CreateElement(TJSConditionalExpression));
1265      Result:=N;
1266      N.A:=L;
1267      L:=Nil;
1268      N.B:=ParseAssignmentExpression;
1269      Consume(tjsColon);
1270      N.C:=ParseAssignmentExpression;
1271      IsLHS:=False;
1272      end;
1273  except
1274    FreeandNil(Result);
1275  end;
1276  {$ifdef debugparser}  Writeln('Exit ParseConditionalExpression');{$endif debugparser}
1277end;
1278
1279function TJSParser.ParseAssignmentExpression: TJSElement;
1280
1281Var
1282  N : TJSElement;
1283  C : TJSElementClass;
1284  A : TJSAssignStatement;
1285
1286begin
1287  {$ifdef debugparser}  Writeln('ParseAssignmentExpression');{$endif debugparser}
1288  Result:=Nil;
1289  N:=ParseConditionalExpression;
1290  If not isLHS then
1291    Result:=N
1292  else
1293    Case CurrentToken of
1294      tjsAssign    : C:=TJSSimpleAssignStatement;
1295      tjsMulEq     : C:=TJSMulEqAssignStatement;
1296      tjsDivEq     : C:=TJSDivEqAssignStatement;
1297      tjsModEq     : C:=TJSModEqAssignStatement;
1298      tjsPlusEq    : C:=TJSAddEqAssignStatement;
1299      tjsMinusEq   : C:=TJSSubEqAssignStatement;
1300      tjsLShiftEq  : C:=TJSLShiftEqAssignStatement;
1301      tjsRShiftEq  : C:=TJSRShiftEqAssignStatement;
1302      tjsURShiftEq : C:=TJSURShiftEqAssignStatement;
1303      tjsANDEq     : C:=TJSANDEqAssignStatement;
1304      tjsOREq      : C:=TJSOREqAssignStatement;
1305      tjsXOREq     : C:=TJSXOREqAssignStatement;
1306    else
1307//      writeln('Strange token',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);
1308      Result:=N
1309    end;
1310  If Result<>Nil then
1311    begin
1312    {$ifdef debugparser}  Writeln('Exit ParseAssignmentExpression - no assignment');{$endif debugparser}
1313    Exit;
1314    end;
1315  A:=TJSAssignStatement(CreateElement(C));
1316  try
1317    Result:=A;
1318    A.Lhs:=N;
1319    GetNextToken;
1320    {$ifdef debugparser}  Writeln('ParseAssignmentExpression - level 2');{$endif debugparser}
1321    N:=ParseAssignmentExpression();
1322    {$ifdef debugparser}  Writeln('Exit ParseAssignmentExpression - level 2');{$endif debugparser}
1323    A.Expr:=N;
1324    IsLhs:=False;
1325  except
1326    FreeAndNil(Result);
1327    Raise;
1328  end;
1329  {$ifdef debugparser}  Writeln('Exit ParseAssignmentExpression');{$endif debugparser}
1330end;
1331
1332function TJSParser.ParseVariableDeclaration: TJSElement;
1333
1334Var
1335  V : TJSVarDeclaration;
1336
1337begin
1338  {$ifdef debugparser}  Writeln('ParseVariableDeclaration');{$endif debugparser}
1339  V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration));;
1340  try
1341    V.Name:=CurrenttokenString;
1342    Consume(tjsIdentifier);
1343    if (CurrentToken=tjsAssign) then
1344      begin
1345      GetNextToken;
1346      V.Init:=ParseAssignmentExpression;
1347      end;
1348    Result:=V;
1349    FCurrentVars.AddNode.Node:=Result;
1350  except
1351    FreeAndNil(V);
1352    Raise;
1353  end;
1354  {$ifdef debugparser}  Writeln('Exit ParseVariableDeclaration');{$endif debugparser}
1355end;
1356
1357function TJSParser.ParseVariableDeclarationList: TJSElement;
1358
1359Var
1360  E,N : TJSElement;
1361  L : TJSVariableDeclarationList;
1362
1363begin
1364  {$ifdef debugparser}  Writeln('ParseVariableDeclarationList entry');{$endif debugparser}
1365  E:=ParseVariableDeclaration;
1366  If (CurrentToken<>tjsComma) then
1367    Result:=E
1368  else
1369    begin
1370    L:=TJSVariableDeclarationList(CreateElement(TJSVariableDeclarationList));
1371    Result:=L;
1372    try
1373      Consume(tjsComma);
1374      N:=ParseVariableDeclarationList();
1375      L.A:=E;
1376      L.B:=N;
1377    except
1378      FreeAndNil(Result);
1379      Raise;
1380    end;
1381    end;
1382  {$ifdef debugparser}  Writeln('ParseVariableDeclarationList exit');{$endif debugparser}
1383end;
1384
1385function TJSParser.ParseVariableStatement : TJSElement;
1386
1387Var
1388  V : TJSVariableStatement;
1389
1390begin
1391  {$ifdef debugparser}  Writeln('ParseVariableStatement entry');{$endif debugparser}
1392  Result:=Nil;
1393  Consume(tjsVar);
1394  Result:=ParseVariableDeclarationList;
1395  try
1396    Consume(tjsSemicolon,true);
1397    V:=TJSVariableStatement(CreateElement(TJSVariableStatement));
1398    V.A:=Result;
1399    Result:=V;
1400  except
1401    FreeAndNil(Result);
1402    Raise;
1403  end;
1404  {$ifdef debugparser}  Writeln('ParseVariableStatement exit');{$endif debugparser}
1405end;
1406
1407function TJSParser.ParseEmptyStatement : TJSElement;
1408
1409begin
1410  Consume(tjsSemiColon,true);
1411  Result:=CreateElement(TJSEmptyStatement);
1412end;
1413
1414function TJSParser.ParseIfStatement : TJSElement;
1415
1416Var
1417  C,BTrue,BFalse : TJSElement;
1418  I : TJSIFstatement;
1419
1420begin
1421  C:=Nil;
1422  BTrue:=Nil;
1423  BFalse:=Nil;
1424  try
1425    Consume(tjsIF);
1426    Consume(tjsBraceOpen);
1427    C:=ParseExpression;
1428    Consume(tjsBraceClose);
1429    BTrue:=ParseStatement;
1430    If (CurrentToken=tjsElse) then
1431      begin
1432      Consume(tjsElse);
1433      BFalse:=ParseStatement;
1434      end;
1435    I:=TJSIfStatement(CreateElement(TJSIfStatement));
1436    I.Cond:=C;
1437    I.BTrue:=Btrue;
1438    I.BFalse:=BFalse;
1439    Result:=I;
1440  except
1441    FreeAndNil(C);
1442    FreeAndNil(BTrue);
1443    FreeAndNil(BFalse);
1444    Raise;
1445  end;
1446end;
1447
1448function TJSParser.ParseIterationStatement : TJSElement;
1449
1450Var
1451  F : TJSForStatement;
1452  FI : TJSForInStatement;
1453  W : TJSWhileStatement;
1454  N : TJSElement;
1455
1456begin
1457  Result:=Nil;
1458  N:=Nil;
1459  CurrentLabelSet.Continuable:=True;
1460  EnterLabel(SEmptyLabel);
1461  try
1462    try
1463    Case CurrentToken of
1464      tjsDo :
1465        begin
1466        GetNextToken;
1467        W:=TJSDoWhileStatement(CreateElement(TJSDoWhileStatement));
1468        Result:=W;
1469        W.Body:=ParseStatement;
1470        Consume(tjsWhile);
1471        Consume(tjsBraceOpen);
1472        W.Cond:=ParseExpression;
1473        Consume(tjsBraceClose);
1474        Consume(tjsSemicolon,True);
1475        end;
1476      tjsWhile :
1477        begin
1478        GetNextToken;
1479        W:=TJSWhileStatement(CreateElement(TJSWhileStatement));
1480        Result:=W;
1481        Consume(tjsBraceOpen);
1482        W.Cond:=ParseExpression;
1483        Consume(tjsBraceClose);
1484        W.Body:=ParseStatement;
1485        Result:=W;
1486        end;
1487      else
1488        // For ?
1489        GetNextToken;
1490        Consume(tjsBraceopen);
1491        If (CurrentToken=tjsVar) then
1492          begin
1493          GetNextToken;
1494          N:=ParseVariableDeclarationList;
1495          // for (var in
1496          If (CurrentToken=tjsIn) and (N is tJSVarDeclaration) then
1497            begin
1498            Fi:=TJSForInStatement(CreateElement(TJSForInStatement));
1499            Result:=Fi;
1500            Fi.LHS:=N;
1501            GetNextToken;
1502            Fi.List:=ParseExpression;
1503            Consume(tjsBraceClose);
1504            Fi.Body:=ParseStatement;
1505            end;
1506          // for (var ;
1507          If (CurrentToken<>tjsSemicolon) then
1508            If (N is tJSVarDeclaration) then
1509              Error(SErrSemicolonOrInExpected,[CurrentTokenString])
1510            else
1511              Error(SErrSemicolonExpected,[CurrentTokenString]);
1512          GetNextToken;
1513          F:=TJSForStatement(CreateElement(TJSForStatement));
1514          Result:=F;
1515          If (CurrentToken<>tjsSemicolon) then
1516            F.Cond:=ParseExpression;
1517          Consume(tjsSemicolon);
1518          If (CurrentToken<>tjsBraceClose) then
1519            F.Incr:=ParseExpression;
1520          Consume(tjsBraceClose);
1521          F.Body:=ParseStatement;
1522          end
1523        else
1524          begin
1525          If (CurrentToken<>tjsSemicolon) then
1526            begin
1527            N:=ParseExpression;
1528            If (CurrentToken=tjsIn) then
1529              begin
1530              Fi:=TJSForInStatement(CreateElement(TJSForInStatement));
1531              Result:=Fi;
1532              Fi.LHS:=N;
1533              N:=Nil; // prevent freeing a second time in case of an exception.
1534              GetNextToken;
1535              Fi.List:=ParseExpression;
1536              Consume(tjsBraceClose);
1537              Fi.Body:=ParseStatement;
1538              Exit; // We must jump out here
1539              end
1540            end
1541          else
1542            N:=Nil;
1543          // For ( Init; Cond; incr)
1544          F:=TJSForStatement(CreateElement(TJSForStatement));
1545          Result:=F;
1546          F.Init:=N;
1547          N:=Nil; // prevent freeing a second time in case of an exception.
1548          Consume(tjsSemicolon);
1549          if (CurrentToken<>tjsSemicolon) then
1550            F.Cond:=ParseExpression;
1551          Consume(tjsSemicolon);
1552          If (CurrentToken<>tjsBraceClose) Then
1553            F.Incr:=ParseExpression;
1554          Consume(tjsBraceClose);
1555          F.Body:=ParseStatement;
1556          end;
1557      end; // Case
1558  Finally
1559    LeaveLabel;
1560    FreeCurrentLabelSet;
1561  end;
1562  except
1563    FreeAndNil(N);
1564    FreeAndNil(Result);
1565    Raise;
1566  end;
1567end;
1568
1569function TJSParser.ParseContinueStatement : TJSElement;
1570
1571Var
1572  L : TJSLabel;
1573  C : TJSContinueStatement;
1574
1575begin
1576  C:=TJSContinueStatement(CreateElement(TJSContinueStatement));
1577  try
1578    Result:=C;
1579    Consume(tjsContinue);
1580    If (CurrentToken=tjsSemicolon) then
1581      L:=LookupLabel(SEmptyLabel,tjsContinue)
1582    else
1583      begin
1584      if (CurrentToken=tjsIdentifier) then
1585        L:=LookupLabel(CurrentTokenString,tjsContinue);
1586      Consume(tjsIdentifier);
1587      end;
1588    Consume(tjsSemicolon,True);
1589    C.Target:=L.Labelset.Target;
1590    C.TargetName:=L.Name;
1591  except
1592    FreeAndNil(C);
1593    Raise;
1594  end;
1595end;
1596
1597function TJSParser.ParseBreakStatement : TJSElement;
1598
1599Var
1600  L : TJSLabel;
1601  B : TJSBreakStatement;
1602
1603begin
1604  B:=TJSBreakStatement(CreateElement(TJSBreakStatement));
1605  try
1606  Result:=B;
1607    Consume(tjsBreak);
1608    If (CurrentToken=tjsSemicolon) then
1609      L:=LookupLabel(SEmptyLabel,tjsBreak)
1610    else
1611      begin
1612      if (CurrentToken=tjsIdentifier) then
1613        L:=LookupLabel(CurrentTokenString,tjsBreak);
1614      Consume(tjsIdentifier);
1615      end;
1616    Consume(tjsSemicolon,True);
1617    B.Target:=L.Labelset.Target;
1618    B.TargetName:=L.Name;
1619  except
1620    FreeAndNil(B);
1621    Raise;
1622  end;
1623end;
1624
1625function TJSParser.ParseReturnStatement : TJSElement;
1626
1627Var
1628  R : TJSreturnStatement;
1629
1630begin
1631  R:=TJSReturnStatement(CreateElement(TJSReturnStatement));
1632  try
1633    Result:=R;
1634    Consume(tjsReturn);
1635    If (FunctionDepth=0) then
1636      Error(SErrReturnNotInFunction);
1637    If Not (CurrentToken in [tjsSemicolon,tjsCurlyBraceClose]) then
1638      R.Expr:=ParseExpression;
1639    Consume(tjsSemicolon,True);
1640  except
1641    FreeAndNil(R);
1642    Raise;
1643  end;
1644end;
1645
1646function TJSParser.ParseWithStatement : TJSElement;
1647
1648Var
1649  W : TJSWithStatement;
1650begin
1651  W:=TJSWithStatement(CreateElement(TJSWithStatement));
1652  try
1653    Consume(tjsWith);
1654    Consume(tjsBraceOpen);
1655    W.A:=ParseExpression;
1656    Consume(tjsBraceClose);
1657    W.B:=ParseStatement;
1658  except
1659    FreeAndNil(W);
1660    Raise;
1661  end;
1662  Result:=W;
1663end;
1664
1665function TJSParser.ParseSwitchStatement : TJSElement;
1666
1667
1668Var
1669  N : TJSSwitchStatement;
1670  Ca : TJSCaseElement;
1671
1672begin
1673  N:=TJSSwitchStatement(CreateElement(TJSSwitchStatement));
1674  try
1675    N.Target:=CurrentLabelset.Target;
1676    EnterLabel(SEmptyLabel);
1677    try
1678      Consume(tjsSwitch);
1679      Consume(tjsBraceOpen);
1680      N.Cond:=ParseExpression;
1681      Consume(tjsBraceClose);
1682      Consume(tjsCurlyBraceOpen);
1683      While (CurrentToken<>tjsCurlyBraceClose) do
1684        begin
1685        If (CurrentToken=tjsCase) then
1686          begin
1687          GetNextToken;
1688          Ca:=N.Cases.AddCase;
1689          Ca.Expr:=ParseExpression;
1690          end
1691        else if (CurrentToken=tjsDefault) then
1692          begin
1693          If (N.TheDefault<>Nil) then
1694            Error(SerrDuplicateSwitchDefault);
1695          Ca:=N.Cases.AddCase;
1696          N.TheDefault:=Ca;
1697          GetNextToken;
1698          end
1699        else
1700          Error(SerrCaseEndExpected);
1701        Consume(tjsColon);
1702        If Not (CurrentToken in [tjsCurlyBraceClose,tjsCase,tjsDefault]) then
1703          Ca.Body:=ParseStatementList;
1704        end;
1705      Consume(tjsCurlyBraceClose);
1706    finally
1707      LeaveLabel;
1708      FreeCurrentLabelSet;
1709    end;
1710    Result:=N;
1711  except
1712    FreeAndNil(N);
1713    Raise;
1714  end;
1715end;
1716
1717function TJSParser.ParseThrowStatement : TJSElement;
1718
1719Var
1720  TS : TJSThrowStatement;
1721
1722begin
1723  TS:=TJSThrowStatement(CreateElement(TJSThrowStatement));
1724  try
1725    Result:=TS;
1726    Consume(tjsThrow);
1727    If IsEndOfLine then
1728      Error(SErrNewlineAfterThrow);
1729    TS.A:=ParseExpression;
1730    Consume(tjsSemicolon,true);
1731  except
1732    FreeAndNil(TS);
1733    Raise;
1734  end;
1735end;
1736
1737function TJSParser.ParseTryStatement : TJSElement;
1738
1739Var
1740  BO,BC,BF : TJSElement;
1741  Id : jstree.TJSString;
1742  T : TJSTryStatement;
1743
1744begin
1745  BO:=Nil;
1746  BC:=Nil;
1747  BF:=Nil;
1748  Result:=Nil;
1749  Consume(tjsTry);
1750  try
1751    Bo:=ParseBlock;
1752    if (CurrentToken=tjscatch) then
1753      begin
1754      Consume(tjsCatch);
1755      Consume(tjsBraceOpen);
1756      if (CurrentToken=tjsIdentifier) then
1757        id:=CurrentTokenString;
1758      Consume(tjsIdentifier);
1759      Consume(tjsBraceClose);
1760      BC:=ParseBlock;
1761      end;
1762    if (CurrentToken=tjsFinally) then
1763      begin
1764      consume(tjsFinally);
1765      BF:=ParseBlock;
1766      end;
1767    If (BF=Nil) and (BC=Nil) then
1768      Error(SErrCatchFinallyExpected);
1769    If Assigned(BC) AND Assigned(BF) then
1770      T:=TJSTryStatement(CreateElement(TJSTryCatchFinallyStatement))
1771    else if Assigned(BC) then
1772      T:=TJSTryStatement(CreateElement(TJSTryCatchStatement))
1773    else
1774      T:=TJSTryStatement(CreateElement(TJSTryFinallyStatement));
1775    Result:=T;
1776    T.Block:=Bo;
1777    Bo:=Nil;
1778    T.BCatch:=BC;
1779    BC:=Nil;
1780    T.BFinally:=BF;
1781    BF:=Nil;
1782    T.Ident:=ID;
1783  except
1784    FreeAndNil(Bo);
1785    FreeAndNil(BC);
1786    FreeAndNil(BF);
1787    FreeAndNil(Result);
1788    Raise;
1789  end;
1790
1791end;
1792
1793function TJSParser.ParseFunctionExpression : TJSFunctionDeclarationStatement;
1794
1795Var
1796  Oni,olhs: Boolean;
1797  F : TJSFunctionDeclarationStatement;
1798  N : String;
1799  Args : TStrings;
1800
1801begin
1802  {$ifdef debugparser} Writeln('>>> ParseFunctionExpression');{$endif}
1803  oni:=NoIn;
1804  olhs:=IsLHS;
1805  F:=Nil;
1806  Args:=Nil;
1807  try
1808    NoIn:=False;
1809    IsLHS:=False;
1810    F:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
1811    try
1812      Consume(tjsFunction);
1813      if (CurrentToken=tjsIdentifier) then
1814        begin
1815        n:=CurrentTokenstring;
1816        GetNextToken;
1817        end
1818      else
1819        n:='';
1820      if n='' then ; // what to do with that?
1821      Consume(tjsBraceOpen);
1822      F.AFunction:= TJSFuncDef.Create;
1823      Args:=ParseFormalParameterList;
1824      try
1825        If Assigned(Args) then
1826          F.AFunction.Params.Assign(Args);
1827      finally
1828        FreeAndNil(Args);
1829      end;
1830      Consume(tjsBraceClose);
1831      Consume(tjsCurlyBraceOpen);
1832      Inc(FFunctionDepth);
1833      try
1834        F.AFunction.Body:=ParseFunctionBody;
1835      Finally
1836        Dec(FFunctionDepth);
1837      end;
1838      Consume(tjsCurlyBraceClose);
1839      Result:=F;
1840    except
1841      FreeAndNil(F);
1842      Raise;
1843    end;
1844  finally
1845    NoIn  := oni;
1846    IsLHS := olhs;
1847  end;
1848  {$ifdef debugparser} Writeln('<<< ParseFunctionExpression');{$endif}
1849end;
1850
1851function TJSParser.ParseFunctionStatement : TJSElement;
1852
1853Var
1854  F : TJSFunctionDeclarationStatement;
1855  I : TJSPrimaryExpressionIdent;
1856  A : TJSAssignStatement;
1857  E : TJSExpressionStatement;
1858
1859begin
1860  {$ifdef debugparser} Writeln('>>> ParseFunctionStatement');{$endif}
1861  F:=Nil;
1862  I:=Nil;
1863  A:=Nil;
1864  try
1865    F:=ParseFunctionExpression;
1866    I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent));
1867    I.Name:=F.AFunction.Name;
1868    A:=TJSAssignStatement(CreateElement(TJSAssignStatement));
1869    A.LHS:=I;
1870    I:=Nil;
1871    A.Expr:=F;
1872    F:=Nil;
1873    E:=TJSExpressionStatement(CreateElement(TJSExpressionStatement));
1874    E.A:=A;
1875    A:=Nil;
1876    Result:=E;
1877  except
1878    FreeAndNil(F);
1879    FreeAndNil(I);
1880    FreeAndNil(A);
1881    Raise;
1882  end;
1883  {$ifdef debugparser} Writeln('<<< ParseFunctionStatement');{$endif}
1884end;
1885
1886function TJSParser.ParseLabeledStatement : TJSElement;
1887
1888Var
1889  OL : TJSLabelSet;
1890  LS : TJSLabeledStatement;
1891begin
1892  LS:=TJSLabeledStatement(CreateElement(TJSLabeledStatement));
1893  try
1894    Result:=LS;
1895    OL:=FCurrentLabelSet;
1896    try
1897      FCurrentLabelSet:=Nil;
1898      LS.target:=CurrentLabelSet.Target;
1899      Repeat
1900        LS.TheLabel:=EnterLabel(CurrentTokenString);
1901        Consume(tjsIdentifier);
1902        Consume(tjsColon);
1903      Until (CurrentToken<>tjsIdentifier) or (PeekNextToken<>tjsColon);
1904      Case CurrentToken of
1905         tjsDo,tjsWhile,tjsFor : LS.A:=ParseIterationStatement;
1906         tjsswitch : LS.A:=ParseSwitchStatement;
1907      else
1908        LS.A:=ParseStatement;
1909      end;
1910    finally
1911      FreeCurrentLabelSet;
1912      FCurrentLabelSet:=Ol;
1913    end;
1914  except
1915    FreeAndNil(LS);
1916    Raise;
1917  end;
1918end;
1919
1920procedure TJSParser.FreeCurrentLabelSet;
1921
1922Var
1923  L : TJSLabelSet;
1924
1925begin
1926  While Assigned(FCurrentLabelSet) do
1927    begin
1928    L:=FCurrentLabelset.Next;
1929    FCurrentLabelSet.Free;
1930    FCurrentLabelSet:=L;
1931    end;
1932end;
1933
1934function TJSParser.ParseExpressionStatement : TJSElement;
1935
1936Var
1937  E : TJSElement;
1938  R : TJSExpressionStatement;
1939begin
1940  {$ifdef debugparser}  Writeln('ParseExpressionStatement');{$endif debugparser}
1941  E:=ParseExpression;
1942  Consume(tjsSemicolon,True);
1943  R:=TJSExpressionStatement(CreateElement(TJSExpressionStatement));
1944  R.A:=E;
1945  Result:=R;
1946  {$ifdef debugparser}  Writeln('Exit ParseExpressionStatement');{$endif debugparser}
1947end;
1948
1949function TJSParser.ParseExpression : TJSElement;
1950
1951Var
1952  C : TJSCommaExpression;
1953
1954begin
1955  {$ifdef debugparser}  Writeln('ParseExpression');{$endif debugparser}
1956  Result:=ParseAssignmentExpression;
1957  try
1958    If (CurrentToken=tjsComma) then
1959      begin
1960      C:=TJSCommaExpression(CreateElement(TJSCommaExpression));
1961      C.A:=Result;
1962      Result:=C;
1963      GetNextToken;
1964      C.B:=ParseExpression();
1965      end;
1966  except
1967    FreeAndNil(Result);
1968    Raise;
1969  end;
1970  {$ifdef debugparser}  Writeln('Exit ParseExpression');{$endif debugparser}
1971end;
1972
1973function TJSParser.ParseStatement : TJSElement;
1974
1975begin
1976  {$ifdef debugparser} Writeln('>>> Parsestatement');{$endif}
1977  Result:=Nil;
1978  Case CurrentToken of
1979    tjsCurlyBraceOpen :
1980      Result:=ParseBlock;
1981    tjsVar:
1982      Result:=ParseVariableStatement;
1983    tjsSemicolon:
1984      Result:=ParseEmptyStatement;
1985    tjsIf:
1986      Result:=ParseIfStatement;
1987    tjsDo,tjsWhile,tjsFor:
1988      Result:=ParseIterationStatement;
1989    tjsContinue:
1990      Result:=ParseContinueStatement;
1991    tjsBreak:
1992      Result:=ParseBreakStatement;
1993    tjsReturn:
1994      Result:=ParseReturnStatement;
1995    tjsWith:
1996      Result:=ParseWithStatement;
1997    tjsSwitch:
1998      Result:=ParseSwitchStatement;
1999    tjsThrow:
2000      Result:=ParseThrowStatement;
2001    tjsTry:
2002      Result:=ParseTryStatement;
2003    tjsFunction:
2004      begin
2005      If (PeekNextToken<>tjsBraceOpen) then
2006        Result:=ParseFunctionStatement;
2007      Error(SErrFunctionNotAllowedHere);
2008      end;
2009    tjsIdentifier:
2010      If (PeekNextToken=tjsColon) then
2011        Result:=ParseLabeledStatement
2012      else
2013        Result:=ParseExpressionStatement;
2014  else
2015    Result:=ParseExpressionStatement;
2016  end;
2017  {$ifdef debugparser} If Assigned(Result) then Writeln('<<< Parsestatement ',Result.ClassName) else Writeln('<<< Parsestatement (null');{$endif}
2018end;
2019
2020function TJSParser.ParseSourceElements : TJSSourceElements;
2021
2022Const
2023  StatementTokens = [tjsNULL, tjsTRUE, tjsFALSE,
2024      tjsTHIS, tjsIdentifier,jstoken.tjsSTRING,tjsNUMBER,
2025      tjsBraceOpen,tjsCurlyBraceOpen,tjsSquaredBraceOpen,
2026      tjsNew,tjsDelete,tjsVoid,tjsTypeOf,
2027      tjsPlusPlus,tjsMinusMinus,
2028      tjsPlus,tjsMinus,tjsNot,tjsNE,tjsSNE,tjsSemicolon,
2029      tjsVAR,tjsIF,tjsDO,tjsWHILE,tjsFOR,jstoken.tjsCONTINUE,jstoken.tjsBREAK,jstoken.tjsReturn,
2030      tjsWith,jstoken.tjsSWITCH,tjsThrow,TjsTry,tjsDIV,tjsDIVEQ];
2031
2032Var
2033  F : TJSFunctionDeclarationStatement;
2034  E : TJSElement;
2035  Done : Boolean;
2036  VS : TJSElementNodes;
2037begin
2038  {$ifdef debugparser} Writeln('>>> Entering source elements');{$endif}
2039  Result:=TJSSourceElements(CreateElement(TJSSourceElements));
2040  try
2041    Done:=False;
2042    VS:=FCurrentVars;
2043    Try
2044      FCurrentVars:=Result.Vars;
2045      Repeat
2046        {$ifdef debugparser} Writeln('Sourceelements start:',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
2047        If (CurrentToken=jstoken.tjsFunction) then
2048          begin
2049          If (PeekNextToken<>tjsBraceOpen) then
2050            begin
2051            F:=Self.ParseFunctionDeclaration;
2052            Result.Functions.AddNode.Node:=F;
2053            end
2054          else
2055            begin
2056            {$ifdef debugparser} Writeln('Function expression detected');{$endif}
2057            E:=Self.ParseStatement;
2058            Result.Statements.AddNode.Node:=E;
2059            end;
2060          end
2061        else if CurrentToken in StatementTokens then
2062          begin
2063          E:=Self.ParseStatement;
2064          Result.Statements.AddNode.Node:=E;
2065          end
2066        else
2067          Done:=True;
2068        {$ifdef debugparser} Writeln('Sourceelements Done : ',Done);{$endif}
2069      Until Done;
2070    Finally
2071      FCurrentVars:=VS;
2072    end;
2073  except
2074    FreeAndNil(Result);
2075    Raise;
2076  end;
2077  {$ifdef debugparser}   Writeln('<<< Exiting source elements');{$endif}
2078end;
2079
2080function TJSParser.ParseFunctionBody : TJSFunctionBody;
2081
2082Var
2083  E : TJSElement;
2084
2085begin
2086  {$ifdef debugparser} Writeln('>>> Entering FunctionBody');{$endif}
2087  Result:=TJSFunctionBody(CreateElement(TJSFunctionBody));
2088  try
2089    E:=Self.ParseSourceElements;
2090    Result.A:=E;
2091  except
2092    FreeAndNil(Result);
2093    Raise;
2094  end;
2095  {$ifdef debugparser} Writeln('<<< Exiting FunctionBody');{$endif}
2096end;
2097
2098Function TJSParser.ParseProgram: TJSFunctionDeclarationStatement;
2099
2100Var
2101  B : TJSElement;
2102begin
2103  {$ifdef debugparser} Writeln('>>> Entering FunctionDeclarationStatement');{$endif}
2104  B:=Parse;
2105  If Not (B is TJSFunctionBody) then
2106    Error('Parse did not result in functionbody');
2107  Result:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
2108  Result.AFunction:=TJSFuncDef.Create;
2109  Result.AFunction.Body:=TJSFunctionBody(B);
2110  {$ifdef debugparser} Writeln('<<< Exiting FunctionDeclarationStatement');{$endif}
2111end;
2112
2113Function TJSParser.Parse: TJSElement;
2114
2115Var
2116  Body : TJSElement;
2117
2118begin
2119  {$ifdef debugparser} Writeln('>>> Parse');{$endif}
2120  Result:=Nil;
2121  CheckParser;
2122  GetNextToken;
2123  Body:=ParseFunctionBody;
2124  Result:=Body;
2125  try
2126    if (CurrentToken<>tjsEOF) then
2127      begin
2128      if (CurrentToken=tjsCurlyBraceClose) then
2129        Error(SErrUnmatchedCurlyBrace)
2130      else if (CurrentToken=tjsBraceClose) then
2131        Error(SerrUnmatchedBrace)
2132      else if (CurrentToken=tjsSquaredBraceClose) then
2133        Error(SerrUnmatchedSquareBrace);
2134      Error(SErrUnexpectedToken,[CurrentTokenString]);
2135      end;
2136    If (Body is TJSFunctionBody) then
2137      TJSFunctionBody(Body).isProgram:=True;
2138  except
2139    FreeAndNil(Result);
2140    Raise;
2141  end;
2142  {$ifdef debugparser} Writeln('<<< Parse');{$endif}
2143end;
2144
2145
2146end.
2147
2148