summaryrefslogtreecommitdiffhomepage
path: root/libs/pyjsparser
diff options
context:
space:
mode:
authorpanni <[email protected]>2019-04-11 02:02:14 +0200
committerpanni <[email protected]>2019-04-11 02:02:14 +0200
commit8cd81774552d21d77ef9eef69743f21ca1b8713a (patch)
treebb0b6e2c34362af2e57aa0578e88c3538d9492b5 /libs/pyjsparser
parentc2a7c1247056a8c307419c578e115085397810e9 (diff)
downloadbazarr-8cd81774552d21d77ef9eef69743f21ca1b8713a.tar.gz
bazarr-8cd81774552d21d77ef9eef69743f21ca1b8713a.zip
core: update to subliminal_patch:head; replace cfscrape; add dependencies
Diffstat (limited to 'libs/pyjsparser')
-rw-r--r--libs/pyjsparser/__init__.py4
-rw-r--r--libs/pyjsparser/parser.py2898
-rw-r--r--libs/pyjsparser/pyjsparserdata.py303
-rw-r--r--libs/pyjsparser/std_nodes.py471
4 files changed, 3676 insertions, 0 deletions
diff --git a/libs/pyjsparser/__init__.py b/libs/pyjsparser/__init__.py
new file mode 100644
index 000000000..2a9de69e9
--- /dev/null
+++ b/libs/pyjsparser/__init__.py
@@ -0,0 +1,4 @@
+__all__ = ['PyJsParser', 'parse', 'JsSyntaxError']
+__author__ = 'Piotr Dabkowski'
+__version__ = '2.2.0'
+from .parser import PyJsParser, parse, JsSyntaxError \ No newline at end of file
diff --git a/libs/pyjsparser/parser.py b/libs/pyjsparser/parser.py
new file mode 100644
index 000000000..a67869ce8
--- /dev/null
+++ b/libs/pyjsparser/parser.py
@@ -0,0 +1,2898 @@
+# The MIT License
+#
+# Copyright 2014, 2015 Piotr Dabkowski
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the 'Software'),
+# to deal in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so, subject
+# to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+from __future__ import unicode_literals
+from .pyjsparserdata import *
+from .std_nodes import *
+from pprint import pprint
+import sys
+
+__all__ = ['PyJsParser', 'parse', 'ENABLE_JS2PY_ERRORS', 'ENABLE_PYIMPORT', 'JsSyntaxError']
+REGEXP_SPECIAL_SINGLE = ('\\', '^', '$', '*', '+', '?', '.', '[', ']', '(', ')', '{', '{', '|', '-')
+ENABLE_PYIMPORT = False
+ENABLE_JS2PY_ERRORS = False
+
+PY3 = sys.version_info >= (3,0)
+
+if PY3:
+ basestring = str
+ long = int
+ xrange = range
+ unicode = str
+
+ESPRIMA_VERSION = '2.2.0'
+DEBUG = False
+# Small naming convention changes
+# len -> leng
+# id -> d
+# type -> typ
+# str -> st
+true = True
+false = False
+null = None
+
+
+class PyJsParser:
+ """ Usage:
+ parser = PyJsParser()
+ parser.parse('var JavaScriptCode = 5.1')
+ """
+
+ def __init__(self):
+ self.clean()
+
+ def test(self, code):
+ pprint(self.parse(code))
+
+ def clean(self):
+ self.strict = None
+ self.sourceType = None
+ self.index = 0
+ self.lineNumber = 1
+ self.lineStart = 0
+ self.hasLineTerminator = None
+ self.lastIndex = None
+ self.lastLineNumber = None
+ self.lastLineStart = None
+ self.startIndex = None
+ self.startLineNumber = None
+ self.startLineStart = None
+ self.scanning = None
+ self.lookahead = None
+ self.state = None
+ self.extra = None
+ self.isBindingElement = None
+ self.isAssignmentTarget = None
+ self.firstCoverInitializedNameError = None
+
+ # 7.4 Comments
+
+ def skipSingleLineComment(self, offset):
+ start = self.index - offset;
+ while self.index < self.length:
+ ch = self.source[self.index];
+ self.index += 1
+ if isLineTerminator(ch):
+ if (ord(ch) == 13 and ord(self.source[self.index]) == 10):
+ self.index += 1
+ self.lineNumber += 1
+ self.hasLineTerminator = True
+ self.lineStart = self.index
+ return
+
+ def skipMultiLineComment(self):
+ while self.index < self.length:
+ ch = ord(self.source[self.index])
+ if isLineTerminator(ch):
+ if (ch == 0x0D and ord(self.source[self.index + 1]) == 0x0A):
+ self.index += 1
+ self.lineNumber += 1
+ self.index += 1
+ self.hasLineTerminator = True
+ self.lineStart = self.index
+ elif ch == 0x2A:
+ # Block comment ends with '*/'.
+ if ord(self.source[self.index + 1]) == 0x2F:
+ self.index += 2
+ return
+ self.index += 1
+ else:
+ self.index += 1
+ self.tolerateUnexpectedToken()
+
+ def skipComment(self):
+ self.hasLineTerminator = False
+ start = (self.index == 0)
+ while self.index < self.length:
+ ch = ord(self.source[self.index])
+ if isWhiteSpace(ch):
+ self.index += 1
+ elif isLineTerminator(ch):
+ self.hasLineTerminator = True
+ self.index += 1
+ if (ch == 0x0D and ord(self.source[self.index]) == 0x0A):
+ self.index += 1
+ self.lineNumber += 1
+ self.lineStart = self.index
+ start = True
+ elif (ch == 0x2F): # U+002F is '/'
+ ch = ord(self.source[self.index + 1])
+ if (ch == 0x2F):
+ self.index += 2
+ self.skipSingleLineComment(2)
+ start = True
+ elif (ch == 0x2A): # U+002A is '*'
+ self.index += 2
+ self.skipMultiLineComment()
+ else:
+ break
+ elif (start and ch == 0x2D): # U+002D is '-'
+ # U+003E is '>'
+ if (ord(self.source[self.index + 1]) == 0x2D) and (ord(self.source[self.index + 2]) == 0x3E):
+ # '-->' is a single-line comment
+ self.index += 3
+ self.skipSingleLineComment(3)
+ else:
+ break
+ elif (ch == 0x3C): # U+003C is '<'
+ if self.source[self.index + 1: self.index + 4] == '!--':
+ # <!--
+ self.index += 4
+ self.skipSingleLineComment(4)
+ else:
+ break
+ else:
+ break
+
+ def scanHexEscape(self, prefix):
+ code = 0
+ leng = 4 if (prefix == 'u') else 2
+ for i in xrange(leng):
+ if self.index < self.length and isHexDigit(self.source[self.index]):
+ ch = self.source[self.index]
+ self.index += 1
+ code = code * 16 + HEX_CONV[ch]
+ else:
+ return ''
+ return unichr(code)
+
+ def scanUnicodeCodePointEscape(self):
+ ch = self.source[self.index]
+ code = 0
+ # At least, one hex digit is required.
+ if ch == '}':
+ self.throwUnexpectedToken()
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ self.index += 1
+ if not isHexDigit(ch):
+ break
+ code = code * 16 + HEX_CONV[ch]
+ if code > 0x10FFFF or ch != '}':
+ self.throwUnexpectedToken()
+ # UTF-16 Encoding
+ if (code <= 0xFFFF):
+ return unichr(code)
+ cu1 = ((code - 0x10000) >> 10) + 0xD800;
+ cu2 = ((code - 0x10000) & 1023) + 0xDC00;
+ return unichr(cu1) + unichr(cu2)
+
+ def ccode(self, offset=0):
+ return ord(self.source[self.index + offset])
+
+ def log_err_case(self):
+ if not DEBUG:
+ return
+ print('INDEX', self.index)
+ print(self.source[self.index - 10:self.index + 10])
+ print('')
+
+ def at(self, loc):
+ return None if loc >= self.length else self.source[loc]
+
+ def substr(self, le, offset=0):
+ return self.source[self.index + offset:self.index + offset + le]
+
+ def getEscapedIdentifier(self):
+ d = self.source[self.index]
+ ch = ord(d)
+ self.index += 1
+ # '\u' (U+005C, U+0075) denotes an escaped character.
+ if (ch == 0x5C):
+ if (ord(self.source[self.index]) != 0x75):
+ self.throwUnexpectedToken()
+ self.index += 1
+ ch = self.scanHexEscape('u')
+ if not ch or ch == '\\' or not isIdentifierStart(ch[0]):
+ self.throwUnexpectedToken()
+ d = ch
+ while (self.index < self.length):
+ ch = self.ccode()
+ if not isIdentifierPart(ch):
+ break
+ self.index += 1
+ d += unichr(ch)
+
+ # '\u' (U+005C, U+0075) denotes an escaped character.
+ if (ch == 0x5C):
+ d = d[0: len(d) - 1]
+ if (self.ccode() != 0x75):
+ self.throwUnexpectedToken()
+ self.index += 1
+ ch = self.scanHexEscape('u');
+ if (not ch or ch == '\\' or not isIdentifierPart(ch[0])):
+ self.throwUnexpectedToken()
+ d += ch
+ return d
+
+ def getIdentifier(self):
+ start = self.index
+ self.index += 1
+ while (self.index < self.length):
+ ch = self.ccode()
+ if (ch == 0x5C):
+ # Blackslash (U+005C) marks Unicode escape sequence.
+ self.index = start
+ return self.getEscapedIdentifier()
+ if (isIdentifierPart(ch)):
+ self.index += 1
+ else:
+ break
+ return self.source[start: self.index]
+
+ def scanIdentifier(self):
+ start = self.index
+
+ # Backslash (U+005C) starts an escaped character.
+ d = self.getEscapedIdentifier() if (self.ccode() == 0x5C) else self.getIdentifier()
+
+ # There is no keyword or literal with only one character.
+ # Thus, it must be an identifier.
+ if (len(d) == 1):
+ type = Token.Identifier
+ elif (isKeyword(d)):
+ type = Token.Keyword
+ elif (d == 'null'):
+ type = Token.NullLiteral
+ elif (d == 'true' or d == 'false'):
+ type = Token.BooleanLiteral
+ else:
+ type = Token.Identifier;
+ return {
+ 'type': type,
+ 'value': d,
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index
+ }
+
+ # 7.7 Punctuators
+
+ def scanPunctuator(self):
+ token = {
+ 'type': Token.Punctuator,
+ 'value': '',
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': self.index,
+ 'end': self.index
+ }
+ # Check for most common single-character punctuators.
+ st = self.source[self.index]
+ if st == '{':
+ self.state['curlyStack'].append('{')
+ self.index += 1
+ elif st == '}':
+ self.index += 1
+ self.state['curlyStack'].pop()
+ elif st in ('.', '(', ')', ';', ',', '[', ']', ':', '?', '~'):
+ self.index += 1
+ else:
+ # 4-character punctuator.
+ st = self.substr(4)
+ if (st == '>>>='):
+ self.index += 4
+ else:
+ # 3-character punctuators.
+ st = st[0:3]
+ if st in ('===', '!==', '>>>', '<<=', '>>='):
+ self.index += 3
+ else:
+ # 2-character punctuators.
+ st = st[0:2]
+ if st in ('&&', '||', '==', '!=', '+=', '-=', '*=', '/=', '++', '--', '<<', '>>', '&=', '|=', '^=',
+ '%=', '<=', '>=', '=>'):
+ self.index += 2
+ else:
+ # 1-character punctuators.
+ st = self.source[self.index]
+ if st in ('<', '>', '=', '!', '+', '-', '*', '%', '&', '|', '^', '/'):
+ self.index += 1
+ if self.index == token['start']:
+ self.throwUnexpectedToken()
+ token['end'] = self.index;
+ token['value'] = st
+ return token
+
+ # 7.8.3 Numeric Literals
+
+ def scanHexLiteral(self, start):
+ number = ''
+ while (self.index < self.length):
+ if (not isHexDigit(self.source[self.index])):
+ break
+ number += self.source[self.index]
+ self.index += 1
+ if not number:
+ self.throwUnexpectedToken()
+ if isIdentifierStart(self.ccode()):
+ self.throwUnexpectedToken()
+ return {
+ 'type': Token.NumericLiteral,
+ 'value': int(number, 16),
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index}
+
+ def scanBinaryLiteral(self, start):
+ number = ''
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ if (ch != '0' and ch != '1'):
+ break
+ number += self.source[self.index]
+ self.index += 1
+
+ if not number:
+ # only 0b or 0B
+ self.throwUnexpectedToken()
+ if (self.index < self.length):
+ ch = self.source[self.index]
+ # istanbul ignore else
+ if (isIdentifierStart(ch) or isDecimalDigit(ch)):
+ self.throwUnexpectedToken();
+ return {
+ 'type': Token.NumericLiteral,
+ 'value': int(number, 2),
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index}
+
+ def scanOctalLiteral(self, prefix, start):
+ if isOctalDigit(prefix):
+ octal = True
+ number = '0' + self.source[self.index]
+ self.index += 1
+ else:
+ octal = False
+ self.index += 1
+ number = ''
+ while (self.index < self.length):
+ if (not isOctalDigit(self.source[self.index])):
+ break
+ number += self.source[self.index]
+ self.index += 1
+ if (not octal and not number):
+ # only 0o or 0O
+ self.throwUnexpectedToken()
+ if (isIdentifierStart(self.ccode()) or isDecimalDigit(self.ccode())):
+ self.throwUnexpectedToken()
+ return {
+ 'type': Token.NumericLiteral,
+ 'value': int(number, 8),
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index}
+
+ def octalToDecimal(self, ch):
+ # \0 is not octal escape sequence
+ octal = (ch != '0')
+ code = int(ch, 8)
+
+ if (self.index < self.length and isOctalDigit(self.source[self.index])):
+ octal = True
+ code = code * 8 + int(self.source[self.index], 8)
+ self.index += 1
+
+ # 3 digits are only allowed when string starts
+ # with 0, 1, 2, 3
+ if (ch in '0123' and self.index < self.length and isOctalDigit(self.source[self.index])):
+ code = code * 8 + int((self.source[self.index]), 8)
+ self.index += 1
+ return {
+ 'code': code,
+ 'octal': octal}
+
+ def isImplicitOctalLiteral(self):
+ # Implicit octal, unless there is a non-octal digit.
+ # (Annex B.1.1 on Numeric Literals)
+ for i in xrange(self.index + 1, self.length):
+ ch = self.source[i];
+ if (ch == '8' or ch == '9'):
+ return False;
+ if (not isOctalDigit(ch)):
+ return True
+ return True
+
+ def scanNumericLiteral(self):
+ ch = self.source[self.index]
+ assert isDecimalDigit(ch) or (ch == '.'), 'Numeric literal must start with a decimal digit or a decimal point'
+ start = self.index
+ number = ''
+ if ch != '.':
+ number = self.source[self.index]
+ self.index += 1
+ ch = self.source[self.index]
+ # Hex number starts with '0x'.
+ # Octal number starts with '0'.
+ # Octal number in ES6 starts with '0o'.
+ # Binary number in ES6 starts with '0b'.
+ if (number == '0'):
+ if (ch == 'x' or ch == 'X'):
+ self.index += 1
+ return self.scanHexLiteral(start);
+ if (ch == 'b' or ch == 'B'):
+ self.index += 1
+ return self.scanBinaryLiteral(start)
+ if (ch == 'o' or ch == 'O'):
+ return self.scanOctalLiteral(ch, start)
+ if (isOctalDigit(ch)):
+ if (self.isImplicitOctalLiteral()):
+ return self.scanOctalLiteral(ch, start);
+ while (isDecimalDigit(self.ccode())):
+ number += self.source[self.index]
+ self.index += 1
+ ch = self.source[self.index];
+ if (ch == '.'):
+ number += self.source[self.index]
+ self.index += 1
+ while (isDecimalDigit(self.source[self.index])):
+ number += self.source[self.index]
+ self.index += 1
+ ch = self.source[self.index]
+ if (ch == 'e' or ch == 'E'):
+ number += self.source[self.index]
+ self.index += 1
+ ch = self.source[self.index]
+ if (ch == '+' or ch == '-'):
+ number += self.source[self.index]
+ self.index += 1
+ if (isDecimalDigit(self.source[self.index])):
+ while (isDecimalDigit(self.source[self.index])):
+ number += self.source[self.index]
+ self.index += 1
+ else:
+ self.throwUnexpectedToken()
+ if (isIdentifierStart(self.source[self.index])):
+ self.throwUnexpectedToken();
+ return {
+ 'type': Token.NumericLiteral,
+ 'value': float(number),
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index}
+
+ # 7.8.4 String Literals
+
+ def _interpret_regexp(self, string, flags):
+ '''Perform sctring escape - for regexp literals'''
+ self.index = 0
+ self.length = len(string)
+ self.source = string
+ self.lineNumber = 0
+ self.lineStart = 0
+ octal = False
+ st = ''
+ inside_square = 0
+ while (self.index < self.length):
+ template = '[%s]' if not inside_square else '%s'
+ ch = self.source[self.index]
+ self.index += 1
+ if ch == '\\':
+ ch = self.source[self.index]
+ self.index += 1
+ if (not isLineTerminator(ch)):
+ if ch == 'u':
+ digs = self.source[self.index:self.index + 4]
+ if len(digs) == 4 and all(isHexDigit(d) for d in digs):
+ st += template % unichr(int(digs, 16))
+ self.index += 4
+ else:
+ st += 'u'
+ elif ch == 'x':
+ digs = self.source[self.index:self.index + 2]
+ if len(digs) == 2 and all(isHexDigit(d) for d in digs):
+ st += template % unichr(int(digs, 16))
+ self.index += 2
+ else:
+ st += 'x'
+ # special meaning - single char.
+ elif ch == '0':
+ st += '\\0'
+ elif ch == 'n':
+ st += '\\n'
+ elif ch == 'r':
+ st += '\\r'
+ elif ch == 't':
+ st += '\\t'
+ elif ch == 'f':
+ st += '\\f'
+ elif ch == 'v':
+ st += '\\v'
+
+ # unescape special single characters like . so that they are interpreted literally
+ elif ch in REGEXP_SPECIAL_SINGLE:
+ st += '\\' + ch
+
+ # character groups
+ elif ch == 'b':
+ st += '\\b'
+ elif ch == 'B':
+ st += '\\B'
+ elif ch == 'w':
+ st += '\\w'
+ elif ch == 'W':
+ st += '\\W'
+ elif ch == 'd':
+ st += '\\d'
+ elif ch == 'D':
+ st += '\\D'
+ elif ch == 's':
+ st += template % u' \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff'
+ elif ch == 'S':
+ 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'
+ else:
+ if isDecimalDigit(ch):
+ num = ch
+ while self.index < self.length and isDecimalDigit(self.source[self.index]):
+ num += self.source[self.index]
+ self.index += 1
+ st += '\\' + num
+
+ else:
+ st += ch # DONT ESCAPE!!!
+ else:
+ self.lineNumber += 1
+ if (ch == '\r' and self.source[self.index] == '\n'):
+ self.index += 1
+ self.lineStart = self.index
+ else:
+ if ch == '[':
+ inside_square = True
+ elif ch == ']':
+ inside_square = False
+ st += ch
+ # print string, 'was transformed to', st
+ return st
+
+ def scanStringLiteral(self):
+ st = ''
+ octal = False
+
+ quote = self.source[self.index]
+ assert quote == '\'' or quote == '"', 'String literal must starts with a quote'
+ start = self.index;
+ self.index += 1
+
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ self.index += 1
+ if (ch == quote):
+ quote = ''
+ break
+ elif (ch == '\\'):
+ ch = self.source[self.index]
+ self.index += 1
+ if (not isLineTerminator(ch)):
+ if ch in 'ux':
+ if (self.source[self.index] == '{'):
+ self.index += 1
+ st += self.scanUnicodeCodePointEscape()
+ else:
+ unescaped = self.scanHexEscape(ch)
+ if (not unescaped):
+ self.throwUnexpectedToken() # with throw I don't know whats the difference
+ st += unescaped
+ elif ch == 'n':
+ st += '\n';
+ elif ch == 'r':
+ st += '\r';
+ elif ch == 't':
+ st += '\t';
+ elif ch == 'b':
+ st += '\b';
+ elif ch == 'f':
+ st += '\f';
+ elif ch == 'v':
+ st += '\x0B'
+ # elif ch in '89':
+ # self.throwUnexpectedToken() # again with throw....
+ else:
+ if isOctalDigit(ch):
+ octToDec = self.octalToDecimal(ch)
+ octal = octToDec.get('octal') or octal
+ st += unichr(octToDec['code'])
+ else:
+ st += ch
+ else:
+ self.lineNumber += 1
+ if (ch == '\r' and self.source[self.index] == '\n'):
+ self.index += 1
+ self.lineStart = self.index
+ elif isLineTerminator(ch):
+ break
+ else:
+ st += ch;
+ if (quote != ''):
+ self.throwUnexpectedToken()
+ return {
+ 'type': Token.StringLiteral,
+ 'value': st,
+ 'octal': octal,
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.startLineStart,
+ 'start': start,
+ 'end': self.index}
+
+ def scanTemplate(self):
+ cooked = ''
+ terminated = False
+ tail = False
+ start = self.index
+ head = (self.source[self.index] == '`')
+ rawOffset = 2
+
+ self.index += 1
+
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ self.index += 1
+ if (ch == '`'):
+ rawOffset = 1;
+ tail = True
+ terminated = True
+ break
+ elif (ch == '$'):
+ if (self.source[self.index] == '{'):
+ self.state['curlyStack'].append('${')
+ self.index += 1
+ terminated = True
+ break;
+ cooked += ch
+ elif (ch == '\\'):
+ ch = self.source[self.index]
+ self.index += 1
+ if (not isLineTerminator(ch)):
+ if ch == 'n':
+ cooked += '\n'
+ elif ch == 'r':
+ cooked += '\r'
+ elif ch == 't':
+ cooked += '\t'
+ elif ch in 'ux':
+ if (self.source[self.index] == '{'):
+ self.index += 1
+ cooked += self.scanUnicodeCodePointEscape()
+ else:
+ restore = self.index
+ unescaped = self.scanHexEscape(ch)
+ if (unescaped):
+ cooked += unescaped
+ else:
+ self.index = restore
+ cooked += ch
+ elif ch == 'b':
+ cooked += '\b'
+ elif ch == 'f':
+ cooked += '\f'
+ elif ch == 'v':
+ cooked += '\v'
+ else:
+ if (ch == '0'):
+ if isDecimalDigit(self.ccode()):
+ # Illegal: \01 \02 and so on
+ self.throwError(Messages.TemplateOctalLiteral)
+ cooked += '\0'
+ elif (isOctalDigit(ch)):
+ # Illegal: \1 \2
+ self.throwError(Messages.TemplateOctalLiteral)
+ else:
+ cooked += ch
+ else:
+ self.lineNumber += 1
+ if (ch == '\r' and self.source[self.index] == '\n'):
+ self.index += 1
+ self.lineStart = self.index
+ elif (isLineTerminator(ch)):
+ self.lineNumber += 1
+ if (ch == '\r' and self.source[self.index] == '\n'):
+ self.index += 1
+ self.lineStart = self.index
+ cooked += '\n'
+ else:
+ cooked += ch;
+ if (not terminated):
+ self.throwUnexpectedToken()
+
+ if (not head):
+ self.state['curlyStack'].pop();
+
+ return {
+ 'type': Token.Template,
+ 'value': {
+ 'cooked': cooked,
+ 'raw': self.source[start + 1:self.index - rawOffset]},
+ 'head': head,
+ 'tail': tail,
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': start,
+ 'end': self.index}
+
+ def testRegExp(self, pattern, flags):
+ # todo: you should return python regexp object
+ return (pattern, flags)
+
+ def scanRegExpBody(self):
+ ch = self.source[self.index]
+ assert ch == '/', 'Regular expression literal must start with a slash'
+ st = ch
+ self.index += 1
+
+ classMarker = False
+ terminated = False
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ self.index += 1
+ st += ch
+ if (ch == '\\'):
+ ch = self.source[self.index]
+ self.index += 1
+ # ECMA-262 7.8.5
+ if (isLineTerminator(ch)):
+ self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
+ st += ch
+ elif (isLineTerminator(ch)):
+ self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
+ elif (classMarker):
+ if (ch == ']'):
+ classMarker = False
+ else:
+ if (ch == '/'):
+ terminated = True
+ break
+ elif (ch == '['):
+ classMarker = True;
+ if (not terminated):
+ self.throwUnexpectedToken(None, Messages.UnterminatedRegExp)
+
+ # Exclude leading and trailing slash.
+ body = st[1:-1]
+ return {
+ 'value': body,
+ 'literal': st}
+
+ def scanRegExpFlags(self):
+ st = ''
+ flags = ''
+ while (self.index < self.length):
+ ch = self.source[self.index]
+ if (not isIdentifierPart(ch)):
+ break
+ self.index += 1
+ if (ch == '\\' and self.index < self.length):
+ ch = self.source[self.index]
+ if (ch == 'u'):
+ self.index += 1
+ restore = self.index
+ ch = self.scanHexEscape('u')
+ if (ch):
+ flags += ch
+ st += '\\u'
+ while restore < self.index:
+ st += self.source[restore]
+ restore += 1
+ else:
+ self.index = restore
+ flags += 'u'
+ st += '\\u'
+ self.tolerateUnexpectedToken()
+ else:
+ st += '\\'
+ self.tolerateUnexpectedToken()
+ else:
+ flags += ch
+ st += ch
+ return {
+ 'value': flags,
+ 'literal': st}
+
+ def scanRegExp(self):
+ self.scanning = True
+ self.lookahead = None
+ self.skipComment()
+ start = self.index
+
+ body = self.scanRegExpBody()
+ flags = self.scanRegExpFlags()
+ value = self.testRegExp(body['value'], flags['value'])
+ scanning = False
+ return {
+ 'literal': body['literal'] + flags['literal'],
+ 'value': value,
+ 'regex': {
+ 'pattern': body['value'],
+ 'flags': flags['value']
+ },
+ 'start': start,
+ 'end': self.index}
+
+ def collectRegex(self):
+ self.skipComment();
+ return self.scanRegExp()
+
+ def isIdentifierName(self, token):
+ return token['type'] in (1, 3, 4, 5)
+
+ # def advanceSlash(self): ???
+
+ def advance(self):
+ if (self.index >= self.length):
+ return {
+ 'type': Token.EOF,
+ 'lineNumber': self.lineNumber,
+ 'lineStart': self.lineStart,
+ 'start': self.index,
+ 'end': self.index}
+ ch = self.ccode()
+
+ if isIdentifierStart(ch):
+ token = self.scanIdentifier()
+ if (self.strict and isStrictModeReservedWord(token['value'])):
+ token['type'] = Token.Keyword
+ return token
+ # Very common: ( and ) and ;
+ if (ch == 0x28 or ch == 0x29 or ch == 0x3B):
+ return self.scanPunctuator()
+
+ # String literal starts with single quote (U+0027) or double quote (U+0022).
+ if (ch == 0x27 or ch == 0x22):
+ return self.scanStringLiteral()
+
+ # Dot (.) U+002E can also start a floating-point number, hence the need
+ # to check the next character.
+ if (ch == 0x2E):
+ if (isDecimalDigit(self.ccode(1))):
+ return self.scanNumericLiteral()
+ return self.scanPunctuator();
+
+ if (isDecimalDigit(ch)):
+ return self.scanNumericLiteral()
+
+ # Slash (/) U+002F can also start a regex.
+ # if (extra.tokenize && ch == 0x2F):
+ # return advanceSlash();
+
+ # Template literals start with ` (U+0060) for template head
+ # or } (U+007D) for template middle or template tail.
+ if (ch == 0x60 or (ch == 0x7D and self.state['curlyStack'][len(self.state['curlyStack']) - 1] == '${')):
+ return self.scanTemplate()
+ return self.scanPunctuator();
+
+ # def collectToken(self):
+ # loc = {
+ # 'start': {
+ # 'line': self.lineNumber,
+ # 'column': self.index - self.lineStart}}
+ #
+ # token = self.advance()
+ #
+ # loc['end'] = {
+ # 'line': self.lineNumber,
+ # 'column': self.index - self.lineStart}
+ # if (token['type'] != Token.EOF):
+ # value = self.source[token['start']: token['end']]
+ # entry = {
+ # 'type': TokenName[token['type']],
+ # 'value': value,
+ # 'range': [token['start'], token['end']],
+ # 'loc': loc}
+ # if (token.get('regex')):
+ # entry['regex'] = {
+ # 'pattern': token['regex']['pattern'],
+ # 'flags': token['regex']['flags']}
+ # self.extra['tokens'].append(entry)
+ # return token;
+
+
+ def lex(self):
+ self.scanning = True
+
+ self.lastIndex = self.index
+ self.lastLineNumber = self.lineNumber
+ self.lastLineStart = self.lineStart
+
+ self.skipComment()
+
+ token = self.lookahead
+
+ self.startIndex = self.index
+ self.startLineNumber = self.lineNumber
+ self.startLineStart = self.lineStart
+
+ self.lookahead = self.advance()
+ self.scanning = False
+ return token
+
+ def peek(self):
+ self.scanning = True
+
+ self.skipComment()
+
+ self.lastIndex = self.index
+ self.lastLineNumber = self.lineNumber
+ self.lastLineStart = self.lineStart
+
+ self.startIndex = self.index
+ self.startLineNumber = self.lineNumber
+ self.startLineStart = self.lineStart
+
+ self.lookahead = self.advance()
+ self.scanning = False
+
+ def createError(self, line, pos, description):
+ global ENABLE_PYIMPORT
+ msg = 'Line ' + unicode(line) + ': ' + unicode(description)
+ if ENABLE_JS2PY_ERRORS:
+ if isinstance(ENABLE_JS2PY_ERRORS, bool):
+ import js2py.base
+ return js2py.base.MakeError('SyntaxError', msg)
+ else:
+ return ENABLE_JS2PY_ERRORS(msg)
+ else:
+ return JsSyntaxError(msg)
+
+
+ # Throw an exception
+
+ def throwError(self, messageFormat, *args):
+ msg = messageFormat % tuple(unicode(e) for e in args)
+ raise self.createError(self.lastLineNumber, self.lastIndex, msg);
+
+ def tolerateError(self, messageFormat, *args):
+ return self.throwError(messageFormat, *args)
+
+ # Throw an exception because of the token.
+
+ def unexpectedTokenError(self, token={}, message=''):
+ msg = message or Messages.UnexpectedToken
+ if (token):
+ typ = token['type']
+ if (not message):
+ if typ == Token.EOF:
+ msg = Messages.UnexpectedEOS
+ elif (typ == Token.Identifier):
+ msg = Messages.UnexpectedIdentifier
+ elif (typ == Token.NumericLiteral):
+ msg = Messages.UnexpectedNumber
+ elif (typ == Token.StringLiteral):
+ msg = Messages.UnexpectedString
+ elif (typ == Token.Template):
+ msg = Messages.UnexpectedTemplate
+ else:
+ msg = Messages.UnexpectedToken;
+ if (typ == Token.Keyword):
+ if (isFutureReservedWord(token['value'])):
+ msg = Messages.UnexpectedReserved
+ elif (self.strict and isStrictModeReservedWord(token['value'])):
+ msg = Messages.StrictReservedWord
+ value = token['value']['raw'] if (typ == Token.Template) else token.get('value')
+ else:
+ value = 'ILLEGAL'
+ msg = msg.replace('%s', unicode(value))
+
+ return (self.createError(token['lineNumber'], token['start'], msg) if (token and token.get('lineNumber')) else
+ self.createError(self.lineNumber if self.scanning else self.lastLineNumber,
+ self.index if self.scanning else self.lastIndex, msg))
+
+ def throwUnexpectedToken(self, token={}, message=''):
+ raise self.unexpectedTokenError(token, message)
+
+ def tolerateUnexpectedToken(self, token={}, message=''):
+ self.throwUnexpectedToken(token, message)
+
+ # Expect the next token to match the specified punctuator.
+ # If not, an exception will be thrown.
+
+ def expect(self, value):
+ token = self.lex()
+ if (token['type'] != Token.Punctuator or token['value'] != value):
+ self.throwUnexpectedToken(token)
+
+ # /**
+ # * @name expectCommaSeparator
+ # * @description Quietly expect a comma when in tolerant mode, otherwise delegates
+ # * to <code>expect(value)</code>
+ # * @since 2.0
+ # */
+ def expectCommaSeparator(self):
+ self.expect(',')
+
+ # Expect the next token to match the specified keyword.
+ # If not, an exception will be thrown.
+
+ def expectKeyword(self, keyword):
+ token = self.lex();
+ if (token['type'] != Token.Keyword or token['value'] != keyword):
+ self.throwUnexpectedToken(token)
+
+ # Return true if the next token matches the specified punctuator.
+
+ def match(self, value):
+ return self.lookahead['type'] == Token.Punctuator and self.lookahead['value'] == value
+
+ # Return true if the next token matches the specified keyword
+
+ def matchKeyword(self, keyword):
+ return self.lookahead['type'] == Token.Keyword and self.lookahead['value'] == keyword
+
+ # Return true if the next token matches the specified contextual keyword
+ # (where an identifier is sometimes a keyword depending on the context)
+
+ def matchContextualKeyword(self, keyword):
+ return self.lookahead['type'] == Token.Identifier and self.lookahead['value'] == keyword
+
+ # Return true if the next token is an assignment operator
+
+ def matchAssign(self):
+ if (self.lookahead['type'] != Token.Punctuator):
+ return False;
+ op = self.lookahead['value']
+ return op in ('=', '*=', '/=', '%=', '+=', '-=', '<<=', '>>=', '>>>=', '&=', '^=', '|=')
+
+ def consumeSemicolon(self):
+ # Catch the very common case first: immediately a semicolon (U+003B).
+
+ if (self.at(self.startIndex) == ';' or self.match(';')):
+ self.lex()
+ return
+
+ if (self.hasLineTerminator):
+ return
+
+ # TODO: FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
+ self.lastIndex = self.startIndex
+ self.lastLineNumber = self.startLineNumber
+ self.lastLineStart = self.startLineStart
+
+ if (self.lookahead['type'] != Token.EOF and not self.match('}')):
+ self.throwUnexpectedToken(self.lookahead)
+
+ # // Cover grammar support.
+ # //
+ # // When an assignment expression position starts with an left parenthesis, the determination of the type
+ # // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
+ # // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
+ # //
+ # // There are three productions that can be parsed in a parentheses pair that needs to be determined
+ # // after the outermost pair is closed. They are:
+ # //
+ # // 1. AssignmentExpression
+ # // 2. BindingElements
+ # // 3. AssignmentTargets
+ # //
+ # // In order to avoid exponential backtracking, we use two flags to denote if the production can be
+ # // binding element or assignment target.
+ # //
+ # // The three productions have the relationship:
+ # //
+ # // BindingElements <= AssignmentTargets <= AssignmentExpression
+ # //
+ # // with a single exception that CoverInitializedName when used directly in an Expression, generates
+ # // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
+ # // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
+ # //
+ # // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
+ # // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
+ # // the CoverInitializedName check is conducted.
+ # //
+ # // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
+ # // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
+ # // pattern. The CoverInitializedName check is deferred.
+
+ def isolateCoverGrammar(self, parser):
+ oldIsBindingElement = self.isBindingElement
+ oldIsAssignmentTarget = self.isAssignmentTarget
+ oldFirstCoverInitializedNameError = self.firstCoverInitializedNameError
+ self.isBindingElement = true
+ self.isAssignmentTarget = true
+ self.firstCoverInitializedNameError = null
+ result = parser()
+ if (self.firstCoverInitializedNameError != null):
+ self.throwUnexpectedToken(self.firstCoverInitializedNameError)
+ self.isBindingElement = oldIsBindingElement
+ self.isAssignmentTarget = oldIsAssignmentTarget
+ self.firstCoverInitializedNameError = oldFirstCoverInitializedNameError
+ return result
+
+ def inheritCoverGrammar(self, parser):
+ oldIsBindingElement = self.isBindingElement
+ oldIsAssignmentTarget = self.isAssignmentTarget
+ oldFirstCoverInitializedNameError = self.firstCoverInitializedNameError
+ self.isBindingElement = true
+ self.isAssignmentTarget = true
+ self.firstCoverInitializedNameError = null
+ result = parser()
+ self.isBindingElement = self.isBindingElement and oldIsBindingElement
+ self.isAssignmentTarget = self.isAssignmentTarget and oldIsAssignmentTarget
+ self.firstCoverInitializedNameError = oldFirstCoverInitializedNameError or self.firstCoverInitializedNameError
+ return result
+
+ def parseArrayPattern(self):
+ node = Node()
+ elements = []
+ self.expect('[');
+ while (not self.match(']')):
+ if (self.match(',')):
+ self.lex()
+ elements.append(null)
+ else:
+ if (self.match('...')):
+ restNode = Node()
+ self.lex()
+ rest = self.parseVariableIdentifier()
+ elements.append(restNode.finishRestElement(rest))
+ break
+ else:
+ elements.append(self.parsePatternWithDefault())
+ if (not self.match(']')):
+ self.expect(',')
+ self.expect(']')
+ return node.finishArrayPattern(elements)
+
+ def parsePropertyPattern(self):
+ node = Node()
+ computed = self.match('[')
+ if (self.lookahead['type'] == Token.Identifier):
+ key = self.parseVariableIdentifier()
+ if (self.match('=')):
+ self.lex();
+ init = self.parseAssignmentExpression()
+ return node.finishProperty(
+ 'init', key, false, WrappingNode(key).finishAssignmentPattern(key, init), false, false)
+ elif (not self.match(':')):
+ return node.finishProperty('init', key, false, key, false, true)
+ else:
+ key = self.parseObjectPropertyKey()
+ self.expect(':')
+ init = self.parsePatternWithDefault()
+ return node.finishProperty('init', key, computed, init, false, false)
+
+ def parseObjectPattern(self):
+ node = Node()
+ properties = []
+ self.expect('{')
+ while (not self.match('}')):
+ properties.append(self.parsePropertyPattern())
+ if (not self.match('}')):
+ self.expect(',')
+ self.lex()
+ return node.finishObjectPattern(properties)
+
+ def parsePattern(self):
+ if (self.lookahead['type'] == Token.Identifier):
+ return self.parseVariableIdentifier()
+ elif (self.match('[')):
+ return self.parseArrayPattern()
+ elif (self.match('{')):
+ return self.parseObjectPattern()
+ self.throwUnexpectedToken(self.lookahead)
+
+ def parsePatternWithDefault(self):
+ startToken = self.lookahead
+
+ pattern = self.parsePattern()
+ if (self.match('=')):
+ self.lex()
+ right = self.isolateCoverGrammar(self.parseAssignmentExpression)
+ pattern = WrappingNode(startToken).finishAssignmentPattern(pattern, right)
+ return pattern
+
+ # 11.1.4 Array Initialiser
+
+ def parseArrayInitialiser(self):
+ elements = []
+ node = Node()
+
+ self.expect('[')
+
+ while (not self.match(']')):
+ if (self.match(',')):
+ self.lex()
+ elements.append(null)
+ elif (self.match('...')):
+ restSpread = Node()
+ self.lex()
+ restSpread.finishSpreadElement(self.inheritCoverGrammar(self.parseAssignmentExpression))
+ if (not self.match(']')):
+ self.isAssignmentTarget = self.isBindingElement = false
+ self.expect(',')
+ elements.append(restSpread)
+ else:
+ elements.append(self.inheritCoverGrammar(self.parseAssignmentExpression))
+ if (not self.match(']')):
+ self.expect(',')
+ self.lex();
+
+ return node.finishArrayExpression(elements)
+
+ # 11.1.5 Object Initialiser
+
+ def parsePropertyFunction(self, node, paramInfo):
+
+ self.isAssignmentTarget = self.isBindingElement = false;
+
+ previousStrict = self.strict;
+ body = self.isolateCoverGrammar(self.parseFunctionSourceElements);
+
+ if (self.strict and paramInfo['firstRestricted']):
+ self.tolerateUnexpectedToken(paramInfo['firstRestricted'], paramInfo.get('message'))
+ if (self.strict and paramInfo.get('stricted')):
+ self.tolerateUnexpectedToken(paramInfo.get('stricted'), paramInfo.get('message'));
+
+ self.strict = previousStrict;
+ return node.finishFunctionExpression(null, paramInfo.get('params'), paramInfo.get('defaults'), body)
+
+ def parsePropertyMethodFunction(self):
+ node = Node();
+
+ params = self.parseParams(null);
+ method = self.parsePropertyFunction(node, params);
+ return method;
+
+ def parseObjectPropertyKey(self):
+ node = Node()
+
+ token = self.lex();
+
+ # // Note: This function is called only from parseObjectProperty(), where
+ # // EOF and Punctuator tokens are already filtered out.
+
+ typ = token['type']
+
+ if typ in [Token.StringLiteral, Token.NumericLiteral]:
+ if self.strict and token.get('octal'):
+ self.tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
+ return node.finishLiteral(token);
+ elif typ in (Token.Identifier, Token.BooleanLiteral, Token.NullLiteral, Token.Keyword):
+ return node.finishIdentifier(token['value']);
+ elif typ == Token.Punctuator:
+ if (token['value'] == '['):
+ expr = self.isolateCoverGrammar(self.parseAssignmentExpression)
+ self.expect(']')
+ return expr
+ self.throwUnexpectedToken(token)
+
+ def lookaheadPropertyName(self):
+ typ = self.lookahead['type']
+ if typ in (Token.Identifier, Token.StringLiteral, Token.BooleanLiteral, Token.NullLiteral, Token.NumericLiteral,
+ Token.Keyword):
+ return true
+ if typ == Token.Punctuator:
+ return self.lookahead['value'] == '['
+ return false
+
+ # // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
+ # // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
+ # // This can only be determined after we consumed up to the left parentheses.
+ # //
+ # // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
+ # // is responsible to visit other options.
+ def tryParseMethodDefinition(self, token, key, computed, node):
+ if (token['type'] == Token.Identifier):
+ # check for `get` and `set`;
+
+ if (token['value'] == 'get' and self.lookaheadPropertyName()):
+ computed = self.match('[');
+ key = self.parseObjectPropertyKey()
+ methodNode = Node()
+ self.expect('(')
+ self.expect(')')
+ value = self.parsePropertyFunction(methodNode, {
+ 'params': [],
+ 'defaults': [],
+ 'stricted': null,
+ 'firstRestricted': null,
+ 'message': null
+ })
+ return node.finishProperty('get', key, computed, value, false, false)
+ elif (token['value'] == 'set' and self.lookaheadPropertyName()):
+ computed = self.match('[')
+ key = self.parseObjectPropertyKey()
+ methodNode = Node()
+ self.expect('(')
+
+ options = {
+ 'params': [],
+ 'defaultCount': 0,
+ 'defaults': [],
+ 'firstRestricted': null,
+ 'paramSet': {}
+ }
+ if (self.match(')')):
+ self.tolerateUnexpectedToken(self.lookahead);
+ else:
+ self.parseParam(options);
+ if (options['defaultCount'] == 0):
+ options['defaults'] = []
+ self.expect(')')
+
+ value = self.parsePropertyFunction(methodNode, options);
+ return node.finishProperty('set', key, computed, value, false, false);
+ if (self.match('(')):
+ value = self.parsePropertyMethodFunction();
+ return node.finishProperty('init', key, computed, value, true, false)
+ return null;
+
+ def checkProto(self, key, computed, hasProto):
+ if (computed == false and (key['type'] == Syntax.Identifier and key['name'] == '__proto__' or
+ key['type'] == Syntax.Literal and key['value'] == '__proto__')):
+ if (hasProto['value']):
+ self.tolerateError(Messages.DuplicateProtoProperty);
+ else:
+ hasProto['value'] = true;
+
+ def parseObjectProperty(self, hasProto):
+ token = self.lookahead
+ node = Node()
+
+ computed = self.match('[');
+ key = self.parseObjectPropertyKey();
+ maybeMethod = self.tryParseMethodDefinition(token, key, computed, node)
+
+ if (maybeMethod):
+ self.checkProto(maybeMethod['key'], maybeMethod['computed'], hasProto);
+ return maybeMethod;
+
+ # // init property or short hand property.
+ self.checkProto(key, computed, hasProto);
+
+ if (self.match(':')):
+ self.lex();
+ value = self.inheritCoverGrammar(self.parseAssignmentExpression)
+ return node.finishProperty('init', key, computed, value, false, false)
+
+ if (token['type'] == Token.Identifier):
+ if (self.match('=')):
+ self.firstCoverInitializedNameError = self.lookahead;
+ self.lex();
+ value = self.isolateCoverGrammar(self.parseAssignmentExpression);
+ return node.finishProperty('init', key, computed,
+ WrappingNode(token).finishAssignmentPattern(key, value), false, true)
+ return node.finishProperty('init', key, computed, key, false, true)
+ self.throwUnexpectedToken(self.lookahead)
+
+ def parseObjectInitialiser(self):
+ properties = []
+ hasProto = {'value': false}
+ node = Node();
+
+ self.expect('{');
+
+ while (not self.match('}')):
+ properties.append(self.parseObjectProperty(hasProto));
+
+ if (not self.match('}')):
+ self.expectCommaSeparator()
+ self.expect('}');
+ return node.finishObjectExpression(properties)
+
+ def reinterpretExpressionAsPattern(self, expr):
+ typ = (expr['type'])
+ if typ in (Syntax.Identifier, Syntax.MemberExpression, Syntax.RestElement, Syntax.AssignmentPattern):
+ pass
+ elif typ == Syntax.SpreadElement:
+ expr['type'] = Syntax.RestElement
+ self.reinterpretExpressionAsPattern(expr.argument)
+ elif typ == Syntax.ArrayExpression:
+ expr['type'] = Syntax.ArrayPattern
+ for i in xrange(len(expr['elements'])):
+ if (expr['elements'][i] != null):
+ self.reinterpretExpressionAsPattern(expr['elements'][i])
+ elif typ == Syntax.ObjectExpression:
+ expr['type'] = Syntax.ObjectPattern
+ for i in xrange(len(expr['properties'])):
+ self.reinterpretExpressionAsPattern(expr['properties'][i]['value']);
+ elif Syntax.AssignmentExpression:
+ expr['type'] = Syntax.AssignmentPattern;
+ self.reinterpretExpressionAsPattern(expr['left'])
+ else:
+ # // Allow other node type for tolerant parsing.
+ return
+
+ def parseTemplateElement(self, option):
+
+ if (self.lookahead['type'] != Token.Template or (option['head'] and not self.lookahead['head'])):
+ self.throwUnexpectedToken()
+
+ node = Node();
+ token = self.lex();
+
+ return node.finishTemplateElement({'raw': token['value']['raw'], 'cooked': token['value']['cooked']},
+ token['tail'])
+
+ def parseTemplateLiteral(self):
+ node = Node()
+
+ quasi = self.parseTemplateElement({'head': true})
+ quasis = [quasi]
+ expressions = []
+
+ while (not quasi['tail']):
+ expressions.append(self.parseExpression());
+ quasi = self.parseTemplateElement({'head': false});
+ quasis.append(quasi)
+ return node.finishTemplateLiteral(quasis, expressions)
+
+ # 11.1.6 The Grouping Operator
+
+ def parseGroupExpression(self):
+ self.expect('(');
+
+ if (self.match(')')):
+ self.lex();
+ if (not self.match('=>')):
+ self.expect('=>')
+ return {
+ 'type': PlaceHolders.ArrowParameterPlaceHolder,
+ 'params': []}
+
+ startToken = self.lookahead
+ if (self.match('...')):
+ expr = self.parseRestElement();
+ self.expect(')');
+ if (not self.match('=>')):
+ self.expect('=>')
+ return {
+ 'type': PlaceHolders.ArrowParameterPlaceHolder,
+ 'params': [expr]}
+
+ self.isBindingElement = true;
+ expr = self.inheritCoverGrammar(self.parseAssignmentExpression);
+
+ if (self.match(',')):
+ self.isAssignmentTarget = false;
+ expressions = [expr]
+
+ while (self.startIndex < self.length):
+ if (not self.match(',')):
+ break
+ self.lex();
+
+ if (self.match('...')):
+ if (not self.isBindingElement):
+ self.throwUnexpectedToken(self.lookahead)
+ expressions.append(self.parseRestElement())
+ self.expect(')');
+ if (not self.match('=>')):
+ self.expect('=>');
+ self.isBindingElement = false
+ for i in xrange(len(expressions)):
+ self.reinterpretExpressionAsPattern(expressions[i])
+ return {
+ 'type': PlaceHolders.ArrowParameterPlaceHolder,
+ 'params': expressions}
+ expressions.append(self.inheritCoverGrammar(self.parseAssignmentExpression))
+ expr = WrappingNode(startToken).finishSequenceExpression(expressions);
+ self.expect(')')
+
+ if (self.match('=>')):
+ if (not self.isBindingElement):
+ self.throwUnexpectedToken(self.lookahead);
+ if (expr['type'] == Syntax.SequenceExpression):
+ for i in xrange(len(expr.expressions)):
+ self.reinterpretExpressionAsPattern(expr['expressions'][i])
+ else:
+ self.reinterpretExpressionAsPattern(expr);
+ expr = {
+ 'type': PlaceHolders.ArrowParameterPlaceHolder,
+ 'params': expr['expressions'] if expr['type'] == Syntax.SequenceExpression else [expr]}
+ self.isBindingElement = false
+ return expr
+
+ # 11.1 Primary Expressions
+
+ def parsePrimaryExpression(self):
+ if (self.match('(')):
+ self.isBindingElement = false;
+ return self.inheritCoverGrammar(self.parseGroupExpression)
+ if (self.match('[')):
+ return self.inheritCoverGrammar(self.parseArrayInitialiser)
+
+ if (self.match('{')):
+ return self.inheritCoverGrammar(self.parseObjectInitialiser)
+
+ typ = self.lookahead['type']
+ node = Node();
+
+ if (typ == Token.Identifier):
+ expr = node.finishIdentifier(self.lex()['value']);
+ elif (typ == Token.StringLiteral or typ == Token.NumericLiteral):
+ self.isAssignmentTarget = self.isBindingElement = false
+ if (self.strict and self.lookahead.get('octal')):
+ self.tolerateUnexpectedToken(self.lookahead, Messages.StrictOctalLiteral)
+ expr = node.finishLiteral(self.lex())
+ elif (typ == Token.Keyword):
+ self.isAssignmentTarget = self.isBindingElement = false
+ if (self.matchKeyword('function')):
+ return self.parseFunctionExpression()
+ if (self.matchKeyword('this')):
+ self.lex()
+ return node.finishThisExpression()
+ if (self.matchKeyword('class')):
+ return self.parseClassExpression()
+ self.throwUnexpectedToken(self.lex())
+ elif (typ == Token.BooleanLiteral):
+ isAssignmentTarget = self.isBindingElement = false
+ token = self.lex();
+ token['value'] = (token['value'] == 'true')
+ expr = node.finishLiteral(token)
+ elif (typ == Token.NullLiteral):
+ self.isAssignmentTarget = self.isBindingElement = false
+ token = self.lex()
+ token['value'] = null;
+ expr = node.finishLiteral(token)
+ elif (self.match('/') or self.match('/=')):
+ self.isAssignmentTarget = self.isBindingElement = false;
+ self.index = self.startIndex;
+ token = self.scanRegExp(); # hehe, here you are!
+ self.lex();
+ expr = node.finishLiteral(token);
+ elif (typ == Token.Template):
+ expr = self.parseTemplateLiteral()
+ else:
+ self.throwUnexpectedToken(self.lex());
+ return expr;
+
+ # 11.2 Left-Hand-Side Expressions
+
+ def parseArguments(self):
+ args = [];
+
+ self.expect('(');
+ if (not self.match(')')):
+ while (self.startIndex < self.length):
+ args.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
+ if (self.match(')')):
+ break
+ self.expectCommaSeparator()
+ self.expect(')')
+ return args;
+
+ def parseNonComputedProperty(self):
+ node = Node()
+
+ token = self.lex();
+
+ if (not self.isIdentifierName(token)):
+ self.throwUnexpectedToken(token)
+ return node.finishIdentifier(token['value'])
+
+ def parseNonComputedMember(self):
+ self.expect('.')
+ return self.parseNonComputedProperty();
+
+ def parseComputedMember(self):
+ self.expect('[')
+
+ expr = self.isolateCoverGrammar(self.parseExpression)
+ self.expect(']')
+
+ return expr
+
+ def parseNewExpression(self):
+ node = Node()
+ self.expectKeyword('new')
+ callee = self.isolateCoverGrammar(self.parseLeftHandSideExpression)
+ args = self.parseArguments() if self.match('(') else []
+
+ self.isAssignmentTarget = self.isBindingElement = false
+
+ return node.finishNewExpression(callee, args)
+
+ def parseLeftHandSideExpressionAllowCall(self):
+ previousAllowIn = self.state['allowIn']
+
+ startToken = self.lookahead;
+ self.state['allowIn'] = true;
+
+ if (self.matchKeyword('super') and self.state['inFunctionBody']):
+ expr = Node();
+ self.lex();
+ expr = expr.finishSuper()
+ if (not self.match('(') and not self.match('.') and not self.match('[')):
+ self.throwUnexpectedToken(self.lookahead);
+ else:
+ expr = self.inheritCoverGrammar(
+ self.parseNewExpression if self.matchKeyword('new') else self.parsePrimaryExpression)
+ while True:
+ if (self.match('.')):
+ self.isBindingElement = false;
+ self.isAssignmentTarget = true;
+ property = self.parseNonComputedMember();
+ expr = WrappingNode(startToken).finishMemberExpression('.', expr, property)
+ elif (self.match('(')):
+ self.isBindingElement = false;
+ self.isAssignmentTarget = false;
+ args = self.parseArguments();
+ expr = WrappingNode(startToken).finishCallExpression(expr, args)
+ elif (self.match('[')):
+ self.isBindingElement = false;
+ self.isAssignmentTarget = true;
+ property = self.parseComputedMember();
+ expr = WrappingNode(startToken).finishMemberExpression('[', expr, property)
+ elif (self.lookahead['type'] == Token.Template and self.lookahead['head']):
+ quasi = self.parseTemplateLiteral()
+ expr = WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi)
+ else:
+ break
+ self.state['allowIn'] = previousAllowIn
+
+ return expr
+
+ def parseLeftHandSideExpression(self):
+ assert self.state['allowIn'], 'callee of new expression always allow in keyword.'
+
+ startToken = self.lookahead
+
+ if (self.matchKeyword('super') and self.state['inFunctionBody']):
+ expr = Node();
+ self.lex();
+ expr = expr.finishSuper();
+ if (not self.match('[') and not self.match('.')):
+ self.throwUnexpectedToken(self.lookahead)
+ else:
+ expr = self.inheritCoverGrammar(
+ self.parseNewExpression if self.matchKeyword('new') else self.parsePrimaryExpression);
+
+ while True:
+ if (self.match('[')):
+ self.isBindingElement = false;
+ self.isAssignmentTarget = true;
+ property = self.parseComputedMember();
+ expr = WrappingNode(startToken).finishMemberExpression('[', expr, property)
+ elif (self.match('.')):
+ self.isBindingElement = false;
+ self.isAssignmentTarget = true;
+ property = self.parseNonComputedMember();
+ expr = WrappingNode(startToken).finishMemberExpression('.', expr, property);
+ elif (self.lookahead['type'] == Token.Template and self.lookahead['head']):
+ quasi = self.parseTemplateLiteral();
+ expr = WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi)
+ else:
+ break
+ return expr
+
+ # 11.3 Postfix Expressions
+
+ def parsePostfixExpression(self):
+ startToken = self.lookahead
+
+ expr = self.inheritCoverGrammar(self.parseLeftHandSideExpressionAllowCall)
+
+ if (not self.hasLineTerminator and self.lookahead['type'] == Token.Punctuator):
+ if (self.match('++') or self.match('--')):
+ # 11.3.1, 11.3.2
+ if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
+ self.tolerateError(Messages.StrictLHSPostfix)
+ if (not self.isAssignmentTarget):
+ self.tolerateError(Messages.InvalidLHSInAssignment);
+ self.isAssignmentTarget = self.isBindingElement = false;
+
+ token = self.lex();
+ expr = WrappingNode(startToken).finishPostfixExpression(token['value'], expr);
+ return expr;
+
+ # 11.4 Unary Operators
+
+ def parseUnaryExpression(self):
+
+ if (self.lookahead['type'] != Token.Punctuator and self.lookahead['type'] != Token.Keyword):
+ expr = self.parsePostfixExpression();
+ elif (self.match('++') or self.match('--')):
+ startToken = self.lookahead;
+ token = self.lex();
+ expr = self.inheritCoverGrammar(self.parseUnaryExpression);
+ # 11.4.4, 11.4.5
+ if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
+ self.tolerateError(Messages.StrictLHSPrefix)
+ if (not self.isAssignmentTarget):
+ self.tolerateError(Messages.InvalidLHSInAssignment)
+ expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr)
+ self.isAssignmentTarget = self.isBindingElement = false
+ elif (self.match('+') or self.match('-') or self.match('~') or self.match('!')):
+ startToken = self.lookahead;
+ token = self.lex();
+ expr = self.inheritCoverGrammar(self.parseUnaryExpression);
+ expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr)
+ self.isAssignmentTarget = self.isBindingElement = false;
+ elif (self.matchKeyword('delete') or self.matchKeyword('void') or self.matchKeyword('typeof')):
+ startToken = self.lookahead;
+ token = self.lex();
+ expr = self.inheritCoverGrammar(self.parseUnaryExpression);
+ expr = WrappingNode(startToken).finishUnaryExpression(token['value'], expr);
+ if (self.strict and expr.operator == 'delete' and expr.argument.type == Syntax.Identifier):
+ self.tolerateError(Messages.StrictDelete)
+ self.isAssignmentTarget = self.isBindingElement = false;
+ else:
+ expr = self.parsePostfixExpression()
+ return expr
+
+ def binaryPrecedence(self, token, allowIn):
+ prec = 0;
+ typ = token['type']
+ if (typ != Token.Punctuator and typ != Token.Keyword):
+ return 0;
+ val = token['value']
+ if val == 'in' and not allowIn:
+ return 0
+ return PRECEDENCE.get(val, 0)
+
+ # 11.5 Multiplicative Operators
+ # 11.6 Additive Operators
+ # 11.7 Bitwise Shift Operators
+ # 11.8 Relational Operators
+ # 11.9 Equality Operators
+ # 11.10 Binary Bitwise Operators
+ # 11.11 Binary Logical Operators
+
+ def parseBinaryExpression(self):
+
+ marker = self.lookahead;
+ left = self.inheritCoverGrammar(self.parseUnaryExpression);
+
+ token = self.lookahead;
+ prec = self.binaryPrecedence(token, self.state['allowIn']);
+ if (prec == 0):
+ return left
+ self.isAssignmentTarget = self.isBindingElement = false;
+ token['prec'] = prec
+ self.lex()
+
+ markers = [marker, self.lookahead];
+ right = self.isolateCoverGrammar(self.parseUnaryExpression);
+
+ stack = [left, token, right];
+
+ while True:
+ prec = self.binaryPrecedence(self.lookahead, self.state['allowIn'])
+ if not prec > 0:
+ break
+ # Reduce: make a binary expression from the three topmost entries.
+ while ((len(stack) > 2) and (prec <= stack[len(stack) - 2]['prec'])):
+ right = stack.pop();
+ operator = stack.pop()['value']
+ left = stack.pop()
+ markers.pop()
+ expr = WrappingNode(markers[len(markers) - 1]).finishBinaryExpression(operator, left, right)
+ stack.append(expr)
+
+ # Shift
+ token = self.lex();
+ token['prec'] = prec;
+ stack.append(token);
+ markers.append(self.lookahead);
+ expr = self.isolateCoverGrammar(self.parseUnaryExpression);
+ stack.append(expr);
+
+ # Final reduce to clean-up the stack.
+ i = len(stack) - 1;
+ expr = stack[i]
+ markers.pop()
+ while (i > 1):
+ expr = WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1]['value'], stack[i - 2], expr);
+ i -= 2
+ return expr
+
+ # 11.12 Conditional Operator
+
+ def parseConditionalExpression(self):
+
+ startToken = self.lookahead
+
+ expr = self.inheritCoverGrammar(self.parseBinaryExpression);
+ if (self.match('?')):
+ self.lex()
+ previousAllowIn = self.state['allowIn']
+ self.state['allowIn'] = true;
+ consequent = self.isolateCoverGrammar(self.parseAssignmentExpression);
+ self.state['allowIn'] = previousAllowIn;
+ self.expect(':');
+ alternate = self.isolateCoverGrammar(self.parseAssignmentExpression)
+
+ expr = WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
+ self.isAssignmentTarget = self.isBindingElement = false;
+ return expr
+
+ # [ES6] 14.2 Arrow Function
+
+ def parseConciseBody(self):
+ if (self.match('{')):
+ return self.parseFunctionSourceElements()
+ return self.isolateCoverGrammar(self.parseAssignmentExpression)
+
+ def checkPatternParam(self, options, param):
+ typ = param.type
+ if typ == Syntax.Identifier:
+ self.validateParam(options, param, param.name);
+ elif typ == Syntax.RestElement:
+ self.checkPatternParam(options, param.argument)
+ elif typ == Syntax.AssignmentPattern:
+ self.checkPatternParam(options, param.left)
+ elif typ == Syntax.ArrayPattern:
+ for i in xrange(len(param.elements)):
+ if (param.elements[i] != null):
+ self.checkPatternParam(options, param.elements[i]);
+ else:
+ assert typ == Syntax.ObjectPattern, 'Invalid type'
+ for i in xrange(len(param.properties)):
+ self.checkPatternParam(options, param.properties[i]['value']);
+
+ def reinterpretAsCoverFormalsList(self, expr):
+ defaults = [];
+ defaultCount = 0;
+ params = [expr];
+ typ = expr.type
+ if typ == Syntax.Identifier:
+ pass
+ elif typ == PlaceHolders.ArrowParameterPlaceHolder:
+ params = expr.params
+ else:
+ return null
+ options = {
+ 'paramSet': {}}
+ le = len(params)
+ for i in xrange(le):
+ param = params[i]
+ if param.type == Syntax.AssignmentPattern:
+ params[i] = param.left;
+ defaults.append(param.right);
+ defaultCount += 1
+ self.checkPatternParam(options, param.left);
+ else:
+ self.checkPatternParam(options, param);
+ params[i] = param;
+ defaults.append(null);
+ if (options.get('message') == Messages.StrictParamDupe):
+ token = options.get('stricted') if self.strict else options['firstRestricted']
+ self.throwUnexpectedToken(token, options.get('message'));
+ if (defaultCount == 0):
+ defaults = []
+ return {
+ 'params': params,
+ 'defaults': defaults,
+ 'stricted': options['stricted'],
+ 'firstRestricted': options['firstRestricted'],
+ 'message': options.get('message')}
+
+ def parseArrowFunctionExpression(self, options, node):
+ if (self.hasLineTerminator):
+ self.tolerateUnexpectedToken(self.lookahead)
+ self.expect('=>')
+ previousStrict = self.strict;
+
+ body = self.parseConciseBody();
+
+ if (self.strict and options['firstRestricted']):
+ self.throwUnexpectedToken(options['firstRestricted'], options.get('message'));
+ if (self.strict and options['stricted']):
+ self.tolerateUnexpectedToken(options['stricted'], options['message']);
+
+ self.strict = previousStrict
+
+ return node.finishArrowFunctionExpression(options['params'], options['defaults'], body,
+ body.type != Syntax.BlockStatement)
+
+ # 11.13 Assignment Operators
+
+ def parseAssignmentExpression(self):
+ startToken = self.lookahead;
+ token = self.lookahead;
+
+ expr = self.parseConditionalExpression();
+
+ if (expr.type == PlaceHolders.ArrowParameterPlaceHolder or self.match('=>')):
+ self.isAssignmentTarget = self.isBindingElement = false;
+ lis = self.reinterpretAsCoverFormalsList(expr)
+
+ if (lis):
+ self.firstCoverInitializedNameError = null;
+ return self.parseArrowFunctionExpression(lis, WrappingNode(startToken))
+ return expr
+
+ if (self.matchAssign()):
+ if (not self.isAssignmentTarget or expr.type==Syntax.Literal):
+ self.tolerateError(Messages.InvalidLHSInAssignment)
+ # 11.13.1
+
+ if (self.strict and expr.type == Syntax.Identifier and isRestrictedWord(expr.name)):
+ self.tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
+ if (not self.match('=')):
+ self.isAssignmentTarget = self.isBindingElement = false;
+ else:
+ self.reinterpretExpressionAsPattern(expr)
+ token = self.lex();
+ right = self.isolateCoverGrammar(self.parseAssignmentExpression)
+ expr = WrappingNode(startToken).finishAssignmentExpression(token['value'], expr, right);
+ self.firstCoverInitializedNameError = null
+ return expr
+
+ # 11.14 Comma Operator
+
+ def parseExpression(self):
+ startToken = self.lookahead
+ expr = self.isolateCoverGrammar(self.parseAssignmentExpression)
+
+ if (self.match(',')):
+ expressions = [expr];
+
+ while (self.startIndex < self.length):
+ if (not self.match(',')):
+ break
+ self.lex();
+ expressions.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
+ expr = WrappingNode(startToken).finishSequenceExpression(expressions);
+ return expr
+
+ # 12.1 Block
+
+ def parseStatementListItem(self):
+ if (self.lookahead['type'] == Token.Keyword):
+ val = (self.lookahead['value'])
+ if val == 'export':
+ if (self.sourceType != 'module'):
+ self.tolerateUnexpectedToken(self.lookahead, Messages.IllegalExportDeclaration)
+ return self.parseExportDeclaration();
+ elif val == 'import':
+ if (self.sourceType != 'module'):
+ self.tolerateUnexpectedToken(self.lookahead, Messages.IllegalImportDeclaration);
+ return self.parseImportDeclaration();
+ elif val == 'const' or val == 'let':
+ return self.parseLexicalDeclaration({'inFor': false});
+ elif val == 'function':
+ return self.parseFunctionDeclaration(Node());
+ elif val == 'class':
+ return self.parseClassDeclaration();
+ elif ENABLE_PYIMPORT and val == 'pyimport': # <<<<< MODIFIED HERE
+ return self.parsePyimportStatement()
+ return self.parseStatement();
+
+ def parsePyimportStatement(self):
+ print(ENABLE_PYIMPORT)
+ assert ENABLE_PYIMPORT
+ n = Node()
+ self.lex()
+ n.finishPyimport(self.parseVariableIdentifier())
+ self.consumeSemicolon()
+ return n
+
+ def parseStatementList(self):
+ list = [];
+ while (self.startIndex < self.length):
+ if (self.match('}')):
+ break
+ list.append(self.parseStatementListItem())
+ return list
+
+ def parseBlock(self):
+ node = Node();
+
+ self.expect('{');
+
+ block = self.parseStatementList()
+
+ self.expect('}');
+
+ return node.finishBlockStatement(block);
+
+ # 12.2 Variable Statement
+
+ def parseVariableIdentifier(self):
+ node = Node()
+
+ token = self.lex()
+
+ if (token['type'] != Token.Identifier):
+ if (self.strict and token['type'] == Token.Keyword and isStrictModeReservedWord(token['value'])):
+ self.tolerateUnexpectedToken(token, Messages.StrictReservedWord);
+ else:
+ self.throwUnexpectedToken(token)
+ return node.finishIdentifier(token['value'])
+
+ def parseVariableDeclaration(self):
+ init = null
+ node = Node();
+
+ d = self.parsePattern();
+
+ # 12.2.1
+ if (self.strict and isRestrictedWord(d.name)):
+ self.tolerateError(Messages.StrictVarName);
+
+ if (self.match('=')):
+ self.lex();
+ init = self.isolateCoverGrammar(self.parseAssignmentExpression);
+ elif (d.type != Syntax.Identifier):
+ self.expect('=')
+ return node.finishVariableDeclarator(d, init)
+
+ def parseVariableDeclarationList(self):
+ lis = []
+
+ while True:
+ lis.append(self.parseVariableDeclaration())
+ if (not self.match(',')):
+ break
+ self.lex();
+ if not (self.startIndex < self.length):
+ break
+
+ return lis;
+
+ def parseVariableStatement(self, node):
+ self.expectKeyword('var')
+
+ declarations = self.parseVariableDeclarationList()
+
+ self.consumeSemicolon()
+
+ return node.finishVariableDeclaration(declarations)
+
+ def parseLexicalBinding(self, kind, options):
+ init = null
+ node = Node()
+
+ d = self.parsePattern();
+
+ # 12.2.1
+ if (self.strict and d.type == Syntax.Identifier and isRestrictedWord(d.name)):
+ self.tolerateError(Messages.StrictVarName);
+
+ if (kind == 'const'):
+ if (not self.matchKeyword('in')):
+ self.expect('=')
+ init = self.isolateCoverGrammar(self.parseAssignmentExpression)
+ elif ((not options['inFor'] and d.type != Syntax.Identifier) or self.match('=')):
+ self.expect('=');
+ init = self.isolateCoverGrammar(self.parseAssignmentExpression);
+ return node.finishVariableDeclarator(d, init)
+
+ def parseBindingList(self, kind, options):
+ list = [];
+
+ while True:
+ list.append(self.parseLexicalBinding(kind, options));
+ if (not self.match(',')):
+ break
+ self.lex();
+ if not (self.startIndex < self.length):
+ break
+ return list;
+
+ def parseLexicalDeclaration(self, options):
+ node = Node();
+
+ kind = self.lex()['value']
+ assert kind == 'let' or kind == 'const', 'Lexical declaration must be either let or const'
+ declarations = self.parseBindingList(kind, options);
+ self.consumeSemicolon();
+ return node.finishLexicalDeclaration(declarations, kind);
+
+ def parseRestElement(self):
+ node = Node();
+
+ self.lex();
+
+ if (self.match('{')):
+ self.throwError(Messages.ObjectPatternAsRestParameter)
+ param = self.parseVariableIdentifier();
+ if (self.match('=')):
+ self.throwError(Messages.DefaultRestParameter);
+
+ if (not self.match(')')):
+ self.throwError(Messages.ParameterAfterRestParameter);
+ return node.finishRestElement(param);
+
+ # 12.3 Empty Statement
+
+ def parseEmptyStatement(self, node):
+ self.expect(';');
+ return node.finishEmptyStatement()
+
+ # 12.4 Expression Statement
+
+ def parseExpressionStatement(self, node):
+ expr = self.parseExpression();
+ self.consumeSemicolon();
+ return node.finishExpressionStatement(expr);
+
+ # 12.5 If statement
+
+ def parseIfStatement(self, node):
+ self.expectKeyword('if');
+
+ self.expect('(');
+
+ test = self.parseExpression();
+
+ self.expect(')');
+
+ consequent = self.parseStatement();
+
+ if (self.matchKeyword('else')):
+ self.lex();
+ alternate = self.parseStatement();
+ else:
+ alternate = null;
+ return node.finishIfStatement(test, consequent, alternate)
+
+ # 12.6 Iteration Statements
+
+ def parseDoWhileStatement(self, node):
+
+ self.expectKeyword('do')
+
+ oldInIteration = self.state['inIteration']
+ self.state['inIteration'] = true
+
+ body = self.parseStatement();
+
+ self.state['inIteration'] = oldInIteration;
+
+ self.expectKeyword('while');
+
+ self.expect('(');
+
+ test = self.parseExpression();
+
+ self.expect(')')
+
+ if (self.match(';')):
+ self.lex()
+ return node.finishDoWhileStatement(body, test)
+
+ def parseWhileStatement(self, node):
+
+ self.expectKeyword('while')
+
+ self.expect('(')
+
+ test = self.parseExpression()
+
+ self.expect(')')
+
+ oldInIteration = self.state['inIteration']
+ self.state['inIteration'] = true
+
+ body = self.parseStatement()
+
+ self.state['inIteration'] = oldInIteration
+
+ return node.finishWhileStatement(test, body)
+
+ def parseForStatement(self, node):
+ previousAllowIn = self.state['allowIn']
+
+ init = test = update = null
+
+ self.expectKeyword('for')
+
+ self.expect('(')
+
+ if (self.match(';')):
+ self.lex()
+ else:
+ if (self.matchKeyword('var')):
+ init = Node()
+ self.lex()
+
+ self.state['allowIn'] = false;
+ init = init.finishVariableDeclaration(self.parseVariableDeclarationList())
+ self.state['allowIn'] = previousAllowIn
+
+ if (len(init.declarations) == 1 and self.matchKeyword('in')):
+ self.lex()
+ left = init
+ right = self.parseExpression()
+ init = null
+ else:
+ self.expect(';')
+ elif (self.matchKeyword('const') or self.matchKeyword('let')):
+ init = Node()
+ kind = self.lex()['value']
+
+ self.state['allowIn'] = false
+ declarations = self.parseBindingList(kind, {'inFor': true})
+ self.state['allowIn'] = previousAllowIn
+
+ if (len(declarations) == 1 and declarations[0].init == null and self.matchKeyword('in')):
+ init = init.finishLexicalDeclaration(declarations, kind);
+ self.lex();
+ left = init;
+ right = self.parseExpression();
+ init = null;
+ else:
+ self.consumeSemicolon();
+ init = init.finishLexicalDeclaration(declarations, kind);
+ else:
+ initStartToken = self.lookahead
+ self.state['allowIn'] = false
+ init = self.inheritCoverGrammar(self.parseAssignmentExpression);
+ self.state['allowIn'] = previousAllowIn;
+
+ if (self.matchKeyword('in')):
+ if (not self.isAssignmentTarget):
+ self.tolerateError(Messages.InvalidLHSInForIn)
+ self.lex();
+ self.reinterpretExpressionAsPattern(init);
+ left = init;
+ right = self.parseExpression();
+ init = null;
+ else:
+ if (self.match(',')):
+ initSeq = [init];
+ while (self.match(',')):
+ self.lex();
+ initSeq.append(self.isolateCoverGrammar(self.parseAssignmentExpression))
+ init = WrappingNode(initStartToken).finishSequenceExpression(initSeq)
+ self.expect(';');
+
+ if ('left' not in locals()):
+ if (not self.match(';')):
+ test = self.parseExpression();
+
+ self.expect(';');
+
+ if (not self.match(')')):
+ update = self.parseExpression();
+
+ self.expect(')');
+
+ oldInIteration = self.state['inIteration']
+ self.state['inIteration'] = true;
+
+ body = self.isolateCoverGrammar(self.parseStatement)
+
+ self.state['inIteration'] = oldInIteration;
+
+ return node.finishForStatement(init, test, update, body) if (
+ 'left' not in locals()) else node.finishForInStatement(left, right, body);
+
+ # 12.7 The continue statement
+
+ def parseContinueStatement(self, node):
+ label = null
+
+ self.expectKeyword('continue');
+
+ # Optimize the most common form: 'continue;'.
+ if ord(self.source[self.startIndex]) == 0x3B:
+ self.lex();
+ if (not self.state['inIteration']):
+ self.throwError(Messages.IllegalContinue)
+ return node.finishContinueStatement(null)
+ if (self.hasLineTerminator):
+ if (not self.state['inIteration']):
+ self.throwError(Messages.IllegalContinue);
+ return node.finishContinueStatement(null);
+
+ if (self.lookahead['type'] == Token.Identifier):
+ label = self.parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if not key in self.state['labelSet']: # todo make sure its correct!
+ self.throwError(Messages.UnknownLabel, label.name);
+ self.consumeSemicolon()
+
+ if (label == null and not self.state['inIteration']):
+ self.throwError(Messages.IllegalContinue)
+ return node.finishContinueStatement(label)
+
+ # 12.8 The break statement
+
+ def parseBreakStatement(self, node):
+ label = null
+
+ self.expectKeyword('break');
+
+ # Catch the very common case first: immediately a semicolon (U+003B).
+ if (ord(self.source[self.lastIndex]) == 0x3B):
+ self.lex();
+
+ if (not (self.state['inIteration'] or self.state['inSwitch'])):
+ self.throwError(Messages.IllegalBreak)
+ return node.finishBreakStatement(null)
+ if (self.hasLineTerminator):
+ if (not (self.state['inIteration'] or self.state['inSwitch'])):
+ self.throwError(Messages.IllegalBreak);
+ return node.finishBreakStatement(null);
+ if (self.lookahead['type'] == Token.Identifier):
+ label = self.parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if not (key in self.state['labelSet']):
+ self.throwError(Messages.UnknownLabel, label.name);
+ self.consumeSemicolon();
+
+ if (label == null and not (self.state['inIteration'] or self.state['inSwitch'])):
+ self.throwError(Messages.IllegalBreak)
+ return node.finishBreakStatement(label);
+
+ # 12.9 The return statement
+
+ def parseReturnStatement(self, node):
+ argument = null;
+
+ self.expectKeyword('return');
+
+ if (not self.state['inFunctionBody']):
+ self.tolerateError(Messages.IllegalReturn);
+
+ # 'return' followed by a space and an identifier is very common.
+ if (ord(self.source[self.lastIndex]) == 0x20):
+ if (isIdentifierStart(self.source[self.lastIndex + 1])):
+ argument = self.parseExpression();
+ self.consumeSemicolon();
+ return node.finishReturnStatement(argument)
+ if (self.hasLineTerminator):
+ # HACK
+ return node.finishReturnStatement(null)
+
+ if (not self.match(';')):
+ if (not self.match('}') and self.lookahead['type'] != Token.EOF):
+ argument = self.parseExpression();
+ self.consumeSemicolon();
+
+ return node.finishReturnStatement(argument);
+
+ # 12.10 The with statement
+
+ def parseWithStatement(self, node):
+ if (self.strict):
+ self.tolerateError(Messages.StrictModeWith)
+
+ self.expectKeyword('with');
+
+ self.expect('(');
+
+ obj = self.parseExpression();
+
+ self.expect(')');
+
+ body = self.parseStatement();
+
+ return node.finishWithStatement(obj, body);
+
+ # 12.10 The swith statement
+
+ def parseSwitchCase(self):
+ consequent = []
+ node = Node();
+
+ if (self.matchKeyword('default')):
+ self.lex();
+ test = null;
+ else:
+ self.expectKeyword('case');
+ test = self.parseExpression();
+
+ self.expect(':');
+
+ while (self.startIndex < self.length):
+ if (self.match('}') or self.matchKeyword('default') or self.matchKeyword('case')):
+ break
+ statement = self.parseStatementListItem()
+ consequent.append(statement)
+ return node.finishSwitchCase(test, consequent)
+
+ def parseSwitchStatement(self, node):
+
+ self.expectKeyword('switch');
+
+ self.expect('(');
+
+ discriminant = self.parseExpression();
+
+ self.expect(')');
+
+ self.expect('{');
+
+ cases = [];
+
+ if (self.match('}')):
+ self.lex();
+ return node.finishSwitchStatement(discriminant, cases);
+
+ oldInSwitch = self.state['inSwitch'];
+ self.state['inSwitch'] = true;
+ defaultFound = false;
+
+ while (self.startIndex < self.length):
+ if (self.match('}')):
+ break;
+ clause = self.parseSwitchCase();
+ if (clause.test == null):
+ if (defaultFound):
+ self.throwError(Messages.MultipleDefaultsInSwitch);
+ defaultFound = true;
+ cases.append(clause);
+
+ self.state['inSwitch'] = oldInSwitch;
+
+ self.expect('}');
+
+ return node.finishSwitchStatement(discriminant, cases);
+
+ # 12.13 The throw statement
+
+ def parseThrowStatement(self, node):
+
+ self.expectKeyword('throw');
+
+ if (self.hasLineTerminator):
+ self.throwError(Messages.NewlineAfterThrow);
+
+ argument = self.parseExpression();
+
+ self.consumeSemicolon();
+
+ return node.finishThrowStatement(argument);
+
+ # 12.14 The try statement
+
+ def parseCatchClause(self):
+ node = Node();
+
+ self.expectKeyword('catch');
+
+ self.expect('(');
+ if (self.match(')')):
+ self.throwUnexpectedToken(self.lookahead);
+ param = self.parsePattern();
+
+ # 12.14.1
+ if (self.strict and isRestrictedWord(param.name)):
+ self.tolerateError(Messages.StrictCatchVariable);
+
+ self.expect(')');
+ body = self.parseBlock();
+ return node.finishCatchClause(param, body);
+
+ def parseTryStatement(self, node):
+ handler = null
+ finalizer = null;
+
+ self.expectKeyword('try');
+
+ block = self.parseBlock();
+
+ if (self.matchKeyword('catch')):
+ handler = self.parseCatchClause()
+
+ if (self.matchKeyword('finally')):
+ self.lex();
+ finalizer = self.parseBlock();
+
+ if (not handler and not finalizer):
+ self.throwError(Messages.NoCatchOrFinally)
+
+ return node.finishTryStatement(block, handler, finalizer)
+
+ # 12.15 The debugger statement
+
+ def parseDebuggerStatement(self, node):
+ self.expectKeyword('debugger');
+
+ self.consumeSemicolon();
+
+ return node.finishDebuggerStatement();
+
+ # 12 Statements
+
+ def parseStatement(self):
+ typ = self.lookahead['type']
+
+ if (typ == Token.EOF):
+ self.throwUnexpectedToken(self.lookahead)
+
+ if (typ == Token.Punctuator and self.lookahead['value'] == '{'):
+ return self.parseBlock()
+
+ self.isAssignmentTarget = self.isBindingElement = true;
+ node = Node();
+ val = self.lookahead['value']
+
+ if (typ == Token.Punctuator):
+ if val == ';':
+ return self.parseEmptyStatement(node);
+ elif val == '(':
+ return self.parseExpressionStatement(node);
+ elif (typ == Token.Keyword):
+ if val == 'break':
+ return self.parseBreakStatement(node);
+ elif val == 'continue':
+ return self.parseContinueStatement(node);
+ elif val == 'debugger':
+ return self.parseDebuggerStatement(node);
+ elif val == 'do':
+ return self.parseDoWhileStatement(node);
+ elif val == 'for':
+ return self.parseForStatement(node);
+ elif val == 'function':
+ return self.parseFunctionDeclaration(node);
+ elif val == 'if':
+ return self.parseIfStatement(node);
+ elif val == 'return':
+ return self.parseReturnStatement(node);
+ elif val == 'switch':
+ return self.parseSwitchStatement(node);
+ elif val == 'throw':
+ return self.parseThrowStatement(node);
+ elif val == 'try':
+ return self.parseTryStatement(node);
+ elif val == 'var':
+ return self.parseVariableStatement(node);
+ elif val == 'while':
+ return self.parseWhileStatement(node);
+ elif val == 'with':
+ return self.parseWithStatement(node);
+
+ expr = self.parseExpression();
+
+ # 12.12 Labelled Statements
+ if ((expr.type == Syntax.Identifier) and self.match(':')):
+ self.lex();
+
+ key = '$' + expr.name
+ if key in self.state['labelSet']:
+ self.throwError(Messages.Redeclaration, 'Label', expr.name);
+ self.state['labelSet'][key] = true
+ labeledBody = self.parseStatement()
+ del self.state['labelSet'][key]
+ return node.finishLabeledStatement(expr, labeledBody)
+ self.consumeSemicolon();
+ return node.finishExpressionStatement(expr)
+
+ # 13 Function Definition
+
+ def parseFunctionSourceElements(self):
+ body = []
+ node = Node()
+ firstRestricted = None
+
+ self.expect('{')
+
+ while (self.startIndex < self.length):
+ if (self.lookahead['type'] != Token.StringLiteral):
+ break
+ token = self.lookahead;
+
+ statement = self.parseStatementListItem()
+ body.append(statement)
+ if (statement.expression.type != Syntax.Literal):
+ # this is not directive
+ break
+ directive = self.source[token['start'] + 1: token['end'] - 1]
+ if (directive == 'use strict'):
+ self.strict = true;
+ if (firstRestricted):
+ self.tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
+ else:
+ if (not firstRestricted and token.get('octal')):
+ firstRestricted = token;
+
+ oldLabelSet = self.state['labelSet']
+ oldInIteration = self.state['inIteration']
+ oldInSwitch = self.state['inSwitch']
+ oldInFunctionBody = self.state['inFunctionBody']
+ oldParenthesisCount = self.state['parenthesizedCount']
+
+ self.state['labelSet'] = {}
+ self.state['inIteration'] = false
+ self.state['inSwitch'] = false
+ self.state['inFunctionBody'] = true
+ self.state['parenthesizedCount'] = 0
+
+ while (self.startIndex < self.length):
+ if (self.match('}')):
+ break
+ body.append(self.parseStatementListItem())
+ self.expect('}')
+
+ self.state['labelSet'] = oldLabelSet;
+ self.state['inIteration'] = oldInIteration;
+ self.state['inSwitch'] = oldInSwitch;
+ self.state['inFunctionBody'] = oldInFunctionBody;
+ self.state['parenthesizedCount'] = oldParenthesisCount;
+
+ return node.finishBlockStatement(body)
+
+ def validateParam(self, options, param, name):
+ key = '$' + name
+ if (self.strict):
+ if (isRestrictedWord(name)):
+ options['stricted'] = param;
+ options['message'] = Messages.StrictParamName
+ if key in options['paramSet']:
+ options['stricted'] = param;
+ options['message'] = Messages.StrictParamDupe;
+ elif (not options['firstRestricted']):
+ if (isRestrictedWord(name)):
+ options['firstRestricted'] = param;
+ options['message'] = Messages.StrictParamName;
+ elif (isStrictModeReservedWord(name)):
+ options['firstRestricted'] = param;
+ options['message'] = Messages.StrictReservedWord;
+ elif key in options['paramSet']:
+ options['firstRestricted'] = param
+ options['message'] = Messages.StrictParamDupe;
+ options['paramSet'][key] = true
+
+ def parseParam(self, options):
+ token = self.lookahead
+ de = None
+ if (token['value'] == '...'):
+ param = self.parseRestElement();
+ self.validateParam(options, param.argument, param.argument.name);
+ options['params'].append(param);
+ options['defaults'].append(null);
+ return false
+ param = self.parsePatternWithDefault();
+ self.validateParam(options, token, token['value']);
+
+ if (param.type == Syntax.AssignmentPattern):
+ de = param.right;
+ param = param.left;
+ options['defaultCount'] += 1
+ options['params'].append(param);
+ options['defaults'].append(de)
+ return not self.match(')')
+
+ def parseParams(self, firstRestricted):
+ options = {
+ 'params': [],
+ 'defaultCount': 0,
+ 'defaults': [],
+ 'firstRestricted': firstRestricted}
+
+ self.expect('(');
+
+ if (not self.match(')')):
+ options['paramSet'] = {};
+ while (self.startIndex < self.length):
+ if (not self.parseParam(options)):
+ break
+ self.expect(',');
+ self.expect(')');
+
+ if (options['defaultCount'] == 0):
+ options['defaults'] = [];
+
+ return {
+ 'params': options['params'],
+ 'defaults': options['defaults'],
+ 'stricted': options.get('stricted'),
+ 'firstRestricted': options.get('firstRestricted'),
+ 'message': options.get('message')}
+
+ def parseFunctionDeclaration(self, node, identifierIsOptional=None):
+ d = null
+ params = []
+ defaults = []
+ message = None
+ firstRestricted = None
+
+ self.expectKeyword('function');
+ if (identifierIsOptional or not self.match('(')):
+ token = self.lookahead;
+ d = self.parseVariableIdentifier();
+ if (self.strict):
+ if (isRestrictedWord(token['value'])):
+ self.tolerateUnexpectedToken(token, Messages.StrictFunctionName);
+ else:
+ if (isRestrictedWord(token['value'])):
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ elif (isStrictModeReservedWord(token['value'])):
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+
+ tmp = self.parseParams(firstRestricted);
+ params = tmp['params']
+ defaults = tmp['defaults']
+ stricted = tmp.get('stricted')
+ firstRestricted = tmp['firstRestricted']
+ if (tmp.get('message')):
+ message = tmp['message'];
+
+ previousStrict = self.strict;
+ body = self.parseFunctionSourceElements();
+ if (self.strict and firstRestricted):
+ self.throwUnexpectedToken(firstRestricted, message);
+
+ if (self.strict and stricted):
+ self.tolerateUnexpectedToken(stricted, message);
+ self.strict = previousStrict;
+
+ return node.finishFunctionDeclaration(d, params, defaults, body);
+
+ def parseFunctionExpression(self):
+ id = null
+ params = []
+ defaults = []
+ node = Node();
+ firstRestricted = None
+ message = None
+
+ self.expectKeyword('function');
+
+ if (not self.match('(')):
+ token = self.lookahead;
+ id = self.parseVariableIdentifier();
+ if (self.strict):
+ if (isRestrictedWord(token['value'])):
+ self.tolerateUnexpectedToken(token, Messages.StrictFunctionName);
+ else:
+ if (isRestrictedWord(token['value'])):
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ elif (isStrictModeReservedWord(token['value'])):
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ tmp = self.parseParams(firstRestricted);
+ params = tmp['params']
+ defaults = tmp['defaults']
+ stricted = tmp.get('stricted')
+ firstRestricted = tmp['firstRestricted']
+ if (tmp.get('message')):
+ message = tmp['message']
+
+ previousStrict = self.strict;
+ body = self.parseFunctionSourceElements();
+ if (self.strict and firstRestricted):
+ self.throwUnexpectedToken(firstRestricted, message);
+ if (self.strict and stricted):
+ self.tolerateUnexpectedToken(stricted, message);
+ self.strict = previousStrict;
+
+ return node.finishFunctionExpression(id, params, defaults, body);
+
+ # todo Translate parse class functions!
+
+ def parseClassExpression(self):
+ raise NotImplementedError()
+
+ def parseClassDeclaration(self):
+ raise NotImplementedError()
+
+ # 14 Program
+
+ def parseScriptBody(self):
+ body = []
+ firstRestricted = None
+
+ while (self.startIndex < self.length):
+ token = self.lookahead;
+ if (token['type'] != Token.StringLiteral):
+ break
+ statement = self.parseStatementListItem();
+ body.append(statement);
+ if (statement.expression.type != Syntax.Literal):
+ # this is not directive
+ break
+ directive = self.source[token['start'] + 1: token['end'] - 1]
+ if (directive == 'use strict'):
+ self.strict = true;
+ if (firstRestricted):
+ self.tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral)
+ else:
+ if (not firstRestricted and token.get('octal')):
+ firstRestricted = token;
+ while (self.startIndex < self.length):
+ statement = self.parseStatementListItem();
+ # istanbul ignore if
+ if (statement is None):
+ break
+ body.append(statement);
+ return body;
+
+ def parseProgram(self):
+ self.peek()
+ node = Node()
+
+ body = self.parseScriptBody()
+ return node.finishProgram(body)
+
+ # DONE!!!
+ def parse(self, code, options={}):
+ if options:
+ raise NotImplementedError('Options not implemented! You can only use default settings.')
+
+ self.clean()
+ self.source = unicode(code) + ' \n ; //END' # I have to add it in order not to check for EOF every time
+ self.index = 0
+ self.lineNumber = 1 if len(self.source) > 0 else 0
+ self.lineStart = 0
+ self.startIndex = self.index
+ self.startLineNumber = self.lineNumber;
+ self.startLineStart = self.lineStart;
+ self.length = len(self.source)
+ self.lookahead = null;
+ self.state = {
+ 'allowIn': true,
+ 'labelSet': {},
+ 'inFunctionBody': false,
+ 'inIteration': false,
+ 'inSwitch': false,
+ 'lastCommentStart': -1,
+ 'curlyStack': [],
+ 'parenthesizedCount': None}
+ self.sourceType = 'script';
+ self.strict = false;
+ program = self.parseProgram();
+ return node_to_dict(program)
+
+
+
+def parse(javascript_code):
+ """Returns syntax tree of javascript_code.
+ Same as PyJsParser().parse For your convenience :) """
+ p = PyJsParser()
+ return p.parse(javascript_code)
+
+
+if __name__ == '__main__':
+ import time
+
+ test_path = None
+ if test_path:
+ f = open(test_path, 'rb')
+ x = f.read()
+ f.close()
+ else:
+ x = 'var $ = "Hello!"'
+ p = PyJsParser()
+ t = time.time()
+ res = p.parse(x)
+ dt = time.time() - t + 0.000000001
+ if test_path:
+ print(len(res))
+ else:
+ pprint(res)
+ print()
+ print('Parsed everyting in', round(dt, 5), 'seconds.')
+ print('Thats %d characters per second' % int(len(x) / dt))
+
+
+
diff --git a/libs/pyjsparser/pyjsparserdata.py b/libs/pyjsparser/pyjsparserdata.py
new file mode 100644
index 000000000..1d6ab2ee2
--- /dev/null
+++ b/libs/pyjsparser/pyjsparserdata.py
@@ -0,0 +1,303 @@
+# The MIT License
+#
+# Copyright 2014, 2015 Piotr Dabkowski
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the 'Software'),
+# to deal in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so, subject
+# to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all copies or
+# substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+from __future__ import unicode_literals
+
+import sys
+import unicodedata
+from collections import defaultdict
+
+PY3 = sys.version_info >= (3,0)
+
+if PY3:
+ unichr = chr
+ xrange = range
+ unicode = str
+
+token = {
+ 'BooleanLiteral': 1,
+ 'EOF': 2,
+ 'Identifier': 3,
+ 'Keyword': 4,
+ 'NullLiteral': 5,
+ 'NumericLiteral': 6,
+ 'Punctuator': 7,
+ 'StringLiteral': 8,
+ 'RegularExpression': 9,
+ 'Template': 10
+ }
+
+
+TokenName = dict((v,k) for k,v in token.items())
+
+FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
+ 'return', 'case', 'delete', 'throw', 'void',
+ # assignment operators
+ '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
+ '&=', '|=', '^=', ',',
+ # binary/unary operators
+ '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
+ '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
+ '<=', '<', '>', '!=', '!==']
+
+syntax= set(('AssignmentExpression',
+ 'AssignmentPattern',
+ 'ArrayExpression',
+ 'ArrayPattern',
+ 'ArrowFunctionExpression',
+ 'BlockStatement',
+ 'BinaryExpression',
+ 'BreakStatement',
+ 'CallExpression',
+ 'CatchClause',
+ 'ClassBody',
+ 'ClassDeclaration',
+ 'ClassExpression',
+ 'ConditionalExpression',
+ 'ContinueStatement',
+ 'DoWhileStatement',
+ 'DebuggerStatement',
+ 'EmptyStatement',
+ 'ExportAllDeclaration',
+ 'ExportDefaultDeclaration',
+ 'ExportNamedDeclaration',
+ 'ExportSpecifier',
+ 'ExpressionStatement',
+ 'ForStatement',
+ 'ForInStatement',
+ 'FunctionDeclaration',
+ 'FunctionExpression',
+ 'Identifier',
+ 'IfStatement',
+ 'ImportDeclaration',
+ 'ImportDefaultSpecifier',
+ 'ImportNamespaceSpecifier',
+ 'ImportSpecifier',
+ 'Literal',
+ 'LabeledStatement',
+ 'LogicalExpression',
+ 'MemberExpression',
+ 'MethodDefinition',
+ 'NewExpression',
+ 'ObjectExpression',
+ 'ObjectPattern',
+ 'Program',
+ 'Property',
+ 'RestElement',
+ 'ReturnStatement',
+ 'SequenceExpression',
+ 'SpreadElement',
+ 'Super',
+ 'SwitchCase',
+ 'SwitchStatement',
+ 'TaggedTemplateExpression',
+ 'TemplateElement',
+ 'TemplateLiteral',
+ 'ThisExpression',
+ 'ThrowStatement',
+ 'TryStatement',
+ 'UnaryExpression',
+ 'UpdateExpression',
+ 'VariableDeclaration',
+ 'VariableDeclarator',
+ 'WhileStatement',
+ 'WithStatement'))
+
+
+# Error messages should be identical to V8.
+messages = {
+ 'UnexpectedToken': 'Unexpected token %s',
+ 'UnexpectedNumber': 'Unexpected number',
+ 'UnexpectedString': 'Unexpected string',
+ 'UnexpectedIdentifier': 'Unexpected identifier',
+ 'UnexpectedReserved': 'Unexpected reserved word',
+ 'UnexpectedTemplate': 'Unexpected quasi %s',
+ 'UnexpectedEOS': 'Unexpected end of input',
+ 'NewlineAfterThrow': 'Illegal newline after throw',
+ 'InvalidRegExp': 'Invalid regular expression',
+ 'UnterminatedRegExp': 'Invalid regular expression: missing /',
+ 'InvalidLHSInAssignment': 'Invalid left-hand side in assignment',
+ 'InvalidLHSInForIn': 'Invalid left-hand side in for-in',
+ 'MultipleDefaultsInSwitch': 'More than one default clause in switch statement',
+ 'NoCatchOrFinally': 'Missing catch or finally after try',
+ 'UnknownLabel': 'Undefined label \'%s\'',
+ 'Redeclaration': '%s \'%s\' has already been declared',
+ 'IllegalContinue': 'Illegal continue statement',
+ 'IllegalBreak': 'Illegal break statement',
+ 'IllegalReturn': 'Illegal return statement',
+ 'StrictModeWith': 'Strict mode code may not include a with statement',
+ 'StrictCatchVariable': 'Catch variable may not be eval or arguments in strict mode',
+ 'StrictVarName': 'Variable name may not be eval or arguments in strict mode',
+ 'StrictParamName': 'Parameter name eval or arguments is not allowed in strict mode',
+ 'StrictParamDupe': 'Strict mode function may not have duplicate parameter names',
+ 'StrictFunctionName': 'Function name may not be eval or arguments in strict mode',
+ 'StrictOctalLiteral': 'Octal literals are not allowed in strict mode.',
+ 'StrictDelete': 'Delete of an unqualified identifier in strict mode.',
+ 'StrictLHSAssignment': 'Assignment to eval or arguments is not allowed in strict mode',
+ 'StrictLHSPostfix': 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+ 'StrictLHSPrefix': 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+ 'StrictReservedWord': 'Use of future reserved word in strict mode',
+ 'TemplateOctalLiteral': 'Octal literals are not allowed in template strings.',
+ 'ParameterAfterRestParameter': 'Rest parameter must be last formal parameter',
+ 'DefaultRestParameter': 'Unexpected token =',
+ 'ObjectPatternAsRestParameter': 'Unexpected token {',
+ 'DuplicateProtoProperty': 'Duplicate __proto__ fields are not allowed in object literals',
+ 'ConstructorSpecialMethod': 'Class constructor may not be an accessor',
+ 'DuplicateConstructor': 'A class may only have one constructor',
+ 'StaticPrototype': 'Classes may not have static property named prototype',
+ 'MissingFromClause': 'Unexpected token',
+ 'NoAsAfterImportNamespace': 'Unexpected token',
+ 'InvalidModuleSpecifier': 'Unexpected token',
+ 'IllegalImportDeclaration': 'Unexpected token',
+ 'IllegalExportDeclaration': 'Unexpected token'}
+
+PRECEDENCE = {'||':1,
+ '&&':2,
+ '|':3,
+ '^':4,
+ '&':5,
+ '==':6,
+ '!=':6,
+ '===':6,
+ '!==':6,
+ '<':7,
+ '>':7,
+ '<=':7,
+ '>=':7,
+ 'instanceof':7,
+ 'in':7,
+ '<<':8,
+ '>>':8,
+ '>>>':8,
+ '+':9,
+ '-':9,
+ '*':11,
+ '/':11,
+ '%':11}
+
+class Token: pass
+class Syntax: pass
+class Messages: pass
+class PlaceHolders:
+ ArrowParameterPlaceHolder = 'ArrowParameterPlaceHolder'
+
+for k,v in token.items():
+ setattr(Token, k, v)
+
+for e in syntax:
+ setattr(Syntax, e, e)
+
+for k,v in messages.items():
+ setattr(Messages, k, v)
+
+#http://stackoverflow.com/questions/14245893/efficiently-list-all-characters-in-a-given-unicode-category
+BOM = u'\uFEFF'
+ZWJ = u'\u200D'
+ZWNJ = u'\u200C'
+TAB = u'\u0009'
+VT = u'\u000B'
+FF = u'\u000C'
+SP = u'\u0020'
+NBSP = u'\u00A0'
+LF = u'\u000A'
+CR = u'\u000D'
+LS = u'\u2028'
+PS = u'\u2029'
+
+U_CATEGORIES = defaultdict(list)
+for c in map(unichr, range(sys.maxunicode + 1)):
+ U_CATEGORIES[unicodedata.category(c)].append(c)
+UNICODE_LETTER = set(U_CATEGORIES['Lu']+U_CATEGORIES['Ll']+
+ U_CATEGORIES['Lt']+U_CATEGORIES['Lm']+
+ U_CATEGORIES['Lo']+U_CATEGORIES['Nl'])
+UNICODE_COMBINING_MARK = set(U_CATEGORIES['Mn']+U_CATEGORIES['Mc'])
+UNICODE_DIGIT = set(U_CATEGORIES['Nd'])
+UNICODE_CONNECTOR_PUNCTUATION = set(U_CATEGORIES['Pc'])
+IDENTIFIER_START = UNICODE_LETTER.union(set(('$','_', '\\'))) # and some fucking unicode escape sequence
+IDENTIFIER_PART = IDENTIFIER_START.union(UNICODE_COMBINING_MARK).union(UNICODE_DIGIT)\
+ .union(UNICODE_CONNECTOR_PUNCTUATION).union(set((ZWJ, ZWNJ)))
+
+WHITE_SPACE = set((0x20, 0x09, 0x0B, 0x0C, 0xA0, 0x1680,
+ 0x180E, 0x2000, 0x2001, 0x2002, 0x2003,
+ 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
+ 0x2009, 0x200A, 0x202F, 0x205F, 0x3000,
+ 0xFEFF))
+
+LINE_TERMINATORS = set((0x0A, 0x0D, 0x2028, 0x2029))
+
+def isIdentifierStart(ch):
+ return (ch if isinstance(ch, unicode) else unichr(ch)) in IDENTIFIER_START
+
+def isIdentifierPart(ch):
+ return (ch if isinstance(ch, unicode) else unichr(ch)) in IDENTIFIER_PART
+
+def isWhiteSpace(ch):
+ return (ord(ch) if isinstance(ch, unicode) else ch) in WHITE_SPACE
+
+def isLineTerminator(ch):
+ return (ord(ch) if isinstance(ch, unicode) else ch) in LINE_TERMINATORS
+
+OCTAL = set(('0', '1', '2', '3', '4', '5', '6', '7'))
+DEC = set(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))
+HEX = set('0123456789abcdefABCDEF')
+HEX_CONV = dict(('0123456789abcdef'[n],n) for n in xrange(16))
+for i,e in enumerate('ABCDEF', 10):
+ HEX_CONV[e] = i
+
+
+def isDecimalDigit(ch):
+ return (ch if isinstance(ch, unicode) else unichr(ch)) in DEC
+
+def isHexDigit(ch):
+ return (ch if isinstance(ch, unicode) else unichr(ch)) in HEX
+
+def isOctalDigit(ch):
+ return (ch if isinstance(ch, unicode) else unichr(ch)) in OCTAL
+
+def isFutureReservedWord(w):
+ return w in ('enum', 'export', 'import', 'super')
+
+
+RESERVED_WORD = set(('implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield', 'let'))
+def isStrictModeReservedWord(w):
+ return w in RESERVED_WORD
+
+def isRestrictedWord(w):
+ return w in ('eval', 'arguments')
+
+
+KEYWORDS = set(('if', 'in', 'do', 'var', 'for', 'new', 'try', 'let', 'this', 'else', 'case',
+ 'void', 'with', 'enum', 'while', 'break', 'catch', 'throw', 'const', 'yield',
+ 'class', 'super', 'return', 'typeof', 'delete', 'switch', 'export', 'import',
+ 'default', 'finally', 'extends', 'function', 'continue', 'debugger', 'instanceof', 'pyimport'))
+def isKeyword(w):
+ # 'const' is specialized as Keyword in V8.
+ # 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next.
+ # Some others are from future reserved words.
+ return w in KEYWORDS
+
+
+class JsSyntaxError(Exception): pass
+
+if __name__=='__main__':
+ assert isLineTerminator('\n')
+ assert isLineTerminator(0x0A)
+ assert isIdentifierStart('$')
+ assert isIdentifierStart(100)
+ assert isWhiteSpace(' ') \ No newline at end of file
diff --git a/libs/pyjsparser/std_nodes.py b/libs/pyjsparser/std_nodes.py
new file mode 100644
index 000000000..a4b37ca3d
--- /dev/null
+++ b/libs/pyjsparser/std_nodes.py
@@ -0,0 +1,471 @@
+from .pyjsparserdata import *
+
+
+class BaseNode:
+ def finish(self):
+ pass
+
+ def finishArrayExpression(self, elements):
+ self.type = Syntax.ArrayExpression
+ self.elements = elements
+ self.finish()
+ return self
+
+ def finishArrayPattern(self, elements):
+ self.type = Syntax.ArrayPattern
+ self.elements = elements
+ self.finish()
+ return self
+
+ def finishArrowFunctionExpression(self, params, defaults, body, expression):
+ self.type = Syntax.ArrowFunctionExpression
+ self.id = None
+ self.params = params
+ self.defaults = defaults
+ self.body = body
+ self.generator = False
+ self.expression = expression
+ self.finish()
+ return self
+
+ def finishAssignmentExpression(self, operator, left, right):
+ self.type = Syntax.AssignmentExpression
+ self.operator = operator
+ self.left = left
+ self.right = right
+ self.finish()
+ return self
+
+ def finishAssignmentPattern(self, left, right):
+ self.type = Syntax.AssignmentPattern
+ self.left = left
+ self.right = right
+ self.finish()
+ return self
+
+ def finishBinaryExpression(self, operator, left, right):
+ self.type = Syntax.LogicalExpression if (operator == '||' or operator == '&&') else Syntax.BinaryExpression
+ self.operator = operator
+ self.left = left
+ self.right = right
+ self.finish()
+ return self
+
+ def finishBlockStatement(self, body):
+ self.type = Syntax.BlockStatement
+ self.body = body
+ self.finish()
+ return self
+
+ def finishBreakStatement(self, label):
+ self.type = Syntax.BreakStatement
+ self.label = label
+ self.finish()
+ return self
+
+ def finishCallExpression(self, callee, args):
+ self.type = Syntax.CallExpression
+ self.callee = callee
+ self.arguments = args
+ self.finish()
+ return self
+
+ def finishCatchClause(self, param, body):
+ self.type = Syntax.CatchClause
+ self.param = param
+ self.body = body
+ self.finish()
+ return self
+
+ def finishClassBody(self, body):
+ self.type = Syntax.ClassBody
+ self.body = body
+ self.finish()
+ return self
+
+ def finishClassDeclaration(self, id, superClass, body):
+ self.type = Syntax.ClassDeclaration
+ self.id = id
+ self.superClass = superClass
+ self.body = body
+ self.finish()
+ return self
+
+ def finishClassExpression(self, id, superClass, body):
+ self.type = Syntax.ClassExpression
+ self.id = id
+ self.superClass = superClass
+ self.body = body
+ self.finish()
+ return self
+
+ def finishConditionalExpression(self, test, consequent, alternate):
+ self.type = Syntax.ConditionalExpression
+ self.test = test
+ self.consequent = consequent
+ self.alternate = alternate
+ self.finish()
+ return self
+
+ def finishContinueStatement(self, label):
+ self.type = Syntax.ContinueStatement
+ self.label = label
+ self.finish()
+ return self
+
+ def finishDebuggerStatement(self, ):
+ self.type = Syntax.DebuggerStatement
+ self.finish()
+ return self
+
+ def finishDoWhileStatement(self, body, test):
+ self.type = Syntax.DoWhileStatement
+ self.body = body
+ self.test = test
+ self.finish()
+ return self
+
+ def finishEmptyStatement(self, ):
+ self.type = Syntax.EmptyStatement
+ self.finish()
+ return self
+
+ def finishExpressionStatement(self, expression):
+ self.type = Syntax.ExpressionStatement
+ self.expression = expression
+ self.finish()
+ return self
+
+ def finishForStatement(self, init, test, update, body):
+ self.type = Syntax.ForStatement
+ self.init = init
+ self.test = test
+ self.update = update
+ self.body = body
+ self.finish()
+ return self
+
+ def finishForInStatement(self, left, right, body):
+ self.type = Syntax.ForInStatement
+ self.left = left
+ self.right = right
+ self.body = body
+ self.each = False
+ self.finish()
+ return self
+
+ def finishFunctionDeclaration(self, id, params, defaults, body):
+ self.type = Syntax.FunctionDeclaration
+ self.id = id
+ self.params = params
+ self.defaults = defaults
+ self.body = body
+ self.generator = False
+ self.expression = False
+ self.finish()
+ return self
+
+ def finishFunctionExpression(self, id, params, defaults, body):
+ self.type = Syntax.FunctionExpression
+ self.id = id
+ self.params = params
+ self.defaults = defaults
+ self.body = body
+ self.generator = False
+ self.expression = False
+ self.finish()
+ return self
+
+ def finishIdentifier(self, name):
+ self.type = Syntax.Identifier
+ self.name = name
+ self.finish()
+ return self
+
+ def finishIfStatement(self, test, consequent, alternate):
+ self.type = Syntax.IfStatement
+ self.test = test
+ self.consequent = consequent
+ self.alternate = alternate
+ self.finish()
+ return self
+
+ def finishLabeledStatement(self, label, body):
+ self.type = Syntax.LabeledStatement
+ self.label = label
+ self.body = body
+ self.finish()
+ return self
+
+ def finishLiteral(self, token):
+ self.type = Syntax.Literal
+ self.value = token['value']
+ self.raw = None # todo fix it?
+ if token.get('regex'):
+ self.regex = token['regex']
+ self.finish()
+ return self
+
+ def finishMemberExpression(self, accessor, object, property):
+ self.type = Syntax.MemberExpression
+ self.computed = accessor == '['
+ self.object = object
+ self.property = property
+ self.finish()
+ return self
+
+ def finishNewExpression(self, callee, args):
+ self.type = Syntax.NewExpression
+ self.callee = callee
+ self.arguments = args
+ self.finish()
+ return self
+
+ def finishObjectExpression(self, properties):
+ self.type = Syntax.ObjectExpression
+ self.properties = properties
+ self.finish()
+ return self
+
+ def finishObjectPattern(self, properties):
+ self.type = Syntax.ObjectPattern
+ self.properties = properties
+ self.finish()
+ return self
+
+ def finishPostfixExpression(self, operator, argument):
+ self.type = Syntax.UpdateExpression
+ self.operator = operator
+ self.argument = argument
+ self.prefix = False
+ self.finish()
+ return self
+
+ def finishProgram(self, body):
+ self.type = Syntax.Program
+ self.body = body
+ self.finish()
+ return self
+
+ def finishPyimport(self, imp):
+ self.type = 'PyimportStatement'
+ self.imp = imp
+ self.finish()
+ return self
+
+ def finishProperty(self, kind, key, computed, value, method, shorthand):
+ self.type = Syntax.Property
+ self.key = key
+ self.computed = computed
+ self.value = value
+ self.kind = kind
+ self.method = method
+ self.shorthand = shorthand
+ self.finish()
+ return self
+
+ def finishRestElement(self, argument):
+ self.type = Syntax.RestElement
+ self.argument = argument
+ self.finish()
+ return self
+
+ def finishReturnStatement(self, argument):
+ self.type = Syntax.ReturnStatement
+ self.argument = argument
+ self.finish()
+ return self
+
+ def finishSequenceExpression(self, expressions):
+ self.type = Syntax.SequenceExpression
+ self.expressions = expressions
+ self.finish()
+ return self
+
+ def finishSpreadElement(self, argument):
+ self.type = Syntax.SpreadElement
+ self.argument = argument
+ self.finish()
+ return self
+
+ def finishSwitchCase(self, test, consequent):
+ self.type = Syntax.SwitchCase
+ self.test = test
+ self.consequent = consequent
+ self.finish()
+ return self
+
+ def finishSuper(self, ):
+ self.type = Syntax.Super
+ self.finish()
+ return self
+
+ def finishSwitchStatement(self, discriminant, cases):
+ self.type = Syntax.SwitchStatement
+ self.discriminant = discriminant
+ self.cases = cases
+ self.finish()
+ return self
+
+ def finishTaggedTemplateExpression(self, tag, quasi):
+ self.type = Syntax.TaggedTemplateExpression
+ self.tag = tag
+ self.quasi = quasi
+ self.finish()
+ return self
+
+ def finishTemplateElement(self, value, tail):
+ self.type = Syntax.TemplateElement
+ self.value = value
+ self.tail = tail
+ self.finish()
+ return self
+
+ def finishTemplateLiteral(self, quasis, expressions):
+ self.type = Syntax.TemplateLiteral
+ self.quasis = quasis
+ self.expressions = expressions
+ self.finish()
+ return self
+
+ def finishThisExpression(self, ):
+ self.type = Syntax.ThisExpression
+ self.finish()
+ return self
+
+ def finishThrowStatement(self, argument):
+ self.type = Syntax.ThrowStatement
+ self.argument = argument
+ self.finish()
+ return self
+
+ def finishTryStatement(self, block, handler, finalizer):
+ self.type = Syntax.TryStatement
+ self.block = block
+ self.guardedHandlers = []
+ self.handlers = [handler] if handler else []
+ self.handler = handler
+ self.finalizer = finalizer
+ self.finish()
+ return self
+
+ def finishUnaryExpression(self, operator, argument):
+ self.type = Syntax.UpdateExpression if (operator == '++' or operator == '--') else Syntax.UnaryExpression
+ self.operator = operator
+ self.argument = argument
+ self.prefix = True
+ self.finish()
+ return self
+
+ def finishVariableDeclaration(self, declarations):
+ self.type = Syntax.VariableDeclaration
+ self.declarations = declarations
+ self.kind = 'var'
+ self.finish()
+ return self
+
+ def finishLexicalDeclaration(self, declarations, kind):
+ self.type = Syntax.VariableDeclaration
+ self.declarations = declarations
+ self.kind = kind
+ self.finish()
+ return self
+
+ def finishVariableDeclarator(self, id, init):
+ self.type = Syntax.VariableDeclarator
+ self.id = id
+ self.init = init
+ self.finish()
+ return self
+
+ def finishWhileStatement(self, test, body):
+ self.type = Syntax.WhileStatement
+ self.test = test
+ self.body = body
+ self.finish()
+ return self
+
+ def finishWithStatement(self, object, body):
+ self.type = Syntax.WithStatement
+ self.object = object
+ self.body = body
+ self.finish()
+ return self
+
+ def finishExportSpecifier(self, local, exported):
+ self.type = Syntax.ExportSpecifier
+ self.exported = exported or local
+ self.local = local
+ self.finish()
+ return self
+
+ def finishImportDefaultSpecifier(self, local):
+ self.type = Syntax.ImportDefaultSpecifier
+ self.local = local
+ self.finish()
+ return self
+
+ def finishImportNamespaceSpecifier(self, local):
+ self.type = Syntax.ImportNamespaceSpecifier
+ self.local = local
+ self.finish()
+ return self
+
+ def finishExportNamedDeclaration(self, declaration, specifiers, src):
+ self.type = Syntax.ExportNamedDeclaration
+ self.declaration = declaration
+ self.specifiers = specifiers
+ self.source = src
+ self.finish()
+ return self
+
+ def finishExportDefaultDeclaration(self, declaration):
+ self.type = Syntax.ExportDefaultDeclaration
+ self.declaration = declaration
+ self.finish()
+ return self
+
+ def finishExportAllDeclaration(self, src):
+ self.type = Syntax.ExportAllDeclaration
+ self.source = src
+ self.finish()
+ return self
+
+ def finishImportSpecifier(self, local, imported):
+ self.type = Syntax.ImportSpecifier
+ self.local = local or imported
+ self.imported = imported
+ self.finish()
+ return self
+
+ def finishImportDeclaration(self, specifiers, src):
+ self.type = Syntax.ImportDeclaration
+ self.specifiers = specifiers
+ self.source = src
+ self.finish()
+ return self
+
+ def __getitem__(self, item):
+ return getattr(self, item)
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+
+
+class Node(BaseNode):
+ pass
+
+
+class WrappingNode(BaseNode):
+ def __init__(self, startToken=None):
+ pass
+
+
+def node_to_dict(node): # extremely important for translation speed
+ if isinstance(node, list):
+ return [node_to_dict(e) for e in node]
+ elif isinstance(node, dict):
+ return dict((k, node_to_dict(v)) for k, v in node.items())
+ elif not isinstance(node, BaseNode):
+ return node
+ return dict((k, node_to_dict(v)) for k, v in node.__dict__.items())