2012-08-22 18:28:59 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
A JavaScript tokenizer / parser / beautifier / compressor .
https : //github.com/mishoo/UglifyJS2
2014-04-15 12:57:14 +00:00
Edited for parsing ColaScript .
2012-08-22 18:28:59 +00:00
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ( 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 >
2014-04-15 12:57:14 +00:00
Copyright 2014 ( c ) TrigenSoftware < danon0404 @ 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" ;
2014-04-22 13:33:43 +00:00
! this . Cola && ( this . Cola = { } ) ;
2012-10-02 09:45:31 +00:00
2014-04-16 16:43:40 +00:00
Cola . 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' ;
2014-05-19 09:58:17 +00:00
Cola . cKEYWORDS = Cola . KEYWORDS . replace ( ' void' , '' ) + ' when clone isset is isnt class singleton injector' ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . KEYWORDS _ATOM = 'false null true' ;
Cola . cKEYWORDS _ATOM = Cola . KEYWORDS _ATOM + ' on yes off no' ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . RESERVED _WORDS = 'abstract boolean byte char double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield' ;
Cola . cRESERVED _WORDS = Cola . RESERVED _WORDS . replace ( ' class' , '' ) + " " + Cola . cKEYWORDS _ATOM + " " + Cola . cKEYWORDS ;
Cola . RESERVED _WORDS += " " + Cola . KEYWORDS _ATOM + " " + Cola . KEYWORDS ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . KEYWORDS _BEFORE _EXPRESSION = 'return new delete throw else case' ;
2014-05-19 09:58:17 +00:00
Cola . cKEYWORDS _BEFORE _EXPRESSION = Cola . KEYWORDS _BEFORE _EXPRESSION += ' when' ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . KEYWORDS = Cola . makePredicate ( Cola . KEYWORDS ) ;
Cola . cKEYWORDS = Cola . makePredicate ( Cola . cKEYWORDS ) ;
Cola . RESERVED _WORDS = Cola . makePredicate ( Cola . RESERVED _WORDS ) ;
Cola . cRESERVED _WORDS = Cola . makePredicate ( Cola . cRESERVED _WORDS ) ;
Cola . KEYWORDS _ATOM = Cola . makePredicate ( Cola . KEYWORDS _ATOM ) ;
Cola . cKEYWORDS _ATOM = Cola . makePredicate ( Cola . cKEYWORDS _ATOM ) ;
Cola . KEYWORDS _BEFORE _EXPRESSION = Cola . makePredicate ( Cola . KEYWORDS _BEFORE _EXPRESSION ) ;
2014-05-19 09:58:17 +00:00
Cola . cKEYWORDS _BEFORE _EXPRESSION = Cola . makePredicate ( Cola . cKEYWORDS _BEFORE _EXPRESSION ) ;
2014-04-16 16:43:40 +00:00
Cola . OPERATOR _CHARS = Cola . makePredicate ( Cola . characters ( "+-*&%=<>!?|~^" ) ) ;
Cola . RE _HEX _NUMBER = /^0x[0-9a-f]+$/i ;
Cola . RE _OCT _NUMBER = /^0[0-7]+$/ ;
Cola . RE _DEC _NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i ;
Cola . OPERATORS = [
2012-05-27 11:09:01 +00:00
"in" ,
"instanceof" ,
"typeof" ,
"new" ,
2014-04-16 16:43:40 +00:00
//"void",
2012-05-27 11:09:01 +00:00
"delete" ,
"++" ,
"--" ,
"+" ,
"-" ,
"!" ,
"~" ,
"&" ,
"|" ,
"^" ,
"*" ,
"/" ,
"%" ,
">>" ,
"<<" ,
">>>" ,
"<" ,
">" ,
"<=" ,
">=" ,
"==" ,
"===" ,
"!=" ,
"!==" ,
"?" ,
"=" ,
"+=" ,
"-=" ,
"/=" ,
"*=" ,
"%=" ,
">>=" ,
"<<=" ,
">>>=" ,
"|=" ,
"^=" ,
"&=" ,
"&&" ,
2014-04-14 03:35:26 +00:00
"||" ,
// ColaScript
2014-04-20 07:31:03 +00:00
"clone" ,
2014-04-18 18:27:47 +00:00
"isset" ,
2014-04-14 03:35:26 +00:00
"is" ,
"isnt" ,
"**" ,
"%%" ,
2014-04-18 18:27:47 +00:00
"?=" ,
"??"
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
] ;
Cola . cOPERATORS = Cola . makePredicate ( Cola . OPERATORS ) ;
2014-04-20 07:31:03 +00:00
Cola . OPERATORS = Cola . OPERATORS . slice ( 0 , Cola . OPERATORS . length - 8 ) ;
2014-04-16 16:43:40 +00:00
Cola . OPERATORS . push ( 'void' ) ;
Cola . OPERATORS = Cola . makePredicate ( Cola . OPERATORS ) ;
2012-05-27 11:09:01 +00:00
2014-05-16 12:27:51 +00:00
Cola . COMPARISON = Cola . makePredicate ( "< > <= >= == === != !==" ) ;
2014-04-16 16:43:40 +00:00
Cola . WHITESPACE _CHARS = Cola . makePredicate ( Cola . characters ( " \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000" ) ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . PUNC _BEFORE _EXPRESSION = Cola . makePredicate ( Cola . characters ( "[{(,.;:" ) ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . PUNC _CHARS = Cola . makePredicate ( Cola . characters ( "[]{}(),;:" ) ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . REGEXP _MODIFIERS = Cola . makePredicate ( Cola . characters ( "gmsiy" ) ) ;
2012-05-27 11:09:01 +00:00
/* -----[ Tokenizer ]----- */
// regexps adapted from http://xregexp.com/plugins/#unicode
2014-04-16 16:43:40 +00:00
Cola . UNICODE = {
2012-05-27 11:09:01 +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 \ \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 - \ \
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]" )
} ;
2014-04-16 16:43:40 +00:00
Cola . is _letter = function ( code ) {
2012-10-11 10:00:58 +00:00
return ( code >= 97 && code <= 122 )
|| ( code >= 65 && code <= 90 )
2014-04-16 16:43:40 +00:00
|| ( code >= 0xaa && Cola . UNICODE . letter . test ( String . fromCharCode ( code ) ) ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _digit = function ( code ) {
2012-10-11 10:00:58 +00:00
return code >= 48 && code <= 57 ; //XXX: find out if "UnicodeDigit" means something else than 0..9
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _alphanumeric _char = function ( code ) {
return Cola . is _digit ( code ) || Cola . is _letter ( code ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _unicode _combining _mark = function ( ch ) {
return Cola . UNICODE . non _spacing _mark . test ( ch ) || Cola . UNICODE . space _combining _mark . test ( ch ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _unicode _connector _punctuation = function ( ch ) {
return Cola . UNICODE . connector _punctuation . test ( ch ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-17 10:10:18 +00:00
Cola . is _identifier = function ( name , is _js ) {
return ( is _js && ! Cola . RESERVED _WORDS ( name ) || ! is _js && ! Cola . cRESERVED _WORDS ( name ) ) && /^[a-z_$][a-z0-9_$]*$/i . test ( name ) ;
2012-08-17 12:59:42 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _identifier _start = function ( code ) {
return code == 36 || code == 95 || Cola . is _letter ( code ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _identifier _char = function ( ch ) {
2012-10-11 10:00:58 +00:00
var code = ch . charCodeAt ( 0 ) ;
2014-04-16 16:43:40 +00:00
return Cola . is _identifier _start ( code )
|| Cola . is _digit ( code )
2012-10-11 10:00:58 +00:00
|| code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
2014-04-16 16:43:40 +00:00
|| Cola . is _unicode _combining _mark ( ch )
|| Cola . is _unicode _connector _punctuation ( ch )
2012-05-27 11:09:01 +00:00
;
} ;
2014-04-16 16:43:40 +00:00
Cola . is _identifier _string = function ( str ) {
2013-05-08 19:37:48 +00:00
var i = str . length ;
if ( i == 0 ) return false ;
2014-04-16 16:43:40 +00:00
if ( ! Cola . is _identifier _start ( str . charCodeAt ( 0 ) ) ) return false ;
2013-05-08 19:37:48 +00:00
while ( -- i >= 0 ) {
2014-04-16 16:43:40 +00:00
if ( ! Cola . is _identifier _char ( str . charAt ( i ) ) )
2013-05-05 18:45:41 +00:00
return false ;
}
return true ;
} ;
2014-04-16 16:43:40 +00:00
Cola . parse _js _number = function ( num ) {
if ( Cola . RE _HEX _NUMBER . test ( num ) ) {
2012-05-27 11:09:01 +00:00
return parseInt ( num . substr ( 2 ) , 16 ) ;
2014-04-16 16:43:40 +00:00
} else if ( Cola . RE _OCT _NUMBER . test ( num ) ) {
2012-05-27 11:09:01 +00:00
return parseInt ( num . substr ( 1 ) , 8 ) ;
2014-04-16 16:43:40 +00:00
} else if ( Cola . RE _DEC _NUMBER . test ( num ) ) {
2012-05-27 11:09:01 +00:00
return parseFloat ( num ) ;
}
} ;
2014-04-16 16:43:40 +00:00
Cola . JS _Parse _Error = function ( message , line , col , pos ) {
2012-05-27 11:09:01 +00:00
this . message = message ;
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 ;
2012-05-27 11:09:01 +00:00
this . stack = new Error ( ) . stack ;
} ;
2014-04-16 16:43:40 +00:00
Cola . JS _Parse _Error . prototype . toString = function ( ) {
2012-05-27 11:09:01 +00:00
return this . message + " (line: " + this . line + ", col: " + this . col + ", pos: " + this . pos + ")" + "\n\n" + this . stack ;
} ;
2014-04-16 16:43:40 +00:00
Cola . js _error = function ( message , filename , line , col , pos ) {
throw new Cola . JS _Parse _Error ( message , line , col , pos ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
Cola . is _token = function ( token , type , val ) {
2012-05-27 11:09:01 +00:00
return token . type == type && ( val == null || token . value == val ) ;
} ;
2014-04-16 16:43:40 +00:00
Cola . EX _EOF = { } ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer = function ( $TEXT , filename , is _js , html5 _comments ) {
2014-04-16 16:43:40 +00:00
this . S = {
2012-09-25 12:30:59 +00:00
text : $TEXT . replace ( /\r\n?|[\n\u2028\u2029]/g , "\n" ) . replace ( /\uFEFF/g , '' ) ,
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 ,
comments _before : [ ]
} ;
2014-05-16 12:27:51 +00:00
this . dumps = [ ] ;
this . dumpi = - 1 ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
if ( ! is _js ) this . S . string = {
at : [ new Cola . Tokenizer . StringInfo ( ) ] ,
level : 0
} ;
2014-04-17 10:10:18 +00:00
if ( is _js ) {
this . KEYWORDS = Cola . KEYWORDS ;
this . KEYWORDS _ATOM = Cola . KEYWORDS _ATOM ;
this . OPERATORS = Cola . OPERATORS ;
2014-04-18 18:27:47 +00:00
this . UNARY _POSTFIX = Cola . UNARY _POSTFIX ;
2014-05-19 09:58:17 +00:00
this . KEYWORDS _BEFORE _EXPRESSION = Cola . KEYWORDS _BEFORE _EXPRESSION ;
2014-04-17 10:10:18 +00:00
} else {
this . KEYWORDS = Cola . cKEYWORDS ;
this . KEYWORDS _ATOM = Cola . cKEYWORDS _ATOM ;
this . OPERATORS = Cola . cOPERATORS ;
2014-04-18 18:27:47 +00:00
this . UNARY _POSTFIX = Cola . cUNARY _POSTFIX ;
2014-05-19 09:58:17 +00:00
this . KEYWORDS _BEFORE _EXPRESSION = Cola . cKEYWORDS _BEFORE _EXPRESSION ;
2014-04-17 10:10:18 +00:00
}
2014-04-16 18:39:27 +00:00
this . is _js = ! ! is _js ;
2014-04-16 16:43:40 +00:00
this . html5 _comments = html5 _comments ;
this . prev _was _dot = false ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . StringInfo = function ( ) {
2014-04-16 16:43:40 +00:00
this . quote = '' ;
this . inside = false ;
this . after _at = false ;
this . inside _at = false ;
this . inside _braces = false ;
this . balance = 0 ;
} ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . with _eof _error = function ( eof _error , cont ) {
2014-04-16 16:43:40 +00:00
return function ( x ) {
try {
2014-04-16 18:39:27 +00:00
return cont . call ( this , x ) ;
2014-04-16 16:43:40 +00:00
} catch ( ex ) {
if ( ex === Cola . EX _EOF ) this . parse _error ( eof _error ) ;
else throw ex ;
2012-05-27 11:09:01 +00:00
}
} ;
2014-04-16 16:43:40 +00:00
} ;
2012-05-27 11:09:01 +00:00
2014-04-19 18:04:11 +00:00
Cola . Tokenizer . prototype . dumpS = function ( ) {
2014-05-16 12:27:51 +00:00
this . dumps [ ++ this . dumpi ] = Cola . clone ( this . S ) ;
2014-04-19 18:04:11 +00:00
} ;
Cola . Tokenizer . prototype . restoreS = function ( ) {
2014-05-16 12:27:51 +00:00
if ( this . dumpi == - 1 ) return ;
this . S = this . dumps [ this . dumpi ] ;
delete this . dumps [ this . dumpi -- ] ;
2014-04-19 18:04:11 +00:00
} ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . peek = function ( offset ) { return this . S . text . charAt ( this . S . pos + ( offset ? offset : 0 ) ) ; } ;
2014-04-16 16:43:40 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . next = function ( signal _eof , in _string ) {
2014-04-16 16:43:40 +00:00
var ch = this . S . text . charAt ( this . S . pos ++ ) ;
if ( signal _eof && ! ch )
throw Cola . EX _EOF ;
if ( ch == "\n" ) {
this . S . newline _before = this . S . newline _before || ! in _string ;
++ this . S . line ;
this . S . col = 0 ;
} else {
++ this . S . col ;
}
return ch ;
} ;
2013-09-06 06:54:30 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . forward = function ( i ) {
2014-04-16 16:43:40 +00:00
while ( i -- > 0 ) this . next ( ) ;
} ;
2013-09-06 06:54:30 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . looking _at = function ( str ) {
2014-04-16 16:43:40 +00:00
return this . S . text . substr ( this . S . pos , str . length ) == str ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . find = function ( what , signal _eof ) {
2014-04-16 16:43:40 +00:00
var pos = this . S . text . indexOf ( what , this . S . pos ) ;
if ( signal _eof && pos == - 1 ) throw Cola . EX _EOF ;
return pos ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . start _token = function ( ) {
2014-04-16 16:43:40 +00:00
this . S . tokline = this . S . line ;
this . S . tokcol = this . S . col ;
this . S . tokpos = this . S . pos ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . token = function ( type , value , is _comment ) {
2014-04-18 18:27:47 +00:00
this . S . regex _allowed = ( ( type == "operator" && ! this . UNARY _POSTFIX ( value ) ) ||
2014-05-19 09:58:17 +00:00
( type == "keyword" && this . KEYWORDS _BEFORE _EXPRESSION ( value ) ) ||
2014-04-16 16:43:40 +00:00
( type == "punc" && Cola . PUNC _BEFORE _EXPRESSION ( value ) ) ) ;
this . prev _was _dot = ( type == "punc" && value == "." ) ;
var ret = {
type : type ,
value : value ,
line : this . S . tokline ,
col : this . S . tokcol ,
pos : this . S . tokpos ,
endpos : this . S . pos ,
nlb : this . S . newline _before ,
file : this . S . filename
} ;
if ( ! is _comment ) {
ret . comments _before = this . S . comments _before ;
this . S . comments _before = [ ] ;
// make note of any newlines in the comments that came before
for ( var i = 0 , len = ret . comments _before . length ; i < len ; i ++ ) {
ret . nlb = ret . nlb || ret . comments _before [ i ] . nlb ;
}
}
this . S . newline _before = false ;
return new Cola . AST _Token ( ret ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . skip _whitespace = function ( ) {
2014-04-16 16:43:40 +00:00
while ( Cola . WHITESPACE _CHARS ( this . peek ( ) ) )
this . next ( ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _while = function ( pred ) {
2014-04-16 16:43:40 +00:00
var ret = "" , ch , i = 0 ;
while ( ( ch = this . peek ( ) ) && pred ( ch , i ++ ) )
ret += this . next ( ) ;
return ret ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . parse _error = function ( err ) {
2014-04-16 16:43:40 +00:00
Cola . js _error ( err , this . S . filename , this . S . tokline , this . S . tokcol , this . S . tokpos ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _num = function ( prefix ) {
2014-04-22 13:33:43 +00:00
var has _e = false , after _e = false , has _x = false , has _dot = prefix == "." , _this = this ;
2014-04-16 16:43:40 +00:00
var num = this . read _while ( function ( ch , i ) {
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 ) : // .
2014-04-22 13:33:43 +00:00
if ( ! _this . is _js && _this . peek ( 1 ) == '.' ) return false ;
2014-04-16 16:43:40 +00:00
return ( ! has _dot && ! has _x && ! has _e ) ? ( has _dot = true ) : false ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 16:43:40 +00:00
return Cola . is _alphanumeric _char ( code ) ;
} ) ;
if ( prefix ) num = prefix + num ;
var valid = Cola . parse _js _number ( num ) ;
if ( ! isNaN ( valid ) ) {
return this . token ( "num" , valid ) ;
} else {
this . parse _error ( "Invalid syntax: " + num ) ;
}
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _escaped _char = function ( in _string ) {
2014-04-16 16:43:40 +00:00
var ch = this . next ( true , in _string ) ;
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 48 : return "\0" ;
case 120 : return String . fromCharCode ( this . hex _bytes ( 2 ) ) ; // \x
case 117 : return String . fromCharCode ( this . hex _bytes ( 4 ) ) ; // \u
case 10 : return "" ; // newline
default : return ch ;
}
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . hex _bytes = function ( n ) {
2014-04-16 16:43:40 +00:00
var num = 0 ;
for ( ; n > 0 ; -- n ) {
var digit = parseInt ( this . next ( true ) , 16 ) ;
if ( isNaN ( digit ) )
this . parse _error ( "Invalid hex-character pattern in string" ) ;
num = ( num << 4 ) | digit ;
}
return num ;
} ;
2014-04-15 10:52:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _string = Cola . Tokenizer . with _eof _error ( "Unterminated string constant" , function ( raw ) {
2014-04-16 16:43:40 +00:00
var quote = this . next ( ) , ret = "" ;
2014-04-14 03:35:26 +00:00
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && ! raw ) {
2014-04-16 16:43:40 +00:00
if ( this . S . string . at [ this . S . string . level ] . inside && ( this . S . string . at [ this . S . string . level ] . inside _at || this . S . string . at [ this . S . string . level ] . inside _braces ) ) {
this . S . string . level ++ ;
2014-04-16 18:39:27 +00:00
this . S . string . at [ this . S . string . level ] = new Cola . Tokenizer . StringInfo ( ) ;
2014-04-15 10:52:01 +00:00
}
2014-04-16 16:43:40 +00:00
this . S . string . at [ this . S . string . level ] . inside = true ;
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
if ( quote != '"' && quote != "'" && quote != '`' ) {
ret = quote ;
quote = this . S . string . at [ this . S . string . level ] . quote ;
} else
if ( quote == this . S . string . at [ this . S . string . level ] . quote ) {
this . S . string . at [ this . S . string . level ] . inside = false ;
this . S . string . at [ this . S . string . level ] . quote = '' ;
if ( this . S . string . level != 0 ) {
delete this . S . string . at [ this . S . string . level ] ;
this . S . string . level -- ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 16:43:40 +00:00
return this . next _token ( ) ;
} else
this . S . string . at [ this . S . string . level ] . quote = quote ;
2014-04-28 08:20:12 +00:00
if ( this . peek ( ) == '@' || this . peek ( ) == '{' && this . peek ( 1 ) == '{' ) return this . token ( "string" , ret ) ;
2014-04-16 16:43:40 +00:00
}
for ( ; ; ) {
var ch = this . next ( true ) ;
2014-04-16 18:39:27 +00:00
if ( ( ! raw || this . is _js ) && ch == "\\" ) {
2014-04-16 16:43:40 +00:00
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
// https://github.com/mishoo/UglifyJS/issues/178
var octal _len = 0 , first = null ;
ch = this . read _while ( function ( ch ) {
if ( ch >= "0" && ch <= "7" ) {
if ( ! first ) {
first = ch ;
return ++ octal _len ;
2014-04-15 10:52:01 +00:00
}
2014-04-16 16:43:40 +00:00
else if ( first <= "3" && octal _len <= 2 ) return ++ octal _len ;
else if ( first >= "4" && octal _len <= 1 ) return ++ octal _len ;
2014-04-14 03:35:26 +00:00
}
2014-04-16 16:43:40 +00:00
return false ;
} ) ;
if ( octal _len > 0 ) ch = String . fromCharCode ( parseInt ( ch , 8 ) ) ;
else ch = this . read _escaped _char ( true ) ;
}
else if ( ch == quote ) {
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && ! raw ) {
2014-04-16 16:43:40 +00:00
this . S . string . at [ this . S . string . level ] . inside = false ;
this . S . string . at [ this . S . string . level ] . quote = '' ;
if ( this . S . string . level != 0 ) {
delete this . S . string . at [ this . S . string . level ] ;
this . S . string . level -- ;
}
}
break ;
2014-04-14 03:35:26 +00:00
}
2014-04-16 16:43:40 +00:00
ret += ch ;
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && ! raw && ( this . peek ( ) == '@' || this . peek ( ) == '{' && this . peek ( 1 ) == '{' ) ) break ;
2014-04-16 16:43:40 +00:00
}
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
return this . token ( "string" , ret ) ;
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _at = function ( ) {
2014-04-16 16:43:40 +00:00
var at = this . next ( ) ;
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
if ( this . S . string . at [ this . S . string . level ] . inside && Cola . is _identifier _char ( this . peek ( ) ) ) {
this . S . string . at [ this . S . string . level ] . after _at = true ;
return this . token ( "punc" , "@" ) ;
} else
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
if ( this . S . string . at [ this . S . string . level ] . inside && this . peek ( ) == '{' ) {
this . S . string . at [ this . S . string . level ] . inside _at = true ;
this . S . string . at [ this . S . string . level ] . balance = 1 ;
return this . token ( "punc" , "@" + this . next ( ) ) ;
2014-05-19 17:29:01 +00:00
} else return this . token ( "punc" , "@" ) ;
2014-04-16 16:43:40 +00:00
this . parse _error ( 'Unexpected character "@"' ) ;
}
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _braces = function ( ) {
2014-04-16 16:43:40 +00:00
this . next ( ) , this . next ( ) ;
this . S . string . at [ this . S . string . level ] . inside _braces = true ;
this . S . string . at [ this . S . string . level ] . balance = 1 ;
return this . token ( "punc" , "{{" ) ;
}
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . skip _line _comment = function ( type ) {
2014-04-16 16:43:40 +00:00
var regex _allowed = this . S . regex _allowed ;
var i = this . find ( "\n" ) , ret ;
if ( i == - 1 ) {
ret = this . S . text . substr ( this . S . pos ) ;
this . S . pos = this . S . text . length ;
} else {
ret = this . S . text . substring ( this . S . pos , i ) ;
this . S . pos = i ;
2014-04-15 10:52:01 +00:00
}
2014-04-16 16:43:40 +00:00
this . S . comments _before . push ( this . token ( type , ret , true ) ) ;
this . S . regex _allowed = regex _allowed ;
return this . next _token ( ) ;
} ;
2014-04-14 03:35:26 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . skip _multiline _comment = Cola . Tokenizer . with _eof _error ( "Unterminated multiline comment" , function ( ) {
2014-04-16 16:43:40 +00:00
var regex _allowed = this . S . regex _allowed ;
var i = this . find ( "*/" , true ) ;
var text = this . S . text . substring ( this . S . pos , i ) ;
var a = text . split ( "\n" ) , n = a . length ;
// update stream position
this . S . pos = i + 2 ;
this . S . line += n - 1 ;
if ( n > 1 ) this . S . col = a [ n - 1 ] . length ;
else this . S . col += a [ n - 1 ] . length ;
this . S . col += 2 ;
var nlb = this . S . newline _before = this . S . newline _before || text . indexOf ( "\n" ) >= 0 ;
this . S . comments _before . push ( this . token ( "comment2" , text , true ) ) ;
this . S . regex _allowed = regex _allowed ;
this . S . newline _before = nlb ;
return this . next _token ( ) ;
} ) ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _name = function ( ) {
2014-04-16 16:43:40 +00:00
var backslash = false , name = "" , ch , escaped = false , hex ;
while ( ( ch = this . peek ( ) ) != null ) {
if ( ! backslash ) {
if ( ch == "\\" ) escaped = backslash = true , this . next ( ) ;
else if ( Cola . is _identifier _char ( ch ) ) name += this . next ( ) ;
else break ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 16:43:40 +00:00
else {
if ( ch != "u" ) this . parse _error ( "Expecting UnicodeEscapeSequence -- uXXXX" ) ;
ch = this . read _escaped _char ( ) ;
if ( ! Cola . is _identifier _char ( ch ) ) this . parse _error ( "Unicode char: " + ch . charCodeAt ( 0 ) + " is not valid in identifier" ) ;
name += ch ;
backslash = false ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 16:43:40 +00:00
}
2014-04-17 10:10:18 +00:00
if ( this . KEYWORDS ( name ) && escaped ) {
2014-04-16 16:43:40 +00:00
hex = name . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) ;
name = "\\u" + "0000" . substr ( hex . length ) + hex + name . slice ( 1 ) ;
}
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && this . S . string . at [ this . S . string . level ] . inside && this . S . string . at [ this . S . string . level ] . after _at ) this . S . string . at [ this . S . string . level ] . after _at = false ;
2014-04-16 16:43:40 +00:00
return name ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _regexp = Cola . Tokenizer . with _eof _error ( "Unterminated regular expression" , function ( regexp ) {
2014-04-16 16:43:40 +00:00
var prev _backslash = false , ch , in _class = false ;
while ( ( ch = this . next ( true ) ) ) if ( prev _backslash ) {
regexp += "\\" + ch ;
prev _backslash = false ;
} else if ( ch == "[" ) {
in _class = true ;
regexp += ch ;
} else if ( ch == "]" && in _class ) {
in _class = false ;
regexp += ch ;
} else if ( ch == "/" && ! in _class ) {
break ;
} else if ( ch == "\\" ) {
prev _backslash = true ;
} else {
regexp += ch ;
}
var mods = this . read _name ( ) ;
2014-04-16 18:39:27 +00:00
return this . token ( "regexp" , this . is _js ? new RegExp ( regexp , mods ) : "/" + regexp + "/" + mods ) ;
2014-04-16 16:43:40 +00:00
} ) ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _operator = function ( prefix ) {
var _this = this ;
2014-04-16 16:43:40 +00:00
function grow ( op ) {
2014-04-16 18:39:27 +00:00
if ( ! _this . peek ( ) ) return op ;
var bigger = op + _this . peek ( ) ;
2014-04-17 10:10:18 +00:00
if ( _this . OPERATORS ( bigger ) ) {
2014-04-16 18:39:27 +00:00
_this . next ( ) ;
2014-04-16 16:43:40 +00:00
return grow ( bigger ) ;
2012-10-11 10:00:58 +00:00
} else {
2014-04-16 16:43:40 +00:00
return op ;
2012-10-11 10:00:58 +00:00
}
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 16:43:40 +00:00
return this . token ( "operator" , grow ( prefix || this . next ( ) ) ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . handle _slash = function ( ) {
2014-04-16 16:43:40 +00:00
this . next ( ) ;
switch ( this . peek ( ) ) {
case "/" :
this . next ( ) ;
return this . skip _line _comment ( "comment1" ) ;
case "*" :
this . next ( ) ;
return this . skip _multiline _comment ( ) ;
}
return this . S . regex _allowed ? this . read _regexp ( "" ) : this . read _operator ( "/" ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . handle _dot = function ( ) {
2014-04-16 16:43:40 +00:00
this . next ( ) ;
2014-04-27 20:30:25 +00:00
if ( ! this . is _js && this . peek ( ) == '.' && this . peek ( 1 ) != "." ) return this . next ( ) , this . token ( "punc" , ".." ) ;
else if ( ! this . is _js && this . peek ( ) == '.' && this . peek ( 1 ) == "." ) return this . next ( ) , this . next ( ) , this . token ( "punc" , "..." ) ;
2014-04-16 16:43:40 +00:00
return Cola . is _digit ( this . peek ( ) . charCodeAt ( 0 ) )
? this . read _num ( "." )
: this . token ( "punc" , "." ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . read _word = function ( ) {
2014-04-16 16:43:40 +00:00
var word = this . read _name ( ) ;
if ( this . prev _was _dot ) return this . token ( "name" , word ) ;
2014-04-17 10:10:18 +00:00
return this . KEYWORDS _ATOM ( word ) ? this . token ( "atom" , word )
: ! this . KEYWORDS ( word ) ? this . token ( "name" , word )
: this . OPERATORS ( word ) ? this . token ( "operator" , word )
2014-04-16 16:43:40 +00:00
: this . token ( "keyword" , word ) ;
2012-05-27 11:09:01 +00:00
} ;
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . next _token = function ( force _regexp ) {
2014-04-16 16:43:40 +00:00
if ( force _regexp != null )
return this . read _regexp ( force _regexp ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
var ch ;
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && this . S . string . at [ this . S . string . level ] . inside && ! this . S . string . at [ this . S . string . level ] . after _at && ! this . S . string . at [ this . S . string . level ] . inside _at && ! this . S . string . at [ this . S . string . level ] . inside _braces ) {
2014-04-16 16:43:40 +00:00
ch = this . peek ( ) ;
if ( ch == '@' ) return this . read _at ( ) ;
if ( ch == '{' && this . peek ( 1 ) == '{' ) return this . read _braces ( ) ;
return this . read _string ( ) ;
}
2014-04-14 03:35:26 +00:00
2014-04-16 16:43:40 +00:00
this . skip _whitespace ( ) ;
this . start _token ( ) ;
if ( this . html5 _comments ) {
if ( this . looking _at ( "<!--" ) ) {
this . forward ( 4 ) ;
return this . skip _line _comment ( "comment3" ) ;
2014-04-14 03:35:26 +00:00
}
2014-04-16 16:43:40 +00:00
if ( this . looking _at ( "-->" ) && this . S . newline _before ) {
this . forward ( 3 ) ;
return this . skip _line _comment ( "comment4" ) ;
2013-09-06 06:54:30 +00:00
}
2014-04-16 16:43:40 +00:00
}
ch = this . peek ( ) ;
if ( ! ch ) return this . token ( "eof" ) ;
var code = ch . charCodeAt ( 0 ) ;
2014-04-17 10:10:18 +00:00
if ( ! this . is _js && code == 96 ) return this . read _string ( ) ;
switch ( code ) {
2014-04-16 18:39:27 +00:00
case 34 : case 39 : return this . read _string ( ) ;
2014-04-16 16:43:40 +00:00
case 46 : return this . handle _dot ( ) ;
case 47 : return this . handle _slash ( ) ;
}
if ( Cola . is _digit ( code ) ) return this . read _num ( ) ;
if ( Cola . PUNC _CHARS ( ch ) ) {
2014-04-16 18:39:27 +00:00
if ( ! this . is _js && this . S . string . at [ this . S . string . level ] . inside && ( this . S . string . at [ this . S . string . level ] . inside _at || this . S . string . at [ this . S . string . level ] . inside _braces ) ) {
2014-04-16 16:43:40 +00:00
if ( ch == '{' ) this . S . string . at [ this . S . string . level ] . balance ++ ;
else if ( ch == '}' ) this . S . string . at [ this . S . string . level ] . balance -- ;
if ( this . S . string . at [ this . S . string . level ] . balance == 0 )
if ( this . S . string . at [ this . S . string . level ] . inside _at ) this . S . string . at [ this . S . string . level ] . inside _at = false ;
else {
this . S . string . at [ this . S . string . level ] . inside _braces = false ;
return this . next ( ) , this . next ( ) , this . token ( "punc" , "}}" ) ;
}
2014-04-14 03:35:26 +00:00
}
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
return this . token ( "punc" , this . next ( ) ) ;
}
2014-04-20 18:56:47 +00:00
if ( ! this . is _js ) {
if ( ch == 'r' && ( this . peek ( 1 ) == '"' || this . peek ( 1 ) == "'" || this . peek ( 1 ) == '`' ) ) return this . next ( ) , this . read _string ( true ) ;
if ( ch + this . peek ( 1 ) == '=>' ) return this . next ( ) , this . next ( ) , this . token ( "punc" , "=>" ) ;
if ( ch == '@' ) return this . read _at ( ) ;
}
2014-04-16 16:43:40 +00:00
if ( Cola . OPERATOR _CHARS ( ch ) ) return this . read _operator ( ) ;
if ( code == 92 || Cola . is _identifier _start ( code ) ) return this . read _word ( ) ;
this . parse _error ( "Unexpected character '" + ch + "'" ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Tokenizer . prototype . context = function ( nc ) {
2014-04-16 16:43:40 +00:00
if ( nc ) this . S = nc ;
return this . S ;
2012-05-27 11:09:01 +00:00
} ;
/* -----[ Parser (constants) ]----- */
2014-04-16 16:43:40 +00:00
Cola . UNARY _PREFIX = Cola . makePredicate ( [
"typeof" ,
"void" ,
"delete" ,
"--" ,
"++" ,
"!" ,
"~" ,
"-" ,
"+"
] ) ;
Cola . cUNARY _PREFIX = Cola . makePredicate ( [
2014-04-20 07:31:03 +00:00
"clone" ,
2014-04-18 18:27:47 +00:00
"isset" ,
2012-05-27 11:09:01 +00:00
"typeof" ,
"delete" ,
"--" ,
"++" ,
"!" ,
"~" ,
"-" ,
"+"
] ) ;
2014-04-16 16:43:40 +00:00
Cola . UNARY _POSTFIX = Cola . makePredicate ( [ "--" , "++" ] ) ;
2014-04-18 18:27:47 +00:00
Cola . cUNARY _POSTFIX = Cola . makePredicate ( [ "--" , "++" , "??" ] ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . ASSIGNMENT = Cola . makePredicate ( [ "=" , "+=" , "-=" , "/=" , "*=" , "%=" , ">>=" , "<<=" , ">>>=" , "|=" , "^=" , "&=" ] ) ;
2014-04-18 18:27:47 +00:00
Cola . cASSIGNMENT = Cola . makePredicate ( [ "=" , "+=" , "-=" , "/=" , "*=" , "%=" , ">>=" , "<<=" , ">>>=" , "|=" , "^=" , "&=" , "?=" ] ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . mergeTokens = 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 ;
2014-04-16 16:43:40 +00:00
} ;
Cola . PRECEDENCE = Cola . mergeTokens (
[
[ "||" ] ,
[ "&&" ] ,
[ "|" ] ,
[ "^" ] ,
[ "&" ] ,
[ "==" , "===" , "!=" , "!==" ] ,
[ "<" , ">" , "<=" , ">=" , "in" , "instanceof" ] ,
[ ">>" , "<<" , ">>>" ] ,
[ "+" , "-" ] ,
[ "*" , "/" , "%" ]
] ,
{ }
) ;
Cola . cPRECEDENCE = Cola . mergeTokens (
2012-05-27 11:09:01 +00:00
[
[ "||" ] ,
[ "&&" ] ,
[ "|" ] ,
[ "^" ] ,
[ "&" ] ,
[ "==" , "===" , "!=" , "!==" ] ,
2014-05-16 12:27:51 +00:00
[ "<" , ">" , "<=" , ">=" , "in" , "instanceof" , "is" , "isnt" ] ,
2012-05-27 11:09:01 +00:00
[ ">>" , "<<" , ">>>" ] ,
[ "+" , "-" ] ,
2014-05-16 12:27:51 +00:00
[ "*" , "/" , "%" , "**" , "%%" ]
2012-05-27 11:09:01 +00:00
] ,
{ }
) ;
2014-04-16 16:43:40 +00:00
Cola . STATEMENTS _WITH _LABELS = Cola . array _to _hash ( [ "for" , "do" , "while" , "switch" ] ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 16:43:40 +00:00
Cola . ATOMIC _START _TOKEN = Cola . array _to _hash ( [ "atom" , "num" , "string" , "regexp" , "name" ] ) ;
2012-05-27 11:09:01 +00:00
/* -----[ Parser ]----- */
2014-04-18 06:10:20 +00:00
Cola . parse = function ( $TEXT , options ) {
return ( new Cola . Parser ( $TEXT , options ) ) . parse ( ) ;
2014-04-16 18:39:27 +00:00
} ;
2014-04-18 06:10:20 +00:00
Cola . Parser = function ( $TEXT , options ) {
2014-04-16 18:39:27 +00:00
var _this = this ;
2012-09-21 11:19:05 +00:00
2014-04-16 18:39:27 +00:00
this . options = Cola . defaults ( options , {
2013-09-06 06:54:30 +00:00
strict : false ,
filename : null ,
toplevel : null ,
expression : false ,
2014-04-18 06:10:20 +00:00
html5 _comments : true ,
is _js : false
2012-09-21 11:19:05 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-18 18:27:47 +00:00
this . is _js = ! ! this . options . is _js ;
2014-04-18 06:10:20 +00:00
this . tokenizer = typeof $TEXT == "string" ? new Cola . Tokenizer ( $TEXT , this . options . filename , this . is _js , this . options . html5 _comments ) : $TEXT ;
2014-04-16 16:43:40 +00:00
2014-04-16 18:39:27 +00:00
this . S = {
input : function ( ) { return _this . tokenizer . next _token ( ) } ,
2012-05-27 11:09:01 +00:00
token : null ,
prev : null ,
peeked : null ,
in _function : 0 ,
in _directives : true ,
in _loop : 0 ,
labels : [ ]
} ;
2014-04-16 18:39:27 +00:00
this . S . input . context = function ( ) { return _this . tokenizer . context ( ) } ;
this . S . token = this . next ( ) ;
2014-05-16 12:27:51 +00:00
this . dumps = [ ] ;
this . dumpi = - 1 ;
2014-04-17 10:10:18 +00:00
2014-04-18 06:10:20 +00:00
if ( this . is _js ) {
2014-04-17 10:10:18 +00:00
this . UNARY _PREFIX = Cola . UNARY _PREFIX ;
this . PRECEDENCE = Cola . PRECEDENCE ;
this . ASSIGNMENT = Cola . ASSIGNMENT ;
2014-04-18 18:27:47 +00:00
this . UNARY _POSTFIX = Cola . UNARY _POSTFIX ;
2014-04-17 10:10:18 +00:00
} else {
this . UNARY _PREFIX = Cola . cUNARY _PREFIX ;
this . PRECEDENCE = Cola . cPRECEDENCE ;
this . ASSIGNMENT = Cola . cASSIGNMENT ;
2014-04-18 18:27:47 +00:00
this . UNARY _POSTFIX = Cola . cUNARY _POSTFIX ;
2014-04-17 10:10:18 +00:00
}
2014-04-16 18:39:27 +00:00
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . parse = function ( ) {
var _this = this ;
if ( this . options . expression ) {
return this . expression ( true ) ;
}
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
return ( function ( ) {
var start = _this . S . token ;
var body = [ ] ;
while ( ! _this . is ( "eof" ) )
body . push ( _this . statement ( ) ) ;
var end = _this . prev ( ) ;
var toplevel = _this . options . toplevel ;
if ( toplevel ) {
toplevel . body = toplevel . body . concat ( body ) ;
toplevel . end = end ;
2012-05-27 11:09:01 +00:00
} else {
2014-04-16 18:39:27 +00:00
toplevel = new Cola . AST _Toplevel ( { start : start , body : body , end : end } ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
toplevel . language = _this . is _js ? 'js' : 'cola' ;
return toplevel ;
} ) ( ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-19 18:04:11 +00:00
Cola . Parser . prototype . dumpS = function ( ) {
2014-05-16 12:27:51 +00:00
this . dumps [ ++ this . dumpi ] = Cola . clone ( this . S ) ;
2014-04-19 18:04:11 +00:00
this . tokenizer . dumpS ( ) ;
} ;
Cola . Parser . prototype . restoreS = function ( ) {
2014-05-16 12:27:51 +00:00
if ( this . dumpi == - 1 ) return ;
2014-04-19 18:04:11 +00:00
this . tokenizer . restoreS ( ) ;
2014-05-16 12:27:51 +00:00
this . S = this . dumps [ this . dumpi ] ;
delete this . dumps [ this . dumpi -- ] ;
2014-04-19 18:04:11 +00:00
} ;
Cola . Parser . prototype . next _until = function ( until ) {
while ( true ) {
if ( until ( this . S . token ) ) break ;
this . next ( ) ;
}
return this . S . token ;
}
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . is = function ( type , value ) {
return Cola . is _token ( this . S . token , type , value ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . peek = function ( ) { return this . S . peeked || ( this . S . peeked = this . S . input ( ) ) ; } ;
2012-05-27 11:09:01 +00:00
2014-05-16 12:27:51 +00:00
Cola . Parser . prototype . next _is = function ( type , value ) {
return Cola . is _token ( this . peek ( ) , type , value ) ;
} ;
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . next = function ( ) {
this . S . prev = this . S . token ;
if ( this . S . peeked ) {
this . S . token = this . S . peeked ;
this . S . peeked = null ;
} else {
this . S . token = this . S . input ( ) ;
}
this . S . in _directives = this . S . in _directives && (
this . S . token . type == "string" || this . is ( "punc" , ";" )
) ;
return this . S . token ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . prev = function ( ) {
return this . S . prev ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . croak = function ( msg , line , col , pos ) {
2014-05-19 09:58:17 +00:00
var ctx = this . S ? this . S . input . context ( ) : { } ;
2014-04-16 18:39:27 +00:00
Cola . js _error ( msg ,
ctx . filename ,
line != null ? line : ctx . tokline ,
col != null ? col : ctx . tokcol ,
pos != null ? pos : ctx . tokpos ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . token _error = function ( token , msg ) {
2014-05-19 09:58:17 +00:00
this . croak ( msg , token . line , token . col , token . pos ) ;
2014-04-16 18:39:27 +00:00
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . unexpected = function ( token ) {
if ( token == null )
token = this . S . token ;
this . token _error ( token , "Unexpected token: " + token . type + " `" + token . value + "`" ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . expect _token = function ( type , val ) {
if ( this . is ( type , val ) ) {
return this . next ( ) ;
}
this . token _error ( this . S . token , "Unexpected token " + this . S . token . type + " `" + this . S . token . value + "`" + ", expected " + type + " `" + val + "`" ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . expect = function ( punc ) { return this . expect _token ( "punc" , punc ) ; } ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . can _insert _semicolon = function ( ) {
2014-04-27 20:30:25 +00:00
if ( ! this . is _js ) return false ;
2014-04-16 18:39:27 +00:00
return ! this . options . strict && (
this . S . token . nlb || this . is ( "eof" ) || this . is ( "punc" , "}" )
) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . semicolon = function ( ) {
if ( this . is ( "punc" , ";" ) ) this . next ( ) ;
else if ( ! this . can _insert _semicolon ( ) ) this . unexpected ( ) ;
} ;
2013-09-02 06:56:27 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . parenthesised = function ( ) {
this . expect ( "(" ) ;
var exp = this . expression ( true ) ;
this . expect ( ")" ) ;
return exp ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . embed _tokens = function ( parser ) {
return function ( ) {
var start = this . S . token ;
2014-05-16 12:27:51 +00:00
var expr = parser . apply ( this , arguments ) ;
2014-04-16 18:39:27 +00:00
var end = this . prev ( ) ;
expr . start = start ;
expr . end = end ;
return expr ;
} ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . handle _regexp = function ( ) {
if ( this . is ( "operator" , "/" ) || this . is ( "operator" , "/=" ) ) {
this . S . peeked = null ;
this . S . token = this . S . input ( this . S . token . value . substr ( 1 ) ) ; // force regexp
}
} ;
Cola . Parser . prototype . statement = Cola . Parser . embed _tokens ( function ( ) {
2014-04-18 18:27:47 +00:00
var tmp , type , _this = this ;
2014-04-16 18:39:27 +00:00
this . handle _regexp ( ) ;
switch ( this . S . token . type ) {
case "string" :
var dir = this . S . in _directives , stat = this . simple _statement ( ) ;
// XXXv2: decide how to fix directives
if ( dir && stat . body instanceof Cola . AST _String && ! this . is ( "punc" , "," ) )
return new Cola . AST _Directive ( { value : stat . body . value } ) ;
return stat ;
case "num" :
case "regexp" :
case "operator" :
case "atom" :
return this . simple _statement ( ) ;
case "name" :
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && this . next _is ( "name" ) ) {
2014-04-19 18:04:11 +00:00
type = this . S . token . value , this . next ( ) ;
2014-05-16 12:27:51 +00:00
if ( this . next _is ( "punc" , "(" ) ) return this . function _ ( Cola . AST _Defun , type ) ;
2014-04-19 18:04:11 +00:00
return tmp = this . var _ ( false , type ) , this . semicolon ( ) , tmp ;
}
if ( ! this . is _js ) {
var _this = this , balance = 1 , isfun = false ;
this . dumpS ( ) ;
this . next ( ) ;
if ( this . is ( 'punc' , '(' ) ) {
this . next ( ) ;
this . next _until ( function ( ) {
if ( _this . is ( 'punc' , '(' ) ) balance ++ ;
else if ( _this . is ( 'punc' , ')' ) ) balance -- ;
return balance == 0 || _this . is ( 'eof' ) ;
} ) ;
2014-04-20 15:38:58 +00:00
isfun = ( this . next ( ) , ( this . is ( 'punc' , '{' ) || this . is ( 'punc' , '=>' ) ) ) ;
2014-04-19 18:04:11 +00:00
}
this . restoreS ( ) ;
if ( isfun ) return this . function _ ( Cola . AST _Defun ) ;
}
2014-05-16 12:27:51 +00:00
return this . next _is ( "punc" , ":" )
2014-04-16 18:39:27 +00:00
? this . labeled _statement ( )
: this . simple _statement ( ) ;
case "punc" :
switch ( this . S . token . value ) {
2014-05-19 17:29:01 +00:00
case "@" :
if ( ! this . is _js && this . next _is ( "name" ) )
return new Cola . AST _Command ( {
name : this . next ( ) . value ,
args : ( function ( ) {
var args = [ ] ;
while ( ! this . peek ( ) . nlb && ! this . next _is ( 'eof' ) ) {
if ( this . next _is ( 'punc' , '{' ) ) {
this . next ( ) ;
args . push ( new Cola . AST _BlockStatement ( {
start : this . S . token ,
body : this . block _ ( ) ,
end : this . prev ( )
} ) ) ;
} else
args . push ( this . next ( ) ) ;
}
this . next ( ) ;
return args ;
} ) . call ( this )
} ) ;
2014-04-16 18:39:27 +00:00
case "{" :
2014-05-19 17:29:01 +00:00
if ( this . is _js ) return new Cola . AST _BlockStatement ( {
start : this . S . token ,
body : this . block _ ( ) ,
end : this . prev ( )
} ) ;
2014-05-16 12:27:51 +00:00
this . dumpS ( ) ;
var balance = 0 , is _object = false ;
this . next _until ( function ( ) {
if ( _this . is ( 'punc' , '{' ) ) balance ++ ;
else if ( _this . is ( 'punc' , '}' ) ) balance -- ;
return balance == 0 || _this . is ( 'eof' ) ;
} ) ;
is _object = this . next _is ( "operator" ) ;
this . restoreS ( ) ;
if ( is _object ) return this . simple _statement ( ) ;
2014-04-16 18:39:27 +00:00
return new Cola . AST _BlockStatement ( {
start : this . S . token ,
body : this . block _ ( ) ,
end : this . prev ( )
2013-09-02 16:36:16 +00:00
} ) ;
2014-05-16 12:27:51 +00:00
2014-04-16 18:39:27 +00:00
case "[" :
case "(" :
return this . simple _statement ( ) ;
case ";" :
this . next ( ) ;
return new Cola . AST _EmptyStatement ( ) ;
default :
this . unexpected ( ) ;
2013-09-02 16:36:16 +00:00
}
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "keyword" :
switch ( tmp = this . S . token . value , this . next ( ) , tmp ) {
case "break" :
return this . break _cont ( Cola . AST _Break ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "continue" :
return this . break _cont ( Cola . AST _Continue ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "debugger" :
this . semicolon ( ) ;
return new Cola . AST _Debugger ( ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "do" :
return new Cola . AST _Do ( {
2014-05-19 09:58:17 +00:00
body : this . in _loop ( function ( ) { return this . statement ( ) } ) ,
2014-04-16 18:39:27 +00:00
condition : ( this . expect _token ( "keyword" , "while" ) , tmp = this . parenthesised ( ) , this . semicolon ( ) , tmp )
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "while" :
return new Cola . AST _While ( {
condition : this . parenthesised ( ) ,
2014-05-19 09:58:17 +00:00
body : this . in _loop ( function ( ) { return this . statement ( ) } )
2014-04-16 18:39:27 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "for" :
return this . for _ ( ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "function" :
return this . function _ ( Cola . AST _Defun ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "if" :
return this . if _ ( ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "return" :
if ( this . S . in _function == 0 )
this . croak ( "'return' outside of function" ) ;
return new Cola . AST _Return ( {
value : ( this . is ( "punc" , ";" )
? ( this . next ( ) , null )
: this . can _insert _semicolon ( )
? null
: ( tmp = this . expression ( true ) , this . semicolon ( ) , tmp ) )
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "switch" :
return new Cola . AST _Switch ( {
2014-05-19 09:58:17 +00:00
expression : this . is ( 'punc' , '{' ) && ! this . is _js ? new Cola . AST _Noop ( ) : this . parenthesised ( ) ,
body : this . in _loop ( this . switch _body _ )
2012-05-27 11:09:01 +00:00
} ) ;
2014-04-16 18:39:27 +00:00
case "throw" :
if ( this . S . token . nlb )
this . croak ( "Illegal newline after 'throw'" ) ;
return new Cola . AST _Throw ( {
value : ( tmp = this . expression ( true ) , this . semicolon ( ) , tmp )
2012-05-27 14:25:31 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "try" :
return this . try _ ( ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "var" :
return tmp = this . var _ ( ) , this . semicolon ( ) , tmp ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "const" :
return tmp = this . const _ ( ) , this . semicolon ( ) , tmp ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
case "with" :
return new Cola . AST _With ( {
expression : this . parenthesised ( ) ,
body : this . statement ( )
} ) ;
default :
this . unexpected ( ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
}
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . labeled _statement = function ( ) {
var label = this . as _symbol ( Cola . AST _Label ) , _this = this ;
if ( Cola . find _if ( function ( l ) { return l . name == label . name } , this . S . labels ) ) {
// 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.
this . croak ( "Label " + label . name + " defined twice" ) ;
}
this . expect ( ":" ) ;
this . S . labels . push ( label ) ;
var stat = this . statement ( ) ;
this . S . labels . pop ( ) ;
if ( ! ( stat instanceof Cola . AST _IterationStatement ) ) {
// check for `continue` that refers to this label.
// those should be reported as syntax errors.
// https://github.com/mishoo/UglifyJS2/issues/287
label . references . forEach ( function ( ref ) {
if ( ref instanceof Cola . AST _Continue ) {
ref = ref . label . start ;
_this . croak ( "Continue label `" + label . name + "` refers to non-IterationStatement." ,
ref . line , ref . col , ref . pos ) ;
2014-04-15 10:52:01 +00:00
}
2014-04-16 18:39:27 +00:00
} ) ;
}
return new Cola . AST _LabeledStatement ( { body : stat , label : label } ) ;
} ;
2014-04-15 10:52:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . simple _statement = function ( tmp ) {
return new Cola . AST _SimpleStatement ( { body : ( tmp = this . expression ( true ) , this . semicolon ( ) , tmp ) } ) ;
} ;
2014-04-15 10:52:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . break _cont = function ( type ) {
var label = null , ldef ;
if ( ! this . can _insert _semicolon ( ) ) {
label = this . as _symbol ( Cola . AST _LabelRef , true ) ;
2014-04-15 10:52:01 +00:00
}
2014-04-16 18:39:27 +00:00
if ( label != null ) {
ldef = Cola . find _if ( function ( l ) { return l . name == label . name } , this . S . labels ) ;
if ( ! ldef )
this . croak ( "Undefined label " + label . name ) ;
label . thedef = ldef ;
}
else if ( this . S . in _loop == 0 )
this . croak ( type . TYPE + " not inside a loop or switch" ) ;
this . semicolon ( ) ;
var stat = new type ( { label : label } ) ;
if ( ldef ) ldef . references . push ( stat ) ;
return stat ;
} ;
2014-04-15 10:52:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . for _ = function ( ) {
this . expect ( "(" ) ;
var init = null ;
if ( ! this . is ( "punc" , ";" ) ) {
init = this . is ( "keyword" , "var" )
? ( this . next ( ) , this . var _ ( true ) )
: this . expression ( true , true ) ;
if ( this . is ( "operator" , "in" ) ) {
if ( init instanceof Cola . AST _Var && init . definitions . length > 1 )
this . croak ( "Only one variable declaration allowed in for..in loop" ) ;
this . next ( ) ;
return this . for _in ( init ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
}
return this . regular _for ( init ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . regular _for = function ( init ) {
this . expect ( ";" ) ;
var test = this . is ( "punc" , ";" ) ? null : this . expression ( true ) ;
this . expect ( ";" ) ;
var step = this . is ( "punc" , ")" ) ? null : this . expression ( true ) ;
this . expect ( ")" ) ;
2014-04-17 10:10:18 +00:00
var _this = this ;
2014-04-16 18:39:27 +00:00
return new Cola . AST _For ( {
init : init ,
condition : test ,
step : step ,
2014-05-19 09:58:17 +00:00
body : this . in _loop ( function ( ) { return this . statement ( ) } )
2014-04-16 18:39:27 +00:00
} ) ;
} ;
Cola . Parser . prototype . for _in = function ( init ) {
var lhs = init instanceof Cola . AST _Var ? init . definitions [ 0 ] . name : null ;
var obj = this . expression ( true ) ;
this . expect ( ")" ) ;
2014-04-17 10:10:18 +00:00
var _this = this ;
2014-04-16 18:39:27 +00:00
return new Cola . AST _ForIn ( {
init : init ,
name : lhs ,
object : obj ,
2014-05-19 09:58:17 +00:00
body : this . in _loop ( function ( ) { return this . statement ( ) } )
2014-04-16 18:39:27 +00:00
} ) ;
} ;
2014-04-27 20:30:25 +00:00
Cola . Parser . prototype . as _funcarg = function ( splatedexist ) {
var name = this . as _symbol ( Cola . AST _SymbolFunarg ) , type = name , argtype = 'positional' , defval = new Cola . AST _Noop ( ) ;
if ( this . is ( "name" ) ) name = this . as _symbol ( Cola . AST _SymbolFunarg ) ;
if ( this . is ( "punc" , "..." ) ) {
if ( splatedexist ) this . token _error ( this . S , "Unexpected token: splated argument can be only one." ) ;
if ( type != name && type . name != "Array" ) this . token _error ( this . S , "Unexpected token: splated argument must have `Array` type." ) ;
this . next ( ) ;
argtype = "splated" ;
} else if ( this . is ( "operator" , "=" ) ) {
this . next ( ) ;
defval = this . expression ( false ) ;
} else if ( this . is ( "punc" , ":" ) ) {
this . next ( ) ;
argtype = "named" ;
if ( ! this . is ( "punc" , "," ) && ! this . is ( "punc" , ")" ) ) {
defval = this . expression ( false ) ;
}
}
2014-05-16 12:27:51 +00:00
return new Cola . AST _ArgDef ( {
2014-04-27 20:30:25 +00:00
name : name ,
type : argtype == "splated" ? "Array" : type == name ? "dynamic" : type . name ,
argtype : argtype ,
defval : defval ,
start : type . start ,
end : this . prev ( )
} ) ;
} ;
2014-04-19 18:04:11 +00:00
Cola . Parser . prototype . function _ = function ( ctor , type ) {
! type && ( type = "dynamic" ) ;
2014-04-20 07:31:03 +00:00
2014-04-27 20:30:25 +00:00
var in _statement = ctor === Cola . AST _Defun , _this = this , splatedexist = false ;
2014-04-16 18:39:27 +00:00
var name = this . is ( "name" ) ? this . as _symbol ( in _statement ? Cola . AST _SymbolDefun : Cola . AST _SymbolLambda ) : null ;
if ( in _statement && ! name )
this . unexpected ( ) ;
this . expect ( "(" ) ;
return new ctor ( {
2014-04-19 18:04:11 +00:00
type : type ,
2014-04-16 18:39:27 +00:00
name : name ,
argnames : ( function ( first , a ) {
while ( ! _this . is ( "punc" , ")" ) ) {
if ( first ) first = false ; else _this . expect ( "," ) ;
2014-04-27 20:30:25 +00:00
a . push ( _this . is _js ? _this . as _symbol ( Cola . AST _SymbolFunarg ) : _this . as _funcarg ( splatedexist ) ) ;
splatedexist = a [ a . length - 1 ] . argtype == "splated" ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
_this . next ( ) ;
return a ;
} ) ( true , [ ] ) ,
body : ( function ( loop , labels ) {
++ _this . S . in _function ;
_this . S . in _directives = true ;
_this . S . in _loop = 0 ;
_this . S . labels = [ ] ;
2014-04-20 15:38:58 +00:00
var tmp , a = ! _this . is _js && _this . is ( "punc" , "=>" )
? ( _this . next ( ) , [ new Cola . AST _Return ( {
start : new Cola . AST _Token ( { nlb : false , type : 'keyword' , value : 'return' } ) ,
value : ( function ( ) {
tmp = _this . expression ( true ) ;
if ( ctor === Cola . AST _Defun ) {
_this . semicolon ( ) ;
_this . next ( ) ;
}
return tmp ;
} ) ( ) ,
end : _this . prev ( )
} ) ] )
: _this . block _ ( ) ;
2014-04-16 18:39:27 +00:00
-- _this . S . in _function ;
_this . S . in _loop = loop ;
_this . S . labels = labels ;
return a ;
} ) ( this . S . in _loop , this . S . labels )
} ) ;
} ;
2014-05-21 18:01:32 +00:00
Cola . Parser . prototype . if _ = function ( inline ) {
var cond = this . parenthesised ( ) , body = ( inline && ! this . is _js ? this . expression ( true ) : this . statement ( ) ) , belse = null ;
2014-04-16 18:39:27 +00:00
if ( this . is ( "keyword" , "else" ) ) {
this . next ( ) ;
2014-05-21 18:01:32 +00:00
if ( inline && ! this . is _js ) belse = this . is ( "keyword" , "if" ) ? ( this . next ( ) , this . if _ ( true ) ) : this . expression ( true ) ;
else belse = this . statement ( ) ;
2014-04-16 18:39:27 +00:00
}
return new Cola . AST _If ( {
condition : cond ,
body : body ,
2014-05-21 18:01:32 +00:00
alternative : belse ,
inline : inline
2014-04-16 18:39:27 +00:00
} ) ;
} ;
Cola . Parser . prototype . block _ = function ( ) {
this . expect ( "{" ) ;
var a = [ ] ;
while ( ! this . is ( "punc" , "}" ) ) {
if ( this . is ( "eof" ) ) this . unexpected ( ) ;
a . push ( this . statement ( ) ) ;
}
this . next ( ) ;
return a ;
} ;
Cola . Parser . prototype . switch _body _ = function ( ) {
this . expect ( "{" ) ;
var a = [ ] , cur = null , branch = null , tmp ;
while ( ! this . is ( "punc" , "}" ) ) {
if ( this . is ( "eof" ) ) this . unexpected ( ) ;
2014-05-19 09:58:17 +00:00
if ( this . is ( "keyword" , "case" ) || ! this . is _js && this . is ( "keyword" , "when" ) ) {
2014-04-16 18:39:27 +00:00
if ( branch ) branch . end = this . prev ( ) ;
cur = [ ] ;
2014-05-19 09:58:17 +00:00
branch = new ( ! this . is _js && this . is ( "keyword" , "when" ) ? Cola . AST _When : Cola . AST _Case ) ( {
2014-04-16 18:39:27 +00:00
start : ( tmp = this . S . token , this . next ( ) , tmp ) ,
expression : this . expression ( true ) ,
body : cur
} ) ;
a . push ( branch ) ;
this . expect ( ":" ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
else if ( this . is ( "keyword" , "default" ) ) {
if ( branch ) branch . end = this . prev ( ) ;
cur = [ ] ;
branch = new Cola . AST _Default ( {
start : ( tmp = this . S . token , this . next ( ) , this . expect ( ":" ) , tmp ) ,
body : cur
} ) ;
a . push ( branch ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
else {
if ( ! cur ) this . unexpected ( ) ;
cur . push ( this . statement ( ) ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
}
if ( branch ) branch . end = this . prev ( ) ;
this . next ( ) ;
return a ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . try _ = function ( ) {
var body = this . block _ ( ) , bcatch = null , bfinally = null ;
if ( this . is ( "keyword" , "catch" ) ) {
var start = this . S . token ;
this . next ( ) ;
this . expect ( "(" ) ;
var name = this . as _symbol ( Cola . AST _SymbolCatch ) ;
this . expect ( ")" ) ;
bcatch = new Cola . AST _Catch ( {
start : start ,
argname : name ,
body : this . block _ ( ) ,
end : this . prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
2014-04-16 18:39:27 +00:00
}
if ( this . is ( "keyword" , "finally" ) ) {
var start = this . S . token ;
this . next ( ) ;
bfinally = new Cola . AST _Finally ( {
start : start ,
body : this . block _ ( ) ,
end : this . prev ( )
} ) ;
}
if ( ! bcatch && ! bfinally )
this . croak ( "Missing catch/finally blocks" ) ;
return new Cola . AST _Try ( {
body : body ,
bcatch : bcatch ,
bfinally : bfinally
2012-05-27 14:25:31 +00:00
} ) ;
2014-04-16 18:39:27 +00:00
} ;
2012-05-27 11:09:01 +00:00
2014-05-16 12:27:51 +00:00
Cola . Parser . prototype . vardefs = function ( no _in , in _const , type ) {
var a = [ ] , was _template = false ;
2014-04-16 18:39:27 +00:00
for ( ; ; ) {
2014-05-16 12:27:51 +00:00
was _template = false ;
2014-04-16 18:39:27 +00:00
a . push ( new Cola . AST _VarDef ( {
start : this . S . token ,
2014-05-16 12:27:51 +00:00
type : type ,
name : ( function ( _this ) {
was _template = ! _this . is _js && ( _this . is ( "punc" , "[" ) || _this . is ( "punc" , "{" ) ) ;
if ( ! _this . is _js && _this . is ( "punc" , "[" ) ) return _this . array _ ( true , true ) ;
if ( ! _this . is _js && _this . is ( "punc" , "{" ) ) return _this . object _ ( true , true ) ;
return _this . as _symbol ( in _const ? Cola . AST _SymbolConst : Cola . AST _SymbolVar ) ;
} ) ( this ) ,
value : this . is ( "operator" , "=" ) ? ( this . next ( ) , this . expression ( false , no _in ) ) : ( was _template ? this . expect _token ( "operator" , "=" ) : null ) ,
2014-04-16 18:39:27 +00:00
end : this . prev ( )
} ) ) ;
if ( ! this . is ( "punc" , "," ) )
break ;
this . next ( ) ;
}
return a ;
} ;
2014-04-18 18:27:47 +00:00
Cola . Parser . prototype . var _ = function ( no _in , type ) {
! type && ( type = "dynamic" ) ;
2014-04-16 18:39:27 +00:00
return new Cola . AST _Var ( {
start : this . prev ( ) ,
2014-05-16 12:27:51 +00:00
definitions : this . vardefs ( no _in , false , type ) ,
2014-04-18 18:27:47 +00:00
type : type ,
2014-04-16 18:39:27 +00:00
end : this . prev ( )
2012-05-27 11:09:01 +00:00
} ) ;
2014-04-16 18:39:27 +00:00
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . const _ = function ( ) {
return new Cola . AST _Const ( {
start : this . prev ( ) ,
definitions : this . vardefs ( false , true ) ,
end : this . prev ( )
} ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . new _ = function ( ) {
var start = this . S . token ;
this . expect _token ( "operator" , "new" ) ;
var newexp = this . expr _atom ( false ) , args ;
if ( this . is ( "punc" , "(" ) ) {
this . next ( ) ;
2014-04-28 08:20:12 +00:00
args = this . expr _list ( ")" , false , false , ! this . is _js ) ;
2014-04-16 18:39:27 +00:00
} else {
args = [ ] ;
}
return this . subscripts ( new Cola . AST _New ( {
start : start ,
expression : newexp ,
args : args ,
end : this . prev ( )
} ) , true ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . string _template _ = function ( start _token ) {
var body = [ new Cola . AST _String ( { start : start _token , end : start _token , value : start _token . value } ) ] ;
this . next ( ) ;
2013-10-30 09:50:22 +00:00
2014-04-16 18:39:27 +00:00
while ( this . is ( 'punc' , '@' ) || this . is ( 'punc' , '@{' ) || this . is ( 'punc' , '{{' ) || this . is ( 'string' , null ) )
if ( this . is ( 'string' , null ) ) {
body . push ( new Cola . AST _String ( { start : this . S . token , end : this . S . token , value : this . S . token . value } ) ) ;
this . next ( ) ;
} else
if ( this . is ( 'punc' , '@' ) ) {
this . next ( ) ;
body . push ( this . _make _symbol ( Cola . AST _SymbolRef ) ) ;
this . next ( ) ;
} else
if ( this . is ( 'punc' , '@{' ) ) {
this . next ( ) ;
body . push ( this . expression ( true ) ) ;
this . expect ( '}' ) ;
} else
if ( this . is ( 'punc' , '{{' ) ) {
this . next ( ) ;
body . push ( this . expression ( true ) ) ;
this . expect ( '}}' ) ;
2012-08-19 12:57:50 +00:00
}
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
var last = body [ body . length - 1 ] ;
body [ 0 ] . value = body [ 0 ] . value . replace ( /^[ \t]*[\n\r]/ , '' ) ;
if ( last instanceof Cola . AST _String ) {
var offstr = last . value . match ( /[\n\r][ \t]*$/ ) ;
if ( offstr ) {
offstr = offstr [ 0 ] ;
for ( var i in body ) if ( body [ i ] instanceof Cola . AST _String ) {
body [ i ] . value = body [ i ] . value . replace ( new RegExp ( offstr , 'g' ) , '\n' ) ;
body [ i ] . value = body [ i ] . value . replace ( /\n/g , '\n' ) ;
}
last . value = last . value . replace ( /[\n\r]$/ , '' ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
}
if ( body . length == 1 ) return body [ 0 ] ;
return new Cola . AST _StringTemplate ( {
start : start _token ,
end : this . prev ( ) ,
body : body
} ) ;
}
Cola . Parser . prototype . as _atom _node = function ( ) {
var tok = this . S . token , ret ;
switch ( tok . type ) {
case "name" :
case "keyword" :
ret = this . _make _symbol ( Cola . AST _SymbolRef ) ;
break ;
case "num" :
ret = new Cola . AST _Number ( { start : tok , end : tok , value : tok . value } ) ;
break ;
case "string" :
if ( this . is _js ) {
ret = new Cola . AST _String ( { start : tok , end : tok , value : tok . value } ) ;
break ;
} else return this . string _template _ ( tok ) ;
case "regexp" :
ret = new Cola . AST _RegExp ( { start : tok , end : tok , value : tok . value } ) ;
break ;
case "atom" :
if ( ! this . is _js ) switch ( tok . value ) {
case "off" : case "no" :
ret = new Cola . AST _False ( { start : tok , end : tok } ) ;
break ;
case "on" : case "yes" :
ret = new Cola . AST _True ( { start : tok , end : tok } ) ;
break ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
switch ( tok . value ) {
case "false" :
ret = new Cola . AST _False ( { start : tok , end : tok } ) ;
break ;
case "true" :
ret = new Cola . AST _True ( { start : tok , end : tok } ) ;
break ;
case "null" :
ret = new Cola . AST _Null ( { start : tok , end : tok } ) ;
break ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
break ;
}
this . next ( ) ;
return ret ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . expr _atom = function ( allow _calls ) {
if ( this . is ( "operator" , "new" ) ) {
return this . new _ ( ) ;
}
2014-04-27 20:30:25 +00:00
var type , start = this . S . token ;
2014-04-16 18:39:27 +00:00
if ( this . is ( "punc" ) ) {
switch ( start . value ) {
case "(" :
2014-04-20 07:31:03 +00:00
if ( ! this . is _js ) {
var _this = this , balance = 1 , isfun = false ;
this . dumpS ( ) ;
this . next ( ) ;
this . next _until ( function ( ) {
if ( _this . is ( 'punc' , '(' ) ) balance ++ ;
else if ( _this . is ( 'punc' , ')' ) ) balance -- ;
return balance == 0 || _this . is ( 'eof' ) ;
} ) ;
2014-04-20 15:38:58 +00:00
isfun = ( this . next ( ) , ( this . is ( 'punc' , '{' ) || this . is ( 'punc' , '=>' ) ) ) ;
2014-04-20 07:31:03 +00:00
this . restoreS ( ) ;
if ( isfun ) return this . function _ ( Cola . AST _Function ) ;
}
2014-04-16 18:39:27 +00:00
this . next ( ) ;
var ex = this . expression ( true ) ;
2012-05-27 14:25:31 +00:00
ex . start = start ;
2014-04-16 18:39:27 +00:00
ex . end = this . S . token ;
this . expect ( ")" ) ;
return this . subscripts ( ex , allow _calls ) ;
case "[" :
return this . subscripts ( this . array _ ( ) , allow _calls ) ;
case "{" :
return this . subscripts ( this . object _ ( ) , allow _calls ) ;
2012-05-27 11:09:01 +00:00
}
2014-04-16 18:39:27 +00:00
this . unexpected ( ) ;
}
2014-04-27 20:30:25 +00:00
if ( ! this . is _js && this . is ( "name" ) ) {
2014-05-16 12:27:51 +00:00
if ( this . next _is ( "name" ) ) {
2014-04-27 20:30:25 +00:00
type = this . S . token . value , this . next ( ) ;
return this . function _ ( Cola . AST _Defun , type ) ;
}
var _this = this , balance = 1 , isfun = false ;
this . dumpS ( ) ;
this . next ( ) ;
if ( this . is ( 'punc' , '(' ) ) {
this . next ( ) ;
this . next _until ( function ( ) {
if ( _this . is ( 'punc' , '(' ) ) balance ++ ;
else if ( _this . is ( 'punc' , ')' ) ) balance -- ;
return balance == 0 || _this . is ( 'eof' ) ;
} ) ;
isfun = ( this . next ( ) , ( this . is ( 'punc' , '{' ) || this . is ( 'punc' , '=>' ) ) ) ;
}
this . restoreS ( ) ;
if ( isfun ) return this . function _ ( Cola . AST _Defun ) ;
}
2014-04-16 18:39:27 +00:00
if ( this . is ( "keyword" , "function" ) ) {
this . next ( ) ;
var func = this . function _ ( Cola . AST _Function ) ;
func . start = start ;
func . end = this . prev ( ) ;
return this . subscripts ( func , allow _calls ) ;
}
2014-05-21 18:01:32 +00:00
if ( this . is ( "keyword" , "if" ) && ! this . is _js ) {
this . next ( ) ;
var f = this . if _ ( true ) , s = f ;
/ * w h i l e ( t r u e ) {
if ( s . body instanceof Cola . AST _BlockStatement && s . body . body . length != 1 ||
! ( s . body instanceof Cola . AST _BlockStatement ) && ! ( s . body instanceof Cola . AST _SimpleStatement ) ) this . unexpected ( s . body . start ) ;
if ( s . alternative instanceof Cola . AST _If ) s = f ;
else if ( s . alternative == null ) break ;
else {
if ( s . alternative instanceof Cola . AST _BlockStatement && s . alternative . body . length != 1 ||
! ( s . alternative instanceof Cola . AST _BlockStatement ) && ! ( s . alternative instanceof Cola . AST _SimpleStatement ) ) this . unexpected ( s . alternative . start ) ;
break ;
}
} * /
return f ;
}
2014-05-19 09:58:17 +00:00
if ( this . is ( "keyword" , "switch" ) && ! this . is _js ) {
this . next ( ) ;
var swtch = {
start : start ,
expression : this . is ( 'punc' , '{' ) ? new Cola . AST _Noop ( ) : this . parenthesised ( ) ,
body : this . in _loop ( this . switch _body _ ) ,
end : this . prev ( )
} , _this = this ;
swtch . body . forEach ( function ( branch ) {
2014-05-21 18:01:32 +00:00
if ( branch . body . length != 1 || ! ( branch . body [ 0 ] instanceof Cola . AST _SimpleStatement ) ) _this . unexpected ( branch . start ) ;
2014-05-19 09:58:17 +00:00
} ) ;
2014-05-19 17:29:01 +00:00
2014-05-19 09:58:17 +00:00
return new Cola . AST _Switch ( swtch ) ;
}
2014-04-16 18:39:27 +00:00
if ( Cola . ATOMIC _START _TOKEN [ this . S . token . type ] ) {
return this . subscripts ( this . as _atom _node ( ) , allow _calls ) ;
}
this . unexpected ( ) ;
} ;
2014-04-27 20:30:25 +00:00
Cola . Parser . prototype . expr _list = function ( closing , allow _trailing _comma , allow _empty , allow _named _args ) {
var first = true , a = [ ] , name ;
2014-04-16 18:39:27 +00:00
while ( ! this . is ( "punc" , closing ) ) {
if ( first ) first = false ; else this . expect ( "," ) ;
if ( allow _trailing _comma && this . is ( "punc" , closing ) ) break ;
if ( this . is ( "punc" , "," ) && allow _empty ) {
a . push ( new Cola . AST _Hole ( { start : this . S . token , end : this . S . token } ) ) ;
2014-04-27 20:30:25 +00:00
} else
if ( this . is ( "name" ) && allow _named _args ) {
name = Cola . $ _cola _clone ( this . S . token ) ;
this . dumpS ( ) ;
this . next ( ) ;
if ( this . is ( "punc" , ":" ) ) {
this . next ( ) ;
a . push ( new Cola . AST _Namedarg ( {
name : name . value ,
value : this . expression ( false ) ,
start : name ,
end : this . prev ( )
} ) ) ;
} else {
this . restoreS ( ) ;
a . push ( this . expression ( false ) )
}
} else a . push ( this . expression ( false ) ) ;
2014-04-16 18:39:27 +00:00
}
this . next ( ) ;
return a ;
} ;
2012-05-27 11:09:01 +00:00
2014-05-16 12:27:51 +00:00
Cola . Parser . prototype . array _ = Cola . Parser . embed _tokens ( function ( is _template , is _var ) {
2014-04-16 18:39:27 +00:00
this . expect ( "[" ) ;
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && ! this . is ( "punc" , "]" ) && ! this . is ( "punc" , "," ) && ! ( this . is ( "name" ) && this . next _is ( "name" ) ) ) {
2014-04-22 13:33:43 +00:00
this . dumpS ( ) ;
2014-05-16 12:27:51 +00:00
var tmp , from = this . expression ( false , false , true ) , triple ;
if ( ( this . is ( "punc" , ".." ) || this . is ( "punc" , "..." ) ) && ! this . next _is ( "punc" , "," ) && ! this . next _is ( "punc" , "]" ) ) {
triple = this . is ( "punc" , "..." ) ;
2014-04-22 13:33:43 +00:00
this . next ( ) ;
return new Cola . AST _ArrayRange ( {
2014-05-16 12:27:51 +00:00
from : from ,
to : ( tmp = this . expression ( true , false , true ) , this . expect ( "]" ) , tmp ) ,
triple : triple ,
start : from . start ,
end : this . prev ( )
2014-04-22 13:33:43 +00:00
} ) ;
}
this . restoreS ( ) ;
}
2014-05-16 12:27:51 +00:00
if ( this . is _js ) return new Cola . AST _Array ( {
2014-04-16 18:39:27 +00:00
elements : this . expr _list ( "]" , ! this . options . strict , true )
} ) ;
2014-05-16 12:27:51 +00:00
var is _array = ( is _template ? false : null ) , vardef = false , first = true , a = [ ] , val , skiped = false ;
while ( ! this . is ( "punc" , "]" ) ) {
if ( first ) first = false ; else this . expect ( "," ) ;
if ( this . is ( "punc" , "," ) || this . is ( "punc" , "]" ) ) {
a . push ( new Cola . AST _Hole ( { start : this . S . token , end : this . S . token } ) ) ;
if ( ! this . options . strict && this . is ( "punc" , "]" ) ) break ;
} else
if ( this . is ( "punc" , "..." ) && is _array !== true ) {
if ( skiped ) this . unexpected ( ) ;
this . next ( ) ;
skiped = true ;
is _array = false ;
a . push ( new Cola . AST _Noop ( ) ) ;
} else
if ( ! is _var && this . is ( "name" ) && this . next _is ( "name" ) && ! Cola . cKEYWORDS ( this . peek ( ) . value ) ) {
if ( is _array === true ) this . unexpected ( ) ;
is _array = false ;
vardef = true ;
a . push ( new Cola . AST _VarDef ( {
start : this . S . token ,
type : this . S . token . value ,
name : ( function ( _this ) {
_this . next ( ) ;
val = _this . as _symbol ( Cola . AST _SymbolVar ) ;
if ( _this . is ( "punc" , "..." ) && is _array !== true ) {
if ( skiped ) _this . unexpected ( ) ;
_this . next ( ) ;
skiped = true ;
is _array = false ;
val . splated = true ;
}
return val ;
} ) ( this ) ,
value : null ,
end : this . prev ( )
} ) )
} else {
if ( is _array === false && this . is ( "punc" , "[" ) ) val = this . array _ ( true , is _var ) ;
else if ( is _array === false && this . is ( "punc" , "{" ) ) val = this . object _ ( true , is _var ) ;
else val = this . expression ( false ) ;
if ( val . vardef ) vardef = true ;
if ( this . is ( "punc" , "..." ) && is _array !== true ) {
if ( skiped ) this . unexpected ( ) ;
this . next ( ) ;
skiped = true ;
is _array = false ;
val . splated = true ;
}
if ( val instanceof Cola . AST _ObjectTemplate || val instanceof Cola . AST _ArrayTemplate ) {
if ( is _array === true ) this . unexpected ( ) ;
is _array = false ;
}
if ( ! ( val instanceof Cola . AST _SymbolRef ||
val instanceof Cola . AST _ObjectTemplate || val instanceof Cola . AST _ArrayTemplate ||
! is _var && ( val instanceof Cola . AST _Dot || val instanceof Cola . AST _Sub ) ||
val instanceof Cola . AST _Object && val . template == true ||
val instanceof Cola . AST _Array && val . template == true ) ) {
if ( is _array === false ) this . unexpected ( ) ;
is _array = true ;
}
a . push ( val ) ;
}
}
this . next ( ) ;
return is _array === true || is _array === null
? new Cola . AST _Array ( { elements : a , template : is _array === null , vardef : vardef } )
: new Cola . AST _ArrayTemplate ( { elements : a , vardef : vardef } ) ;
2014-04-16 18:39:27 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2014-05-16 12:27:51 +00:00
Cola . Parser . prototype . object _ = Cola . Parser . embed _tokens ( function ( is _template , is _var ) {
2014-04-16 18:39:27 +00:00
this . expect ( "{" ) ;
2014-05-16 12:27:51 +00:00
var first = true , a = [ ] , ptype , is _object = ( is _template ? false : null ) , vardef = false , val ;
2014-04-16 18:39:27 +00:00
while ( ! this . is ( "punc" , "}" ) ) {
if ( first ) first = false ; else this . expect ( "," ) ;
if ( ! this . options . strict && this . is ( "punc" , "}" ) )
// allow trailing comma
break ;
var start = this . S . token ;
var type = start . type ;
var name = this . as _property _name ( ) ;
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && ! is _var && this . is ( "name" ) && ! this . next _is ( "punc" , "(" ) && ! Cola . cKEYWORDS ( name ) ) {
vardef = true ;
ptype = name ;
name = this . as _name ( ) ;
} else ptype = false ;
2014-04-16 18:39:27 +00:00
if ( type == "name" && ! this . is ( "punc" , ":" ) ) {
if ( name == "get" ) {
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && is _object === false ) this . unexpected ( ) ;
is _object = true ;
2014-04-16 18:39:27 +00:00
a . push ( new Cola . AST _ObjectGetter ( {
start : start ,
2014-05-16 12:27:51 +00:00
type : ptype ,
2014-04-16 18:39:27 +00:00
key : this . as _atom _node ( ) ,
value : this . function _ ( Cola . AST _Accessor ) ,
end : this . prev ( )
} ) ) ;
continue ;
}
if ( name == "set" ) {
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && is _object === false ) this . unexpected ( ) ;
is _object = true ;
2014-04-16 18:39:27 +00:00
a . push ( new Cola . AST _ObjectSetter ( {
start : start ,
2014-05-16 12:27:51 +00:00
type : ptype ,
2014-04-16 18:39:27 +00:00
key : this . as _atom _node ( ) ,
value : this . function _ ( Cola . AST _Accessor ) ,
end : this . prev ( )
} ) ) ;
continue ;
}
2012-05-27 11:09:01 +00:00
}
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && ! this . is ( "punc" , ":" ) ) {
2014-05-21 18:01:32 +00:00
//if (is_object === true) this.unexpected();
//is_object = false;
val = new Cola . AST _SymbolRef ( { name : name } ) ;
2014-05-16 12:27:51 +00:00
} else {
this . expect ( ":" ) ;
if ( is _object === false && this . is ( "punc" , "[" ) ) val = this . array _ ( true , is _var ) ;
else if ( is _object === false && this . is ( "punc" , "{" ) ) val = this . object _ ( true , is _var ) ;
else val = this . expression ( false ) ;
if ( ptype && ! ( val instanceof Cola . AST _SymbolRef ) ) this . unexpected ( val . start ) ;
if ( val . vardef ) vardef = true ;
if ( val instanceof Cola . AST _ObjectTemplate || val instanceof Cola . AST _ArrayTemplate ) {
if ( is _object === true || ptype ) this . unexpected ( ) ;
is _object = false ;
}
if ( ! ( val instanceof Cola . AST _SymbolRef ||
val instanceof Cola . AST _ObjectTemplate || val instanceof Cola . AST _ArrayTemplate ||
! is _var && ( val instanceof Cola . AST _Dot || val instanceof Cola . AST _Sub ) ||
val instanceof Cola . AST _Object && val . template == true ||
val instanceof Cola . AST _Array && val . template == true ) ) {
if ( is _object === false ) this . unexpected ( ) ;
is _object = true ;
}
}
2014-04-16 18:39:27 +00:00
a . push ( new Cola . AST _ObjectKeyVal ( {
start : start ,
2014-05-16 12:27:51 +00:00
type : ptype ,
2014-04-16 18:39:27 +00:00
key : name ,
2014-05-16 12:27:51 +00:00
value : val ,
2014-04-16 18:39:27 +00:00
end : this . prev ( )
} ) ) ;
}
this . next ( ) ;
2014-05-16 12:27:51 +00:00
return is _object === true || is _object === null
? new Cola . AST _Object ( { properties : a , template : is _object === null , vardef : vardef } )
: new Cola . AST _ObjectTemplate ( { properties : a , vardef : vardef } ) ;
2014-04-16 18:39:27 +00:00
} ) ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . as _property _name = function ( ) {
var tmp = this . S . token ;
this . next ( ) ;
switch ( tmp . type ) {
case "num" :
case "string" :
case "name" :
case "operator" :
case "keyword" :
case "atom" :
return tmp . value ;
default :
this . unexpected ( ) ;
}
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . as _name = function ( ) {
var tmp = this . S . token ;
this . next ( ) ;
switch ( tmp . type ) {
case "name" :
case "operator" :
case "keyword" :
case "atom" :
return tmp . value ;
default :
this . unexpected ( ) ;
}
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . _make _symbol = function ( type ) {
var name = this . S . token . value ;
return new ( name == "this" ? Cola . AST _This : type ) ( {
name : String ( name ) ,
start : this . S . token ,
end : this . S . token
} ) ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . as _symbol = function ( type , noerror ) {
if ( ! this . is ( "name" ) ) {
if ( ! noerror ) this . croak ( "Name expected" ) ;
return null ;
}
var sym = this . _make _symbol ( type ) ;
this . next ( ) ;
return sym ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . subscripts = function ( expr , allow _calls ) {
var start = expr . start ;
if ( this . is ( "punc" , "." ) ) {
this . next ( ) ;
return this . subscripts ( new Cola . AST _Dot ( {
start : start ,
expression : expr ,
property : this . as _name ( ) ,
end : this . prev ( )
} ) , allow _calls ) ;
}
if ( this . is ( "punc" , "[" ) ) {
this . next ( ) ;
2014-04-22 13:33:43 +00:00
2014-05-16 12:27:51 +00:00
var prop , triple ;
2014-04-22 13:33:43 +00:00
if ( this . is _js ) prop = this . expression ( true ) ;
else if ( this . is ( "punc" , "]" ) ) prop = new Cola . AST _Noop ( ) ;
else {
2014-05-16 12:27:51 +00:00
if ( this . is ( "punc" , ".." ) || this . is ( "punc" , "..." ) ) prop = new Cola . AST _Number ( { value : 0 } ) ;
else prop = this . expression ( true , false , true ) ;
2014-04-22 13:33:43 +00:00
this . dumpS ( ) ;
2014-05-16 12:27:51 +00:00
if ( this . is ( "punc" , ".." ) || this . is ( "punc" , "..." ) ) {
triple = this . is ( "punc" , "..." ) ;
2014-04-22 13:33:43 +00:00
this . next ( ) ;
prop = new Cola . AST _ArrayRange ( {
2014-05-16 12:27:51 +00:00
from : prop ,
to : ( this . is ( "punc" , "]" ) ? new Cola . AST _Noop ( ) : this . expression ( true , false , true ) ) ,
triple : triple ,
start : prop . start ,
end : this . prev ( )
2014-04-22 13:33:43 +00:00
} ) ;
} else this . restoreS ( ) ;
}
2014-04-16 18:39:27 +00:00
this . expect ( "]" ) ;
return this . subscripts ( new Cola . AST _Sub ( {
start : start ,
expression : expr ,
property : prop ,
end : this . prev ( )
} ) , allow _calls ) ;
}
if ( allow _calls && this . is ( "punc" , "(" ) ) {
this . next ( ) ;
return this . subscripts ( new Cola . AST _Call ( {
start : start ,
expression : expr ,
2014-04-27 20:30:25 +00:00
args : this . expr _list ( ")" , false , false , ! this . is _js ) ,
2014-04-16 18:39:27 +00:00
end : this . prev ( )
} ) , true ) ;
}
return expr ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . maybe _unary = function ( allow _calls ) {
var start = this . S . token ;
2014-04-17 10:10:18 +00:00
if ( this . is ( "operator" ) && this . UNARY _PREFIX ( start . value ) ) {
2014-04-16 18:39:27 +00:00
this . next ( ) ;
this . handle _regexp ( ) ;
var ex = this . make _unary ( Cola . AST _UnaryPrefix , start . value , this . maybe _unary ( allow _calls ) ) ;
ex . start = start ;
ex . end = this . prev ( ) ;
return ex ;
}
var val = this . expr _atom ( allow _calls ) ;
2014-04-18 18:27:47 +00:00
while ( this . is ( "operator" ) && this . UNARY _POSTFIX ( this . S . token . value ) && ! this . S . token . nlb ) {
2014-04-16 18:39:27 +00:00
val = this . make _unary ( Cola . AST _UnaryPostfix , this . S . token . value , val ) ;
val . start = start ;
val . end = this . S . token ;
this . next ( ) ;
}
return val ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . make _unary = function ( ctor , op , expr ) {
if ( ( op == "++" || op == "--" ) && ! this . is _assignable ( expr ) )
this . croak ( "Invalid use of " + op + " operator" ) ;
return new ctor ( { operator : op , expression : expr } ) ;
} ;
2014-05-16 12:27:51 +00:00
/ *
a <= b < c == d
as
( ( ( a <= b ) && ( b < c ) ) && c == d )
* /
Cola . Parser . prototype . expr _op = function ( left , min _prec , no _in , is _comp , rightest ) {
var op = this . is ( "operator" ) ? this . S . token . value : null , cop = Cola . COMPARISON ( op ) ;
2014-04-16 18:39:27 +00:00
if ( op == "in" && no _in ) op = null ;
2014-04-17 10:10:18 +00:00
var prec = op != null ? this . PRECEDENCE [ op ] : null ;
2014-05-16 12:27:51 +00:00
if ( ! this . is _js && is _comp && cop ) {
this . next ( ) ;
var right = this . maybe _unary ( true ) ;
return this . expr _op ( new Cola . AST _Binary ( {
start : left . start ,
left : left ,
operator : "&&" ,
right : new Cola . AST _Binary ( {
start : rightest . start ,
left : rightest ,
operator : op ,
right : right ,
end : right . end
} ) ,
end : right . end
} ) , min _prec , no _in , true , right ) ;
}
2014-04-16 18:39:27 +00:00
if ( prec != null && prec > min _prec ) {
this . next ( ) ;
2014-05-16 12:27:51 +00:00
var right = ! this . is _js && cop ? this . maybe _unary ( true ) : this . expr _op ( this . maybe _unary ( true ) , prec , no _in ) ;
2014-04-16 18:39:27 +00:00
return this . expr _op ( new Cola . AST _Binary ( {
start : left . start ,
left : left ,
operator : op ,
right : right ,
end : right . end
2014-05-16 12:27:51 +00:00
} ) , min _prec , no _in , cop , right ) ;
2013-05-15 10:27:23 +00:00
}
2014-04-16 18:39:27 +00:00
return left ;
} ;
2013-05-15 10:27:23 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . expr _ops = function ( no _in ) {
return this . expr _op ( this . maybe _unary ( true ) , 0 , no _in ) ;
} ;
Cola . Parser . prototype . maybe _conditional = function ( no _in ) {
var start = this . S . token ;
var expr = this . expr _ops ( no _in ) ;
if ( this . is ( "operator" , "?" ) ) {
this . next ( ) ;
var yes = this . expression ( false ) ;
2014-04-18 18:27:47 +00:00
2014-04-16 18:39:27 +00:00
return new Cola . AST _Conditional ( {
start : start ,
condition : expr ,
consequent : yes ,
2014-04-18 18:27:47 +00:00
alternative : this . is _js || this . is ( 'punc' , ':' ) ? ( this . expect ( ":" ) , this . expression ( false , no _in ) ) : new Cola . AST _Noop ( ) ,
2014-04-16 18:39:27 +00:00
end : this . prev ( )
} ) ;
}
return expr ;
} ;
Cola . Parser . prototype . is _assignable = function ( expr ) {
if ( ! this . options . strict ) return true ;
if ( expr instanceof Cola . AST _This ) return false ;
return ( expr instanceof Cola . AST _PropAccess || expr instanceof Cola . AST _Symbol ) ;
} ;
Cola . Parser . prototype . maybe _assign = function ( no _in ) {
var start = this . S . token ;
var left = this . maybe _conditional ( no _in ) , val = this . S . token . value ;
2014-04-17 10:10:18 +00:00
if ( this . is ( "operator" ) && this . ASSIGNMENT ( val ) ) {
2014-04-16 18:39:27 +00:00
if ( this . is _assignable ( left ) ) {
this . next ( ) ;
return new Cola . AST _Assign ( {
start : start ,
left : left ,
operator : val ,
right : this . maybe _assign ( no _in ) ,
end : this . prev ( )
} ) ;
2012-09-21 11:19:05 +00:00
}
2014-04-16 18:39:27 +00:00
this . croak ( "Invalid assignment" ) ;
}
return left ;
} ;
2014-05-03 11:40:47 +00:00
Cola . Parser . prototype . cascade = function ( expr , start ) {
var last , props = {
start : start ,
expression : expr ,
subexpressions : [ ]
} ;
while ( this . next ( ) ) {
if ( this . is ( "name" ) || this . is ( "punc" , "[" ) ) {
last = this . expression ( false , false , true ) ;
if ( this . is ( "punc" , ":" ) ) {
last = this . cascade ( last , last . start ) ;
this . next ( ) ;
}
props . subexpressions . push ( last ) ;
if ( ! ( last instanceof Cola . AST _SymbolRef
|| last instanceof Cola . AST _Binary
|| last instanceof Cola . AST _Call
|| last instanceof Cola . AST _Sub
|| last instanceof Cola . AST _Dot
|| last instanceof Cola . AST _Array
|| last instanceof Cola . AST _Cascade
) ) this . unexpected ( ) ;
}
if ( ! this . is ( "punc" , ".." ) ) break ;
}
props . end = this . S . token ;
return new Cola . AST _Cascade ( props ) ;
} ;
Cola . Parser . prototype . expression = function ( commas , no _in , in _dd ) {
2014-04-16 18:39:27 +00:00
var start = this . S . token ;
var expr = this . maybe _assign ( no _in ) ;
2014-05-03 11:40:47 +00:00
if ( ! in _dd && ! this . is _js && this . is ( "punc" , ".." ) ) return this . cascade ( expr , start ) ;
2014-04-16 18:39:27 +00:00
if ( commas && this . is ( "punc" , "," ) ) {
2014-05-16 12:27:51 +00:00
if ( expr instanceof Cola . AST _Assign && ( expr . left instanceof Cola . AST _ArrayTemplate || expr . left instanceof Cola . AST _ObjectTemplate ||
( expr . left instanceof Cola . AST _Array || expr . left instanceof Cola . AST _Object ) && expr . left . template ) && expr . left . vardef ) this . unexpected ( ) ;
2014-04-16 18:39:27 +00:00
this . next ( ) ;
return new Cola . AST _Seq ( {
start : start ,
car : expr ,
cdr : this . expression ( true , no _in ) ,
end : this . peek ( )
} ) ;
}
return expr ;
} ;
2012-05-27 11:09:01 +00:00
2014-04-16 18:39:27 +00:00
Cola . Parser . prototype . in _loop = function ( cont ) {
++ this . S . in _loop ;
2014-05-19 09:58:17 +00:00
var ret = cont . call ( this ) ;
2014-04-16 18:39:27 +00:00
-- this . S . in _loop ;
return ret ;
2012-05-27 11:09:01 +00:00
} ;