2012-08-22 18:28:59 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
A JavaScript tokenizer / parser / beautifier / compressor .
https : //github.com/mishoo/UglifyJS2
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ( C ) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
Author : Mihai Bazon
< mihai . bazon @ gmail . com >
http : //mihai.bazon.net/blog
Distributed under the BSD license :
2012-08-27 08:01:27 +00:00
Copyright 2012 ( c ) Mihai Bazon < mihai . bazon @ gmail . com >
2012-08-22 18:28:59 +00:00
Parser based on parse - js ( http : //marijn.haverbeke.nl/parse-js/).
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the following
disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the following
disclaimer in the documentation and / or other materials
provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “ AS IS ” AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY ,
OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR
TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2012-10-02 09:45:31 +00:00
"use strict" ;
2018-06-09 17:40:40 +00:00
var utils = require ( "./utils" ) ;
var characters = utils . characters ;
var find _if = utils . find _if ;
var configure _error _stack = utils . configure _error _stack ;
var defaults = utils . defaults ;
var makePredicate = utils . makePredicate ;
var all = utils . all ;
var HOP = utils . HOP ;
var merge = utils . merge ;
2018-06-13 10:50:22 +00:00
var AST = require ( "./ast" ) ;
2018-06-09 17:40:40 +00:00
2012-10-11 08:52:05 +00:00
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with' ;
var KEYWORDS _ATOM = 'false null true' ;
2016-03-15 15:20:32 +00:00
var RESERVED _WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield'
2012-10-11 08:52:05 +00:00
+ " " + KEYWORDS _ATOM + " " + KEYWORDS ;
var KEYWORDS _BEFORE _EXPRESSION = 'return new delete throw else case' ;
2012-05-27 11:09:01 +00:00
2012-10-11 08:52:05 +00:00
KEYWORDS = makePredicate ( KEYWORDS ) ;
RESERVED _WORDS = makePredicate ( RESERVED _WORDS ) ;
KEYWORDS _BEFORE _EXPRESSION = makePredicate ( KEYWORDS _BEFORE _EXPRESSION ) ;
KEYWORDS _ATOM = makePredicate ( KEYWORDS _ATOM ) ;
2012-05-27 11:09:01 +00:00
2012-10-11 08:52:05 +00:00
var OPERATOR _CHARS = makePredicate ( characters ( "+-*&%=<>!?|~^" ) ) ;
2012-05-27 11:09:01 +00:00
var RE _HEX _NUMBER = /^0x[0-9a-f]+$/i ;
var RE _OCT _NUMBER = /^0[0-7]+$/ ;
2012-10-11 08:52:05 +00:00
var OPERATORS = makePredicate ( [
2012-05-27 11:09:01 +00:00
"in" ,
"instanceof" ,
"typeof" ,
"new" ,
"void" ,
"delete" ,
"++" ,
"--" ,
"+" ,
"-" ,
"!" ,
"~" ,
"&" ,
"|" ,
"^" ,
"*" ,
"/" ,
"%" ,
">>" ,
"<<" ,
">>>" ,
"<" ,
">" ,
"<=" ,
">=" ,
"==" ,
"===" ,
"!=" ,
"!==" ,
"?" ,
"=" ,
"+=" ,
"-=" ,
"/=" ,
"*=" ,
"%=" ,
">>=" ,
"<<=" ,
">>>=" ,
"|=" ,
"^=" ,
"&=" ,
"&&" ,
"||"
] ) ;
2016-06-13 10:36:47 +00:00
var WHITESPACE _CHARS = makePredicate ( characters ( " \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF" ) ) ;
var NEWLINE _CHARS = makePredicate ( characters ( "\n\r\u2028\u2029" ) ) ;
2012-05-27 11:09:01 +00:00
2017-04-18 20:27:13 +00:00
var PUNC _BEFORE _EXPRESSION = makePredicate ( characters ( "[{(,;:" ) ) ;
2012-05-27 11:09:01 +00:00
2012-10-11 08:52:05 +00:00
var PUNC _CHARS = makePredicate ( characters ( "[]{}(),;:" ) ) ;
2012-05-27 11:09:01 +00:00
/* -----[ Tokenizer ]----- */
// regexps adapted from http://xregexp.com/plugins/#unicode
var UNICODE = {
2015-01-18 23:59:29 +00:00
letter : new 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 \ \u037F \ \u0386 \ \u0388 - \ \u038A \ \u038C \ \u038E - \ \u03A1 \ \u03A3 - \ \u03F5 \ \u03F7 - \ \u0481 \ \u048A - \ \u052F \ \u0531 - \ \u0556 \ \u0559 \ \u0561 - \ \u0587 \ \u05D0 - \ \u05EA \ \u05F0 - \ \u05F2 \ \u0620 - \ \u064A \ \u066E \ \u066F \ \u0671 - \ \u06D3 \ \u06D5 \ \u06E5 \ \u06E6 \ \u06EE \ \u06EF \ \u06FA - \ \u06FC \ \u06FF \ \u0710 \ \u0712 - \ \u072F \ \u074D - \ \u07A5 \ \u07B1 \ \u07CA - \ \u07EA \ \u07F4 \ \u07F5 \ \u07FA \ \u0800 - \ \u0815 \ \u081A \ \u0824 \ \u0828 \ \u0840 - \ \u0858 \ \u08A0 - \ \u08B2 \ \u0904 - \ \u0939 \ \u093D \ \u0950 \ \u0958 - \ \u0961 \ \u0971 - \ \u0980 \ \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 - \ \u0C39 \ \u0C3D \ \u0C58 \ \u0C59 \ \u0C60 \ \u0C61 \ \u0C85 - \ \u0C8C \ \u0C8E - \ \u0C90 \ \u0C92 - \ \u0CA8 \ \u0CAA - \ \u0CB3 \ \u0CB5 - \ \u0CB9 \ \u0CBD \ \u0CDE \ \u0CE0 \ \u0CE1 \ \u0CF1 \ \u0CF2 \ \u0D05 - \ \u0D0C \ \u0D0E - \ \u0D10 \ \u0D12 - \ \u0D3A \ \u0D3D \ \u0D4E \ \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 - \ \u0EDF \ \u0F00 \ \u0F40 - \ \u0F47 \ \u0F49 - \ \u0F6C \ \u0F88 - \ \u0F8C \ \u1000 - \ \u102A \ \u103F \ \u1050 - \ \u1055 \ \u105A - \ \u105D \ \u1061 \ \u1065 \ \u1066 \ \u106E - \ \u1070 \ \u1075 - \ \u1081 \ \u108E \ \u10A0 - \ \u10C5 \ \u10C7 \ \u10CD \ \u10D0 - \ \u10FA \ \u10FC - \ \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 - \ \u167F \ \u1681 - \ \u169A \ \u16A0 - \ \u16EA \ \u16EE - \ \u16F8 \ \u1700 - \ \u170C \ \u170E - \ \u1711 \ \u1720 - \ \u1731 \ \u1740 - \ \u1751 \ \u1760 - \ \u176C \ \u176E - \ \u1770 \ \u1780 - \ \u17B3 \ \u17D7 \ \u17DC \ \u1820 - \ \u1877 \ \u1880 - \ \u18A8 \ \u18AA \ \u18B0 - \ \u18F5 \ \u1900 - \ \u191E \ \u1950 - \ \u196D \ \u1970 - \ \u1974 \ \u1980 - \ \u19AB \ \u19C1 - \ \u19C7 \ \u1A00 - \ \u1A16 \ \u1A20 - \ \u1A54 \ \u1AA7 \ \u1B05 - \ \u1B33 \ \u1B45 - \ \u1B4B \ \u1B83 - \ \u1BA0 \ \u1BAE \ \u1BAF \ \u1BBA - \ \u1BE5 \ \u1C00 - \ \u1C23 \ \u1C4D - \ \u1C4F \ \u1C5A - \ \u1C7D \ \u1CE9 - \ \u1CEC \ \u1CEE - \ \u1CF1 \ \u1CF5 \ \u1CF6 \ \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 - \ \u209C \ \u2102 \ \u2107 \ \u210A - \ \u2113 \ \u2115 \ \u2119 - \ \u211D \ \u2124 \ \u2126 \ \u2128 \ \u212A - \ \u212D \ \u212F - \ \u2139 \ \u213C - \ \u213F \ \u2145 - \ \u2149 \ \u214E \ \u2160 - \ \u2188 \ \u2C00 - \ \u2C2E \ \u2C30 - \ \u2C5E \ \u2C60 - \ \u2CE4 \ \u2CEB - \ \u2CEE \ \u2CF2 \ \u2CF3 \ \u2D00 - \ \u2D25 \ \u2D27 \ \u2D2D \ \u2D30 - \ \u2D67 \ \u2D6F \ \u2D80 - \ \u2D96 \ \u2DA0 - \ \u2DA6 \ \u2DA8 - \ \u2DAE \ \u2DB0 - \ \u2DB6 \ \u2DB8 - \ \u2DBE \ \u2DC0 - \ \u2DC6 \ \u2DC8 - \ \u2DCE \ \u2DD0 - \ \u2DD6 \ \u2DD8 - \ \u2DDE \ \u2E2F \ \u3005 - \ \u3007 \ \u3021 - \ \u3029 \ \u3031 - \ \u3035 \ \u3038 - \ \u303C \ \u3041 - \ \u3096 \ \u309D - \ \u309F \ \u30A1 - \ \u30FA \ \u30FC - \ \u30FF \ \u3105 - \ \u312D \ \u3131 - \ \u318E \ \u31A0 - \ \u31BA \ \u31F0 - \ \u31FF \ \u3400 - \ \u4DB5 \ \u4E00 - \ \u9FCC \ \uA000 - \ \uA48C \ \uA4D0 - \ \uA4FD \ \uA500 - \ \uA60C \ \uA610 - \ \uA61F \ \uA62A \ \uA62B \ \uA640 - \ \uA66E \ \uA67F - \ \uA69D \ \uA6A0 - \ \uA6EF \ \uA717 - \ \uA71F \ \uA722 - \ \uA788 \ \uA78B - \ \uA78E \ \uA790 - \ \uA7AD \ \uA7B0 \ \uA7B1 \ \uA7F7 - \ \uA801 \ \uA803 - \ \uA805 \ \uA807 - \ \uA80A \ \
2015-01-19 20:35:53 +00:00
digit : new RegExp ( "[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]" ) ,
2012-05-27 11:09:01 +00:00
non _spacing _mark : new 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]" ) ,
space _combining _mark : new 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]" ) ,
connector _punctuation : new RegExp ( "[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]" )
} ;
2012-10-11 10:00:58 +00:00
function is _letter ( code ) {
return ( code >= 97 && code <= 122 )
|| ( code >= 65 && code <= 90 )
|| ( code >= 0xaa && UNICODE . letter . test ( String . fromCharCode ( code ) ) ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2017-12-10 17:15:44 +00:00
function is _surrogate _pair _head ( code ) {
if ( typeof code == "string" )
code = code . charCodeAt ( 0 ) ;
return code >= 0xd800 && code <= 0xdbff ;
}
function is _surrogate _pair _tail ( code ) {
if ( typeof code == "string" )
code = code . charCodeAt ( 0 ) ;
return code >= 0xdc00 && code <= 0xdfff ;
}
2012-10-11 10:00:58 +00:00
function is _digit ( code ) {
2015-01-19 20:35:53 +00:00
return code >= 48 && code <= 57 ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-10-11 10:00:58 +00:00
function is _alphanumeric _char ( code ) {
return is _digit ( code ) || is _letter ( code ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2015-01-19 20:35:53 +00:00
function is _unicode _digit ( code ) {
return UNICODE . digit . test ( String . fromCharCode ( code ) ) ;
}
2012-05-27 11:09:01 +00:00
function is _unicode _combining _mark ( ch ) {
return UNICODE . non _spacing _mark . test ( ch ) || UNICODE . space _combining _mark . test ( ch ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function is _unicode _connector _punctuation ( ch ) {
return UNICODE . connector _punctuation . test ( ch ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-08-17 12:59:42 +00:00
function is _identifier ( name ) {
2018-04-03 07:15:01 +00:00
return ! RESERVED _WORDS [ name ] && /^[a-z_$][a-z0-9_$]*$/i . test ( name ) ;
2018-06-06 09:50:56 +00:00
}
2012-08-17 12:59:42 +00:00
2012-10-11 10:00:58 +00:00
function is _identifier _start ( code ) {
return code == 36 || code == 95 || is _letter ( code ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function is _identifier _char ( ch ) {
2012-10-11 10:00:58 +00:00
var code = ch . charCodeAt ( 0 ) ;
return is _identifier _start ( code )
|| is _digit ( code )
|| code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
2012-05-27 11:09:01 +00:00
|| is _unicode _combining _mark ( ch )
|| is _unicode _connector _punctuation ( ch )
2015-01-19 20:35:53 +00:00
|| is _unicode _digit ( code )
2012-05-27 11:09:01 +00:00
;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
function is _identifier _string ( str ) {
2014-04-18 07:47:38 +00:00
return /^[a-z_$][a-z0-9_$]*$/i . test ( str ) ;
2018-06-06 09:50:56 +00:00
}
2013-05-05 18:45:41 +00:00
2012-05-27 11:09:01 +00:00
function parse _js _number ( num ) {
if ( RE _HEX _NUMBER . test ( num ) ) {
return parseInt ( num . substr ( 2 ) , 16 ) ;
} else if ( RE _OCT _NUMBER . test ( num ) ) {
return parseInt ( num . substr ( 1 ) , 8 ) ;
2015-11-09 10:28:27 +00:00
} else {
2015-11-09 11:15:20 +00:00
var val = parseFloat ( num ) ;
if ( val == num ) return val ;
2012-05-27 11:09:01 +00:00
}
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2014-08-11 11:40:01 +00:00
function JS _Parse _Error ( message , filename , line , col , pos ) {
2012-05-27 11:09:01 +00:00
this . message = message ;
2014-08-11 11:40:01 +00:00
this . filename = filename ;
2012-10-02 13:39:53 +00:00
this . line = line ;
this . col = col ;
2012-10-11 12:25:38 +00:00
this . pos = pos ;
2018-06-06 09:50:56 +00:00
}
2017-02-26 19:40:54 +00:00
JS _Parse _Error . prototype = Object . create ( Error . prototype ) ;
JS _Parse _Error . prototype . constructor = JS _Parse _Error ;
JS _Parse _Error . prototype . name = "SyntaxError" ;
configure _error _stack ( JS _Parse _Error ) ;
2012-05-27 11:09:01 +00:00
2012-09-21 11:38:52 +00:00
function js _error ( message , filename , line , col , pos ) {
2014-08-11 11:40:01 +00:00
throw new JS _Parse _Error ( message , filename , line , col , pos ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function is _token ( token , type , val ) {
return token . type == type && ( val == null || token . value == val ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
var EX _EOF = { } ;
2015-02-20 15:08:01 +00:00
function tokenizer ( $TEXT , filename , html5 _comments , shebang ) {
2012-05-27 11:09:01 +00:00
var S = {
2015-05-20 13:17:46 +00:00
text : $TEXT ,
2012-09-21 11:38:52 +00:00
filename : filename ,
2013-07-15 08:59:23 +00:00
pos : 0 ,
tokpos : 0 ,
line : 1 ,
tokline : 0 ,
col : 0 ,
tokcol : 0 ,
2012-05-27 11:09:01 +00:00
newline _before : false ,
regex _allowed : false ,
2016-05-20 08:25:35 +00:00
comments _before : [ ] ,
directives : { } ,
directive _stack : [ ]
2012-05-27 11:09:01 +00:00
} ;
2018-06-06 09:50:56 +00:00
function peek ( ) {
return S . text . charAt ( S . pos ) ;
}
2012-05-27 11:09:01 +00:00
function next ( signal _eof , in _string ) {
var ch = S . text . charAt ( S . pos ++ ) ;
if ( signal _eof && ! ch )
throw EX _EOF ;
2018-04-03 07:15:01 +00:00
if ( NEWLINE _CHARS [ ch ] ) {
2012-05-27 11:09:01 +00:00
S . newline _before = S . newline _before || ! in _string ;
++ S . line ;
S . col = 0 ;
2015-01-05 10:14:42 +00:00
if ( ! in _string && ch == "\r" && peek ( ) == "\n" ) {
// treat a \r\n sequence as a single \n
++ S . pos ;
ch = "\n" ;
}
2012-05-27 11:09:01 +00:00
} else {
++ S . col ;
}
return ch ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-09-06 06:54:30 +00:00
function forward ( i ) {
while ( i -- > 0 ) next ( ) ;
2018-06-06 09:50:56 +00:00
}
2013-09-06 06:54:30 +00:00
function looking _at ( str ) {
return S . text . substr ( S . pos , str . length ) == str ;
2018-06-06 09:50:56 +00:00
}
2013-09-06 06:54:30 +00:00
2016-04-25 04:42:18 +00:00
function find _eol ( ) {
var text = S . text ;
for ( var i = S . pos , n = S . text . length ; i < n ; ++ i ) {
var ch = text [ i ] ;
2018-04-03 07:15:01 +00:00
if ( NEWLINE _CHARS [ ch ] )
2016-04-25 04:42:18 +00:00
return i ;
}
return - 1 ;
2018-06-06 09:50:56 +00:00
}
2016-04-25 04:42:18 +00:00
2012-05-27 11:09:01 +00:00
function find ( what , signal _eof ) {
var pos = S . text . indexOf ( what , S . pos ) ;
if ( signal _eof && pos == - 1 ) throw EX _EOF ;
return pos ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function start _token ( ) {
S . tokline = S . line ;
S . tokcol = S . col ;
S . tokpos = S . pos ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-09-02 08:09:54 +00:00
var prev _was _dot = false ;
2012-05-27 11:09:01 +00:00
function token ( type , value , is _comment ) {
2018-04-03 07:15:01 +00:00
S . regex _allowed = ( ( type == "operator" && ! UNARY _POSTFIX [ value ] ) ||
( type == "keyword" && KEYWORDS _BEFORE _EXPRESSION [ value ] ) ||
( type == "punc" && PUNC _BEFORE _EXPRESSION [ value ] ) ) ;
2017-05-15 21:40:49 +00:00
if ( type == "punc" && value == "." ) {
prev _was _dot = true ;
} else if ( ! is _comment ) {
prev _was _dot = false ;
}
2012-05-27 11:09:01 +00:00
var ret = {
2014-08-08 11:15:43 +00:00
type : type ,
value : value ,
line : S . tokline ,
col : S . tokcol ,
pos : S . tokpos ,
endline : S . line ,
endcol : S . col ,
endpos : S . pos ,
nlb : S . newline _before ,
file : filename
2012-05-27 11:09:01 +00:00
} ;
2015-11-11 20:15:25 +00:00
if ( /^(?:num|string|regexp)$/i . test ( type ) ) {
2015-11-12 10:18:25 +00:00
ret . raw = $TEXT . substring ( ret . pos , ret . endpos ) ;
2015-11-11 20:15:25 +00:00
}
2012-05-27 11:09:01 +00:00
if ( ! is _comment ) {
ret . comments _before = S . comments _before ;
2017-12-21 20:59:54 +00:00
ret . comments _after = S . comments _before = [ ] ;
2012-05-27 11:09:01 +00:00
}
S . newline _before = false ;
2018-06-13 10:50:22 +00:00
return new AST . Token ( ret ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function skip _whitespace ( ) {
2018-04-03 07:15:01 +00:00
while ( WHITESPACE _CHARS [ peek ( ) ] )
2012-05-27 11:09:01 +00:00
next ( ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function read _while ( pred ) {
2012-10-11 10:00:58 +00:00
var ret = "" , ch , i = 0 ;
while ( ( ch = peek ( ) ) && pred ( ch , i ++ ) )
2012-05-27 11:09:01 +00:00
ret += next ( ) ;
return ret ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function parse _error ( err ) {
2012-09-21 11:38:52 +00:00
js _error ( err , filename , S . tokline , S . tokcol , S . tokpos ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function read _num ( prefix ) {
var has _e = false , after _e = false , has _x = false , has _dot = prefix == "." ;
2018-06-06 09:50:56 +00:00
var num = read _while ( function ( ch , i ) {
2012-10-11 10:00:58 +00:00
var code = ch . charCodeAt ( 0 ) ;
switch ( code ) {
case 120 : case 88 : // xX
return has _x ? false : ( has _x = true ) ;
case 101 : case 69 : // eE
return has _x ? true : has _e ? false : ( has _e = after _e = true ) ;
case 45 : // -
return after _e || ( i == 0 && ! prefix ) ;
case 43 : // +
return after _e ;
case ( after _e = false , 46 ) : // .
return ( ! has _dot && ! has _x && ! has _e ) ? ( has _dot = true ) : false ;
2012-05-27 11:09:01 +00:00
}
2012-10-11 10:00:58 +00:00
return is _alphanumeric _char ( code ) ;
2012-05-27 11:09:01 +00:00
} ) ;
2012-10-11 10:00:58 +00:00
if ( prefix ) num = prefix + num ;
2016-07-21 01:19:24 +00:00
if ( RE _OCT _NUMBER . test ( num ) && next _token . has _directive ( "use strict" ) ) {
2017-02-26 19:40:54 +00:00
parse _error ( "Legacy octal literals are not allowed in strict mode" ) ;
2016-07-21 01:19:24 +00:00
}
2012-05-27 11:09:01 +00:00
var valid = parse _js _number ( num ) ;
if ( ! isNaN ( valid ) ) {
2015-11-11 20:15:25 +00:00
return token ( "num" , valid ) ;
2012-05-27 11:09:01 +00:00
} else {
2017-02-26 19:40:54 +00:00
parse _error ( "Invalid syntax: " + num ) ;
2012-05-27 11:09:01 +00:00
}
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function read _escaped _char ( in _string ) {
var ch = next ( true , in _string ) ;
2012-10-11 10:00:58 +00:00
switch ( ch . charCodeAt ( 0 ) ) {
case 110 : return "\n" ;
case 114 : return "\r" ;
case 116 : return "\t" ;
case 98 : return "\b" ;
case 118 : return "\u000b" ; // \v
case 102 : return "\f" ;
case 120 : return String . fromCharCode ( hex _bytes ( 2 ) ) ; // \x
case 117 : return String . fromCharCode ( hex _bytes ( 4 ) ) ; // \u
case 10 : return "" ; // newline
2015-04-23 09:08:19 +00:00
case 13 : // \r
if ( peek ( ) == "\n" ) { // DOS newline
next ( true , in _string ) ;
return "" ;
}
2012-05-27 11:09:01 +00:00
}
2016-06-23 14:53:48 +00:00
if ( ch >= "0" && ch <= "7" )
return read _octal _escape _sequence ( ch ) ;
2015-04-23 09:08:19 +00:00
return ch ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2016-06-23 14:53:48 +00:00
function read _octal _escape _sequence ( ch ) {
// Read
var p = peek ( ) ;
if ( p >= "0" && p <= "7" ) {
ch += next ( true ) ;
if ( ch [ 0 ] <= "3" && ( p = peek ( ) ) >= "0" && p <= "7" )
ch += next ( true ) ;
}
// Parse
if ( ch === "0" ) return "\0" ;
if ( ch . length > 0 && next _token . has _directive ( "use strict" ) )
2017-02-26 19:40:54 +00:00
parse _error ( "Legacy octal escape sequences are not allowed in strict mode" ) ;
2016-06-23 14:53:48 +00:00
return String . fromCharCode ( parseInt ( ch , 8 ) ) ;
}
2012-05-27 11:09:01 +00:00
function hex _bytes ( n ) {
var num = 0 ;
for ( ; n > 0 ; -- n ) {
var digit = parseInt ( next ( true ) , 16 ) ;
if ( isNaN ( digit ) )
2017-02-26 19:40:54 +00:00
parse _error ( "Invalid hex-character pattern in string" ) ;
2012-05-27 11:09:01 +00:00
num = ( num << 4 ) | digit ;
}
return num ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
var read _string = with _eof _error ( "Unterminated string constant" , function ( quote _char ) {
2012-10-11 10:00:58 +00:00
var quote = next ( ) , ret = "" ;
for ( ; ; ) {
2015-04-23 09:08:19 +00:00
var ch = next ( true , true ) ;
2016-06-23 14:53:48 +00:00
if ( ch == "\\" ) ch = read _escaped _char ( true ) ;
2018-04-03 07:15:01 +00:00
else if ( NEWLINE _CHARS [ ch ] ) parse _error ( "Unterminated string constant" ) ;
2012-10-11 10:00:58 +00:00
else if ( ch == quote ) break ;
ret += ch ;
}
2015-01-27 20:26:27 +00:00
var tok = token ( "string" , ret ) ;
tok . quote = quote _char ;
return tok ;
2012-10-11 10:00:58 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2013-09-06 06:54:30 +00:00
function skip _line _comment ( type ) {
var regex _allowed = S . regex _allowed ;
2016-04-25 04:42:18 +00:00
var i = find _eol ( ) , ret ;
2012-05-27 11:09:01 +00:00
if ( i == - 1 ) {
ret = S . text . substr ( S . pos ) ;
S . pos = S . text . length ;
} else {
ret = S . text . substring ( S . pos , i ) ;
S . pos = i ;
}
2014-08-08 11:15:43 +00:00
S . col = S . tokcol + ( S . pos - S . tokpos ) ;
2013-09-06 06:54:30 +00:00
S . comments _before . push ( token ( type , ret , true ) ) ;
S . regex _allowed = regex _allowed ;
2016-04-15 23:58:46 +00:00
return next _token ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
var skip _multiline _comment = with _eof _error ( "Unterminated multiline comment" , function ( ) {
2013-09-06 06:54:30 +00:00
var regex _allowed = S . regex _allowed ;
2012-10-11 10:00:58 +00:00
var i = find ( "*/" , true ) ;
2016-06-13 10:36:47 +00:00
var text = S . text . substring ( S . pos , i ) . replace ( /\r\n|\r|\u2028|\u2029/g , '\n' ) ;
2012-10-11 10:00:58 +00:00
// update stream position
2016-06-13 10:36:47 +00:00
forward ( text . length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2 ) ;
2013-09-06 06:54:30 +00:00
S . comments _before . push ( token ( "comment2" , text , true ) ) ;
S . regex _allowed = regex _allowed ;
2016-04-15 23:58:46 +00:00
return next _token ;
2012-10-11 10:00:58 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
function read _name ( ) {
var backslash = false , name = "" , ch , escaped = false , hex ;
while ( ( ch = peek ( ) ) != null ) {
if ( ! backslash ) {
if ( ch == "\\" ) escaped = backslash = true , next ( ) ;
else if ( is _identifier _char ( ch ) ) name += next ( ) ;
else break ;
}
else {
2017-02-26 19:40:54 +00:00
if ( ch != "u" ) parse _error ( "Expecting UnicodeEscapeSequence -- uXXXX" ) ;
2012-05-27 11:09:01 +00:00
ch = read _escaped _char ( ) ;
2017-02-26 19:40:54 +00:00
if ( ! is _identifier _char ( ch ) ) parse _error ( "Unicode char: " + ch . charCodeAt ( 0 ) + " is not valid in identifier" ) ;
2012-05-27 11:09:01 +00:00
name += ch ;
backslash = false ;
}
}
2018-04-03 07:15:01 +00:00
if ( KEYWORDS [ name ] && escaped ) {
2012-05-27 11:09:01 +00:00
hex = name . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) ;
name = "\\u" + "0000" . substr ( hex . length ) + hex + name . slice ( 1 ) ;
}
return name ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2017-05-17 12:10:50 +00:00
var read _regexp = with _eof _error ( "Unterminated regular expression" , function ( source ) {
2012-10-11 10:00:58 +00:00
var prev _backslash = false , ch , in _class = false ;
2018-04-03 07:15:01 +00:00
while ( ( ch = next ( true ) ) ) if ( NEWLINE _CHARS [ ch ] ) {
2017-02-26 19:40:54 +00:00
parse _error ( "Unexpected line terminator" ) ;
2016-06-13 10:36:47 +00:00
} else if ( prev _backslash ) {
2017-05-17 12:10:50 +00:00
source += "\\" + ch ;
2012-10-11 10:00:58 +00:00
prev _backslash = false ;
} else if ( ch == "[" ) {
in _class = true ;
2017-05-17 12:10:50 +00:00
source += ch ;
2012-10-11 10:00:58 +00:00
} else if ( ch == "]" && in _class ) {
in _class = false ;
2017-05-17 12:10:50 +00:00
source += ch ;
2012-10-11 10:00:58 +00:00
} else if ( ch == "/" && ! in _class ) {
break ;
} else if ( ch == "\\" ) {
prev _backslash = true ;
} else {
2017-05-17 12:10:50 +00:00
source += ch ;
2012-10-11 10:00:58 +00:00
}
var mods = read _name ( ) ;
2015-05-14 19:03:54 +00:00
try {
2017-05-17 12:10:50 +00:00
var regexp = new RegExp ( source , mods ) ;
regexp . raw _source = source ;
return token ( "regexp" , regexp ) ;
2015-05-14 19:03:54 +00:00
} catch ( e ) {
2017-05-17 12:10:50 +00:00
parse _error ( e . message ) ;
2015-05-14 19:03:54 +00:00
}
2012-10-11 10:00:58 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
function read _operator ( prefix ) {
function grow ( op ) {
if ( ! peek ( ) ) return op ;
var bigger = op + peek ( ) ;
2018-04-03 07:15:01 +00:00
if ( OPERATORS [ bigger ] ) {
2012-05-27 11:09:01 +00:00
next ( ) ;
return grow ( bigger ) ;
} else {
return op ;
}
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
return token ( "operator" , grow ( prefix || next ( ) ) ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function handle _slash ( ) {
next ( ) ;
switch ( peek ( ) ) {
case "/" :
2013-09-06 06:54:30 +00:00
next ( ) ;
return skip _line _comment ( "comment1" ) ;
2012-05-27 11:09:01 +00:00
case "*" :
2013-09-06 06:54:30 +00:00
next ( ) ;
return skip _multiline _comment ( ) ;
2012-05-27 11:09:01 +00:00
}
return S . regex _allowed ? read _regexp ( "" ) : read _operator ( "/" ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function handle _dot ( ) {
next ( ) ;
2012-10-11 10:00:58 +00:00
return is _digit ( peek ( ) . charCodeAt ( 0 ) )
2012-05-27 11:09:01 +00:00
? read _num ( "." )
: token ( "punc" , "." ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function read _word ( ) {
var word = read _name ( ) ;
2013-09-02 08:36:48 +00:00
if ( prev _was _dot ) return token ( "name" , word ) ;
2018-04-03 07:15:01 +00:00
return KEYWORDS _ATOM [ word ] ? token ( "atom" , word )
: ! KEYWORDS [ word ] ? token ( "name" , word )
: OPERATORS [ word ] ? token ( "operator" , word )
2012-05-27 11:09:01 +00:00
: token ( "keyword" , word ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function with _eof _error ( eof _error , cont ) {
2012-10-11 10:00:58 +00:00
return function ( x ) {
try {
return cont ( x ) ;
} catch ( ex ) {
if ( ex === EX _EOF ) parse _error ( eof _error ) ;
else throw ex ;
}
} ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function next _token ( force _regexp ) {
if ( force _regexp != null )
return read _regexp ( force _regexp ) ;
2017-03-05 04:16:02 +00:00
if ( shebang && S . pos == 0 && looking _at ( "#!" ) ) {
start _token ( ) ;
forward ( 2 ) ;
skip _line _comment ( "comment5" ) ;
}
2016-04-15 23:58:46 +00:00
for ( ; ; ) {
skip _whitespace ( ) ;
start _token ( ) ;
if ( html5 _comments ) {
if ( looking _at ( "<!--" ) ) {
forward ( 4 ) ;
skip _line _comment ( "comment3" ) ;
continue ;
}
if ( looking _at ( "-->" ) && S . newline _before ) {
forward ( 3 ) ;
skip _line _comment ( "comment4" ) ;
continue ;
}
2013-09-06 06:54:30 +00:00
}
2016-04-15 23:58:46 +00:00
var ch = peek ( ) ;
if ( ! ch ) return token ( "eof" ) ;
var code = ch . charCodeAt ( 0 ) ;
switch ( code ) {
case 34 : case 39 : return read _string ( ch ) ;
case 46 : return handle _dot ( ) ;
case 47 : {
var tok = handle _slash ( ) ;
if ( tok === next _token ) continue ;
return tok ;
}
2013-09-06 06:54:30 +00:00
}
2016-04-15 23:58:46 +00:00
if ( is _digit ( code ) ) return read _num ( ) ;
2018-04-03 07:15:01 +00:00
if ( PUNC _CHARS [ ch ] ) return token ( "punc" , next ( ) ) ;
if ( OPERATOR _CHARS [ ch ] ) return read _operator ( ) ;
2016-04-15 23:58:46 +00:00
if ( code == 92 || is _identifier _start ( code ) ) return read _word ( ) ;
break ;
2015-02-20 15:08:01 +00:00
}
2017-02-26 19:40:54 +00:00
parse _error ( "Unexpected character '" + ch + "'" ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
next _token . context = function ( nc ) {
if ( nc ) S = nc ;
return S ;
} ;
2016-05-20 08:25:35 +00:00
next _token . add _directive = function ( directive ) {
S . directive _stack [ S . directive _stack . length - 1 ] . push ( directive ) ;
if ( S . directives [ directive ] === undefined ) {
S . directives [ directive ] = 1 ;
} else {
S . directives [ directive ] ++ ;
}
}
next _token . push _directives _stack = function ( ) {
S . directive _stack . push ( [ ] ) ;
}
next _token . pop _directives _stack = function ( ) {
var directives = S . directive _stack [ S . directive _stack . length - 1 ] ;
for ( var i = 0 ; i < directives . length ; i ++ ) {
S . directives [ directives [ i ] ] -- ;
}
S . directive _stack . pop ( ) ;
}
next _token . has _directive = function ( directive ) {
2017-04-23 12:05:22 +00:00
return S . directives [ directive ] > 0 ;
2016-05-20 08:25:35 +00:00
}
2012-05-27 11:09:01 +00:00
return next _token ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
/* -----[ Parser (constants) ]----- */
2012-10-11 10:00:58 +00:00
var UNARY _PREFIX = makePredicate ( [
2012-05-27 11:09:01 +00:00
"typeof" ,
"void" ,
"delete" ,
"--" ,
"++" ,
"!" ,
"~" ,
"-" ,
"+"
] ) ;
2012-10-11 10:00:58 +00:00
var UNARY _POSTFIX = makePredicate ( [ "--" , "++" ] ) ;
2012-05-27 11:09:01 +00:00
2012-10-11 10:00:58 +00:00
var ASSIGNMENT = makePredicate ( [ "=" , "+=" , "-=" , "/=" , "*=" , "%=" , ">>=" , "<<=" , ">>>=" , "|=" , "^=" , "&=" ] ) ;
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
var PRECEDENCE = function ( a , ret ) {
2013-10-30 07:10:56 +00:00
for ( var i = 0 ; i < a . length ; ++ i ) {
2012-05-27 11:09:01 +00:00
var b = a [ i ] ;
for ( var j = 0 ; j < b . length ; ++ j ) {
2013-10-30 07:10:56 +00:00
ret [ b [ j ] ] = i + 1 ;
2012-05-27 11:09:01 +00:00
}
}
return ret ;
2018-06-06 09:50:56 +00:00
} ( [
[ "||" ] ,
[ "&&" ] ,
[ "|" ] ,
[ "^" ] ,
[ "&" ] ,
[ "==" , "===" , "!=" , "!==" ] ,
[ "<" , ">" , "<=" , ">=" , "in" , "instanceof" ] ,
[ ">>" , "<<" , ">>>" ] ,
[ "+" , "-" ] ,
[ "*" , "/" , "%" ]
] , { } ) ;
2012-05-27 11:09:01 +00:00
2017-06-03 06:00:59 +00:00
var ATOMIC _START _TOKEN = makePredicate ( [ "atom" , "num" , "string" , "regexp" , "name" ] ) ;
2012-05-27 11:09:01 +00:00
/* -----[ Parser ]----- */
2012-09-21 11:19:05 +00:00
function parse ( $TEXT , options ) {
options = defaults ( options , {
2017-03-31 08:41:04 +00:00
bare _returns : false ,
2013-09-06 06:54:30 +00:00
expression : false ,
2017-03-31 08:41:04 +00:00
filename : null ,
2013-09-06 06:54:30 +00:00
html5 _comments : true ,
2015-02-20 15:08:01 +00:00
shebang : true ,
2017-03-31 08:41:04 +00:00
strict : false ,
toplevel : null ,
2017-05-28 10:21:44 +00:00
} , true ) ;
2012-05-27 11:09:01 +00:00
var S = {
2013-09-06 06:54:30 +00:00
input : ( typeof $TEXT == "string"
? tokenizer ( $TEXT , options . filename ,
2015-02-20 15:08:01 +00:00
options . html5 _comments , options . shebang )
2013-09-06 06:54:30 +00:00
: $TEXT ) ,
2012-05-27 11:09:01 +00:00
token : null ,
prev : null ,
peeked : null ,
in _function : 0 ,
in _directives : true ,
in _loop : 0 ,
labels : [ ]
} ;
S . token = next ( ) ;
function is ( type , value ) {
return is _token ( S . token , type , value ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
function peek ( ) {
return S . peeked || ( S . peeked = S . input ( ) ) ;
}
2012-05-27 11:09:01 +00:00
function next ( ) {
S . prev = S . token ;
if ( S . peeked ) {
S . token = S . peeked ;
S . peeked = null ;
} else {
S . token = S . input ( ) ;
}
S . in _directives = S . in _directives && (
S . token . type == "string" || is ( "punc" , ";" )
) ;
return S . token ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function prev ( ) {
return S . prev ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function croak ( msg , line , col , pos ) {
var ctx = S . input . context ( ) ;
js _error ( msg ,
2012-09-21 11:38:52 +00:00
ctx . filename ,
2012-05-27 11:09:01 +00:00
line != null ? line : ctx . tokline ,
col != null ? col : ctx . tokcol ,
pos != null ? pos : ctx . tokpos ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function token _error ( token , msg ) {
croak ( msg , token . line , token . col ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function unexpected ( token ) {
if ( token == null )
token = S . token ;
2017-02-26 19:40:54 +00:00
token _error ( token , "Unexpected token: " + token . type + " (" + token . value + ")" ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function expect _token ( type , val ) {
if ( is ( type , val ) ) {
return next ( ) ;
}
2017-02-26 19:40:54 +00:00
token _error ( S . token , "Unexpected token " + S . token . type + " «" + S . token . value + "»" + ", expected " + type + " «" + val + "»" ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-06-06 09:50:56 +00:00
function expect ( punc ) {
return expect _token ( "punc" , punc ) ;
}
2012-05-27 11:09:01 +00:00
2017-12-25 17:38:01 +00:00
function has _newline _before ( token ) {
return token . nlb || ! all ( token . comments _before , function ( comment ) {
return ! comment . nlb ;
} ) ;
}
2012-05-27 11:09:01 +00:00
function can _insert _semicolon ( ) {
2017-12-25 17:38:01 +00:00
return ! options . strict
&& ( is ( "eof" ) || is ( "punc" , "}" ) || has _newline _before ( S . token ) ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2015-12-17 22:02:35 +00:00
function semicolon ( optional ) {
2012-05-27 11:09:01 +00:00
if ( is ( "punc" , ";" ) ) next ( ) ;
2015-12-17 22:02:35 +00:00
else if ( ! optional && ! can _insert _semicolon ( ) ) unexpected ( ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function parenthesised ( ) {
2012-08-17 12:59:42 +00:00
expect ( "(" ) ;
2012-10-11 10:00:58 +00:00
var exp = expression ( true ) ;
2012-08-17 12:59:42 +00:00
expect ( ")" ) ;
return exp ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function embed _tokens ( parser ) {
return function ( ) {
var start = S . token ;
2018-01-04 10:45:51 +00:00
var expr = parser . apply ( null , arguments ) ;
2012-05-27 11:09:01 +00:00
var end = prev ( ) ;
expr . start = start ;
expr . end = end ;
return expr ;
} ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-09-02 06:56:27 +00:00
function handle _regexp ( ) {
2012-05-27 11:09:01 +00:00
if ( is ( "operator" , "/" ) || is ( "operator" , "/=" ) ) {
S . peeked = null ;
S . token = S . input ( S . token . value . substr ( 1 ) ) ; // force regexp
}
2018-06-06 09:50:56 +00:00
}
2013-09-02 06:56:27 +00:00
2018-01-04 10:45:51 +00:00
var statement = embed _tokens ( function ( strict _defun ) {
2013-09-02 06:56:27 +00:00
handle _regexp ( ) ;
2012-05-27 11:09:01 +00:00
switch ( S . token . type ) {
case "string" :
2017-05-14 18:37:53 +00:00
if ( S . in _directives ) {
2017-05-15 15:02:55 +00:00
var token = peek ( ) ;
2017-05-14 18:37:53 +00:00
if ( S . token . raw . indexOf ( "\\" ) == - 1
2017-12-25 17:38:01 +00:00
&& ( is _token ( token , "punc" , ";" )
|| is _token ( token , "punc" , "}" )
|| has _newline _before ( token )
|| is _token ( token , "eof" ) ) ) {
2016-06-13 19:11:08 +00:00
S . input . add _directive ( S . token . value ) ;
2016-05-20 08:25:35 +00:00
} else {
S . in _directives = false ;
}
}
2012-05-27 11:09:01 +00:00
var dir = S . in _directives , stat = simple _statement ( ) ;
2018-06-13 10:50:22 +00:00
return dir ? new AST . Directive ( stat . body ) : stat ;
2012-05-27 11:09:01 +00:00
case "num" :
case "regexp" :
case "operator" :
case "atom" :
return simple _statement ( ) ;
case "name" :
return is _token ( peek ( ) , "punc" , ":" )
? labeled _statement ( )
: simple _statement ( ) ;
case "punc" :
switch ( S . token . value ) {
case "{" :
2018-06-13 10:50:22 +00:00
return new AST . BlockStatement ( {
2012-09-05 08:31:02 +00:00
start : S . token ,
body : block _ ( ) ,
end : prev ( )
} ) ;
2012-05-27 11:09:01 +00:00
case "[" :
case "(" :
return simple _statement ( ) ;
case ";" :
2016-06-13 19:11:08 +00:00
S . in _directives = false ;
2012-05-27 11:09:01 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . EmptyStatement ( ) ;
2012-05-27 11:09:01 +00:00
default :
unexpected ( ) ;
}
case "keyword" :
2017-05-15 15:02:55 +00:00
switch ( S . token . value ) {
2012-05-27 11:09:01 +00:00
case "break" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return break _cont ( AST . Break ) ;
2012-05-27 11:09:01 +00:00
case "continue" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return break _cont ( AST . Continue ) ;
2012-05-27 11:09:01 +00:00
case "debugger" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2012-05-27 11:09:01 +00:00
semicolon ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . Debugger ( ) ;
2012-05-27 11:09:01 +00:00
case "do" :
2017-05-15 15:02:55 +00:00
next ( ) ;
var body = in _loop ( statement ) ;
expect _token ( "keyword" , "while" ) ;
var condition = parenthesised ( ) ;
semicolon ( true ) ;
2018-06-13 10:50:22 +00:00
return new AST . Do ( {
2017-05-15 15:02:55 +00:00
body : body ,
condition : condition
2012-05-27 11:09:01 +00:00
} ) ;
case "while" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . While ( {
2012-05-27 11:09:01 +00:00
condition : parenthesised ( ) ,
body : in _loop ( statement )
} ) ;
case "for" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2012-05-27 11:09:01 +00:00
return for _ ( ) ;
case "function" :
2018-01-04 10:45:51 +00:00
if ( ! strict _defun && S . input . has _directive ( "use strict" ) ) {
croak ( "In strict mode code, functions can only be declared at top level or immediately within another function." ) ;
}
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return function _ ( AST . Defun ) ;
2012-05-27 11:09:01 +00:00
case "if" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2012-05-27 11:09:01 +00:00
return if _ ( ) ;
case "return" :
2014-10-20 15:12:13 +00:00
if ( S . in _function == 0 && ! options . bare _returns )
2017-02-26 19:40:54 +00:00
croak ( "'return' outside of function" ) ;
2017-05-15 15:02:55 +00:00
next ( ) ;
var value = null ;
if ( is ( "punc" , ";" ) ) {
next ( ) ;
} else if ( ! can _insert _semicolon ( ) ) {
value = expression ( true ) ;
semicolon ( ) ;
}
2018-06-13 10:50:22 +00:00
return new AST . Return ( {
2017-05-15 15:02:55 +00:00
value : value
2012-05-27 11:09:01 +00:00
} ) ;
case "switch" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . Switch ( {
2012-05-27 11:09:01 +00:00
expression : parenthesised ( ) ,
2012-10-11 10:00:58 +00:00
body : in _loop ( switch _body _ )
2012-05-27 11:09:01 +00:00
} ) ;
case "throw" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2017-12-25 17:38:01 +00:00
if ( has _newline _before ( S . token ) )
2017-02-26 19:40:54 +00:00
croak ( "Illegal newline after 'throw'" ) ;
2017-05-15 15:02:55 +00:00
var value = expression ( true ) ;
semicolon ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . Throw ( {
2017-05-15 15:02:55 +00:00
value : value
2012-05-27 11:09:01 +00:00
} ) ;
case "try" :
2017-05-15 15:02:55 +00:00
next ( ) ;
2012-05-27 11:09:01 +00:00
return try _ ( ) ;
case "var" :
2017-05-15 15:02:55 +00:00
next ( ) ;
var node = var _ ( ) ;
semicolon ( ) ;
return node ;
2012-05-27 11:09:01 +00:00
case "with" :
2016-06-12 16:58:20 +00:00
if ( S . input . has _directive ( "use strict" ) ) {
2017-02-26 19:40:54 +00:00
croak ( "Strict mode may not include a with statement" ) ;
2016-06-12 16:58:20 +00:00
}
2017-05-15 15:02:55 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . With ( {
2012-05-27 11:09:01 +00:00
expression : parenthesised ( ) ,
body : statement ( )
} ) ;
}
}
2017-03-10 02:49:41 +00:00
unexpected ( ) ;
2012-05-27 11:09:01 +00:00
} ) ;
function labeled _statement ( ) {
2018-06-13 10:50:22 +00:00
var label = as _symbol ( AST . Label ) ;
2018-03-22 19:43:52 +00:00
if ( ! all ( S . labels , function ( l ) {
return l . name != label . name ;
} ) ) {
2012-08-19 12:57:50 +00:00
// ECMA-262, 12.12: An ECMAScript program is considered
// syntactically incorrect if it contains a
// LabelledStatement that is enclosed by a
// LabelledStatement with the same Identifier as label.
2017-02-26 19:40:54 +00:00
croak ( "Label " + label . name + " defined twice" ) ;
2012-08-19 12:57:50 +00:00
}
2012-05-27 11:09:01 +00:00
expect ( ":" ) ;
S . labels . push ( label ) ;
2012-10-04 05:49:18 +00:00
var stat = statement ( ) ;
2012-05-27 11:09:01 +00:00
S . labels . pop ( ) ;
2018-06-13 10:50:22 +00:00
if ( ! ( stat instanceof AST . IterationStatement ) ) {
2013-09-02 16:36:16 +00:00
// check for `continue` that refers to this label.
// those should be reported as syntax errors.
// https://github.com/mishoo/UglifyJS2/issues/287
2018-06-06 09:50:56 +00:00
label . references . forEach ( function ( ref ) {
2018-06-13 10:50:22 +00:00
if ( ref instanceof AST . Continue ) {
2013-09-02 16:36:16 +00:00
ref = ref . label . start ;
2017-02-26 19:40:54 +00:00
croak ( "Continue label `" + label . name + "` refers to non-IterationStatement." ,
2013-09-02 16:36:16 +00:00
ref . line , ref . col , ref . pos ) ;
}
} ) ;
}
2018-06-13 10:50:22 +00:00
return new AST . LabeledStatement ( { body : stat , label : label } ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-10-11 10:00:58 +00:00
function simple _statement ( tmp ) {
2018-06-13 10:50:22 +00:00
return new AST . SimpleStatement ( { body : ( tmp = expression ( true ) , semicolon ( ) , tmp ) } ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function break _cont ( type ) {
2013-09-02 16:36:16 +00:00
var label = null , ldef ;
2012-05-27 11:09:01 +00:00
if ( ! can _insert _semicolon ( ) ) {
2018-06-13 10:50:22 +00:00
label = as _symbol ( AST . LabelRef , true ) ;
2012-05-27 11:09:01 +00:00
}
2012-08-19 12:57:50 +00:00
if ( label != null ) {
2018-06-06 09:50:56 +00:00
ldef = find _if ( function ( l ) {
return l . name == label . name ;
} , S . labels ) ;
if ( ! ldef ) croak ( "Undefined label " + label . name ) ;
2013-09-02 16:36:16 +00:00
label . thedef = ldef ;
2018-06-06 09:50:56 +00:00
} else if ( S . in _loop == 0 ) croak ( type . TYPE + " not inside a loop or switch" ) ;
2012-05-27 11:09:01 +00:00
semicolon ( ) ;
2013-09-02 16:36:16 +00:00
var stat = new type ( { label : label } ) ;
if ( ldef ) ldef . references . push ( stat ) ;
return stat ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function for _ ( ) {
expect ( "(" ) ;
var init = null ;
if ( ! is ( "punc" , ";" ) ) {
init = is ( "keyword" , "var" )
? ( next ( ) , var _ ( true ) )
: expression ( true , true ) ;
if ( is ( "operator" , "in" ) ) {
2018-06-13 10:50:22 +00:00
if ( init instanceof AST . Var ) {
2017-06-22 20:14:30 +00:00
if ( init . definitions . length > 1 )
croak ( "Only one variable declaration allowed in for..in loop" , init . start . line , init . start . col , init . start . pos ) ;
} else if ( ! is _assignable ( init ) ) {
croak ( "Invalid left-hand side in for..in loop" , init . start . line , init . start . col , init . start . pos ) ;
}
2012-05-27 11:09:01 +00:00
next ( ) ;
return for _in ( init ) ;
}
}
return regular _for ( init ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function regular _for ( init ) {
expect ( ";" ) ;
2012-10-11 10:00:58 +00:00
var test = is ( "punc" , ";" ) ? null : expression ( true ) ;
2012-05-27 11:09:01 +00:00
expect ( ";" ) ;
2012-10-11 10:00:58 +00:00
var step = is ( "punc" , ")" ) ? null : expression ( true ) ;
2012-05-27 11:09:01 +00:00
expect ( ")" ) ;
2018-06-13 10:50:22 +00:00
return new AST . For ( {
2012-05-27 11:09:01 +00:00
init : init ,
condition : test ,
step : step ,
body : in _loop ( statement )
} ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function for _in ( init ) {
2012-10-11 10:00:58 +00:00
var obj = expression ( true ) ;
2012-05-27 11:09:01 +00:00
expect ( ")" ) ;
2018-06-13 10:50:22 +00:00
return new AST . ForIn ( {
2012-05-27 11:09:01 +00:00
init : init ,
object : obj ,
body : in _loop ( statement )
} ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-10-30 09:50:22 +00:00
var function _ = function ( ctor ) {
2018-06-13 10:50:22 +00:00
var in _statement = ctor === AST . Defun ;
var name = is ( "name" ) ? as _symbol ( in _statement ? AST . SymbolDefun : AST . SymbolLambda ) : null ;
2012-05-27 11:09:01 +00:00
if ( in _statement && ! name )
unexpected ( ) ;
2018-06-13 10:50:22 +00:00
if ( name && ctor !== AST . Accessor && ! ( name instanceof AST . SymbolDeclaration ) )
2017-09-30 18:10:41 +00:00
unexpected ( prev ( ) ) ;
2012-05-27 11:09:01 +00:00
expect ( "(" ) ;
2017-04-23 12:05:22 +00:00
var argnames = [ ] ;
for ( var first = true ; ! is ( "punc" , ")" ) ; ) {
if ( first ) first = false ; else expect ( "," ) ;
2018-06-13 10:50:22 +00:00
argnames . push ( as _symbol ( AST . SymbolFunarg ) ) ;
2017-04-23 12:05:22 +00:00
}
next ( ) ;
var loop = S . in _loop ;
var labels = S . labels ;
++ S . in _function ;
S . in _directives = true ;
S . input . push _directives _stack ( ) ;
S . in _loop = 0 ;
S . labels = [ ] ;
2018-01-04 10:45:51 +00:00
var body = block _ ( true ) ;
2017-04-23 12:05:22 +00:00
if ( S . input . has _directive ( "use strict" ) ) {
if ( name ) strict _verify _symbol ( name ) ;
argnames . forEach ( strict _verify _symbol ) ;
}
S . input . pop _directives _stack ( ) ;
-- S . in _function ;
S . in _loop = loop ;
S . labels = labels ;
2012-05-27 11:09:01 +00:00
return new ctor ( {
name : name ,
2017-04-23 12:05:22 +00:00
argnames : argnames ,
body : body
2012-05-27 11:09:01 +00:00
} ) ;
} ;
function if _ ( ) {
var cond = parenthesised ( ) , body = statement ( ) , belse = null ;
if ( is ( "keyword" , "else" ) ) {
next ( ) ;
belse = statement ( ) ;
}
2018-06-13 10:50:22 +00:00
return new AST . If ( {
2012-05-27 11:09:01 +00:00
condition : cond ,
2012-09-03 09:11:44 +00:00
body : body ,
2012-05-27 11:09:01 +00:00
alternative : belse
} ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2018-01-04 10:45:51 +00:00
function block _ ( strict _defun ) {
2012-05-27 11:09:01 +00:00
expect ( "{" ) ;
var a = [ ] ;
while ( ! is ( "punc" , "}" ) ) {
if ( is ( "eof" ) ) unexpected ( ) ;
2018-01-04 10:45:51 +00:00
a . push ( statement ( strict _defun ) ) ;
2012-05-27 11:09:01 +00:00
}
next ( ) ;
2012-09-05 08:31:02 +00:00
return a ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-10-11 10:00:58 +00:00
function switch _body _ ( ) {
2012-05-27 11:09:01 +00:00
expect ( "{" ) ;
2012-10-11 10:00:58 +00:00
var a = [ ] , cur = null , branch = null , tmp ;
2012-05-27 11:09:01 +00:00
while ( ! is ( "punc" , "}" ) ) {
if ( is ( "eof" ) ) unexpected ( ) ;
if ( is ( "keyword" , "case" ) ) {
2012-05-27 14:25:31 +00:00
if ( branch ) branch . end = prev ( ) ;
2012-05-27 11:09:01 +00:00
cur = [ ] ;
2018-06-13 10:50:22 +00:00
branch = new AST . Case ( {
2012-10-11 10:00:58 +00:00
start : ( tmp = S . token , next ( ) , tmp ) ,
expression : expression ( true ) ,
2012-05-27 14:25:31 +00:00
body : cur
} ) ;
a . push ( branch ) ;
2012-05-27 11:09:01 +00:00
expect ( ":" ) ;
}
else if ( is ( "keyword" , "default" ) ) {
2012-05-27 14:25:31 +00:00
if ( branch ) branch . end = prev ( ) ;
2012-05-27 11:09:01 +00:00
cur = [ ] ;
2018-06-13 10:50:22 +00:00
branch = new AST . Default ( {
2012-10-11 10:00:58 +00:00
start : ( tmp = S . token , next ( ) , expect ( ":" ) , tmp ) ,
2012-05-27 14:25:31 +00:00
body : cur
2012-10-11 10:00:58 +00:00
} ) ;
2012-05-27 14:25:31 +00:00
a . push ( branch ) ;
2012-05-27 11:09:01 +00:00
}
else {
if ( ! cur ) unexpected ( ) ;
cur . push ( statement ( ) ) ;
}
}
2012-05-27 14:25:31 +00:00
if ( branch ) branch . end = prev ( ) ;
2012-05-27 11:09:01 +00:00
next ( ) ;
2012-10-03 12:52:01 +00:00
return a ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function try _ ( ) {
2012-09-05 08:31:02 +00:00
var body = block _ ( ) , bcatch = null , bfinally = null ;
2012-05-27 11:09:01 +00:00
if ( is ( "keyword" , "catch" ) ) {
2012-05-27 14:25:31 +00:00
var start = S . token ;
2012-05-27 11:09:01 +00:00
next ( ) ;
expect ( "(" ) ;
2018-06-13 10:50:22 +00:00
var name = as _symbol ( AST . SymbolCatch ) ;
2012-05-27 11:09:01 +00:00
expect ( ")" ) ;
2018-06-13 10:50:22 +00:00
bcatch = new AST . Catch ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
argname : name ,
2012-09-05 08:31:02 +00:00
body : block _ ( ) ,
2012-05-27 14:25:31 +00:00
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
}
if ( is ( "keyword" , "finally" ) ) {
2012-05-27 14:25:31 +00:00
var start = S . token ;
2012-05-27 11:09:01 +00:00
next ( ) ;
2018-06-13 10:50:22 +00:00
bfinally = new AST . Finally ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-09-05 08:31:02 +00:00
body : block _ ( ) ,
2012-05-27 14:25:31 +00:00
end : prev ( )
} ) ;
2012-05-27 11:09:01 +00:00
}
if ( ! bcatch && ! bfinally )
2017-02-26 19:40:54 +00:00
croak ( "Missing catch/finally blocks" ) ;
2018-06-13 10:50:22 +00:00
return new AST . Try ( {
2012-09-05 08:31:02 +00:00
body : body ,
2012-05-27 11:09:01 +00:00
bcatch : bcatch ,
bfinally : bfinally
} ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2017-05-12 06:57:41 +00:00
function vardefs ( no _in ) {
2012-05-27 11:09:01 +00:00
var a = [ ] ;
for ( ; ; ) {
2018-06-13 10:50:22 +00:00
a . push ( new AST . VarDef ( {
2012-05-27 11:09:01 +00:00
start : S . token ,
2018-06-13 10:50:22 +00:00
name : as _symbol ( AST . SymbolVar ) ,
2017-05-12 06:57:41 +00:00
value : is ( "operator" , "=" ) ? ( next ( ) , expression ( false , no _in ) ) : null ,
2012-05-27 11:09:01 +00:00
end : prev ( )
} ) ) ;
if ( ! is ( "punc" , "," ) )
break ;
next ( ) ;
}
return a ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var var _ = function ( no _in ) {
2018-06-13 10:50:22 +00:00
return new AST . Var ( {
2012-05-27 14:25:31 +00:00
start : prev ( ) ,
2017-05-12 06:57:41 +00:00
definitions : vardefs ( no _in ) ,
2012-05-27 14:25:31 +00:00
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
2015-08-06 19:27:46 +00:00
var new _ = function ( allow _calls ) {
2012-05-27 14:25:31 +00:00
var start = S . token ;
expect _token ( "operator" , "new" ) ;
2012-05-27 11:09:01 +00:00
var newexp = expr _atom ( false ) , args ;
if ( is ( "punc" , "(" ) ) {
next ( ) ;
args = expr _list ( ")" ) ;
} else {
args = [ ] ;
}
2018-06-13 10:50:22 +00:00
var call = new AST . New ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
expression : newexp ,
2012-05-27 14:25:31 +00:00
args : args ,
end : prev ( )
2018-01-02 20:48:07 +00:00
} ) ;
mark _pure ( call ) ;
return subscripts ( call , allow _calls ) ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
function as _atom _node ( ) {
var tok = S . token , ret ;
switch ( tok . type ) {
case "name" :
2018-06-13 10:50:22 +00:00
ret = _make _symbol ( AST . SymbolRef ) ;
2013-10-30 09:50:22 +00:00
break ;
2012-05-27 11:09:01 +00:00
case "num" :
2018-06-13 10:50:22 +00:00
ret = new AST . Number ( { start : tok , end : tok , value : tok . value } ) ;
2012-05-27 11:09:01 +00:00
break ;
case "string" :
2018-06-13 10:50:22 +00:00
ret = new AST . String ( {
2015-01-27 20:26:27 +00:00
start : tok ,
end : tok ,
value : tok . value ,
quote : tok . quote
} ) ;
2012-05-27 11:09:01 +00:00
break ;
case "regexp" :
2018-06-13 10:50:22 +00:00
ret = new AST . RegExp ( { start : tok , end : tok , value : tok . value } ) ;
2012-05-27 11:09:01 +00:00
break ;
case "atom" :
switch ( tok . value ) {
case "false" :
2018-06-13 10:50:22 +00:00
ret = new AST . False ( { start : tok , end : tok } ) ;
2012-05-27 11:09:01 +00:00
break ;
case "true" :
2018-06-13 10:50:22 +00:00
ret = new AST . True ( { start : tok , end : tok } ) ;
2012-05-27 11:09:01 +00:00
break ;
case "null" :
2018-06-13 10:50:22 +00:00
ret = new AST . Null ( { start : tok , end : tok } ) ;
2012-05-27 11:09:01 +00:00
break ;
}
break ;
}
next ( ) ;
return ret ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
var expr _atom = function ( allow _calls ) {
if ( is ( "operator" , "new" ) ) {
2015-08-06 19:27:46 +00:00
return new _ ( allow _calls ) ;
2012-05-27 11:09:01 +00:00
}
2012-05-27 14:25:31 +00:00
var start = S . token ;
2012-05-27 11:09:01 +00:00
if ( is ( "punc" ) ) {
2012-05-27 14:25:31 +00:00
switch ( start . value ) {
2012-05-27 11:09:01 +00:00
case "(" :
next ( ) ;
2012-10-11 10:00:58 +00:00
var ex = expression ( true ) ;
2017-12-24 04:38:45 +00:00
var len = start . comments _before . length ;
[ ] . unshift . apply ( ex . start . comments _before , start . comments _before ) ;
start . comments _before = ex . start . comments _before ;
start . comments _before _length = len ;
if ( len == 0 && start . comments _before . length > 0 ) {
var comment = start . comments _before [ 0 ] ;
if ( ! comment . nlb ) {
comment . nlb = start . nlb ;
start . nlb = false ;
}
}
2017-12-21 20:59:54 +00:00
start . comments _after = ex . start . comments _after ;
2012-05-27 14:25:31 +00:00
ex . start = start ;
expect ( ")" ) ;
2017-12-21 20:59:54 +00:00
var end = prev ( ) ;
end . comments _before = ex . end . comments _before ;
[ ] . push . apply ( ex . end . comments _after , end . comments _after ) ;
end . comments _after = ex . end . comments _after ;
ex . end = end ;
2018-06-13 10:50:22 +00:00
if ( ex instanceof AST . Call ) mark _pure ( ex ) ;
2012-05-27 14:25:31 +00:00
return subscripts ( ex , allow _calls ) ;
2012-05-27 11:09:01 +00:00
case "[" :
return subscripts ( array _ ( ) , allow _calls ) ;
case "{" :
return subscripts ( object _ ( ) , allow _calls ) ;
}
unexpected ( ) ;
}
if ( is ( "keyword" , "function" ) ) {
next ( ) ;
2018-06-13 10:50:22 +00:00
var func = function _ ( AST . Function ) ;
2012-05-27 11:09:01 +00:00
func . start = start ;
func . end = prev ( ) ;
return subscripts ( func , allow _calls ) ;
}
2018-04-03 07:15:01 +00:00
if ( ATOMIC _START _TOKEN [ S . token . type ] ) {
2012-05-27 11:09:01 +00:00
return subscripts ( as _atom _node ( ) , allow _calls ) ;
}
unexpected ( ) ;
} ;
function expr _list ( closing , allow _trailing _comma , allow _empty ) {
var first = true , a = [ ] ;
while ( ! is ( "punc" , closing ) ) {
if ( first ) first = false ; else expect ( "," ) ;
if ( allow _trailing _comma && is ( "punc" , closing ) ) break ;
if ( is ( "punc" , "," ) && allow _empty ) {
2018-06-13 10:50:22 +00:00
a . push ( new AST . Hole ( { start : S . token , end : S . token } ) ) ;
2012-05-27 11:09:01 +00:00
} else {
a . push ( expression ( false ) ) ;
}
}
next ( ) ;
return a ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var array _ = embed _tokens ( function ( ) {
expect ( "[" ) ;
2018-06-13 10:50:22 +00:00
return new AST . Array ( {
2012-09-21 11:19:05 +00:00
elements : expr _list ( "]" , ! options . strict , true )
2012-05-27 11:09:01 +00:00
} ) ;
2012-05-27 14:25:31 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2017-02-20 09:14:53 +00:00
var create _accessor = embed _tokens ( function ( ) {
2018-06-13 10:50:22 +00:00
return function _ ( AST . Accessor ) ;
2017-02-20 09:14:53 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
var object _ = embed _tokens ( function ( ) {
2012-05-27 14:25:31 +00:00
expect ( "{" ) ;
2012-05-27 11:09:01 +00:00
var first = true , a = [ ] ;
while ( ! is ( "punc" , "}" ) ) {
if ( first ) first = false ; else expect ( "," ) ;
2012-09-21 11:19:05 +00:00
if ( ! options . strict && is ( "punc" , "}" ) )
2012-05-27 11:09:01 +00:00
// allow trailing comma
break ;
var start = S . token ;
var type = start . type ;
var name = as _property _name ( ) ;
if ( type == "name" && ! is ( "punc" , ":" ) ) {
2018-06-13 10:50:22 +00:00
var key = new AST . SymbolAccessor ( {
2017-05-13 18:10:34 +00:00
start : S . token ,
2018-01-18 16:36:30 +00:00
name : "" + as _property _name ( ) ,
2017-05-13 18:10:34 +00:00
end : prev ( )
} ) ;
2012-08-17 12:59:42 +00:00
if ( name == "get" ) {
2018-06-13 10:50:22 +00:00
a . push ( new AST . ObjectGetter ( {
2012-05-27 11:09:01 +00:00
start : start ,
2017-05-13 18:10:34 +00:00
key : key ,
2017-02-20 09:14:53 +00:00
value : create _accessor ( ) ,
2012-05-27 11:09:01 +00:00
end : prev ( )
} ) ) ;
continue ;
}
2012-08-17 12:59:42 +00:00
if ( name == "set" ) {
2018-06-13 10:50:22 +00:00
a . push ( new AST . ObjectSetter ( {
2012-05-27 11:09:01 +00:00
start : start ,
2017-05-13 18:10:34 +00:00
key : key ,
2017-02-20 09:14:53 +00:00
value : create _accessor ( ) ,
2012-05-27 11:09:01 +00:00
end : prev ( )
} ) ) ;
continue ;
}
}
expect ( ":" ) ;
2018-06-13 10:50:22 +00:00
a . push ( new AST . ObjectKeyVal ( {
2012-05-27 11:09:01 +00:00
start : start ,
2015-01-27 20:26:27 +00:00
quote : start . quote ,
2018-01-18 16:36:30 +00:00
key : "" + name ,
2012-05-27 11:09:01 +00:00
value : expression ( false ) ,
end : prev ( )
} ) ) ;
}
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . Object ( { properties : a } ) ;
2012-05-27 11:09:01 +00:00
} ) ;
function as _property _name ( ) {
2012-10-13 09:42:01 +00:00
var tmp = S . token ;
switch ( tmp . type ) {
2017-04-18 20:27:13 +00:00
case "operator" :
2018-04-03 07:15:01 +00:00
if ( ! KEYWORDS [ tmp . value ] ) unexpected ( ) ;
2012-05-27 11:09:01 +00:00
case "num" :
case "string" :
2012-05-27 14:25:31 +00:00
case "name" :
case "keyword" :
case "atom" :
2017-04-18 20:27:13 +00:00
next ( ) ;
2012-10-13 09:42:01 +00:00
return tmp . value ;
2012-05-27 14:25:31 +00:00
default :
unexpected ( ) ;
2012-05-27 11:09:01 +00:00
}
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
function as _name ( ) {
2012-10-13 09:42:01 +00:00
var tmp = S . token ;
2017-04-18 20:27:13 +00:00
if ( tmp . type != "name" ) unexpected ( ) ;
2012-10-13 09:42:01 +00:00
next ( ) ;
2017-04-18 20:27:13 +00:00
return tmp . value ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-10-30 09:50:22 +00:00
function _make _symbol ( type ) {
var name = S . token . value ;
2018-06-13 10:50:22 +00:00
return new ( name == "this" ? AST . This : type ) ( {
2013-10-30 09:50:22 +00:00
name : String ( name ) ,
start : S . token ,
end : S . token
} ) ;
2018-06-06 09:50:56 +00:00
}
2013-10-30 09:50:22 +00:00
2017-04-23 12:05:22 +00:00
function strict _verify _symbol ( sym ) {
if ( sym . name == "arguments" || sym . name == "eval" )
croak ( "Unexpected " + sym . name + " in strict mode" , sym . start . line , sym . start . col , sym . start . pos ) ;
}
2012-08-19 12:57:50 +00:00
function as _symbol ( type , noerror ) {
if ( ! is ( "name" ) ) {
2017-02-26 19:40:54 +00:00
if ( ! noerror ) croak ( "Name expected" ) ;
2012-08-19 12:57:50 +00:00
return null ;
}
2013-10-30 09:50:22 +00:00
var sym = _make _symbol ( type ) ;
2018-06-13 10:50:22 +00:00
if ( S . input . has _directive ( "use strict" ) && sym instanceof AST . SymbolDeclaration ) {
2017-04-23 12:05:22 +00:00
strict _verify _symbol ( sym ) ;
}
2012-05-27 11:09:01 +00:00
next ( ) ;
return sym ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2017-12-24 04:38:45 +00:00
function mark _pure ( call ) {
var start = call . start ;
var comments = start . comments _before ;
var i = HOP ( start , "comments_before_length" ) ? start . comments _before _length : comments . length ;
while ( -- i >= 0 ) {
var comment = comments [ i ] ;
if ( /[@#]__PURE__/ . test ( comment . value ) ) {
call . pure = comment ;
break ;
}
}
}
2012-05-27 14:25:31 +00:00
var subscripts = function ( expr , allow _calls ) {
var start = expr . start ;
2012-05-27 11:09:01 +00:00
if ( is ( "punc" , "." ) ) {
next ( ) ;
2018-06-13 10:50:22 +00:00
return subscripts ( new AST . Dot ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
expression : expr ,
2012-05-27 14:25:31 +00:00
property : as _name ( ) ,
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) , allow _calls ) ;
}
if ( is ( "punc" , "[" ) ) {
next ( ) ;
2012-10-11 10:00:58 +00:00
var prop = expression ( true ) ;
2012-05-27 14:25:31 +00:00
expect ( "]" ) ;
2018-06-13 10:50:22 +00:00
return subscripts ( new AST . Sub ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
expression : expr ,
2012-05-27 14:25:31 +00:00
property : prop ,
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) , allow _calls ) ;
}
if ( allow _calls && is ( "punc" , "(" ) ) {
next ( ) ;
2018-06-13 10:50:22 +00:00
var call = new AST . Call ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
expression : expr ,
2012-05-27 14:25:31 +00:00
args : expr _list ( ")" ) ,
end : prev ( )
2017-12-24 04:38:45 +00:00
} ) ;
mark _pure ( call ) ;
return subscripts ( call , true ) ;
2012-05-27 11:09:01 +00:00
}
return expr ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var maybe _unary = function ( allow _calls ) {
2012-10-13 09:42:01 +00:00
var start = S . token ;
2018-04-03 07:15:01 +00:00
if ( is ( "operator" ) && UNARY _PREFIX [ start . value ] ) {
2012-10-13 09:42:01 +00:00
next ( ) ;
2013-09-02 06:56:27 +00:00
handle _regexp ( ) ;
2018-06-13 10:50:22 +00:00
var ex = make _unary ( AST . UnaryPrefix , start , maybe _unary ( allow _calls ) ) ;
2012-05-27 14:25:31 +00:00
ex . start = start ;
ex . end = prev ( ) ;
return ex ;
2012-05-27 11:09:01 +00:00
}
var val = expr _atom ( allow _calls ) ;
2018-04-03 07:15:01 +00:00
while ( is ( "operator" ) && UNARY _POSTFIX [ S . token . value ] && ! has _newline _before ( S . token ) ) {
2018-06-13 10:50:22 +00:00
val = make _unary ( AST . UnaryPostfix , S . token , val ) ;
2012-05-27 14:25:31 +00:00
val . start = start ;
val . end = S . token ;
2012-05-27 11:09:01 +00:00
next ( ) ;
}
return val ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
2017-04-18 20:27:13 +00:00
function make _unary ( ctor , token , expr ) {
var op = token . value ;
2017-04-23 12:05:22 +00:00
switch ( op ) {
case "++" :
case "--" :
if ( ! is _assignable ( expr ) )
croak ( "Invalid use of " + op + " operator" , token . line , token . col , token . pos ) ;
break ;
case "delete" :
2018-06-13 10:50:22 +00:00
if ( expr instanceof AST . SymbolRef && S . input . has _directive ( "use strict" ) )
2017-04-23 12:05:22 +00:00
croak ( "Calling delete on expression not allowed in strict mode" , expr . start . line , expr . start . col , expr . start . pos ) ;
break ;
}
2012-05-27 11:09:01 +00:00
return new ctor ( { operator : op , expression : expr } ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var expr _op = function ( left , min _prec , no _in ) {
2012-05-27 11:09:01 +00:00
var op = is ( "operator" ) ? S . token . value : null ;
if ( op == "in" && no _in ) op = null ;
var prec = op != null ? PRECEDENCE [ op ] : null ;
if ( prec != null && prec > min _prec ) {
next ( ) ;
var right = expr _op ( maybe _unary ( true ) , prec , no _in ) ;
2018-06-13 10:50:22 +00:00
return expr _op ( new AST . Binary ( {
2012-05-27 14:25:31 +00:00
start : left . start ,
2012-05-27 11:09:01 +00:00
left : left ,
operator : op ,
2012-05-27 14:25:31 +00:00
right : right ,
end : right . end
2012-05-27 11:09:01 +00:00
} ) , min _prec , no _in ) ;
}
return left ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
function expr _ops ( no _in ) {
return expr _op ( maybe _unary ( true ) , 0 , no _in ) ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var maybe _conditional = function ( no _in ) {
var start = S . token ;
2012-05-27 11:09:01 +00:00
var expr = expr _ops ( no _in ) ;
if ( is ( "operator" , "?" ) ) {
next ( ) ;
var yes = expression ( false ) ;
expect ( ":" ) ;
2018-06-13 10:50:22 +00:00
return new AST . Conditional ( {
2012-05-27 14:25:31 +00:00
start : start ,
condition : expr ,
consequent : yes ,
alternative : expression ( false , no _in ) ,
2014-01-21 08:38:59 +00:00
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
}
return expr ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
function is _assignable ( expr ) {
2018-06-13 10:50:22 +00:00
return expr instanceof AST . PropAccess || expr instanceof AST . SymbolRef ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var maybe _assign = function ( no _in ) {
var start = S . token ;
2012-05-27 11:09:01 +00:00
var left = maybe _conditional ( no _in ) , val = S . token . value ;
2018-04-03 07:15:01 +00:00
if ( is ( "operator" ) && ASSIGNMENT [ val ] ) {
2012-05-27 11:09:01 +00:00
if ( is _assignable ( left ) ) {
next ( ) ;
2018-06-13 10:50:22 +00:00
return new AST . Assign ( {
2012-05-27 14:25:31 +00:00
start : start ,
2012-05-27 11:09:01 +00:00
left : left ,
2012-10-11 10:00:58 +00:00
operator : val ,
2012-05-27 14:25:31 +00:00
right : maybe _assign ( no _in ) ,
2013-01-26 12:24:54 +00:00
end : prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
}
2017-02-26 19:40:54 +00:00
croak ( "Invalid assignment" ) ;
2012-05-27 11:09:01 +00:00
}
return left ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var expression = function ( commas , no _in ) {
var start = S . token ;
2017-04-12 13:56:27 +00:00
var exprs = [ ] ;
while ( true ) {
exprs . push ( maybe _assign ( no _in ) ) ;
if ( ! commas || ! is ( "punc" , "," ) ) break ;
2012-05-27 11:09:01 +00:00
next ( ) ;
2017-04-12 13:56:27 +00:00
commas = true ;
2012-05-27 11:09:01 +00:00
}
2018-06-13 10:50:22 +00:00
return exprs . length == 1 ? exprs [ 0 ] : new AST . Sequence ( {
2017-04-12 13:56:27 +00:00
start : start ,
expressions : exprs ,
end : peek ( )
} ) ;
2012-05-27 14:25:31 +00:00
} ;
2012-05-27 11:09:01 +00:00
function in _loop ( cont ) {
++ S . in _loop ;
var ret = cont ( ) ;
-- S . in _loop ;
return ret ;
2018-06-06 09:50:56 +00:00
}
2012-05-27 11:09:01 +00:00
2013-05-15 10:27:23 +00:00
if ( options . expression ) {
return expression ( true ) ;
}
2018-06-06 09:50:56 +00:00
return function ( ) {
2012-09-21 11:19:05 +00:00
var start = S . token ;
var body = [ ] ;
2016-05-20 08:25:35 +00:00
S . input . push _directives _stack ( ) ;
2012-09-21 11:19:05 +00:00
while ( ! is ( "eof" ) )
2018-01-04 10:45:51 +00:00
body . push ( statement ( true ) ) ;
2016-05-20 08:25:35 +00:00
S . input . pop _directives _stack ( ) ;
2012-09-21 11:19:05 +00:00
var end = prev ( ) ;
var toplevel = options . toplevel ;
if ( toplevel ) {
toplevel . body = toplevel . body . concat ( body ) ;
toplevel . end = end ;
} else {
2018-06-13 10:50:22 +00:00
toplevel = new AST . Toplevel ( { start : start , body : body , end : end } ) ;
2012-09-21 11:19:05 +00:00
}
return toplevel ;
2018-06-06 09:50:56 +00:00
} ( ) ;
}
2018-06-09 17:40:40 +00:00
merge ( exports , {
KEYWORDS : KEYWORDS ,
KEYWORDS _ATOM : KEYWORDS _ATOM ,
RESERVED _WORDS : RESERVED _WORDS ,
KEYWORDS _BEFORE _EXPRESSION : KEYWORDS _BEFORE _EXPRESSION ,
OPERATOR _CHARS : OPERATOR _CHARS ,
RE _HEX _NUMBER : RE _HEX _NUMBER ,
RE _OCT _NUMBER : RE _OCT _NUMBER ,
OPERATORS : OPERATORS ,
WHITESPACE _CHARS : WHITESPACE _CHARS ,
NEWLINE _CHARS : NEWLINE _CHARS ,
PUNC _BEFORE _EXPRESSION : PUNC _BEFORE _EXPRESSION ,
PUNC _CHARS : PUNC _CHARS ,
UNICODE : UNICODE ,
is _letter : is _letter ,
is _surrogate _pair _head : is _surrogate _pair _head ,
is _surrogate _pair _tail : is _surrogate _pair _tail ,
is _digit : is _digit ,
is _alphanumeric _char : is _alphanumeric _char ,
is _unicode _digit : is _unicode _digit ,
is _unicode _combining _mark : is _unicode _combining _mark ,
is _unicode _connector _punctuation : is _unicode _connector _punctuation ,
is _identifier : is _identifier ,
is _identifier _start : is _identifier _start ,
is _identifier _char : is _identifier _char ,
is _identifier _string : is _identifier _string ,
parse _js _number : parse _js _number ,
JS _Parse _Error : JS _Parse _Error ,
js _error : js _error ,
is _token : is _token ,
EX _EOF : EX _EOF ,
tokenizer : tokenizer ,
UNARY _PREFIX : UNARY _PREFIX ,
UNARY _POSTFIX : UNARY _POSTFIX ,
ASSIGNMENT : ASSIGNMENT ,
PRECEDENCE : PRECEDENCE ,
ATOMIC _START _TOKEN : ATOMIC _START _TOKEN ,
parse : parse ,
} ) ;