rapydscript-ns 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agignore +1 -0
- package/.gitattributes +4 -0
- package/.github/workflows/ci.yml +38 -0
- package/.github/workflows/web-repl-page-deploy.yml +42 -0
- package/=template.pyj +5 -0
- package/CHANGELOG.md +456 -0
- package/CONTRIBUTORS +13 -0
- package/HACKING.md +103 -0
- package/LICENSE +24 -0
- package/README.md +2512 -0
- package/TODO.md +327 -0
- package/add-toc-to-readme +2 -0
- package/bin/export +75 -0
- package/bin/rapydscript +70 -0
- package/bin/web-repl-export +102 -0
- package/build +3 -0
- package/package.json +46 -0
- package/publish.py +37 -0
- package/release/baselib-plain-pretty.js +4370 -0
- package/release/baselib-plain-ugly.js +3 -0
- package/release/compiler.js +18394 -0
- package/release/signatures.json +31 -0
- package/session.vim +4 -0
- package/setup.cfg +2 -0
- package/src/ast.pyj +1356 -0
- package/src/baselib-builtins.pyj +279 -0
- package/src/baselib-containers.pyj +723 -0
- package/src/baselib-errors.pyj +37 -0
- package/src/baselib-internal.pyj +421 -0
- package/src/baselib-itertools.pyj +97 -0
- package/src/baselib-str.pyj +798 -0
- package/src/compiler.pyj +36 -0
- package/src/errors.pyj +30 -0
- package/src/lib/aes.pyj +646 -0
- package/src/lib/collections.pyj +695 -0
- package/src/lib/elementmaker.pyj +83 -0
- package/src/lib/encodings.pyj +126 -0
- package/src/lib/functools.pyj +148 -0
- package/src/lib/gettext.pyj +569 -0
- package/src/lib/itertools.pyj +580 -0
- package/src/lib/math.pyj +193 -0
- package/src/lib/numpy.pyj +2101 -0
- package/src/lib/operator.pyj +11 -0
- package/src/lib/pythonize.pyj +20 -0
- package/src/lib/random.pyj +118 -0
- package/src/lib/re.pyj +470 -0
- package/src/lib/traceback.pyj +63 -0
- package/src/lib/uuid.pyj +77 -0
- package/src/monaco-language-service/analyzer.js +526 -0
- package/src/monaco-language-service/builtins.js +543 -0
- package/src/monaco-language-service/completions.js +498 -0
- package/src/monaco-language-service/diagnostics.js +643 -0
- package/src/monaco-language-service/dts.js +550 -0
- package/src/monaco-language-service/hover.js +121 -0
- package/src/monaco-language-service/index.js +386 -0
- package/src/monaco-language-service/scope.js +162 -0
- package/src/monaco-language-service/signature.js +144 -0
- package/src/output/__init__.pyj +0 -0
- package/src/output/classes.pyj +296 -0
- package/src/output/codegen.pyj +492 -0
- package/src/output/comments.pyj +45 -0
- package/src/output/exceptions.pyj +105 -0
- package/src/output/functions.pyj +491 -0
- package/src/output/literals.pyj +109 -0
- package/src/output/loops.pyj +444 -0
- package/src/output/modules.pyj +329 -0
- package/src/output/operators.pyj +429 -0
- package/src/output/statements.pyj +463 -0
- package/src/output/stream.pyj +309 -0
- package/src/output/treeshake.pyj +182 -0
- package/src/output/utils.pyj +72 -0
- package/src/parse.pyj +3106 -0
- package/src/string_interpolation.pyj +72 -0
- package/src/tokenizer.pyj +702 -0
- package/src/unicode_aliases.pyj +576 -0
- package/src/utils.pyj +192 -0
- package/test/_import_one.pyj +37 -0
- package/test/_import_two/__init__.pyj +11 -0
- package/test/_import_two/level2/__init__.pyj +0 -0
- package/test/_import_two/level2/deep.pyj +4 -0
- package/test/_import_two/other.pyj +6 -0
- package/test/_import_two/sub.pyj +13 -0
- package/test/aes_vectors.pyj +421 -0
- package/test/annotations.pyj +80 -0
- package/test/baselib.pyj +319 -0
- package/test/classes.pyj +452 -0
- package/test/collections.pyj +152 -0
- package/test/decorators.pyj +77 -0
- package/test/dict_spread.pyj +76 -0
- package/test/docstrings.pyj +39 -0
- package/test/elementmaker_test.pyj +45 -0
- package/test/ellipsis.pyj +49 -0
- package/test/functions.pyj +151 -0
- package/test/generators.pyj +41 -0
- package/test/generic.pyj +370 -0
- package/test/imports.pyj +72 -0
- package/test/internationalization.pyj +73 -0
- package/test/lint.pyj +164 -0
- package/test/loops.pyj +85 -0
- package/test/numpy.pyj +734 -0
- package/test/omit_function_metadata.pyj +20 -0
- package/test/regexp.pyj +55 -0
- package/test/repl.pyj +121 -0
- package/test/scoped_flags.pyj +76 -0
- package/test/starargs.pyj +506 -0
- package/test/starred_assign.pyj +104 -0
- package/test/str.pyj +198 -0
- package/test/subscript_tuple.pyj +53 -0
- package/test/unit/fixtures/fibonacci_expected.js +46 -0
- package/test/unit/index.js +2989 -0
- package/test/unit/language-service-builtins.js +815 -0
- package/test/unit/language-service-completions.js +1067 -0
- package/test/unit/language-service-dts.js +543 -0
- package/test/unit/language-service-hover.js +455 -0
- package/test/unit/language-service-scope.js +833 -0
- package/test/unit/language-service-signature.js +458 -0
- package/test/unit/language-service.js +705 -0
- package/test/unit/run-language-service.js +41 -0
- package/test/unit/web-repl.js +484 -0
- package/tools/build-language-service.js +190 -0
- package/tools/cli.js +547 -0
- package/tools/compile.js +219 -0
- package/tools/compiler.js +108 -0
- package/tools/completer.js +131 -0
- package/tools/embedded_compiler.js +251 -0
- package/tools/export.js +316 -0
- package/tools/gettext.js +185 -0
- package/tools/ini.js +65 -0
- package/tools/lint.js +705 -0
- package/tools/msgfmt.js +187 -0
- package/tools/repl.js +223 -0
- package/tools/self.js +162 -0
- package/tools/test.js +118 -0
- package/tools/utils.js +128 -0
- package/tools/web_repl.js +95 -0
- package/try +41 -0
- package/web-repl/env.js +74 -0
- package/web-repl/index.html +163 -0
- package/web-repl/language-service.js +4084 -0
- package/web-repl/main.js +254 -0
- package/web-repl/prism.css +139 -0
- package/web-repl/prism.js +113 -0
- package/web-repl/rapydscript.js +435 -0
- package/web-repl/sha1.js +25 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
+
from __python__ import hash_literals
|
|
4
|
+
|
|
5
|
+
from unicode_aliases import ALIAS_MAP
|
|
6
|
+
from utils import make_predicate, characters
|
|
7
|
+
from ast import AST_Token
|
|
8
|
+
from errors import SyntaxError
|
|
9
|
+
from string_interpolation import interpolate
|
|
10
|
+
|
|
11
|
+
RE_HEX_NUMBER = /^0x[0-9a-f]+$/i
|
|
12
|
+
RE_OCT_NUMBER = /^0[0-7]+$/
|
|
13
|
+
RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i
|
|
14
|
+
|
|
15
|
+
OPERATOR_CHARS = make_predicate(characters("+-*&%=<>!?|~^@"))
|
|
16
|
+
|
|
17
|
+
ASCII_CONTROL_CHARS = {'a':7, 'b':8, 'f': 12, 'n': 10, 'r': 13, 't': 9, 'v': 11}
|
|
18
|
+
HEX_PAT = /[a-fA-F0-9]/
|
|
19
|
+
NAME_PAT = /[a-zA-Z ]/
|
|
20
|
+
|
|
21
|
+
OPERATORS = make_predicate([
|
|
22
|
+
"in",
|
|
23
|
+
"instanceof",
|
|
24
|
+
"typeof",
|
|
25
|
+
"new",
|
|
26
|
+
"void",
|
|
27
|
+
"del",
|
|
28
|
+
"+",
|
|
29
|
+
"-",
|
|
30
|
+
"not",
|
|
31
|
+
"~",
|
|
32
|
+
"&",
|
|
33
|
+
"|",
|
|
34
|
+
"^",
|
|
35
|
+
"**",
|
|
36
|
+
"*",
|
|
37
|
+
"//",
|
|
38
|
+
"/",
|
|
39
|
+
"%",
|
|
40
|
+
">>",
|
|
41
|
+
"<<",
|
|
42
|
+
">>>",
|
|
43
|
+
"<",
|
|
44
|
+
">",
|
|
45
|
+
"<=",
|
|
46
|
+
">=",
|
|
47
|
+
"==",
|
|
48
|
+
"is",
|
|
49
|
+
"!=",
|
|
50
|
+
"=",
|
|
51
|
+
"+=",
|
|
52
|
+
"-=",
|
|
53
|
+
"//=",
|
|
54
|
+
"/=",
|
|
55
|
+
"*=",
|
|
56
|
+
"%=",
|
|
57
|
+
">>=",
|
|
58
|
+
"<<=",
|
|
59
|
+
">>>=",
|
|
60
|
+
"|=",
|
|
61
|
+
"^=",
|
|
62
|
+
"&=",
|
|
63
|
+
"and",
|
|
64
|
+
"or",
|
|
65
|
+
"@",
|
|
66
|
+
"->",
|
|
67
|
+
":="
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
OP_MAP = {
|
|
71
|
+
'or': "||",
|
|
72
|
+
'and': "&&",
|
|
73
|
+
'not': "!",
|
|
74
|
+
'del': "delete",
|
|
75
|
+
'None': "null",
|
|
76
|
+
'is': "===",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
WHITESPACE_CHARS = make_predicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"))
|
|
80
|
+
|
|
81
|
+
PUNC_BEFORE_EXPRESSION = make_predicate(characters("[{(,.;:"))
|
|
82
|
+
|
|
83
|
+
PUNC_CHARS = make_predicate(characters("[]{}(),;:?"))
|
|
84
|
+
|
|
85
|
+
KEYWORDS = "as assert async await break class continue def del do elif else except finally for from global if import in is lambda new nonlocal pass raise return yield try while with or and not"
|
|
86
|
+
|
|
87
|
+
KEYWORDS_ATOM = "False None True"
|
|
88
|
+
|
|
89
|
+
# see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar
|
|
90
|
+
RESERVED_WORDS = ("break case class catch const continue debugger default delete do else export extends"
|
|
91
|
+
" finally for function if import in instanceof new return switch this throw try typeof var void"
|
|
92
|
+
" while with yield enum implements static private package let public protected interface await null true false" )
|
|
93
|
+
|
|
94
|
+
KEYWORDS_BEFORE_EXPRESSION = "return yield new del raise elif else if"
|
|
95
|
+
|
|
96
|
+
ALL_KEYWORDS = KEYWORDS + " " + KEYWORDS_ATOM
|
|
97
|
+
|
|
98
|
+
KEYWORDS = make_predicate(KEYWORDS)
|
|
99
|
+
RESERVED_WORDS = make_predicate(RESERVED_WORDS)
|
|
100
|
+
KEYWORDS_BEFORE_EXPRESSION = make_predicate(KEYWORDS_BEFORE_EXPRESSION)
|
|
101
|
+
KEYWORDS_ATOM = make_predicate(KEYWORDS_ATOM)
|
|
102
|
+
IDENTIFIER_PAT = /^[a-z_$][_a-z0-9$]*$/i
|
|
103
|
+
|
|
104
|
+
def is_string_modifier(val):
|
|
105
|
+
for ch in val:
|
|
106
|
+
if 'vrufVRUF'.indexOf(ch) is -1:
|
|
107
|
+
return False
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def is_letter(code):
|
|
111
|
+
return code >= 97 and code <= 122 or code >= 65 and code <= 90 or code >= 170 and UNICODE.letter.test(String.fromCharCode(code))
|
|
112
|
+
|
|
113
|
+
def is_digit(code):
|
|
114
|
+
return code >= 48 and code <= 57
|
|
115
|
+
|
|
116
|
+
def is_alphanumeric_char(code):
|
|
117
|
+
return is_digit(code) or is_letter(code)
|
|
118
|
+
|
|
119
|
+
def is_unicode_combining_mark(ch):
|
|
120
|
+
return UNICODE.non_spacing_mark.test(ch) or UNICODE.space_combining_mark.test(ch)
|
|
121
|
+
|
|
122
|
+
def is_unicode_connector_punctuation(ch):
|
|
123
|
+
return UNICODE.connector_punctuation.test(ch)
|
|
124
|
+
|
|
125
|
+
def is_identifier(name):
|
|
126
|
+
return not RESERVED_WORDS[name] and not KEYWORDS[name] and not KEYWORDS_ATOM[name] and IDENTIFIER_PAT.test(name)
|
|
127
|
+
|
|
128
|
+
def is_identifier_start(code):
|
|
129
|
+
return code is 36 or code is 95 or is_letter(code)
|
|
130
|
+
|
|
131
|
+
def is_identifier_char(ch):
|
|
132
|
+
code = ch.charCodeAt(0)
|
|
133
|
+
return is_identifier_start(code) or is_digit(code) or code is 8204 or code is 8205 or is_unicode_combining_mark(ch) or is_unicode_connector_punctuation(ch)
|
|
134
|
+
|
|
135
|
+
def parse_js_number(num):
|
|
136
|
+
if RE_HEX_NUMBER.test(num):
|
|
137
|
+
return parseInt(num.substr(2), 16)
|
|
138
|
+
elif RE_OCT_NUMBER.test(num):
|
|
139
|
+
return parseInt(num.substr(1), 8)
|
|
140
|
+
elif RE_DEC_NUMBER.test(num):
|
|
141
|
+
return parseFloat(num)
|
|
142
|
+
|
|
143
|
+
# regexps adapted from http://xregexp.com/plugins/#unicode
|
|
144
|
+
UNICODE = { # {{{
|
|
145
|
+
'letter': RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
|
146
|
+
'non_spacing_mark': RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
|
147
|
+
'space_combining_mark': RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
|
148
|
+
'connector_punctuation': RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
|
149
|
+
} # }}}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def is_token(token, type, val):
|
|
153
|
+
return token.type is type and (val is None or val is undefined or token.value is val)
|
|
154
|
+
|
|
155
|
+
EX_EOF = {}
|
|
156
|
+
|
|
157
|
+
def tokenizer(raw_text, filename):
|
|
158
|
+
S = {
|
|
159
|
+
'text': raw_text.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ""),
|
|
160
|
+
'filename': filename,
|
|
161
|
+
'pos': 0,
|
|
162
|
+
'tokpos': 0,
|
|
163
|
+
'line': 1,
|
|
164
|
+
'tokline': 0,
|
|
165
|
+
'col': 0,
|
|
166
|
+
'tokcol': 0,
|
|
167
|
+
'newline_before': False,
|
|
168
|
+
'regex_allowed': False,
|
|
169
|
+
'comments_before': v'[]',
|
|
170
|
+
'whitespace_before': v'[]',
|
|
171
|
+
'newblock': False,
|
|
172
|
+
'endblock': False,
|
|
173
|
+
'indentation_matters': v'[ true ]',
|
|
174
|
+
'cached_whitespace': "",
|
|
175
|
+
'prev': undefined,
|
|
176
|
+
'index_or_slice': v'[ false ]',
|
|
177
|
+
'expecting_object_literal_key': False, # This is set by the parser when it is expecting an object literal key
|
|
178
|
+
'prev_was_comma': False, # True when the previous token was a ',' — used to detect positional-only '/' separator
|
|
179
|
+
}
|
|
180
|
+
def peek():
|
|
181
|
+
return S.text.charAt(S.pos)
|
|
182
|
+
|
|
183
|
+
def prevChar():
|
|
184
|
+
return S.text.charAt(S.tokpos - 1)
|
|
185
|
+
|
|
186
|
+
def next(signal_eof, in_string):
|
|
187
|
+
ch = S.text.charAt(S.pos)
|
|
188
|
+
S.pos += 1
|
|
189
|
+
if signal_eof and not ch:
|
|
190
|
+
raise EX_EOF
|
|
191
|
+
|
|
192
|
+
if ch is "\n":
|
|
193
|
+
S.newline_before = S.newline_before or not in_string
|
|
194
|
+
S.line += 1
|
|
195
|
+
S.col = 0
|
|
196
|
+
else:
|
|
197
|
+
S.col += 1
|
|
198
|
+
return ch
|
|
199
|
+
|
|
200
|
+
def find(what, signal_eof):
|
|
201
|
+
pos = S.text.indexOf(what, S.pos)
|
|
202
|
+
if signal_eof and pos is -1:
|
|
203
|
+
raise EX_EOF
|
|
204
|
+
return pos
|
|
205
|
+
|
|
206
|
+
def start_token():
|
|
207
|
+
S.tokline = S.line
|
|
208
|
+
S.tokcol = S.col
|
|
209
|
+
S.tokpos = S.pos
|
|
210
|
+
|
|
211
|
+
def token(type, value, is_comment, keep_newline):
|
|
212
|
+
S.prev_was_comma = (type is "punc" and value is ",")
|
|
213
|
+
S.regex_allowed = (type is "operator"
|
|
214
|
+
or type is "keyword" and KEYWORDS_BEFORE_EXPRESSION[value]
|
|
215
|
+
or type is "punc" and PUNC_BEFORE_EXPRESSION[value])
|
|
216
|
+
|
|
217
|
+
if type is "operator" and value is "is" and S.text.substr(S.pos).trimLeft().substr(0, 4).trimRight() is "not":
|
|
218
|
+
next_token()
|
|
219
|
+
value = "!=="
|
|
220
|
+
|
|
221
|
+
if type is "operator" and OP_MAP[value]:
|
|
222
|
+
value = OP_MAP[value]
|
|
223
|
+
|
|
224
|
+
ret = {
|
|
225
|
+
'type': type,
|
|
226
|
+
'value': value,
|
|
227
|
+
'line': S.tokline,
|
|
228
|
+
'col': S.tokcol,
|
|
229
|
+
'pos': S.tokpos,
|
|
230
|
+
'endpos': S.pos,
|
|
231
|
+
'nlb': S.newline_before,
|
|
232
|
+
'file': filename,
|
|
233
|
+
'leading_whitespace': S.whitespace_before[-1] or '',
|
|
234
|
+
}
|
|
235
|
+
if not is_comment:
|
|
236
|
+
ret.comments_before = S.comments_before
|
|
237
|
+
S.comments_before = v'[]' # Use a plain JS array for speed
|
|
238
|
+
# make note of any newlines in the comments that came before
|
|
239
|
+
for i in range(ret.comments_before.length):
|
|
240
|
+
ret.nlb = ret.nlb or ret.comments_before[i].nlb
|
|
241
|
+
|
|
242
|
+
if not keep_newline:
|
|
243
|
+
S.newline_before = False
|
|
244
|
+
|
|
245
|
+
if type is "punc":
|
|
246
|
+
# if (value is ":" && peek() is "\n") {
|
|
247
|
+
if value is ":" and not S.index_or_slice[-1]
|
|
248
|
+
and not S.expecting_object_literal_key
|
|
249
|
+
and (not S.text.substring(S.pos + 1, find("\n")).trim() or not S.text.substring(S.pos + 1, find("#")).trim()):
|
|
250
|
+
S.newblock = True
|
|
251
|
+
S.indentation_matters.push(True)
|
|
252
|
+
|
|
253
|
+
if value is "[":
|
|
254
|
+
if S.prev and (
|
|
255
|
+
S.prev.type is "name" or
|
|
256
|
+
(S.prev.type is 'punc' and ')]'.indexOf(S.prev.value) is not -1)
|
|
257
|
+
):
|
|
258
|
+
S.index_or_slice.push(True)
|
|
259
|
+
else:
|
|
260
|
+
S.index_or_slice.push(False)
|
|
261
|
+
S.indentation_matters.push(False)
|
|
262
|
+
elif value is "{" or value is "(":
|
|
263
|
+
S.indentation_matters.push(False)
|
|
264
|
+
elif value is "]":
|
|
265
|
+
S.index_or_slice.pop()
|
|
266
|
+
S.indentation_matters.pop()
|
|
267
|
+
elif value is "}" or value is ")":
|
|
268
|
+
S.indentation_matters.pop()
|
|
269
|
+
S.prev = AST_Token(ret)
|
|
270
|
+
return S.prev
|
|
271
|
+
|
|
272
|
+
# this will transform leading whitespace to block tokens unless
|
|
273
|
+
# part of array/hash, and skip non-leading whitespace
|
|
274
|
+
def parse_whitespace():
|
|
275
|
+
leading_whitespace = ""
|
|
276
|
+
whitespace_exists = False
|
|
277
|
+
while WHITESPACE_CHARS[peek()]:
|
|
278
|
+
whitespace_exists = True
|
|
279
|
+
ch = next()
|
|
280
|
+
if ch is "\n":
|
|
281
|
+
leading_whitespace = ""
|
|
282
|
+
else:
|
|
283
|
+
leading_whitespace += ch
|
|
284
|
+
if peek() is not "#":
|
|
285
|
+
if not whitespace_exists:
|
|
286
|
+
leading_whitespace = S.cached_whitespace
|
|
287
|
+
else:
|
|
288
|
+
S.cached_whitespace = leading_whitespace
|
|
289
|
+
if S.newline_before or S.endblock:
|
|
290
|
+
return test_indent_token(leading_whitespace)
|
|
291
|
+
|
|
292
|
+
def test_indent_token(leading_whitespace):
|
|
293
|
+
most_recent = S.whitespace_before[-1] or ""
|
|
294
|
+
S.endblock = False
|
|
295
|
+
if S.indentation_matters[-1] and leading_whitespace is not most_recent:
|
|
296
|
+
if S.newblock and leading_whitespace and leading_whitespace.indexOf(most_recent) is 0:
|
|
297
|
+
# positive indent, new block
|
|
298
|
+
S.newblock = False
|
|
299
|
+
S.whitespace_before.push(leading_whitespace)
|
|
300
|
+
return 1
|
|
301
|
+
elif most_recent and most_recent.indexOf(leading_whitespace) is 0:
|
|
302
|
+
# negative indent, block is ending
|
|
303
|
+
S.endblock = True
|
|
304
|
+
S.whitespace_before.pop()
|
|
305
|
+
return -1
|
|
306
|
+
else:
|
|
307
|
+
# indent mismatch, inconsistent indentation
|
|
308
|
+
S.tokline = S.line
|
|
309
|
+
S.tokcol = 0
|
|
310
|
+
parse_error("Inconsistent indentation")
|
|
311
|
+
return 0
|
|
312
|
+
|
|
313
|
+
def read_while(pred):
|
|
314
|
+
ret = ""
|
|
315
|
+
i = 0
|
|
316
|
+
ch = ''
|
|
317
|
+
while (ch = peek()) and pred(ch, i):
|
|
318
|
+
i += 1
|
|
319
|
+
ret += next()
|
|
320
|
+
return ret
|
|
321
|
+
|
|
322
|
+
def parse_error(err, is_eof):
|
|
323
|
+
raise new SyntaxError(err, filename, S.tokline, S.tokcol, S.tokpos, is_eof)
|
|
324
|
+
|
|
325
|
+
def read_num(prefix):
|
|
326
|
+
has_e = False
|
|
327
|
+
has_x = False
|
|
328
|
+
has_dot = prefix is "."
|
|
329
|
+
if not prefix and peek() is '0' and S.text.charAt(S.pos + 1) is 'b':
|
|
330
|
+
next(), next()
|
|
331
|
+
num = read_while(def(ch): return ch is '0' or ch is '1';)
|
|
332
|
+
valid = parseInt(num, 2)
|
|
333
|
+
if isNaN(valid):
|
|
334
|
+
parse_error('Invalid syntax for a binary number')
|
|
335
|
+
return token('num', valid)
|
|
336
|
+
seen = v'[]'
|
|
337
|
+
num = read_while(def(ch, i):
|
|
338
|
+
nonlocal has_dot, has_e, has_x
|
|
339
|
+
seen.push(ch)
|
|
340
|
+
if ch is 'x' or ch is 'X':
|
|
341
|
+
if has_x or seen.length is not 2 or seen[0] is not '0':
|
|
342
|
+
return False
|
|
343
|
+
has_x = True
|
|
344
|
+
return True
|
|
345
|
+
elif ch is 'e' or ch is 'E':
|
|
346
|
+
if has_x:
|
|
347
|
+
return True
|
|
348
|
+
if has_e or i == 0:
|
|
349
|
+
return False
|
|
350
|
+
has_e = True
|
|
351
|
+
return True
|
|
352
|
+
elif ch is '-':
|
|
353
|
+
if i is 0 and not prefix:
|
|
354
|
+
return True
|
|
355
|
+
if has_e and seen[i-1].toLowerCase() is 'e':
|
|
356
|
+
return True
|
|
357
|
+
return False
|
|
358
|
+
elif ch is '+':
|
|
359
|
+
if has_e and seen[i-1].toLowerCase() is 'e':
|
|
360
|
+
return True
|
|
361
|
+
return False
|
|
362
|
+
elif ch is '.':
|
|
363
|
+
return (has_dot = True) if not has_dot and not has_x and not has_e else False
|
|
364
|
+
return is_alphanumeric_char(ch.charCodeAt(0))
|
|
365
|
+
)
|
|
366
|
+
if prefix:
|
|
367
|
+
num = prefix + num
|
|
368
|
+
|
|
369
|
+
valid = parse_js_number(num)
|
|
370
|
+
if not isNaN(valid):
|
|
371
|
+
return token("num", valid)
|
|
372
|
+
else:
|
|
373
|
+
parse_error("Invalid syntax: " + num)
|
|
374
|
+
|
|
375
|
+
def read_hex_digits(count):
|
|
376
|
+
ans = ''
|
|
377
|
+
while count > 0:
|
|
378
|
+
count -= 1
|
|
379
|
+
if not HEX_PAT.test(peek()):
|
|
380
|
+
return ans
|
|
381
|
+
ans += next()
|
|
382
|
+
nval = parseInt(ans, 16)
|
|
383
|
+
if nval > 0x10FFFF:
|
|
384
|
+
return ans
|
|
385
|
+
return nval
|
|
386
|
+
|
|
387
|
+
def read_escape_sequence():
|
|
388
|
+
q = next(True)
|
|
389
|
+
if q is '\n':
|
|
390
|
+
return ''
|
|
391
|
+
if q is '\\':
|
|
392
|
+
return q
|
|
393
|
+
if '"\''.indexOf(q) is not -1:
|
|
394
|
+
return q
|
|
395
|
+
if ASCII_CONTROL_CHARS[q]:
|
|
396
|
+
return String.fromCharCode(ASCII_CONTROL_CHARS[q])
|
|
397
|
+
if '0' <= q <= '7':
|
|
398
|
+
octal = q
|
|
399
|
+
if '0' <= peek() <= '7':
|
|
400
|
+
octal += next()
|
|
401
|
+
if '0' <= peek() <= '7':
|
|
402
|
+
octal += next()
|
|
403
|
+
code = parseInt(octal, 8)
|
|
404
|
+
if isNaN(code):
|
|
405
|
+
return '\\' + octal
|
|
406
|
+
return String.fromCharCode(code)
|
|
407
|
+
if q is 'x':
|
|
408
|
+
code = read_hex_digits(2)
|
|
409
|
+
if jstype(code) is 'number':
|
|
410
|
+
return String.fromCharCode(code)
|
|
411
|
+
return '\\x' + code
|
|
412
|
+
if q is 'u':
|
|
413
|
+
code = read_hex_digits(4)
|
|
414
|
+
if jstype(code) is 'number':
|
|
415
|
+
return String.fromCharCode(code)
|
|
416
|
+
return '\\u' + code
|
|
417
|
+
if q is 'U':
|
|
418
|
+
code = read_hex_digits(8)
|
|
419
|
+
if jstype(code) is 'number':
|
|
420
|
+
if code <= 0xFFFF:
|
|
421
|
+
return String.fromCharCode(code)
|
|
422
|
+
code -= 0x10000
|
|
423
|
+
return String.fromCharCode(0xD800+(code>>10), 0xDC00+(code&0x3FF))
|
|
424
|
+
return '\\U' + code
|
|
425
|
+
if q is 'N' and peek() is '{':
|
|
426
|
+
next()
|
|
427
|
+
name = read_while(def (ch): return NAME_PAT.test(ch);)
|
|
428
|
+
if peek() is not '}':
|
|
429
|
+
return '\\N{' + name
|
|
430
|
+
next()
|
|
431
|
+
key = (name or '').toLowerCase()
|
|
432
|
+
if not name or not Object.prototype.hasOwnProperty.call(ALIAS_MAP, key):
|
|
433
|
+
return '\\N{' + name + '}'
|
|
434
|
+
code = ALIAS_MAP[key]
|
|
435
|
+
if code <= 0xFFFF:
|
|
436
|
+
return String.fromCharCode(code)
|
|
437
|
+
code -= 0x10000
|
|
438
|
+
return String.fromCharCode(0xD800+(code>>10), 0xDC00+(code&0x3FF))
|
|
439
|
+
return '\\' + q
|
|
440
|
+
|
|
441
|
+
def with_eof_error(eof_error, cont):
|
|
442
|
+
return def():
|
|
443
|
+
try:
|
|
444
|
+
return cont.apply(None, arguments)
|
|
445
|
+
except as ex:
|
|
446
|
+
if ex is EX_EOF:
|
|
447
|
+
parse_error(eof_error, True)
|
|
448
|
+
else:
|
|
449
|
+
raise
|
|
450
|
+
|
|
451
|
+
read_string = with_eof_error("Unterminated string constant", def(is_raw_literal, is_js_literal):
|
|
452
|
+
quote = next()
|
|
453
|
+
tok_type = 'js' if is_js_literal else 'string'
|
|
454
|
+
ret = ""
|
|
455
|
+
is_multiline = False
|
|
456
|
+
if peek() is quote:
|
|
457
|
+
# two quotes in a row
|
|
458
|
+
next(True)
|
|
459
|
+
if peek() is quote:
|
|
460
|
+
# multiline string (3 quotes in a row)
|
|
461
|
+
next(True)
|
|
462
|
+
is_multiline = True
|
|
463
|
+
else:
|
|
464
|
+
return token(tok_type, '')
|
|
465
|
+
|
|
466
|
+
while True:
|
|
467
|
+
ch = next(True, True)
|
|
468
|
+
if not ch:
|
|
469
|
+
break
|
|
470
|
+
if ch is "\n" and not is_multiline:
|
|
471
|
+
parse_error("End of line while scanning string literal")
|
|
472
|
+
|
|
473
|
+
if ch is "\\":
|
|
474
|
+
ret += ('\\' + next(True)) if is_raw_literal else read_escape_sequence()
|
|
475
|
+
continue
|
|
476
|
+
|
|
477
|
+
if ch is quote:
|
|
478
|
+
if not is_multiline:
|
|
479
|
+
break
|
|
480
|
+
if peek() is quote:
|
|
481
|
+
next()
|
|
482
|
+
if peek() is quote:
|
|
483
|
+
next()
|
|
484
|
+
break
|
|
485
|
+
else:
|
|
486
|
+
ch += quote
|
|
487
|
+
ret += ch
|
|
488
|
+
return token(tok_type, ret)
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
def handle_interpolated_string(string, start_tok):
|
|
492
|
+
def raise_error(err):
|
|
493
|
+
raise new SyntaxError(err, filename, start_tok.line, start_tok.col, start_tok.pos, False)
|
|
494
|
+
S.text = S.text[:S.pos] + '(' + interpolate(string, raise_error) + ')' + S.text[S.pos:]
|
|
495
|
+
return token('punc', next())
|
|
496
|
+
|
|
497
|
+
def read_line_comment(shebang):
|
|
498
|
+
if not shebang:
|
|
499
|
+
next()
|
|
500
|
+
i = find("\n")
|
|
501
|
+
|
|
502
|
+
if i is -1:
|
|
503
|
+
ret = S.text.substr(S.pos)
|
|
504
|
+
S.pos = S.text.length
|
|
505
|
+
else:
|
|
506
|
+
ret = S.text.substring(S.pos, i)
|
|
507
|
+
S.pos = i
|
|
508
|
+
|
|
509
|
+
return token("shebang" if shebang else "comment1", ret, True)
|
|
510
|
+
|
|
511
|
+
def read_name():
|
|
512
|
+
name = ch = ""
|
|
513
|
+
while (ch = peek()) is not None:
|
|
514
|
+
if ch is "\\":
|
|
515
|
+
if S.text.charAt(S.pos + 1) is "\n":
|
|
516
|
+
S.pos += 2
|
|
517
|
+
continue
|
|
518
|
+
break
|
|
519
|
+
elif is_identifier_char(ch):
|
|
520
|
+
name += next()
|
|
521
|
+
else:
|
|
522
|
+
break
|
|
523
|
+
return name
|
|
524
|
+
|
|
525
|
+
read_regexp = with_eof_error("Unterminated regular expression", def():
|
|
526
|
+
prev_backslash = False
|
|
527
|
+
regexp = ch = ''
|
|
528
|
+
in_class = False
|
|
529
|
+
verbose_regexp = False
|
|
530
|
+
in_comment = False
|
|
531
|
+
|
|
532
|
+
if peek() is '/':
|
|
533
|
+
next(True)
|
|
534
|
+
if peek() is '/':
|
|
535
|
+
verbose_regexp = True
|
|
536
|
+
next(True)
|
|
537
|
+
else: # empty regexp (//)
|
|
538
|
+
mods = read_name()
|
|
539
|
+
return token("regexp", RegExp(regexp, mods))
|
|
540
|
+
while True:
|
|
541
|
+
ch = next(True)
|
|
542
|
+
if not ch:
|
|
543
|
+
break
|
|
544
|
+
if in_comment:
|
|
545
|
+
if ch is '\n':
|
|
546
|
+
in_comment = False
|
|
547
|
+
continue
|
|
548
|
+
if prev_backslash:
|
|
549
|
+
regexp += "\\" + ch
|
|
550
|
+
prev_backslash = False
|
|
551
|
+
elif ch is "[":
|
|
552
|
+
in_class = True
|
|
553
|
+
regexp += ch
|
|
554
|
+
elif ch is "]" and in_class:
|
|
555
|
+
in_class = False
|
|
556
|
+
regexp += ch
|
|
557
|
+
elif ch is "/" and not in_class:
|
|
558
|
+
if verbose_regexp:
|
|
559
|
+
if peek() is not '/':
|
|
560
|
+
regexp += '\\/'
|
|
561
|
+
continue
|
|
562
|
+
next(True)
|
|
563
|
+
if peek() is not '/':
|
|
564
|
+
regexp += '\\/\\/'
|
|
565
|
+
continue
|
|
566
|
+
next(True)
|
|
567
|
+
break
|
|
568
|
+
elif ch is "\\":
|
|
569
|
+
prev_backslash = True
|
|
570
|
+
elif verbose_regexp and not in_class and ' \n\r\t'.indexOf(ch) is not -1:
|
|
571
|
+
pass
|
|
572
|
+
elif verbose_regexp and not in_class and ch is '#':
|
|
573
|
+
in_comment = True
|
|
574
|
+
else:
|
|
575
|
+
regexp += ch
|
|
576
|
+
|
|
577
|
+
mods = read_name()
|
|
578
|
+
return token("regexp", RegExp(regexp, mods))
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
def read_operator(prefix):
|
|
582
|
+
def grow(op):
|
|
583
|
+
if not peek():
|
|
584
|
+
return op
|
|
585
|
+
|
|
586
|
+
bigger = op + peek()
|
|
587
|
+
if OPERATORS[bigger]:
|
|
588
|
+
next()
|
|
589
|
+
return grow(bigger)
|
|
590
|
+
else:
|
|
591
|
+
return op
|
|
592
|
+
op = grow(prefix or next())
|
|
593
|
+
if op is '->':
|
|
594
|
+
# pretend that this is an operator as the tokenizer only allows
|
|
595
|
+
# one character punctuation.
|
|
596
|
+
return token('punc', op)
|
|
597
|
+
return token("operator", op)
|
|
598
|
+
|
|
599
|
+
def handle_slash():
|
|
600
|
+
next()
|
|
601
|
+
if S.regex_allowed:
|
|
602
|
+
# When the previous token was ',' and what follows the '/' (skipping
|
|
603
|
+
# optional whitespace) is ',' or ')', this is the positional-only
|
|
604
|
+
# parameter separator, not a regex literal.
|
|
605
|
+
if S.prev_was_comma:
|
|
606
|
+
i = S.pos
|
|
607
|
+
while i < S.text.length and WHITESPACE_CHARS[S.text.charAt(i)]:
|
|
608
|
+
i += 1
|
|
609
|
+
if i < S.text.length:
|
|
610
|
+
c = S.text.charAt(i)
|
|
611
|
+
if c is ',' or c is ')':
|
|
612
|
+
return read_operator("/")
|
|
613
|
+
return read_regexp("")
|
|
614
|
+
return read_operator("/")
|
|
615
|
+
|
|
616
|
+
def handle_dot():
|
|
617
|
+
next()
|
|
618
|
+
if peek() is '.' and S.text.charAt(S.pos + 1) is '.':
|
|
619
|
+
next() # consume second '.'
|
|
620
|
+
next() # consume third '.'
|
|
621
|
+
return token("atom", "Ellipsis")
|
|
622
|
+
return read_num(".") if is_digit(peek().charCodeAt(0)) else token("punc", ".")
|
|
623
|
+
|
|
624
|
+
def read_word():
|
|
625
|
+
word = read_name()
|
|
626
|
+
return token("atom", word) if KEYWORDS_ATOM[word] else (token("name", word) if not KEYWORDS[word] else (token("operator", word) if OPERATORS[word] and prevChar() is not "." else token("keyword", word)))
|
|
627
|
+
|
|
628
|
+
def next_token():
|
|
629
|
+
|
|
630
|
+
indent = parse_whitespace()
|
|
631
|
+
# if indent is 1:
|
|
632
|
+
# return token("punc", "{")
|
|
633
|
+
if indent is -1:
|
|
634
|
+
return token("punc", "}", False, True)
|
|
635
|
+
|
|
636
|
+
start_token()
|
|
637
|
+
ch = peek()
|
|
638
|
+
if not ch:
|
|
639
|
+
return token("eof")
|
|
640
|
+
|
|
641
|
+
code = ch.charCodeAt(0)
|
|
642
|
+
tmp_ = code
|
|
643
|
+
if tmp_ is 34 or tmp_ is 39: # double-quote (") or single quote (')
|
|
644
|
+
return read_string(False)
|
|
645
|
+
elif tmp_ is 35: # pound-sign (#)
|
|
646
|
+
if S.pos is 0 and S.text.charAt(1) is '!':
|
|
647
|
+
#shebang
|
|
648
|
+
return read_line_comment(True)
|
|
649
|
+
regex_allowed = S.regex_allowed
|
|
650
|
+
S.comments_before.push(read_line_comment())
|
|
651
|
+
S.regex_allowed = regex_allowed
|
|
652
|
+
return next_token()
|
|
653
|
+
elif tmp_ is 46: # dot (.)
|
|
654
|
+
return handle_dot()
|
|
655
|
+
elif tmp_ is 47: # slash (/)
|
|
656
|
+
return handle_slash()
|
|
657
|
+
|
|
658
|
+
if is_digit(code):
|
|
659
|
+
return read_num()
|
|
660
|
+
|
|
661
|
+
if PUNC_CHARS[ch]:
|
|
662
|
+
if ch is ':' and S.text.charAt(S.pos + 1) is '=':
|
|
663
|
+
next() # consume ':'
|
|
664
|
+
next() # consume '='
|
|
665
|
+
return token("operator", ":=")
|
|
666
|
+
return token("punc", next())
|
|
667
|
+
|
|
668
|
+
if OPERATOR_CHARS[ch]:
|
|
669
|
+
return read_operator()
|
|
670
|
+
|
|
671
|
+
if code is 92 and S.text.charAt(S.pos + 1) is "\n":
|
|
672
|
+
# backslash will consume the newline character that follows
|
|
673
|
+
next()
|
|
674
|
+
# backslash
|
|
675
|
+
next()
|
|
676
|
+
# newline
|
|
677
|
+
S.newline_before = False
|
|
678
|
+
return next_token()
|
|
679
|
+
|
|
680
|
+
if is_identifier_start(code):
|
|
681
|
+
tok = read_word()
|
|
682
|
+
if '\'"'.indexOf(peek()) is not -1 and is_string_modifier(tok.value):
|
|
683
|
+
mods = tok.value.toLowerCase()
|
|
684
|
+
start_pos_for_string = S.tokpos
|
|
685
|
+
stok = read_string(mods.indexOf('r') is not -1, mods.indexOf('v') is not -1)
|
|
686
|
+
tok.endpos = stok.endpos
|
|
687
|
+
if stok.type is not 'js' and mods.indexOf('f') is not -1:
|
|
688
|
+
tok.col += start_pos_for_string - tok.pos
|
|
689
|
+
return handle_interpolated_string(stok.value, tok)
|
|
690
|
+
tok.value = stok.value
|
|
691
|
+
tok.type = stok.type
|
|
692
|
+
return tok
|
|
693
|
+
|
|
694
|
+
parse_error("Unexpected character «" + ch + "»")
|
|
695
|
+
|
|
696
|
+
next_token.context = def(nc):
|
|
697
|
+
nonlocal S
|
|
698
|
+
if nc:
|
|
699
|
+
S = nc
|
|
700
|
+
return S
|
|
701
|
+
|
|
702
|
+
return next_token
|