fix(userdata): Dropped sloppy JSOn parser in favour of a true JavaScript AST analyzer
[plugin.video.netflix.git] / resources / lib / pyjsparser / parser.py
1 # The MIT License
2 #
3 # Copyright 2014, 2015 Piotr Dabkowski
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the 'Software'),
7 # to deal in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 # the Software, and to permit persons to whom the Software is furnished to do so, subject
10 # to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in all copies or
13 # substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
16 # LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
19 #  OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
20 from __future__ import unicode_literals
21 from .pyjsparserdata import *
22 from .std_nodes import *
23 from pprint import pprint
24 import sys
25
26 __all__ = ['PyJsParser', 'parse', 'ENABLE_JS2PY_ERRORS', 'ENABLE_PYIMPORT', 'JsSyntaxError']
27 REGEXP_SPECIAL_SINGLE = ('\\', '^', '$', '*', '+', '?', '.', '[', ']', '(', ')', '{', '{', '|', '-')
28 ENABLE_PYIMPORT = False
29 ENABLE_JS2PY_ERRORS = False
30
31 PY3 = sys.version_info >= (3,0)
32
33 if PY3:
34     basestring = str
35     long = int
36     xrange = range
37     unicode = str
38
39 ESPRIMA_VERSION = '2.2.0'
40 DEBUG = False
41 # Small naming convention changes
42 # len -> leng
43 # id -> d
44 # type -> typ
45 # str -> st
46 true = True
47 false = False
48 null = None
49
50
51 class PyJsParser:
52     """ Usage:
53         parser = PyJsParser()
54         parser.parse('var JavaScriptCode = 5.1')
55     """
56
57     def __init__(self):
58         self.clean()
59
60     def test(self, code):
61         pprint(self.parse(code))
62
63     def clean(self):
64         self.strict = None
65         self.sourceType = None
66         self.index = 0
67         self.lineNumber = 1
68         self.lineStart = 0
69         self.hasLineTerminator = None
70         self.lastIndex = None
71         self.lastLineNumber = None
72         self.lastLineStart = None
73         self.startIndex = None
74         self.startLineNumber = None
75         self.startLineStart = None
76         self.scanning = None
77         self.lookahead = None
78         self.state = None
79         self.extra = None
80         self.isBindingElement = None
81         self.isAssignmentTarget = None
82         self.firstCoverInitializedNameError = None
83
84     # 7.4 Comments
85
86     def skipSingleLineComment(self, offset):
87         start = self.index - offset;
88         while self.index < self.length:
89             ch = self.source[self.index];
90             self.index += 1
91             if isLineTerminator(ch):
92                 if (ord(ch) == 13 and ord(self.source[self.index]) == 10):
93                     self.index += 1
94                 self.lineNumber += 1
95                 self.hasLineTerminator = True
96                 self.lineStart = self.index
97                 return
98
99     def skipMultiLineComment(self):
100         while self.index < self.length:
101             ch = ord(self.source[self.index])
102             if isLineTerminator(ch):
103                 if (ch == 0x0D and ord(self.source[self.index + 1]) == 0x0A):
104                     self.index += 1
105                 self.lineNumber += 1
106                 self.index += 1
107                 self.hasLineTerminator = True
108                 self.lineStart = self.index
109             elif ch == 0x2A:
110                 # Block comment ends with '*/'.
111                 if ord(self.source[self.index + 1]) == 0x2F:
112                     self.index += 2
113                     return
114                 self.index += 1
115             else:
116                 self.index += 1
117         self.tolerateUnexpectedToken()
118
119     def skipComment(self):
120         self.hasLineTerminator = False
121         start = (self.index == 0)
122         while self.index < self.length:
123             ch = ord(self.source[self.index])
124             if isWhiteSpace(ch):
125                 self.index += 1
126             elif isLineTerminator(ch):
127                 self.hasLineTerminator = True
128                 self.index += 1
129                 if (ch == 0x0D and ord(self.source[self.index]) == 0x0A):
130                     self.index += 1
131                 self.lineNumber += 1
132                 self.lineStart = self.index
133                 start = True
134             elif (ch == 0x2F):  # U+002F is '/'
135                 ch = ord(self.source[self.index + 1])
136                 if (ch == 0x2F):
137                     self.index += 2
138                     self.skipSingleLineComment(2)
139                     start = True
140                 elif (ch == 0x2A):  # U+002A is '*'
141                     self.index += 2
142                     self.skipMultiLineComment()
143                 else:
144                     break
145             elif (start and ch == 0x2D):  # U+002D is '-'
146                 # U+003E is '>'
147                 if (ord(self.source[self.index + 1]) == 0x2D) and (ord(self.source[self.index + 2]) == 0x3E):
148                     # '-->' is a single-line comment
149                     self.index += 3
150                     self.skipSingleLineComment(3)
151                 else:
152                     break
153             elif (ch == 0x3C):  # U+003C is '<'
154                 if self.source[self.index + 1: self.index + 4] == '!--':
155                     # <!--
156                     self.index += 4
157                     self.skipSingleLineComment(4)
158                 else:
159                     break
160             else:
161                 break
162
163     def scanHexEscape(self, prefix):
164         code = 0
165         leng = 4 if (prefix == 'u') else 2
166         for i in xrange(leng):
167             if self.index < self.length and isHexDigit(self.source[self.index]):
168                 ch = self.source[self.index]
169                 self.index += 1
170                 code = code * 16 + HEX_CONV[ch]
171             else:
172                 return ''
173         return unichr(code)
174
175     def scanUnicodeCodePointEscape(self):
176         ch = self.source[self.index]
177         code = 0
178         # At least, one hex digit is required.
179         if ch == '}':
180             self.throwUnexpectedToken()
181         while (self.index < self.length):
182             ch = self.source[self.index]
183             self.index += 1
184             if not isHexDigit(ch):
185                 break
186             code = code * 16 + HEX_CONV[ch]
187         if code > 0x10FFFF or ch != '}':
188             self.throwUnexpectedToken()
189         # UTF-16 Encoding
190         if (code <= 0xFFFF):
191             return unichr(code)
192         cu1 = ((code - 0x10000) >> 10) + 0xD800;
193         cu2 = ((code - 0x10000) & 1023) + 0xDC00;
194         return unichr(cu1) + unichr(cu2)
195
196     def ccode(self, offset=0):
197         return ord(self.source[self.index + offset])
198
199     def log_err_case(self):
200         if not DEBUG:
201             return
202         print('INDEX', self.index)
203         print(self.source[self.index - 10:self.index + 10])
204         print('')
205
206     def at(self, loc):
207         return None if loc >= self.length else self.source[loc]
208
209     def substr(self, le, offset=0):
210         return self.source[self.index + offset:self.index + offset + le]
211
212     def getEscapedIdentifier(self):
213         d = self.source[self.index]
214         ch = ord(d)
215         self.index += 1
216         # '\u' (U+005C, U+0075) denotes an escaped character.
217         if (ch == 0x5C):
218             if (ord(self.source[self.index]) != 0x75):
219                 self.throwUnexpectedToken()
220             self.index += 1
221             ch = self.scanHexEscape('u')
222             if not ch or ch == '\\' or not isIdentifierStart(ch[0]):
223                 self.throwUnexpectedToken()
224             d = ch
225         while (self.index < self.length):
226             ch = self.ccode()
227             if not isIdentifierPart(ch):
228                 break
229             self.index += 1
230             d += unichr(ch)
231
232             # '\u' (U+005C, U+0075) denotes an escaped character.
233             if (ch == 0x5C):
234                 d = d[0: len(d) - 1]
235                 if (self.ccode() != 0x75):
236                     self.throwUnexpectedToken()
237                 self.index += 1
238                 ch = self.scanHexEscape('u');
239                 if (not ch or ch == '\\' or not isIdentifierPart(ch[0])):
240                     self.throwUnexpectedToken()
241                 d += ch
242         return d
243
244     def getIdentifier(self):
245         start = self.index
246         self.index += 1
247         while (self.index < self.length):
248             ch = self.ccode()
249             if (ch == 0x5C):
250                 # Blackslash (U+005C) marks Unicode escape sequence.
251                 self.index = start
252                 return self.getEscapedIdentifier()
253             if (isIdentifierPart(ch)):
254                 self.index += 1
255             else:
256                 break
257         return self.source[start: self.index]
258
259     def scanIdentifier(self):
260         start = self.index
261
262         # Backslash (U+005C) starts an escaped character.
263         d = self.getEscapedIdentifier() if (self.ccode() == 0x5C) else self.getIdentifier()
264
265         # There is no keyword or literal with only one character.
266         # Thus, it must be an identifier.
267         if (len(d) == 1):
268             type = Token.Identifier
269         elif (isKeyword(d)):
270             type = Token.Keyword
271         elif (d == 'null'):
272             type = Token.NullLiteral
273         elif (i == 'true' or d == 'false'):
274             type = Token.BooleanLiteral
275         else:
276             type = Token.Identifier;
277         return {
278             'type': type,
279             'value': d,
280             'lineNumber': self.lineNumber,
281             'lineStart': self.lineStart,
282             'start': start,
283             'end': self.index
284         }
285
286     # 7.7 Punctuators
287
288     def scanPunctuator(self):
289         token = {
290             'type': Token.Punctuator,
291             'value': '',
292             'lineNumber': self.lineNumber,
293             'lineStart': self.lineStart,
294             'start': self.index,
295             'end': self.index
296         }
297         # Check for most common single-character punctuators.
298         st = self.source[self.index]
299         if st == '{':
300             self.state['curlyStack'].append('{')
301             self.index += 1
302         elif st == '}':
303             self.index += 1
304             self.state['curlyStack'].pop()
305         elif st in ('.', '(', ')', ';', ',', '[', ']', ':', '?', '~'):
306             self.index += 1
307         else:
308             # 4-character punctuator.
309             st = self.substr(4)
310             if (st == '>>>='):
311                 self.index += 4
312             else:
313                 # 3-character punctuators.
314                 st = st[0:3]
315                 if st in ('===', '!==', '>>>', '<<=', '>>='):
316                     self.index += 3
317                 else:
318                     # 2-character punctuators.
319                     st = st[0:2]
320                     if st in ('&&', '||', '==', '!=', '+=', '-=', '*=', '/=', '++', '--', '<<', '>>', '&=', '|=', '^=',
321                               '%=', '<=', '>=', '=>'):
322                         self.index += 2
323                     else:
324                         # 1-character punctuators.
325                         st = self.source[self.index]
326                         if st in ('<', '>', '=', '!', '+', '-', '*', '%', '&', '|', '^', '/'):
327                             self.index += 1
328         if self.index == token['start']:
329             self.throwUnexpectedToken()
330         token['end'] = self.index;
331         token['value'] = st
332         return token
333
334     # 7.8.3 Numeric Literals
335
336     def scanHexLiteral(self, start):
337         number = ''
338         while (self.index < self.length):
339             if (not isHexDigit(self.source[self.index])):
340                 break
341             number += self.source[self.index]
342             self.index += 1
343         if not number:
344             self.throwUnexpectedToken()
345         if isIdentifierStart(self.ccode()):
346             self.throwUnexpectedToken()
347         return {
348             'type': Token.NumericLiteral,
349             'value': int(number, 16),
350             'lineNumber': self.lineNumber,
351             'lineStart': self.lineStart,
352             'start': start,
353             'end': self.index}
354
355     def scanBinaryLiteral(self, start):
356         number = ''
357         while (self.index < self.length):
358             ch = self.source[self.index]
359             if (ch != '0' and ch != '1'):
360                 break
361             number += self.source[self.index]
362             self.index += 1
363
364         if not number:
365             # only 0b or 0B
366             self.throwUnexpectedToken()
367         if (self.index < self.length):
368             ch = self.source[self.index]
369             # istanbul ignore else
370             if (isIdentifierStart(ch) or isDecimalDigit(ch)):
371                 self.throwUnexpectedToken();
372         return {
373             'type': Token.NumericLiteral,
374             'value': int(number, 2),
375             'lineNumber': self.lineNumber,
376             'lineStart': self.lineStart,
377             'start': start,
378             'end': self.index}
379
380     def scanOctalLiteral(self, prefix, start):
381         if isOctalDigit(prefix):
382             octal = True
383             number = '0' + self.source[self.index]
384             self.index += 1
385         else:
386             octal = False
387             self.index += 1
388             number = ''
389         while (self.index < self.length):
390             if (not isOctalDigit(self.source[self.index])):
391                 break
392             number += self.source[self.index]
393             self.index += 1
394         if (not octal and not number):
395             # only 0o or 0O
396             self.throwUnexpectedToken()
397         if (isIdentifierStart(self.ccode()) or isDecimalDigit(self.ccode())):
398             self.throwUnexpectedToken()
399         return {
400             'type': Token.NumericLiteral,
401             'value': int(number, 8),
402             'lineNumber': self.lineNumber,
403             'lineStart': self.lineStart,
404             'start': start,
405             'end': self.index}
406
407     def octalToDecimal(self, ch):
408         # \0 is not octal escape sequence
409         octal = (ch != '0')
410         code = int(ch, 8)
411
412         if (self.index < self.length and isOctalDigit(self.source[self.index])):
413             octal = True
414             code = code * 8 + int(self.source[self.index], 8)
415             self.index += 1
416
417             # 3 digits are only allowed when string starts
418             # with 0, 1, 2, 3
419             if (ch in '0123' and self.index < self.length and isOctalDigit(self.source[self.index])):
420                 code = code * 8 + int((self.source[self.index]), 8)
421                 self.index += 1
422         return {
423             'code': code,
424             'octal': octal}
425
426     def isImplicitOctalLiteral(self):
427         # Implicit octal, unless there is a non-octal digit.
428         # (Annex B.1.1 on Numeric Literals)
429         for i in xrange(self.index + 1, self.length):
430             ch = self.source[i];
431             if (ch == '8' or ch == '9'):
432                 return False;
433             if (not isOctalDigit(ch)):
434                 return True
435         return True
436
437     def scanNumericLiteral(self):
438         ch = self.source[self.index]
439         assert isDecimalDigit(ch) or (ch == '.'), 'Numeric literal must start with a decimal digit or a decimal point'
440         start = self.index
441         number = ''
442         if ch != '.':
443             number = self.source[self.index]
444             self.index += 1
445             ch = self.source[self.index]
446             # Hex number starts with '0x'.
447             # Octal number starts with '0'.
448             # Octal number in ES6 starts with '0o'.
449             # Binary number in ES6 starts with '0b'.
450             if (number == '0'):
451                 if (ch == 'x' or ch == 'X'):
452                     self.index += 1
453                     return self.scanHexLiteral(start);
454                 if (ch == 'b' or ch == 'B'):
455                     self.index += 1
456                     return self.scanBinaryLiteral(start)
457                 if (ch == 'o' or ch == 'O'):
458                     return self.scanOctalLiteral(ch, start)
459                 if (isOctalDigit(ch)):
460                     if (self.isImplicitOctalLiteral()):
461                         return self.scanOctalLiteral(ch, start);
462             while (isDecimalDigit(self.ccode())):
463                 number += self.source[self.index]
464                 self.index += 1
465             ch = self.source[self.index];
466         if (ch == '.'):
467             number += self.source[self.index]
468             self.index += 1
469             while (isDecimalDigit(self.source[self.index])):
470                 number += self.source[self.index]
471                 self.index += 1
472             ch = self.source[self.index]
473         if (ch == 'e' or ch == 'E'):
474             number += self.source[self.index]
475             self.index += 1
476             ch = self.source[self.index]
477             if (ch == '+' or ch == '-'):
478                 number += self.source[self.index]
479                 self.index += 1
480             if (isDecimalDigit(self.source[self.index])):
481                 while (isDecimalDigit(self.source[self.index])):
482                     number += self.source[self.index]
483                     self.index += 1
484             else:
485                 self.throwUnexpectedToken()
486         if (isIdentifierStart(self.source[self.index])):
487             self.throwUnexpectedToken();
488         return {
489             'type': Token.NumericLiteral,
490             'value': float(number),
491             'lineNumber': self.lineNumber,
492             'lineStart': self.lineStart,
493             'start': start,
494             'end': self.index}
495
496     # 7.8.4 String Literals
497
498     def _interpret_regexp(self, string, flags):
499         '''Perform sctring escape - for regexp literals'''
500         self.index = 0
501         self.length = len(string)
502         self.source = string
503         self.lineNumber = 0
504         self.lineStart = 0
505         octal = False
506         st = ''
507         inside_square = 0
508         while (self.index < self.length):
509             template = '[%s]' if not inside_square else '%s'
510             ch = self.source[self.index]
511             self.index += 1
512             if ch == '\\':
513                 ch = self.source[self.index]
514                 self.index += 1
515                 if (not isLineTerminator(ch)):
516                     if ch == 'u':
517                         digs = self.source[self.index:self.index + 4]
518                         if len(digs) == 4 and all(isHexDigit(d) for d in digs):
519                             st += template % unichr(int(digs, 16))
520                             self.index += 4
521                         else:
522                             st += 'u'
523                     elif ch == 'x':
524                         digs = self.source[self.index:self.index + 2]
525                         if len(digs) == 2 and all(isHexDigit(d) for d in digs):
526                             st += template % unichr(int(digs, 16))
527                             self.index += 2
528                         else:
529                             st += 'x'
530                     # special meaning - single char.
531                     elif ch == '0':
532                         st += '\\0'
533                     elif ch == 'n':
534                         st += '\\n'
535                     elif ch == 'r':
536                         st += '\\r'
537                     elif ch == 't':
538                         st += '\\t'
539                     elif ch == 'f':
540                         st += '\\f'
541                     elif ch == 'v':
542                         st += '\\v'
543
544                     # unescape special single characters like . so that they are interpreted literally
545                     elif ch in REGEXP_SPECIAL_SINGLE:
546                         st += '\\' + ch
547
548                     # character groups
549                     elif ch == 'b':
550                         st += '\\b'
551                     elif ch == 'B':
552                         st += '\\B'
553                     elif ch == 'w':
554                         st += '\\w'
555                     elif ch == 'W':
556                         st += '\\W'
557                     elif ch == 'd':
558                         st += '\\d'
559                     elif ch == 'D':
560                         st += '\\D'
561                     elif ch == 's':
562                         st += template % u' \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff'
563                     elif ch == 'S':
564                         st += template % u'\u0000-\u0008\u000e-\u001f\u0021-\u009f\u00a1-\u167f\u1681-\u180d\u180f-\u1fff\u200b-\u2027\u202a-\u202e\u2030-\u205e\u2060-\u2fff\u3001-\ufefe\uff00-\uffff'
565                     else:
566                         if isDecimalDigit(ch):
567                             num = ch
568                             while self.index < self.length and isDecimalDigit(self.source[self.index]):
569                                 num += self.source[self.index]
570                                 self.index += 1
571                             st += '\\' + num
572
573                         else:
574                             st += ch  # DONT ESCAPE!!!
575                 else:
576                     self.lineNumber += 1
577                     if (ch == '\r' and self.source[self.index] == '\n'):
578                         self.index += 1
579                     self.lineStart = self.index
580             else:
581                 if ch == '[':
582                     inside_square = True
583                 elif ch == ']':
584                     inside_square = False
585                 st += ch
586         # print string, 'was transformed to', st
587         return st
588
589     def scanStringLiteral(self):
590         st = ''
591         octal = False
592
593         quote = self.source[self.index]
594         assert quote == '\'' or quote == '"', 'String literal must starts with a quote'
595         start = self.index;
596         self.index += 1
597
598         while (self.index < self.length):
599             ch = self.source[self.index]
600             self.index += 1
601             if (ch == quote):
602                 quote = ''
603                 break
604             elif (ch == '\\'):
605                 ch = self.source[self.index]
606                 self.index += 1
607                 if (not isLineTerminator(ch)):
608                     if ch in 'ux':
609                         if (self.source[self.index] == '{'):
610                             self.index += 1
611                             st += self.scanUnicodeCodePointEscape()
612                         else:
613                             unescaped = self.scanHexEscape(ch)
614                             if (not unescaped):
615                                 self.throwUnexpectedToken()  # with throw I don't know whats the difference
616                             st += unescaped
617                     elif ch == 'n':
618                         st += '\n';
619                     elif ch == 'r':
620                         st += '\r';
621                     elif ch == 't':
622                         st += '\t';
623                     elif ch == 'b':
624                         st += '\b';
625                     elif ch == 'f':
626                         st += '\f';
627                     elif ch == 'v':
628                         st += '\x0B'
629                     # elif ch in '89':
630                     #    self.throwUnexpectedToken() # again with throw....
631                     else:
632                         if isOctalDigit(ch):
633                             octToDec = self.octalToDecimal(ch)
634                             octal = octToDec.get('octal') or octal
635                             st += unichr(octToDec['code'])
636                         else:
637                             st += ch
638                 else:
639                     self.lineNumber += 1
640                     if (ch == '\r' and self.source[self.index] == '\n'):
641                         self.index += 1
642                     self.lineStart = self.index
643             elif isLineTerminator(ch):
644                 break
645             else:
646                 st += ch;
647         if (quote != ''):
648             self.throwUnexpectedToken()
649         return {
650             'type': Token.StringLiteral,
651             'value': st,
652             'octal': octal,
653             'lineNumber': self.lineNumber,
654             'lineStart': self.startLineStart,
655             'start': start,
656             'end': self.index}
657
658     def scanTemplate(self):
659         cooked = ''
660         terminated = False
661         tail = False
662         start = self.index
663         head = (self.source[self.index] == '`')
664         rawOffset = 2
665
666         self.index += 1
667
668         while (self.index < self.length):
669             ch = self.source[self.index]
670             self.index += 1
671             if (ch == '`'):
672                 rawOffset = 1;
673                 tail = True
674                 terminated = True
675                 break
676             elif (ch == '$'):
677                 if (self.source[self.index] == '{'):
678                     self.state['curlyStack'].append('${')
679                     self.index += 1
680                     terminated = True
681                     break;
682                 cooked += ch
683             elif (ch == '\\'):
684                 ch = self.source[self.index]
685                 self.index += 1
686                 if (not isLineTerminator(ch)):
687                     if ch == 'n':
688                         cooked += '\n'
689                     elif ch == 'r':
690                         cooked += '\r'
691                     elif ch == 't':
692                         cooked += '\t'
693                     elif ch in 'ux':
694                         if (self.source[self.index] == '{'):
695                             self.index += 1
696                             cooked += self.scanUnicodeCodePointEscape()
697                         else:
698                             restore = self.index
699                             unescaped = self.scanHexEscape(ch)
700                             if (unescaped):
701                                 cooked += unescaped
702                             else:
703                                 self.index = restore
704                                 cooked += ch
705                     elif ch == 'b':
706                         cooked += '\b'
707                     elif ch == 'f':
708                         cooked += '\f'
709                     elif ch == 'v':
710                         cooked += '\v'
711                     else:
712                         if (ch == '0'):
713                             if isDecimalDigit(self.ccode()):
714                                 # Illegal: \01 \02 and so on
715                                 self.throwError(Messages.TemplateOctalLiteral)
716                             cooked += '\0'
717                         elif (isOctalDigit(ch)):
718                             # Illegal: \1 \2
719                             self.throwError(Messages.TemplateOctalLiteral)
720                         else:
721                             cooked += ch
722                 else:
723                     self.lineNumber += 1
724                     if (ch == '\r' and self.source[self.index] == '\n'):
725                         self.index += 1
726                     self.lineStart = self.index
727             elif (isLineTerminator(ch)):
728                 self.lineNumber += 1
729                 if (ch == '\r' and self.source[self.index] == '\n'):
730                     self.index += 1
731                 self.lineStart = self.index
732                 cooked += '\n'
733             else:
734                 cooked += ch;
735         if (not terminated):
736             self.throwUnexpectedToken()
737
738         if (not head):
739             self.state['curlyStack'].pop();
740
741         return {
742             'type': Token.Template,
743             'value': {
744                 'cooked': cooked,
745                 'raw': self.source[start + 1:self.index - rawOffset]},
746             'head': head,
747             'tail': tail,
748             'lineNumber': self.lineNumber,
749             'lineStart': self.lineStart,
750             'start': start,
751             'end': self.index}
752
753     def testRegExp(self, pattern, flags):
754         # todo: you should return python regexp object
755         return (pattern, flags)
756
757     def scanRegExpBody(self):
758         ch = self.source[self.index]
759         assert ch == '/', 'Regular expression literal must start with a slash'
760         st = ch
761         self.index += 1
762
763         classMarker = False
764         terminated = False
765         while (self.index < self.length):
766             ch = self.source[self.index]
767             self.index += 1
768             st += ch
769             if (ch == '\\'):
770                 ch = self.source[self.index]
771                 self.index += 1
772                 # ECMA-262 7.8.5
773                 if (isLineTerminator(ch)):
774                     self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
775                 st += ch
776             elif (isLineTerminator(ch)):
777                 self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
778             elif (classMarker):
779                 if (ch == ']'):
780                     classMarker = False
781             else:
782                 if (ch == '/'):
783                     terminated = True
784                     break
785                 elif (ch == '['):
786                     classMarker = True;
787         if (not terminated):
788             self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
789
790         # Exclude leading and trailing slash.
791         body = st[1:-1]
792         return {
793             'value': body,
794             'literal': st}
795
796     def scanRegExpFlags(self):
797         st = ''
798         flags = ''
799         while (self.index < self.length):
800             ch = self.source[self.index]
801             if (not isIdentifierPart(ch)):
802                 break
803             self.index += 1
804             if (ch == '\\' and self.index < self.length):
805                 ch = self.source[self.index]
806                 if (ch == 'u'):
807                     self.index += 1
808                     restore = self.index
809                     ch = self.scanHexEscape('u')
810                     if (ch):
811                         flags += ch
812                         st += '\\u'
813                         while restore < self.index:
814                             st += self.source[restore]
815                             restore += 1
816                     else:
817                         self.index = restore
818                         flags += 'u'
819                         st += '\\u'
820                     self.tolerateUnexpectedToken()
821                 else:
822                     st += '\\'
823                     self.tolerateUnexpectedToken()
824             else:
825                 flags += ch
826                 st += ch
827         return {
828             'value': flags,
829             'literal': st}
830
831     def scanRegExp(self):
832         self.scanning = True
833         self.lookahead = None
834         self.skipComment()
835         start = self.index
836
837         body = self.scanRegExpBody()
838         flags = self.scanRegExpFlags()
839         value = self.testRegExp(body['value'], flags['value'])
840         scanning = False
841         return {
842             'literal': body['literal'] + flags['literal'],
843             'value': value,
844             'regex': {
845                 'pattern': body['value'],
846                 'flags': flags['value']
847             },
848             'start': start,
849             'end': self.index}
850
851     def collectRegex(self):
852         self.skipComment();
853         return self.scanRegExp()
854
855     def isIdentifierName(self, token):
856         return token['type'] in (1, 3, 4, 5)
857
858     # def advanceSlash(self): ???
859
860     def advance(self):
861         if (self.index >= self.length):
862             return {
863                 'type': Token.EOF,
864                 'lineNumber': self.lineNumber,
865                 'lineStart': self.lineStart,
866                 'start': self.index,
867                 'end': self.index}
868         ch = self.ccode()
869
870         if isIdentifierStart(ch):
871             token = self.scanIdentifier()
872             if (self.strict and isStrictModeReservedWord(token['value'])):
873                 token['type'] = Token.Keyword
874             return token
875         # Very common: ( and ) and ;
876         if (ch == 0x28 or ch == 0x29 or ch == 0x3B):
877             return self.scanPunctuator()
878
879         # String literal starts with single quote (U+0027) or double quote (U+0022).
880         if (ch == 0x27 or ch == 0x22):
881             return self.scanStringLiteral()
882
883         # Dot (.) U+002E can also start a floating-point number, hence the need
884         # to check the next character.
885         if (ch == 0x2E):
886             if (isDecimalDigit(self.ccode(1))):
887                 return self.scanNumericLiteral()
888             return self.scanPunctuator();
889
890         if (isDecimalDigit(ch)):
891             return self.scanNumericLiteral()
892
893         # Slash (/) U+002F can also start a regex.
894         # if (extra.tokenize && ch == 0x2F):
895         #    return advanceSlash();
896
897         # Template literals start with ` (U+0060) for template head
898         # or } (U+007D) for template middle or template tail.
899         if (ch == 0x60 or (ch == 0x7D and self.state['curlyStack'][len(self.state['curlyStack']) - 1] == '${')):
900             return self.scanTemplate()
901         return self.scanPunctuator();
902
903     # def collectToken(self):
904     #    loc = {
905     #        'start': {
906     #            'line': self.lineNumber,
907     #            'column': self.index - self.lineStart}}
908     #
909     #    token = self.advance()
910     #
911     #    loc['end'] = {
912     #        'line': self.lineNumber,
913     #        'column': self.index - self.lineStart}
914     #    if (token['type'] != Token.EOF):
915     #        value = self.source[token['start']: token['end']]
916     #        entry = {
917     #            'type': TokenName[token['type']],
918     #            'value': value,
919     #            'range': [token['start'], token['end']],
920     #            'loc': loc}
921     #        if (token.get('regex')):
922     #            entry['regex'] = {
923     #                'pattern': token['regex']['pattern'],
924     #                'flags': token['regex']['flags']}
925     #        self.extra['tokens'].append(entry)
926     #    return token;
927
928
929     def lex(self):
930         self.scanning = True
931
932         self.lastIndex = self.index
933         self.lastLineNumber = self.lineNumber
934         self.lastLineStart = self.lineStart
935
936         self.skipComment()
937
938         token = self.lookahead
939
940         self.startIndex = self.index
941         self.startLineNumber = self.lineNumber
942         self.startLineStart = self.lineStart
943
944         self.lookahead = self.advance()
945         self.scanning = False
946         return token
947
948     def peek(self):
949         self.scanning = True
950
951         self.skipComment()
952
953         self.lastIndex = self.index
954         self.lastLineNumber = self.lineNumber
955         self.lastLineStart = self.lineStart
956
957         self.startIndex = self.index
958         self.startLineNumber = self.lineNumber
959         self.startLineStart = self.lineStart
960
961         self.lookahead = self.advance()
962         self.scanning = False
963
964     def createError(self, line, pos, description):
965         global ENABLE_PYIMPORT
966         if ENABLE_JS2PY_ERRORS:
967             old_pyimport = ENABLE_PYIMPORT  # ENABLE_PYIMPORT will be affected by js2py import
968             self.log_err_case()
969             try:
970                 from js2py.base import ERRORS, Js, JsToPyException
971             except:
972                 raise Exception("ENABLE_JS2PY_ERRORS was set to True, but Js2Py was not found!")
973             ENABLE_PYIMPORT = old_pyimport
974             error = ERRORS['SyntaxError']('Line ' + unicode(line) + ': ' + unicode(description))
975             error.put('index', Js(pos))
976             error.put('lineNumber', Js(line))
977             error.put('column', Js(pos - (self.lineStart if self.scanning else self.lastLineStart) + 1))
978             error.put('description', Js(description))
979             return JsToPyException(error)
980         else:
981             return JsSyntaxError('Line ' + unicode(line) + ': ' + unicode(description))
982
983
984     # Throw an exception
985
986     def throwError(self, messageFormat, *args):
987         msg = messageFormat % tuple(unicode(e) for e in args)
988         raise self.createError(self.lastLineNumber, self.lastIndex, msg);
989
990     def tolerateError(self, messageFormat, *args):
991         return self.throwError(messageFormat, *args)
992
993     # Throw an exception because of the token.
994
995     def unexpectedTokenError(self, token={}, message=''):
996         msg = message or Messages.UnexpectedToken
997         if (token):
998             typ = token['type']
999             if (not message):
1000                 if typ == Token.EOF:
1001                     msg = Messages.UnexpectedEOS
1002                 elif (typ == Token.Identifier):
1003                     msg = Messages.UnexpectedIdentifier
1004                 elif (typ == Token.NumericLiteral):
1005                     msg = Messages.UnexpectedNumber
1006                 elif (typ == Token.StringLiteral):
1007                     msg = Messages.UnexpectedString
1008                 elif (typ == Token.Template):
1009                     msg = Messages.UnexpectedTemplate
1010                 else:
1011                     msg = Messages.UnexpectedToken;
1012                 if (typ == Token.Keyword):
1013                     if (isFutureReservedWord(token['value'])):
1014                         msg = Messages.UnexpectedReserved
1015                     elif (self.strict and isStrictModeReservedWord(token['value'])):
1016                         msg = Messages.StrictReservedWord
1017             value = token['value']['raw'] if (typ == Token.Template)  else token.get('value')
1018         else:
1019             value = 'ILLEGAL'
1020         msg = msg.replace('%s', unicode(value))
1021
1022         return (self.createError(token['lineNumber'], token['start'], msg) if (token and token.get('lineNumber')) else
1023                 self.createError(self.lineNumber if self.scanning else self.lastLineNumber,
1024                                  self.index if self.scanning else self.lastIndex, msg))
1025
1026     def throwUnexpectedToken(self, token={}, message=''):
1027         raise self.unexpectedTokenError(token, message)
1028
1029     def tolerateUnexpectedToken(self, token={}, message=''):
1030         self.throwUnexpectedToken(token, message)
1031
1032     # Expect the next token to match the specified punctuator.
1033     # If not, an exception will be thrown.
1034
1035     def expect(self, value):
1036         token = self.lex()
1037         if (token['type'] != Token.Punctuator or token['value'] != value):
1038             self.throwUnexpectedToken(token)
1039
1040     # /**
1041     # * @name expectCommaSeparator
1042     # * @description Quietly expect a comma when in tolerant mode, otherwise delegates
1043     # * to <code>expect(value)</code>
1044     # * @since 2.0
1045     # */
1046     def expectCommaSeparator(self):
1047         self.expect(',')
1048
1049     # Expect the next token to match the specified keyword.
1050     # If not, an exception will be thrown.
1051
1052     def expectKeyword(self, keyword):
1053         token = self.lex();
1054         if (token['type'] != Token.Keyword or token['value'] != keyword):
1055             self.throwUnexpectedToken(token)
1056
1057     # Return true if the next token matches the specified punctuator.
1058
1059     def match(self, value):
1060         return self.lookahead['type'] == Token.Punctuator and self.lookahead['value'] == value
1061
1062     # Return true if the next token matches the specified keyword
1063
1064     def matchKeyword(self, keyword):
1065         return self.lookahead['type'] == Token.Keyword and self.lookahead['value'] == keyword
1066
1067     # Return true if the next token matches the specified contextual keyword
1068     # (where an identifier is sometimes a keyword depending on the context)
1069
1070     def matchContextualKeyword(self, keyword):
1071         return self.lookahead['type'] == Token.Identifier and self.lookahead['value'] == keyword
1072
1073     # Return true if the next token is an assignment operator
1074
1075     def matchAssign(self):
1076         if (self.lookahead['type'] != Token.Punctuator):
1077             return False;
1078         op = self.lookahead['value']
1079         return op in ('=', '*=', '/=', '%=', '+=', '-=', '<<=', '>>=', '>>>=', '&=', '^=', '|=')
1080
1081     def consumeSemicolon(self):
1082         # Catch the very common case first: immediately a semicolon (U+003B).
1083
1084         if (self.at(self.startIndex) == ';' or self.match(';')):
1085             self.lex()
1086             return
1087
1088         if (self.hasLineTerminator):
1089             return
1090
1091         # TODO: FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
1092         self.lastIndex = self.startIndex
1093         self.lastLineNumber = self.startLineNumber
1094         self.lastLineStart = self.startLineStart
1095
1096         if (self.lookahead['type'] != Token.EOF and not self.match('}')):
1097             self.throwUnexpectedToken(self.lookahead)
1098
1099     # // Cover grammar support.
1100     # //
1101     # // When an assignment expression position starts with an left parenthesis, the determination of the type
1102     # // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
1103     # // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
1104     # //
1105     # // There are three productions that can be parsed in a parentheses pair that needs to be determined
1106     # // after the outermost pair is closed. They are:
1107     # //
1108     # //   1. AssignmentExpression
1109     # //   2. BindingElements
1110     # //   3. AssignmentTargets
1111     # //
1112     # // In order to avoid exponential backtracking, we use two flags to denote if the production can be
1113     # // binding element or assignment target.
1114     # //
1115     # // The three productions have the relationship:
1116     # //
1117     # //   BindingElements <= AssignmentTargets <= AssignmentExpression
1118     # //
1119     # // with a single exception that CoverInitializedName when used directly in an Expression, generates
1120     # // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
1121     # // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
1122     # //
1123     # // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
1124     # // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
1125     # // the CoverInitializedName check is conducted.
1126     # //
1127     # // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
1128     # // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
1129     # // pattern. The CoverInitializedName check is deferred.
1130
1131     def isolateCoverGrammar(self, parser):
1132         oldIsBindingElement = self.isBindingElement
1133         oldIsAssignmentTarget = self.isAssignmentTarget
1134         oldFirstCoverInitializedNameError = self.firstCoverInitializedNameError
1135         self.isBindingElement = true
1136         self.isAssignmentTarget = true
1137         self.firstCoverInitializedNameError = null
1138         result = parser()
1139         if (self.firstCoverInitializedNameError != null):
1140             self.throwUnexpectedToken(self.firstCoverInitializedNameError)
1141         self.isBindingElement = oldIsBindingElement
1142         self.isAssignmentTarget = oldIsAssignmentTarget
1143         self.firstCoverInitializedNameError = oldFirstCoverInitializedNameError
1144         return result
1145
1146     def inheritCoverGrammar(self, parser):
1147         oldIsBindingElement = self.isBindingElement
1148         oldIsAssignmentTarget = self.isAssignmentTarget
1149         oldFirstCoverInitializedNameError = self.firstCoverInitializedNameError
1150         self.isBindingElement = true
1151         self.isAssignmentTarget = true
1152         self.firstCoverInitializedNameError = null
1153         result = parser()
1154         self.isBindingElement = self.isBindingElement and oldIsBindingElement
1155         self.isAssignmentTarget = self.isAssignmentTarget and oldIsAssignmentTarget
1156         self.firstCoverInitializedNameError = oldFirstCoverInitializedNameError or self.firstCoverInitializedNameError
1157         return result
1158
1159     def parseArrayPattern(self):
1160         node = Node()
1161         elements = []
1162         self.expect('[');
1163         while (not self.match(']')):
1164             if (self.match(',')):
1165                 self.lex()
1166                 elements.append(null)
1167             else:
1168                 if (self.match('...')):
1169                     restNode = Node()
1170                     self.lex()
1171                     rest = self.parseVariableIdentifier()
1172                     elements.append(restNode.finishRestElement(rest))
1173                     break
1174                 else:
1175                     elements.append(self.parsePatternWithDefault())
1176                 if (not self.match(']')):
1177                     self.expect(',')
1178         self.expect(']')
1179         return node.finishArrayPattern(elements)
1180
1181     def parsePropertyPattern(self):
1182         node = Node()
1183         computed = self.match('[')
1184         if (self.lookahead['type'] == Token.Identifier):
1185             key = self.parseVariableIdentifier()
1186             if (self.match('=')):
1187                 self.lex();
1188                 init = self.parseAssignmentExpression()
1189                 return node.finishProperty(
1190                     'init', key, false, WrappingNode(key).finishAssignmentPattern(key, init), false, false)
1191             elif (not self.match(':')):
1192                 return node.finishProperty('init', key, false, key, false, true)
1193         else:
1194             key = self.parseObjectPropertyKey()
1195         self.expect(':')
1196         init = self.parsePatternWithDefault()
1197         return node.finishProperty('init', key, computed, init, false, false)
1198
1199     def parseObjectPattern(self):
1200         node = Node()
1201         properties = []
1202         self.expect('{')
1203         while (not self.match('}')):
1204             properties.append(self.parsePropertyPattern())
1205             if (not self.match('}')):
1206                 self.expect(',')
1207         self.lex()
1208         return node.finishObjectPattern(properties)
1209
1210     def parsePattern(self):
1211         if (self.lookahead['type'] == Token.Identifier):
1212             return self.parseVariableIdentifier()
1213         elif (self.match('[')):
1214             return self.parseArrayPattern()
1215         elif (self.match('{')):
1216             return self.parseObjectPattern()
1217         self.throwUnexpectedToken(self.lookahead)
1218
1219     def parsePatternWithDefault(self):
1220         startToken = self.lookahead
1221
1222         pattern = self.parsePattern()
1223         if (self.match('=')):
1224             self.lex()
1225             right = self.isolateCoverGrammar(self.parseAssignmentExpression)
1226             pattern = WrappingNode(startToken).finishAssignmentPattern(pattern, right)
1227         return pattern
1228
1229     # 11.1.4 Array Initialiser
1230
1231     def parseArrayInitialiser(self):
1232         elements = []
1233         node = Node()
1234
1235         self.expect('[')
1236
1237         while (not self.match(']')):
1238             if (self.match(',')):
1239                 self.lex()
1240                 elements.append(null)
1241             elif (self.match('...')):
1242                 restSpread = Node()
1243                 self.lex()
1244                 restSpread.finishSpreadElement(self.inheritCoverGrammar(self.parseAssignmentExpression))
1245                 if (not self.match(']')):
1246                     self.isAssignmentTarget = self.isBindingElement = false
1247                     self.expect(',')
1248                 elements.append(restSpread)
1249             else:
1250                 elements.append(self.inheritCoverGrammar(self.parseAssignmentExpression))
1251                 if (not self.match(']')):
1252                     self.expect(',')
1253         self.lex();
1254
1255         return node.finishArrayExpression(elements)
1256
1257     # 11.1.5 Object Initialiser
1258
1259     def parsePropertyFunction(self, node, paramInfo):
1260
1261         self.isAssignmentTarget = self.isBindingElement = false;
1262
1263         previousStrict = self.strict;
1264         body = self.isolateCoverGrammar(self.parseFunctionSourceElements);
1265
1266         if (self.strict and paramInfo['firstRestricted']):
1267             self.tolerateUnexpectedToken(paramInfo['firstRestricted'], paramInfo.get('message'))
1268         if (self.strict and paramInfo['stricted']):
1269             self.tolerateUnexpectedToken(paramInfo['stricted'], paramInfo.get('message'));
1270
1271         self.strict = previousStrict;
1272         return node.finishFunctionExpression(null, paramInfo['params'], paramInfo['defaults'], body)
1273
1274     def parsePropertyMethodFunction(self):
1275         node = Node();
1276
1277         params = self.parseParams();
1278         method = self.parsePropertyFunction(node, params);
1279         return method;
1280
1281     def parseObjectPropertyKey(self):
1282         node = Node()
1283
1284         token = self.lex();
1285
1286         # // Note: This function is called only from parseObjectProperty(), where
1287         # // EOF and Punctuator tokens are already filtered out.
1288
1289         typ = token['type']
1290
1291         if typ in [Token.StringLiteral, Token.NumericLiteral]:
1292             if self.strict and token.get('octal'):
1293                 self.tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
1294             return node.finishLiteral(token);
1295         elif typ in (Token.Identifier, Token.BooleanLiteral, Token.NullLiteral, Token.Keyword):
1296             return node.finishIdentifier(token['value']);
1297         elif typ == Token.Punctuator:
1298             if (token['value'] == '['):
1299                 expr = self.isolateCoverGrammar(self.parseAssignmentExpression)
1300                 self.expect(']')
1301                 return expr
1302         self.throwUnexpectedToken(token)
1303
1304     def lookaheadPropertyName(self):
1305         typ = self.lookahead['type']
1306         if typ in (Token.Identifier, Token.StringLiteral, Token.BooleanLiteral, Token.NullLiteral, Token.NumericLiteral,
1307                    Token.Keyword):
1308             return true
1309         if typ == Token.Punctuator:
1310             return self.lookahead['value'] == '['
1311         return false
1312
1313     # // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
1314     # // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
1315     # // This can only be determined after we consumed up to the left parentheses.
1316     # //
1317     # // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
1318     # // is responsible to visit other options.
1319     def tryParseMethodDefinition(self, token, key, computed, node):
1320         if (token['type'] == Token.Identifier):
1321             # check for `get` and `set`;
1322
1323             if (token['value'] == 'get' and self.lookaheadPropertyName()):
1324                 computed = self.match('[');
1325                 key = self.parseObjectPropertyKey()
1326                 methodNode = Node()
1327                 self.expect('(')
1328                 self.expect(')')
1329                 value = self.parsePropertyFunction(methodNode, {
1330                     'params': [],
1331                     'defaults': [],
1332                     'stricted': null,
1333                     'firstRestricted': null,
1334                     'message': null
1335                 })
1336                 return node.finishProperty('get', key, computed, value, false, false)
1337             elif (token['value'] == 'set' and self.lookaheadPropertyName()):
1338                 computed = self.match('[')
1339                 key = self.parseObjectPropertyKey()
1340                 methodNode = Node()
1341                 self.expect('(')
1342
1343                 options = {
1344                     'params': [],
1345                     'defaultCount': 0,
1346                     'defaults': [],
1347                     'firstRestricted': null,
1348                     'paramSet': {}
1349                 }
1350                 if (self.match(')')):
1351                     self.tolerateUnexpectedToken(self.lookahead);
1352                 else:
1353                     self.parseParam(options);
1354                     if (options['defaultCount'] == 0):
1355                         options['defaults'] = []
1356                 self.expect(')')
1357
1358                 value = self.parsePropertyFunction(methodNode, options);
1359                 return node.finishProperty('set', key, computed, value, false, false);
1360         if (self.match('(')):
1361             value = self.parsePropertyMethodFunction();
1362             return node.finishProperty('init', key, computed, value, true, false)
1363         return null;
1364
1365     def checkProto(self, key, computed, hasProto):
1366         if (computed == false and (key['type'] == Syntax.Identifier and key['name'] == '__proto__' or
1367                                                key['type'] == Syntax.Literal and key['value'] == '__proto__')):
1368             if (hasProto['value']):
1369                 self.tolerateError(Messages.DuplicateProtoProperty);
1370             else:
1371                 hasProto['value'] = true;
1372
1373     def parseObjectProperty(self, hasProto):
1374         token = self.lookahead
1375         node = Node()
1376
1377         computed = self.match('[');
1378         key = self.parseObjectPropertyKey();
1379         maybeMethod = self.tryParseMethodDefinition(token, key, computed, node)
1380
1381         if (maybeMethod):
1382             self.checkProto(maybeMethod['key'], maybeMethod['computed'], hasProto);
1383             return maybeMethod;
1384
1385         # // init property or short hand property.
1386         self.checkProto(key, computed, hasProto);
1387
1388         if (self.match(':')):
1389             self.lex();
1390             value = self.inheritCoverGrammar(self.parseAssignmentExpression)
1391             return node.finishProperty('init', key, computed, value, false, false)
1392
1393         if (token['type'] == Token.Identifier):
1394             if (self.match('=')):
1395                 self.firstCoverInitializedNameError = self.lookahead;
1396                 self.lex();
1397                 value = self.isolateCoverGrammar(self.parseAssignmentExpression);
1398                 return node.finishProperty('init', key, computed,
1399                                            WrappingNode(token).finishAssignmentPattern(key, value), false, true)
1400             return node.finishProperty('init', key, computed, key, false, true)
1401         self.throwUnexpectedToken(self.lookahead)
1402
1403     def parseObjectInitialiser(self):
1404         properties = []
1405         hasProto = {'value': false}
1406         node = Node();
1407
1408         self.expect('{');
1409
1410         while (not self.match('}')):
1411             properties.append(self.parseObjectProperty(hasProto));
1412
1413             if (not self.match('}')):
1414                 self.expectCommaSeparator()
1415         self.expect('}');
1416         return node.finishObjectExpression(properties)
1417
1418     def reinterpretExpressionAsPattern(self, expr):
1419         typ = (expr['type'])
1420         if typ in (Syntax.Identifier, Syntax.MemberExpression, Syntax.RestElement, Syntax.AssignmentPattern):
1421             pass
1422         elif typ == Syntax.SpreadElement:
1423             expr['type'] = Syntax.RestElement
1424             self.reinterpretExpressionAsPattern(expr.argument)
1425         elif typ == Syntax.ArrayExpression:
1426             expr['type'] = Syntax.ArrayPattern
1427             for i in xrange(len(expr['elements'])):
1428                 if (expr['elements'][i] != null):
1429                     self.reinterpretExpressionAsPattern(expr['elements'][i])
1430         elif typ == Syntax.ObjectExpression:
1431             expr['type'] = Syntax.ObjectPattern
1432             for i in xrange(len(expr['properties'])):
1433                 self.reinterpretExpressionAsPattern(expr['properties'][i]['value']);
1434         elif Syntax.AssignmentExpression:
1435             expr['type'] = Syntax.AssignmentPattern;
1436             self.reinterpretExpressionAsPattern(expr['left'])
1437         else:
1438             # // Allow other node type for tolerant parsing.
1439             return
1440
1441     def parseTemplateElement(self, option):
1442
1443         if (self.lookahead['type'] != Token.Template or (option['head'] and not self.lookahead['head'])):
1444             self.throwUnexpectedToken()
1445
1446         node = Node();
1447         token = self.lex();
1448
1449         return node.finishTemplateElement({'raw': token['value']['raw'], 'cooked': token['value']['cooked']},
1450                                           token['tail'])
1451
1452     def parseTemplateLiteral(self):
1453         node = Node()
1454
1455         quasi = self.parseTemplateElement({'head': true})
1456         quasis = [quasi]
1457         expressions = []
1458
1459         while (not quasi['tail']):
1460             expressions.append(self.parseExpression());
1461             quasi = self.parseTemplateElement({'head': false});
1462             quasis.append(quasi)
1463         return node.finishTemplateLiteral(quasis, expressions)
1464
1465     # 11.1.6 The Grouping Operator
1466
1467     def parseGroupExpression(self):
1468         self.expect('(');
1469
1470         if (self.match(')')):
1471             self.lex();
1472             if (not self.match('=>')):
1473                 self.expect('=>')
1474             return {
1475                 'type': PlaceHolders.ArrowParameterPlaceHolder,
1476                 'params': []}
1477
1478         startToken = self.lookahead
1479         if (self.match('...')):
1480             expr = self.parseRestElement();
1481             self.expect(')');
1482             if (not self.match('=>')):
1483                 self.expect('=>')
1484             return {
1485                 'type': PlaceHolders.ArrowParameterPlaceHolder,
1486                 'params': [expr]}
1487
1488         self.isBindingElement = true;
1489         expr = self.inheritCoverGrammar(self.parseAssignmentExpression);
1490
1491         if (self.match(',')):
1492             self.isAssignmentTarget = false;
1493             expressions = [expr]
1494
1495             while (self.startIndex < self.length):
1496                 if (not self.match(',')):
1497                     break
1498                 self.lex();
1499
1500                 if (self.match('...')):
1501                     if (not self.isBindingElement):
1502                         self.throwUnexpectedToken(self.lookahead)
1503                     expressions.append(self.parseRestElement())
1504                     self.expect(')');
1505                     if (not self.match('=>')):
1506                         self.expect('=>');
1507                     self.isBindingElement = false
1508                     for i in xrange(len(expressions)):
1509                         self.reinterpretExpressionAsPattern(expressions[i])
1510                     return {
1511                         'type': PlaceHolders.ArrowParameterPlaceHolder,
1512                         'params': expressions}
1513                 expressions.append(self.inheritCoverGrammar(self.parseAssignmentExpression))
1514             expr = WrappingNode(startToken).finishSequenceExpression(expressions);
1515         self.expect(')')
1516
1517         if (self.match('=>')):
1518             if (not self.isBindingElement):
1519                 self.throwUnexpectedToken(self.lookahead);
1520             if (expr['type'] == Syntax.SequenceExpression):
1521                 for i in xrange(len(expr.expressions)):
1522                     self.reinterpretExpressionAsPattern(expr['expressions'][i])
1523             else:
1524                 self.reinterpretExpressionAsPattern(expr);
1525             expr = {
1526                 'type': PlaceHolders.ArrowParameterPlaceHolder,
1527                 'params': expr['expressions'] if expr['type'] == Syntax.SequenceExpression  else [expr]}
1528         self.isBindingElement = false
1529         return expr
1530
1531     # 11.1 Primary Expressions
1532
1533     def parsePrimaryExpression(self):
1534         if (self.match('(')):
1535             self.isBindingElement = false;
1536             return self.inheritCoverGrammar(self.parseGroupExpression)
1537         if (self.match('[')):
1538             return self.inheritCoverGrammar(self.parseArrayInitialiser)
1539
1540         if (self.match('{')):
1541             return self.inheritCoverGrammar(self.parseObjectInitialiser)
1542
1543         typ = self.lookahead['type']
1544         node = Node();
1545
1546         if (typ == Token.Identifier):
1547             expr = node.finishIdentifier(self.lex()['value']);
1548         elif (typ == Token.StringLiteral or typ == Token.NumericLiteral):
1549             self.isAssignmentTarget = self.isBindingElement = false
1550             if (self.strict and self.lookahead.get('octal')):
1551                 self.tolerateUnexpectedToken(self.lookahead, Messages.StrictOctalLiteral)
1552             expr = node.finishLiteral(self.lex())
1553         elif (typ == Token.Keyword):
1554             self.isAssignmentTarget = self.isBindingElement = false
1555             if (self.matchKeyword('function')):
1556                 return self.parseFunctionExpression()
1557             if (self.matchKeyword('this')):
1558                 self.lex()
1559                 return node.finishThisExpression()
1560             if (self.matchKeyword('class')):
1561                 return self.parseClassExpression()
1562             self.throwUnexpectedToken(self.lex())
1563         elif (typ == Token.BooleanLiteral):
1564             isAssignmentTarget = self.isBindingElement = false
1565             token = self.lex();
1566             token['value'] = (token['value'] == 'true')
1567             expr = node.finishLiteral(token)
1568         elif (typ == Token.NullLiteral):
1569             self.isAssignmentTarget = self.isBindingElement = false
1570             token = self.lex()
1571             token['value'] = null;
1572             expr = node.finishLiteral(token)
1573         elif (self.match('/') or self.match('/=')):
1574             self.isAssignmentTarget = self.isBindingElement = false;
1575             self.index = self.startIndex;
1576             token = self.scanRegExp();  # hehe, here you are!
1577             self.lex();
1578             expr = node.finishLiteral(token);
1579         elif (typ == Token.Template):
1580             expr = self.parseTemplateLiteral()
1581         else:
1582             self.throwUnexpectedToken(self.lex());
1583         return expr;
1584
1585     # 11.2 Left-Hand-Side Expressions
1586
1587     def parseArguments(self):
1588         args = [];
1589
1590         self.expect('(');
1591         if (not self.match(')')):
1592             while (self.startIndex < self.length):
1593                 args.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
1594                 if (self.match(')')):
1595                     break
1596                 self.expectCommaSeparator()
1597         self.expect(')')
1598         return args;
1599
1600     def parseNonComputedProperty(self):
1601         node = Node()
1602
1603         token = self.lex();
1604
1605         if (not self.isIdentifierName(token)):
1606             self.throwUnexpectedToken(token)
1607         return node.finishIdentifier(token['value'])
1608
1609     def parseNonComputedMember(self):
1610         self.expect('.')
1611         return self.parseNonComputedProperty();
1612
1613     def parseComputedMember(self):
1614         self.expect('[')
1615
1616         expr = self.isolateCoverGrammar(self.parseExpression)
1617         self.expect(']')
1618
1619         return expr
1620
1621     def parseNewExpression(self):
1622         node = Node()
1623         self.expectKeyword('new')
1624         callee = self.isolateCoverGrammar(self.parseLeftHandSideExpression)
1625         args = self.parseArguments() if self.match('(') else []
1626
1627         self.isAssignmentTarget = self.isBindingElement = false
1628
1629         return node.finishNewExpression(callee, args)
1630
1631     def parseLeftHandSideExpressionAllowCall(self):
1632         previousAllowIn = self.state['allowIn']
1633
1634         startToken = self.lookahead;
1635         self.state['allowIn'] = true;
1636
1637         if (self.matchKeyword('super') and self.state['inFunctionBody']):
1638             expr = Node();
1639             self.lex();
1640             expr = expr.finishSuper()
1641             if (not self.match('(') and not self.match('.') and not self.match('[')):
1642                 self.throwUnexpectedToken(self.lookahead);
1643         else:
1644             expr = self.inheritCoverGrammar(
1645                 self.parseNewExpression if self.matchKeyword('new') else self.parsePrimaryExpression)
1646         while True:
1647             if (self.match('.')):
1648                 self.isBindingElement = false;
1649                 self.isAssignmentTarget = true;
1650                 property = self.parseNonComputedMember();
1651                 expr = WrappingNode(startToken).finishMemberExpression('.', expr, property)
1652             elif (self.match('(')):
1653                 self.isBindingElement = false;
1654                 self.isAssignmentTarget = false;
1655                 args = self.parseArguments();
1656                 expr = WrappingNode(startToken).finishCallExpression(expr, args)
1657             elif (self.match('[')):
1658                 self.isBindingElement = false;
1659                 self.isAssignmentTarget = true;
1660                 property = self.parseComputedMember();
1661                 expr = WrappingNode(startToken).finishMemberExpression('[', expr, property)
1662             elif (self.lookahead['type'] == Token.Template and self.lookahead['head']):
1663                 quasi = self.parseTemplateLiteral()
1664                 expr = WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi)
1665             else:
1666                 break
1667         self.state['allowIn'] = previousAllowIn
1668
1669         return expr
1670
1671     def parseLeftHandSideExpression(self):
1672         assert self.state['allowIn'], 'callee of new expression always allow in keyword.'
1673
1674         startToken = self.lookahead
1675
1676         if (self.matchKeyword('super') and self.state['inFunctionBody']):
1677             expr = Node();
1678             self.lex();
1679             expr = expr.finishSuper();
1680             if (not self.match('[') and not self.match('.')):
1681                 self.throwUnexpectedToken(self.lookahead)
1682         else:
1683             expr = self.inheritCoverGrammar(
1684                 self.parseNewExpression if self.matchKeyword('new') else self.parsePrimaryExpression);
1685
1686         while True:
1687             if (self.match('[')):
1688                 self.isBindingElement = false;
1689                 self.isAssignmentTarget = true;
1690                 property = self.parseComputedMember();
1691                 expr = WrappingNode(startToken).finishMemberExpression('[', expr, property)
1692             elif (self.match('.')):
1693                 self.isBindingElement = false;
1694                 self.isAssignmentTarget = true;
1695                 property = self.parseNonComputedMember();
1696                 expr = WrappingNode(startToken).finishMemberExpression('.', expr, property);
1697             elif (self.lookahead['type'] == Token.Template and self.lookahead['head']):
1698                 quasi = self.parseTemplateLiteral();
1699                 expr = WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi)
1700             else:
1701                 break
1702         return expr
1703
1704     # 11.3 Postfix Expressions
1705
1706     def parsePostfixExpression(self):
1707         startToken = self.lookahead
1708
1709         expr = self.inheritCoverGrammar(self.parseLeftHandSideExpressionAllowCall)
1710
1711         if (not self.hasLineTerminator and self.lookahead['type'] == Token.Punctuator):
1712             if (self.match('++') or self.match('--')):
1713                 # 11.3.1, 11.3.2
1714                 if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
1715                     self.tolerateError(Messages.StrictLHSPostfix)
1716                 if (not self.isAssignmentTarget):
1717                     self.tolerateError(Messages.InvalidLHSInAssignment);
1718                 self.isAssignmentTarget = self.isBindingElement = false;
1719
1720                 token = self.lex();
1721                 expr = WrappingNode(startToken).finishPostfixExpression(token['value'], expr);
1722         return expr;
1723
1724     # 11.4 Unary Operators
1725
1726     def parseUnaryExpression(self):
1727
1728         if (self.lookahead['type'] != Token.Punctuator and self.lookahead['type'] != Token.Keyword):
1729             expr = self.parsePostfixExpression();
1730         elif (self.match('++') or self.match('--')):
1731             startToken = self.lookahead;
1732             token = self.lex();
1733             expr = self.inheritCoverGrammar(self.parseUnaryExpression);
1734             # 11.4.4, 11.4.5
1735             if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
1736                 self.tolerateError(Messages.StrictLHSPrefix)
1737             if (not self.isAssignmentTarget):
1738                 self.tolerateError(Messages.InvalidLHSInAssignment)
1739             expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr)
1740             self.isAssignmentTarget = self.isBindingElement = false
1741         elif (self.match('+') or self.match('-') or self.match('~') or self.match('!')):
1742             startToken = self.lookahead;
1743             token = self.lex();
1744             expr = self.inheritCoverGrammar(self.parseUnaryExpression);
1745             expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr)
1746             self.isAssignmentTarget = self.isBindingElement = false;
1747         elif (self.matchKeyword('delete') or self.matchKeyword('void') or self.matchKeyword('typeof')):
1748             startToken = self.lookahead;
1749             token = self.lex();
1750             expr = self.inheritCoverGrammar(self.parseUnaryExpression);
1751             expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr);
1752             if (self.strict and expr.operator == 'delete' and expr.argument.type == Syntax.Identifier):
1753                 self.tolerateError(Messages.StrictDelete)
1754             self.isAssignmentTarget = self.isBindingElement = false;
1755         else:
1756             expr = self.parsePostfixExpression()
1757         return expr
1758
1759     def binaryPrecedence(self, token, allowIn):
1760         prec = 0;
1761         typ = token['type']
1762         if (typ != Token.Punctuator and typ != Token.Keyword):
1763             return 0;
1764         val = token['value']
1765         if val == 'in' and not allowIn:
1766             return 0
1767         return PRECEDENCE.get(val, 0)
1768
1769     # 11.5 Multiplicative Operators
1770     # 11.6 Additive Operators
1771     # 11.7 Bitwise Shift Operators
1772     # 11.8 Relational Operators
1773     # 11.9 Equality Operators
1774     # 11.10 Binary Bitwise Operators
1775     # 11.11 Binary Logical Operators
1776
1777     def parseBinaryExpression(self):
1778
1779         marker = self.lookahead;
1780         left = self.inheritCoverGrammar(self.parseUnaryExpression);
1781
1782         token = self.lookahead;
1783         prec = self.binaryPrecedence(token, self.state['allowIn']);
1784         if (prec == 0):
1785             return left
1786         self.isAssignmentTarget = self.isBindingElement = false;
1787         token['prec'] = prec
1788         self.lex()
1789
1790         markers = [marker, self.lookahead];
1791         right = self.isolateCoverGrammar(self.parseUnaryExpression);
1792
1793         stack = [left, token, right];
1794
1795         while True:
1796             prec = self.binaryPrecedence(self.lookahead, self.state['allowIn'])
1797             if not prec > 0:
1798                 break
1799             # Reduce: make a binary expression from the three topmost entries.
1800             while ((len(stack) > 2) and (prec <= stack[len(stack) - 2]['prec'])):
1801                 right = stack.pop();
1802                 operator = stack.pop()['value']
1803                 left = stack.pop()
1804                 markers.pop()
1805                 expr = WrappingNode(markers[len(markers) - 1]).finishBinaryExpression(operator, left, right)
1806                 stack.append(expr)
1807
1808             # Shift
1809             token = self.lex();
1810             token['prec'] = prec;
1811             stack.append(token);
1812             markers.append(self.lookahead);
1813             expr = self.isolateCoverGrammar(self.parseUnaryExpression);
1814             stack.append(expr);
1815
1816         # Final reduce to clean-up the stack.
1817         i = len(stack) - 1;
1818         expr = stack[i]
1819         markers.pop()
1820         while (i > 1):
1821             expr = WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1]['value'], stack[i - 2], expr);
1822             i -= 2
1823         return expr
1824
1825     # 11.12 Conditional Operator
1826
1827     def parseConditionalExpression(self):
1828
1829         startToken = self.lookahead
1830
1831         expr = self.inheritCoverGrammar(self.parseBinaryExpression);
1832         if (self.match('?')):
1833             self.lex()
1834             previousAllowIn = self.state['allowIn']
1835             self.state['allowIn'] = true;
1836             consequent = self.isolateCoverGrammar(self.parseAssignmentExpression);
1837             self.state['allowIn'] = previousAllowIn;
1838             self.expect(':');
1839             alternate = self.isolateCoverGrammar(self.parseAssignmentExpression)
1840
1841             expr = WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
1842             self.isAssignmentTarget = self.isBindingElement = false;
1843         return expr
1844
1845     # [ES6] 14.2 Arrow Function
1846
1847     def parseConciseBody(self):
1848         if (self.match('{')):
1849             return self.parseFunctionSourceElements()
1850         return self.isolateCoverGrammar(self.parseAssignmentExpression)
1851
1852     def checkPatternParam(self, options, param):
1853         typ = param.type
1854         if typ == Syntax.Identifier:
1855             self.validateParam(options, param, param.name);
1856         elif typ == Syntax.RestElement:
1857             self.checkPatternParam(options, param.argument)
1858         elif typ == Syntax.AssignmentPattern:
1859             self.checkPatternParam(options, param.left)
1860         elif typ == Syntax.ArrayPattern:
1861             for i in xrange(len(param.elements)):
1862                 if (param.elements[i] != null):
1863                     self.checkPatternParam(options, param.elements[i]);
1864         else:
1865             assert typ == Syntax.ObjectPattern, 'Invalid type'
1866             for i in xrange(len(param.properties)):
1867                 self.checkPatternParam(options, param.properties[i]['value']);
1868
1869     def reinterpretAsCoverFormalsList(self, expr):
1870         defaults = [];
1871         defaultCount = 0;
1872         params = [expr];
1873         typ = expr.type
1874         if typ == Syntax.Identifier:
1875             pass
1876         elif typ == PlaceHolders.ArrowParameterPlaceHolder:
1877             params = expr.params
1878         else:
1879             return null
1880         options = {
1881             'paramSet': {}}
1882         le = len(params)
1883         for i in xrange(le):
1884             param = params[i]
1885             if param.type == Syntax.AssignmentPattern:
1886                 params[i] = param.left;
1887                 defaults.append(param.right);
1888                 defaultCount += 1
1889                 self.checkPatternParam(options, param.left);
1890             else:
1891                 self.checkPatternParam(options, param);
1892                 params[i] = param;
1893                 defaults.append(null);
1894         if (options.get('message') == Messages.StrictParamDupe):
1895             token = options['stricted'] if self.strict else options['firstRestricted']
1896             self.throwUnexpectedToken(token, options.get('message'));
1897         if (defaultCount == 0):
1898             defaults = []
1899         return {
1900             'params': params,
1901             'defaults': defaults,
1902             'stricted': options['stricted'],
1903             'firstRestricted': options['firstRestricted'],
1904             'message': options.get('message')}
1905
1906     def parseArrowFunctionExpression(self, options, node):
1907         if (self.hasLineTerminator):
1908             self.tolerateUnexpectedToken(self.lookahead)
1909         self.expect('=>')
1910         previousStrict = self.strict;
1911
1912         body = self.parseConciseBody();
1913
1914         if (self.strict and options['firstRestricted']):
1915             self.throwUnexpectedToken(options['firstRestricted'], options.get('message'));
1916         if (self.strict and options['stricted']):
1917             self.tolerateUnexpectedToken(options['stricted'], options['message']);
1918
1919         self.strict = previousStrict
1920
1921         return node.finishArrowFunctionExpression(options['params'], options['defaults'], body,
1922                                                   body.type != Syntax.BlockStatement)
1923
1924     # 11.13 Assignment Operators
1925
1926     def parseAssignmentExpression(self):
1927         startToken = self.lookahead;
1928         token = self.lookahead;
1929
1930         expr = self.parseConditionalExpression();
1931
1932         if (expr.type == PlaceHolders.ArrowParameterPlaceHolder or self.match('=>')):
1933             self.isAssignmentTarget = self.isBindingElement = false;
1934             lis = self.reinterpretAsCoverFormalsList(expr)
1935
1936             if (lis):
1937                 self.firstCoverInitializedNameError = null;
1938                 return self.parseArrowFunctionExpression(lis, WrappingNode(startToken))
1939             return expr
1940
1941         if (self.matchAssign()):
1942             if (not self.isAssignmentTarget):
1943                 self.tolerateError(Messages.InvalidLHSInAssignment)
1944             # 11.13.1
1945
1946             if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
1947                 self.tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
1948             if (not self.match('=')):
1949                 self.isAssignmentTarget = self.isBindingElement = false;
1950             else:
1951                 self.reinterpretExpressionAsPattern(expr)
1952             token = self.lex();
1953             right = self.isolateCoverGrammar(self.parseAssignmentExpression)
1954             expr = WrappingNode(startToken).finishAssignmentExpression(token['value'], expr, right);
1955             self.firstCoverInitializedNameError = null
1956         return expr
1957
1958     # 11.14 Comma Operator
1959
1960     def parseExpression(self):
1961         startToken = self.lookahead
1962         expr = self.isolateCoverGrammar(self.parseAssignmentExpression)
1963
1964         if (self.match(',')):
1965             expressions = [expr];
1966
1967             while (self.startIndex < self.length):
1968                 if (not self.match(',')):
1969                     break
1970                 self.lex();
1971                 expressions.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
1972             expr = WrappingNode(startToken).finishSequenceExpression(expressions);
1973         return expr
1974
1975     # 12.1 Block
1976
1977     def parseStatementListItem(self):
1978         if (self.lookahead['type'] == Token.Keyword):
1979             val = (self.lookahead['value'])
1980             if val == 'export':
1981                 if (self.sourceType != 'module'):
1982                     self.tolerateUnexpectedToken(self.lookahead, Messages.IllegalExportDeclaration)
1983                 return self.parseExportDeclaration();
1984             elif val == 'import':
1985                 if (self.sourceType != 'module'):
1986                     self.tolerateUnexpectedToken(self.lookahead, Messages.IllegalImportDeclaration);
1987                 return self.parseImportDeclaration();
1988             elif val == 'const' or val == 'let':
1989                 return self.parseLexicalDeclaration({'inFor': false});
1990             elif val == 'function':
1991                 return self.parseFunctionDeclaration(Node());
1992             elif val == 'class':
1993                 return self.parseClassDeclaration();
1994             elif ENABLE_PYIMPORT and val == 'pyimport':  # <<<<< MODIFIED HERE
1995                 return self.parsePyimportStatement()
1996         return self.parseStatement();
1997
1998     def parsePyimportStatement(self):
1999         print(ENABLE_PYIMPORT)
2000         assert ENABLE_PYIMPORT
2001         n = Node()
2002         self.lex()
2003         n.finishPyimport(self.parseVariableIdentifier())
2004         self.consumeSemicolon()
2005         return n
2006
2007     def parseStatementList(self):
2008         list = [];
2009         while (self.startIndex < self.length):
2010             if (self.match('}')):
2011                 break
2012             list.append(self.parseStatementListItem())
2013         return list
2014
2015     def parseBlock(self):
2016         node = Node();
2017
2018         self.expect('{');
2019
2020         block = self.parseStatementList()
2021
2022         self.expect('}');
2023
2024         return node.finishBlockStatement(block);
2025
2026     # 12.2 Variable Statement
2027
2028     def parseVariableIdentifier(self):
2029         node = Node()
2030
2031         token = self.lex()
2032
2033         if (token['type'] != Token.Identifier):
2034             if (self.strict and token['type'] == Token.Keyword and isStrictModeReservedWord(token['value'])):
2035                 self.tolerateUnexpectedToken(token, Messages.StrictReservedWord);
2036             else:
2037                 self.throwUnexpectedToken(token)
2038         return node.finishIdentifier(token['value'])
2039
2040     def parseVariableDeclaration(self):
2041         init = null
2042         node = Node();
2043
2044         d = self.parsePattern();
2045
2046         # 12.2.1
2047         if (self.strict and isRestrictedWord(d.name)):
2048             self.tolerateError(Messages.StrictVarName);
2049
2050         if (self.match('=')):
2051             self.lex();
2052             init = self.isolateCoverGrammar(self.parseAssignmentExpression);
2053         elif (d.type != Syntax.Identifier):
2054             self.expect('=')
2055         return node.finishVariableDeclarator(d, init)
2056
2057     def parseVariableDeclarationList(self):
2058         lis = []
2059
2060         while True:
2061             lis.append(self.parseVariableDeclaration())
2062             if (not self.match(',')):
2063                 break
2064             self.lex();
2065             if not (self.startIndex < self.length):
2066                 break
2067
2068         return lis;
2069
2070     def parseVariableStatement(self, node):
2071         self.expectKeyword('var')
2072
2073         declarations = self.parseVariableDeclarationList()
2074
2075         self.consumeSemicolon()
2076
2077         return node.finishVariableDeclaration(declarations)
2078
2079     def parseLexicalBinding(self, kind, options):
2080         init = null
2081         node = Node()
2082
2083         d = self.parsePattern();
2084
2085         # 12.2.1
2086         if (self.strict and d.type == Syntax.Identifier and isRestrictedWord(d.name)):
2087             self.tolerateError(Messages.StrictVarName);
2088
2089         if (kind == 'const'):
2090             if (not self.matchKeyword('in')):
2091                 self.expect('=')
2092                 init = self.isolateCoverGrammar(self.parseAssignmentExpression)
2093         elif ((not options['inFor'] and d.type != Syntax.Identifier) or self.match('=')):
2094             self.expect('=');
2095             init = self.isolateCoverGrammar(self.parseAssignmentExpression);
2096         return node.finishVariableDeclarator(d, init)
2097
2098     def parseBindingList(self, kind, options):
2099         list = [];
2100
2101         while True:
2102             list.append(self.parseLexicalBinding(kind, options));
2103             if (not self.match(',')):
2104                 break
2105             self.lex();
2106             if not (self.startIndex < self.length):
2107                 break
2108         return list;
2109
2110     def parseLexicalDeclaration(self, options):
2111         node = Node();
2112
2113         kind = self.lex()['value']
2114         assert kind == 'let' or kind == 'const', 'Lexical declaration must be either let or const'
2115         declarations = self.parseBindingList(kind, options);
2116         self.consumeSemicolon();
2117         return node.finishLexicalDeclaration(declarations, kind);
2118
2119     def parseRestElement(self):
2120         node = Node();
2121
2122         self.lex();
2123
2124         if (self.match('{')):
2125             self.throwError(Messages.ObjectPatternAsRestParameter)
2126         param = self.parseVariableIdentifier();
2127         if (self.match('=')):
2128             self.throwError(Messages.DefaultRestParameter);
2129
2130         if (not self.match(')')):
2131             self.throwError(Messages.ParameterAfterRestParameter);
2132         return node.finishRestElement(param);
2133
2134     # 12.3 Empty Statement
2135
2136     def parseEmptyStatement(self, node):
2137         self.expect(';');
2138         return node.finishEmptyStatement()
2139
2140     # 12.4 Expression Statement
2141
2142     def parseExpressionStatement(self, node):
2143         expr = self.parseExpression();
2144         self.consumeSemicolon();
2145         return node.finishExpressionStatement(expr);
2146
2147     # 12.5 If statement
2148
2149     def parseIfStatement(self, node):
2150         self.expectKeyword('if');
2151
2152         self.expect('(');
2153
2154         test = self.parseExpression();
2155
2156         self.expect(')');
2157
2158         consequent = self.parseStatement();
2159
2160         if (self.matchKeyword('else')):
2161             self.lex();
2162             alternate = self.parseStatement();
2163         else:
2164             alternate = null;
2165         return node.finishIfStatement(test, consequent, alternate)
2166
2167     # 12.6 Iteration Statements
2168
2169     def parseDoWhileStatement(self, node):
2170
2171         self.expectKeyword('do')
2172
2173         oldInIteration = self.state['inIteration']
2174         self.state['inIteration'] = true
2175
2176         body = self.parseStatement();
2177
2178         self.state['inIteration'] = oldInIteration;
2179
2180         self.expectKeyword('while');
2181
2182         self.expect('(');
2183
2184         test = self.parseExpression();
2185
2186         self.expect(')')
2187
2188         if (self.match(';')):
2189             self.lex()
2190         return node.finishDoWhileStatement(body, test)
2191
2192     def parseWhileStatement(self, node):
2193
2194         self.expectKeyword('while')
2195
2196         self.expect('(')
2197
2198         test = self.parseExpression()
2199
2200         self.expect(')')
2201
2202         oldInIteration = self.state['inIteration']
2203         self.state['inIteration'] = true
2204
2205         body = self.parseStatement()
2206
2207         self.state['inIteration'] = oldInIteration
2208
2209         return node.finishWhileStatement(test, body)
2210
2211     def parseForStatement(self, node):
2212         previousAllowIn = self.state['allowIn']
2213
2214         init = test = update = null
2215
2216         self.expectKeyword('for')
2217
2218         self.expect('(')
2219
2220         if (self.match(';')):
2221             self.lex()
2222         else:
2223             if (self.matchKeyword('var')):
2224                 init = Node()
2225                 self.lex()
2226
2227                 self.state['allowIn'] = false;
2228                 init = init.finishVariableDeclaration(self.parseVariableDeclarationList())
2229                 self.state['allowIn'] = previousAllowIn
2230
2231                 if (len(init.declarations) == 1 and self.matchKeyword('in')):
2232                     self.lex()
2233                     left = init
2234                     right = self.parseExpression()
2235                     init = null
2236                 else:
2237                     self.expect(';')
2238             elif (self.matchKeyword('const') or self.matchKeyword('let')):
2239                 init = Node()
2240                 kind = self.lex()['value']
2241
2242                 self.state['allowIn'] = false
2243                 declarations = self.parseBindingList(kind, {'inFor': true})
2244                 self.state['allowIn'] = previousAllowIn
2245
2246                 if (len(declarations) == 1 and declarations[0].init == null and self.matchKeyword('in')):
2247                     init = init.finishLexicalDeclaration(declarations, kind);
2248                     self.lex();
2249                     left = init;
2250                     right = self.parseExpression();
2251                     init = null;
2252                 else:
2253                     self.consumeSemicolon();
2254                     init = init.finishLexicalDeclaration(declarations, kind);
2255             else:
2256                 initStartToken = self.lookahead
2257                 self.state['allowIn'] = false
2258                 init = self.inheritCoverGrammar(self.parseAssignmentExpression);
2259                 self.state['allowIn'] = previousAllowIn;
2260
2261                 if (self.matchKeyword('in')):
2262                     if (not self.isAssignmentTarget):
2263                         self.tolerateError(Messages.InvalidLHSInForIn)
2264                     self.lex();
2265                     self.reinterpretExpressionAsPattern(init);
2266                     left = init;
2267                     right = self.parseExpression();
2268                     init = null;
2269                 else:
2270                     if (self.match(',')):
2271                         initSeq = [init];
2272                         while (self.match(',')):
2273                             self.lex();
2274                             initSeq.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
2275                         init = WrappingNode(initStartToken).finishSequenceExpression(initSeq)
2276                     self.expect(';');
2277
2278         if ('left' not in locals()):
2279             if (not self.match(';')):
2280                 test = self.parseExpression();
2281
2282             self.expect(';');
2283
2284             if (not self.match(')')):
2285                 update = self.parseExpression();
2286
2287         self.expect(')');
2288
2289         oldInIteration = self.state['inIteration']
2290         self.state['inIteration'] = true;
2291
2292         body = self.isolateCoverGrammar(self.parseStatement)
2293
2294         self.state['inIteration'] = oldInIteration;
2295
2296         return node.finishForStatement(init, test, update, body) if (
2297         'left' not in locals()) else node.finishForInStatement(left, right, body);
2298
2299     # 12.7 The continue statement
2300
2301     def parseContinueStatement(self, node):
2302         label = null
2303
2304         self.expectKeyword('continue');
2305
2306         # Optimize the most common form: 'continue;'.
2307         if ord(self.source[self.startIndex]) == 0x3B:
2308             self.lex();
2309             if (not self.state['inIteration']):
2310                 self.throwError(Messages.IllegalContinue)
2311             return node.finishContinueStatement(null)
2312         if (self.hasLineTerminator):
2313             if (not self.state['inIteration']):
2314                 self.throwError(Messages.IllegalContinue);
2315             return node.finishContinueStatement(null);
2316
2317         if (self.lookahead['type'] == Token.Identifier):
2318             label = self.parseVariableIdentifier();
2319
2320             key = '$' + label.name;
2321             if not key in self.state['labelSet']:  # todo make sure its correct!
2322                 self.throwError(Messages.UnknownLabel, label.name);
2323         self.consumeSemicolon()
2324
2325         if (label == null and not self.state['inIteration']):
2326             self.throwError(Messages.IllegalContinue)
2327         return node.finishContinueStatement(label)
2328
2329     # 12.8 The break statement
2330
2331     def parseBreakStatement(self, node):
2332         label = null
2333
2334         self.expectKeyword('break');
2335
2336         # Catch the very common case first: immediately a semicolon (U+003B).
2337         if (ord(self.source[self.lastIndex]) == 0x3B):
2338             self.lex();
2339
2340             if (not (self.state['inIteration'] or self.state['inSwitch'])):
2341                 self.throwError(Messages.IllegalBreak)
2342             return node.finishBreakStatement(null)
2343         if (self.hasLineTerminator):
2344             if (not (self.state['inIteration'] or self.state['inSwitch'])):
2345                 self.throwError(Messages.IllegalBreak);
2346             return node.finishBreakStatement(null);
2347         if (self.lookahead['type'] == Token.Identifier):
2348             label = self.parseVariableIdentifier();
2349
2350             key = '$' + label.name;
2351             if not (key in self.state['labelSet']):
2352                 self.throwError(Messages.UnknownLabel, label.name);
2353         self.consumeSemicolon();
2354
2355         if (label == null and not (self.state['inIteration'] or self.state['inSwitch'])):
2356             self.throwError(Messages.IllegalBreak)
2357         return node.finishBreakStatement(label);
2358
2359     # 12.9 The return statement
2360
2361     def parseReturnStatement(self, node):
2362         argument = null;
2363
2364         self.expectKeyword('return');
2365
2366         if (not self.state['inFunctionBody']):
2367             self.tolerateError(Messages.IllegalReturn);
2368
2369         # 'return' followed by a space and an identifier is very common.
2370         if (ord(self.source[self.lastIndex]) == 0x20):
2371             if (isIdentifierStart(self.source[self.lastIndex + 1])):
2372                 argument = self.parseExpression();
2373                 self.consumeSemicolon();
2374                 return node.finishReturnStatement(argument)
2375         if (self.hasLineTerminator):
2376             # HACK
2377             return node.finishReturnStatement(null)
2378
2379         if (not self.match(';')):
2380             if (not self.match('}') and self.lookahead['type'] != Token.EOF):
2381                 argument = self.parseExpression();
2382         self.consumeSemicolon();
2383
2384         return node.finishReturnStatement(argument);
2385
2386     # 12.10 The with statement
2387
2388     def parseWithStatement(self, node):
2389         if (self.strict):
2390             self.tolerateError(Messages.StrictModeWith)
2391
2392         self.expectKeyword('with');
2393
2394         self.expect('(');
2395
2396         obj = self.parseExpression();
2397
2398         self.expect(')');
2399
2400         body = self.parseStatement();
2401
2402         return node.finishWithStatement(obj, body);
2403
2404     # 12.10 The swith statement
2405
2406     def parseSwitchCase(self):
2407         consequent = []
2408         node = Node();
2409
2410         if (self.matchKeyword('default')):
2411             self.lex();
2412             test = null;
2413         else:
2414             self.expectKeyword('case');
2415             test = self.parseExpression();
2416
2417         self.expect(':');
2418
2419         while (self.startIndex < self.length):
2420             if (self.match('}') or self.matchKeyword('default') or self.matchKeyword('case')):
2421                 break
2422             statement = self.parseStatementListItem()
2423             consequent.append(statement)
2424         return node.finishSwitchCase(test, consequent)
2425
2426     def parseSwitchStatement(self, node):
2427
2428         self.expectKeyword('switch');
2429
2430         self.expect('(');
2431
2432         discriminant = self.parseExpression();
2433
2434         self.expect(')');
2435
2436         self.expect('{');
2437
2438         cases = [];
2439
2440         if (self.match('}')):
2441             self.lex();
2442             return node.finishSwitchStatement(discriminant, cases);
2443
2444         oldInSwitch = self.state['inSwitch'];
2445         self.state['inSwitch'] = true;
2446         defaultFound = false;
2447
2448         while (self.startIndex < self.length):
2449             if (self.match('}')):
2450                 break;
2451             clause = self.parseSwitchCase();
2452             if (clause.test == null):
2453                 if (defaultFound):
2454                     self.throwError(Messages.MultipleDefaultsInSwitch);
2455                 defaultFound = true;
2456             cases.append(clause);
2457
2458         self.state['inSwitch'] = oldInSwitch;
2459
2460         self.expect('}');
2461
2462         return node.finishSwitchStatement(discriminant, cases);
2463
2464     # 12.13 The throw statement
2465
2466     def parseThrowStatement(self, node):
2467
2468         self.expectKeyword('throw');
2469
2470         if (self.hasLineTerminator):
2471             self.throwError(Messages.NewlineAfterThrow);
2472
2473         argument = self.parseExpression();
2474
2475         self.consumeSemicolon();
2476
2477         return node.finishThrowStatement(argument);
2478
2479     # 12.14 The try statement
2480
2481     def parseCatchClause(self):
2482         node = Node();
2483
2484         self.expectKeyword('catch');
2485
2486         self.expect('(');
2487         if (self.match(')')):
2488             self.throwUnexpectedToken(self.lookahead);
2489         param = self.parsePattern();
2490
2491         # 12.14.1
2492         if (self.strict and isRestrictedWord(param.name)):
2493             self.tolerateError(Messages.StrictCatchVariable);
2494
2495         self.expect(')');
2496         body = self.parseBlock();
2497         return node.finishCatchClause(param, body);
2498
2499     def parseTryStatement(self, node):
2500         handler = null
2501         finalizer = null;
2502
2503         self.expectKeyword('try');
2504
2505         block = self.parseBlock();
2506
2507         if (self.matchKeyword('catch')):
2508             handler = self.parseCatchClause()
2509
2510         if (self.matchKeyword('finally')):
2511             self.lex();
2512             finalizer = self.parseBlock();
2513
2514         if (not handler and not finalizer):
2515             self.throwError(Messages.NoCatchOrFinally)
2516
2517         return node.finishTryStatement(block, handler, finalizer)
2518
2519     # 12.15 The debugger statement
2520
2521     def parseDebuggerStatement(self, node):
2522         self.expectKeyword('debugger');
2523
2524         self.consumeSemicolon();
2525
2526         return node.finishDebuggerStatement();
2527
2528     # 12 Statements
2529
2530     def parseStatement(self):
2531         typ = self.lookahead['type']
2532
2533         if (typ == Token.EOF):
2534             self.throwUnexpectedToken(self.lookahead)
2535
2536         if (typ == Token.Punctuator and self.lookahead['value'] == '{'):
2537             return self.parseBlock()
2538
2539         self.isAssignmentTarget = self.isBindingElement = true;
2540         node = Node();
2541         val = self.lookahead['value']
2542
2543         if (typ == Token.Punctuator):
2544             if val == ';':
2545                 return self.parseEmptyStatement(node);
2546             elif val == '(':
2547                 return self.parseExpressionStatement(node);
2548         elif (typ == Token.Keyword):
2549             if val == 'break':
2550                 return self.parseBreakStatement(node);
2551             elif val == 'continue':
2552                 return self.parseContinueStatement(node);
2553             elif val == 'debugger':
2554                 return self.parseDebuggerStatement(node);
2555             elif val == 'do':
2556                 return self.parseDoWhileStatement(node);
2557             elif val == 'for':
2558                 return self.parseForStatement(node);
2559             elif val == 'function':
2560                 return self.parseFunctionDeclaration(node);
2561             elif val == 'if':
2562                 return self.parseIfStatement(node);
2563             elif val == 'return':
2564                 return self.parseReturnStatement(node);
2565             elif val == 'switch':
2566                 return self.parseSwitchStatement(node);
2567             elif val == 'throw':
2568                 return self.parseThrowStatement(node);
2569             elif val == 'try':
2570                 return self.parseTryStatement(node);
2571             elif val == 'var':
2572                 return self.parseVariableStatement(node);
2573             elif val == 'while':
2574                 return self.parseWhileStatement(node);
2575             elif val == 'with':
2576                 return self.parseWithStatement(node);
2577
2578         expr = self.parseExpression();
2579
2580         # 12.12 Labelled Statements
2581         if ((expr.type == Syntax.Identifier) and self.match(':')):
2582             self.lex();
2583
2584             key = '$' + expr.name
2585             if key in self.state['labelSet']:
2586                 self.throwError(Messages.Redeclaration, 'Label', expr.name);
2587             self.state['labelSet'][key] = true
2588             labeledBody = self.parseStatement()
2589             del self.state['labelSet'][key]
2590             return node.finishLabeledStatement(expr, labeledBody)
2591         self.consumeSemicolon();
2592         return node.finishExpressionStatement(expr)
2593
2594     # 13 Function Definition
2595
2596     def parseFunctionSourceElements(self):
2597         body = []
2598         node = Node()
2599         firstRestricted = None
2600
2601         self.expect('{')
2602
2603         while (self.startIndex < self.length):
2604             if (self.lookahead['type'] != Token.StringLiteral):
2605                 break
2606             token = self.lookahead;
2607
2608             statement = self.parseStatementListItem()
2609             body.append(statement)
2610             if (statement.expression.type != Syntax.Literal):
2611                 # this is not directive
2612                 break
2613             directive = self.source[token['start'] + 1: token['end'] - 1]
2614             if (directive == 'use strict'):
2615                 self.strict = true;
2616                 if (firstRestricted):
2617                     self.tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
2618             else:
2619                 if (not firstRestricted and token.get('octal')):
2620                     firstRestricted = token;
2621
2622         oldLabelSet = self.state['labelSet']
2623         oldInIteration = self.state['inIteration']
2624         oldInSwitch = self.state['inSwitch']
2625         oldInFunctionBody = self.state['inFunctionBody']
2626         oldParenthesisCount = self.state['parenthesizedCount']
2627
2628         self.state['labelSet'] = {}
2629         self.state['inIteration'] = false
2630         self.state['inSwitch'] = false
2631         self.state['inFunctionBody'] = true
2632         self.state['parenthesizedCount'] = 0
2633
2634         while (self.startIndex < self.length):
2635             if (self.match('}')):
2636                 break
2637             body.append(self.parseStatementListItem())
2638         self.expect('}')
2639
2640         self.state['labelSet'] = oldLabelSet;
2641         self.state['inIteration'] = oldInIteration;
2642         self.state['inSwitch'] = oldInSwitch;
2643         self.state['inFunctionBody'] = oldInFunctionBody;
2644         self.state['parenthesizedCount'] = oldParenthesisCount;
2645
2646         return node.finishBlockStatement(body)
2647
2648     def validateParam(self, options, param, name):
2649         key = '$' + name
2650         if (self.strict):
2651             if (isRestrictedWord(name)):
2652                 options['stricted'] = param;
2653                 options['message'] = Messages.StrictParamName
2654             if key in options['paramSet']:
2655                 options['stricted'] = param;
2656                 options['message'] = Messages.StrictParamDupe;
2657         elif (not options['firstRestricted']):
2658             if (isRestrictedWord(name)):
2659                 options['firstRestricted'] = param;
2660                 options['message'] = Messages.StrictParamName;
2661             elif (isStrictModeReservedWord(name)):
2662                 options['firstRestricted'] = param;
2663                 options['message'] = Messages.StrictReservedWord;
2664             elif key in options['paramSet']:
2665                 options['firstRestricted'] = param
2666                 options['message'] = Messages.StrictParamDupe;
2667         options['paramSet'][key] = true
2668
2669     def parseParam(self, options):
2670         token = self.lookahead
2671         de = None
2672         if (token['value'] == '...'):
2673             param = self.parseRestElement();
2674             self.validateParam(options, param.argument, param.argument.name);
2675             options['params'].append(param);
2676             options['defaults'].append(null);
2677             return false
2678         param = self.parsePatternWithDefault();
2679         self.validateParam(options, token, token['value']);
2680
2681         if (param.type == Syntax.AssignmentPattern):
2682             de = param.right;
2683             param = param.left;
2684             options['defaultCount'] += 1
2685         options['params'].append(param);
2686         options['defaults'].append(de)
2687         return not self.match(')')
2688
2689     def parseParams(self, firstRestricted):
2690         options = {
2691             'params': [],
2692             'defaultCount': 0,
2693             'defaults': [],
2694             'firstRestricted': firstRestricted}
2695
2696         self.expect('(');
2697
2698         if (not self.match(')')):
2699             options['paramSet'] = {};
2700             while (self.startIndex < self.length):
2701                 if (not self.parseParam(options)):
2702                     break
2703                 self.expect(',');
2704         self.expect(')');
2705
2706         if (options['defaultCount'] == 0):
2707             options['defaults'] = [];
2708
2709         return {
2710             'params': options['params'],
2711             'defaults': options['defaults'],
2712             'stricted': options.get('stricted'),
2713             'firstRestricted': options.get('firstRestricted'),
2714             'message': options.get('message')}
2715
2716     def parseFunctionDeclaration(self, node, identifierIsOptional=None):
2717         d = null
2718         params = []
2719         defaults = []
2720         message = None
2721         firstRestricted = None
2722
2723         self.expectKeyword('function');
2724         if (identifierIsOptional or not self.match('(')):
2725             token = self.lookahead;
2726             d = self.parseVariableIdentifier();
2727             if (self.strict):
2728                 if (isRestrictedWord(token['value'])):
2729                     self.tolerateUnexpectedToken(token, Messages.StrictFunctionName);
2730             else:
2731                 if (isRestrictedWord(token['value'])):
2732                     firstRestricted = token;
2733                     message = Messages.StrictFunctionName;
2734                 elif (isStrictModeReservedWord(token['value'])):
2735                     firstRestricted = token;
2736                     message = Messages.StrictReservedWord;
2737
2738         tmp = self.parseParams(firstRestricted);
2739         params = tmp['params']
2740         defaults = tmp['defaults']
2741         stricted = tmp['stricted']
2742         firstRestricted = tmp['firstRestricted']
2743         if (tmp.get('message')):
2744             message = tmp['message'];
2745
2746         previousStrict = self.strict;
2747         body = self.parseFunctionSourceElements();
2748         if (self.strict and firstRestricted):
2749             self.throwUnexpectedToken(firstRestricted, message);
2750
2751         if (self.strict and stricted):
2752             self.tolerateUnexpectedToken(stricted, message);
2753         self.strict = previousStrict;
2754
2755         return node.finishFunctionDeclaration(d, params, defaults, body);
2756
2757     def parseFunctionExpression(self):
2758         id = null
2759         params = []
2760         defaults = []
2761         node = Node();
2762         firstRestricted = None
2763         message = None
2764
2765         self.expectKeyword('function');
2766
2767         if (not self.match('(')):
2768             token = self.lookahead;
2769             id = self.parseVariableIdentifier();
2770             if (self.strict):
2771                 if (isRestrictedWord(token['value'])):
2772                     self.tolerateUnexpectedToken(token, Messages.StrictFunctionName);
2773             else:
2774                 if (isRestrictedWord(token['value'])):
2775                     firstRestricted = token;
2776                     message = Messages.StrictFunctionName;
2777                 elif (isStrictModeReservedWord(token['value'])):
2778                     firstRestricted = token;
2779                     message = Messages.StrictReservedWord;
2780         tmp = self.parseParams(firstRestricted);
2781         params = tmp['params']
2782         defaults = tmp['defaults']
2783         stricted = tmp['stricted']
2784         firstRestricted = tmp['firstRestricted']
2785         if (tmp.get('message')):
2786             message = tmp['message']
2787
2788         previousStrict = self.strict;
2789         body = self.parseFunctionSourceElements();
2790         if (self.strict and firstRestricted):
2791             self.throwUnexpectedToken(firstRestricted, message);
2792         if (self.strict and stricted):
2793             self.tolerateUnexpectedToken(stricted, message);
2794         self.strict = previousStrict;
2795
2796         return node.finishFunctionExpression(id, params, defaults, body);
2797
2798     # todo Translate parse class functions!
2799
2800     def parseClassExpression(self):
2801         raise NotImplementedError()
2802
2803     def parseClassDeclaration(self):
2804         raise NotImplementedError()
2805
2806     # 14 Program
2807
2808     def parseScriptBody(self):
2809         body = []
2810         firstRestricted = None
2811
2812         while (self.startIndex < self.length):
2813             token = self.lookahead;
2814             if (token['type'] != Token.StringLiteral):
2815                 break
2816             statement = self.parseStatementListItem();
2817             body.append(statement);
2818             if (statement.expression.type != Syntax.Literal):
2819                 # this is not directive
2820                 break
2821             directive = self.source[token['start'] + 1: token['end'] - 1]
2822             if (directive == 'use strict'):
2823                 self.strict = true;
2824                 if (firstRestricted):
2825                     self.tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral)
2826             else:
2827                 if (not firstRestricted and token.get('octal')):
2828                     firstRestricted = token;
2829         while (self.startIndex < self.length):
2830             statement = self.parseStatementListItem();
2831             # istanbul ignore if
2832             if (statement is None):
2833                 break
2834             body.append(statement);
2835         return body;
2836
2837     def parseProgram(self):
2838         self.peek()
2839         node = Node()
2840
2841         body = self.parseScriptBody()
2842         return node.finishProgram(body)
2843
2844     # DONE!!!
2845     def parse(self, code, options={}):
2846         if options:
2847             raise NotImplementedError('Options not implemented! You can only use default settings.')
2848
2849         self.clean()
2850         self.source = unicode(code) + ' \n ; //END'  # I have to add it in order not to check for EOF every time
2851         self.index = 0
2852         self.lineNumber = 1 if len(self.source) > 0 else 0
2853         self.lineStart = 0
2854         self.startIndex = self.index
2855         self.startLineNumber = self.lineNumber;
2856         self.startLineStart = self.lineStart;
2857         self.length = len(self.source)
2858         self.lookahead = null;
2859         self.state = {
2860             'allowIn': true,
2861             'labelSet': {},
2862             'inFunctionBody': false,
2863             'inIteration': false,
2864             'inSwitch': false,
2865             'lastCommentStart': -1,
2866             'curlyStack': [],
2867             'parenthesizedCount': None}
2868         self.sourceType = 'script';
2869         self.strict = false;
2870         program = self.parseProgram();
2871         return node_to_dict(program)
2872
2873
2874
2875 def parse(javascript_code):
2876     """Returns syntax tree of javascript_code.
2877        Same as PyJsParser().parse  For your convenience :) """
2878     p = PyJsParser()
2879     return p.parse(javascript_code)
2880
2881
2882 if __name__ == '__main__':
2883     import time
2884
2885     test_path = None
2886     if test_path:
2887         f = open(test_path, 'rb')
2888         x = f.read()
2889         f.close()
2890     else:
2891         x = 'var $ = "Hello!"'
2892     p = PyJsParser()
2893     t = time.time()
2894     res = p.parse(x)
2895     dt = time.time() - t + 0.000000001
2896     if test_path:
2897         print(len(res))
2898     else:
2899         pprint(res)
2900     print()
2901     print('Parsed everyting in', round(dt, 5), 'seconds.')
2902     print('Thats %d characters per second' % int(len(x) / dt))