From 34819e6a730ff060ac58744b90d0b89ab12c0c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 18 Nov 2012 10:06:16 -0800 Subject: [PATCH] Switch to using Mozilla's standardized AST model for PaperScript parsing though Acorn.js or Esprima.js and their support for ranges. No more AST mingling but direct code modification means we're finally getting accurate error messages! Sticking to Esprima for now since Acorn still has some issues with ranges: https://github.com/marijnh/acorn/issues/14 --- build/preprocess.sh | 2 +- lib/acorn-min.js | 2 +- lib/acorn.js | 16 +- lib/esprima-min.js | 36 + lib/esprima.js | 3809 +++++++++++++++++++++++++++++++++++++++ src/core/PaperScript.js | 193 +- 6 files changed, 3981 insertions(+), 77 deletions(-) create mode 100644 lib/esprima-min.js create mode 100644 lib/esprima.js diff --git a/build/preprocess.sh b/build/preprocess.sh index 0d93ee07..6624a3bb 100755 --- a/build/preprocess.sh +++ b/build/preprocess.sh @@ -42,7 +42,7 @@ case $1 in ;; compressed) eval $COMMAND > temp.js - ../../uglifyjs/bin/uglifyjs temp.js --extra --unsafe --reserved-names "$eval,$sign" > $5 + ../../uglifyjs/bin/uglifyjs temp.js --extra --unsafe --reserved-names "_$_,$_" > $5 rm temp.js ;; esac diff --git a/lib/acorn-min.js b/lib/acorn-min.js index 0c9913f3..9bfae99e 100644 --- a/lib/acorn-min.js +++ b/lib/acorn-min.js @@ -12,4 +12,4 @@ // Please use the [github bug tracker][ghbt] to report issues. // // [ghbt]: https://github.com/marijnh/acorn/issues -(function(e){"use strict";function k(e,t){throw typeof e=="number"&&(e=o(n,e)),t+=" ("+e.line+":"+e.column+")",new SyntaxError(t)}function Mt(e){function s(e){if(e.length==1)return t+="return str === "+JSON.stringify(e[0])+";";t+="switch(str){";for(var n=0;n3){n.sort(function(e,t){return t.length-e.length}),t+="switch(str.length){";for(var r=0;r=170&&qt.test(String.fromCharCode(e))}function Xt(e){return e<48?e===36:e<58?!0:e<65?!1:e<91?!0:e<97?e===95:e<123?!0:e>=170&&Rt.test(String.fromCharCode(e))}function Vt(){zt.lastIndex=b;var e=zt.exec(n);return e?e.index+e[0].length:n.length+1}function $t(){while(w<=u)++y,b=w,w=Vt();return{line:y,column:u-b}}function Jt(){y=1,u=b=0,w=Vt(),m=!0,g=null,Yt()}function Kt(e,n){f=u,t.locations&&(c=$t()),h=e,Yt(),p=n,v=g,m=e.beforeExpr}function Qt(){var e=n.indexOf("*/",u+=2);e===-1&&k(u-2,"Unterminated comment"),t.trackComments&&(g||(g=[])).push(n.slice(u,e)),u=e+2}function Gt(){var e=u,t=n.charCodeAt(u+=2);while(u8)++u;else if(e===32||e===160)++u;else{if(!(e>=5760&&jt.test(String.fromCharCode(e))))break;++u}}}function Zt(e){a=u,t.locations&&(l=$t()),d=g;if(e)return tn();if(u>=r)return Kt(_);var i=n.charCodeAt(u);if(Wt(i)||i===92)return ln();var s=n.charCodeAt(u+1);switch(i){case 46:if(s>=48&&s<=57)return sn(String.fromCharCode(i));return++u,Kt(dt);case 40:return++u,Kt(ft);case 41:return++u,Kt(lt);case 59:return++u,Kt(ht);case 44:return++u,Kt(ct);case 91:return++u,Kt(st);case 93:return++u,Kt(ot);case 123:return++u,Kt(ut);case 125:return++u,Kt(at);case 58:return++u,Kt(pt);case 63:return++u,Kt(vt);case 48:if(s===120||s===88)return rn();case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return sn(String.fromCharCode(i));case 34:case 39:return on(i);case 47:if(m)return++u,tn();if(s===61)return en(yt,2);return en(mt,1);case 37:case 42:if(s===61)return en(yt,2);return en(Ot,1);case 124:case 38:if(s===i)return en(i===124?St:xt,2);if(s===61)return en(yt,2);return en(i===124?Tt:Ct,1);case 94:if(s===61)return en(yt,2);return en(Nt,1);case 43:case 45:if(s===i)return en(wt,2);if(s===61)return en(yt,2);return en(bt,1);case 60:case 62:var o=1;if(s===i)return o=i===62&&n.charCodeAt(u+2)===62?3:2,n.charCodeAt(u+o)===61?en(yt,o+1):en(At,o);return s===61&&(o=n.charCodeAt(u+2)===61?3:2),en(Lt,o);case 61:case 33:if(s===61)return en(kt,n.charCodeAt(u+2)===61?3:2);return en(i===61?gt:Et,1);case 126:return en(Et,1)}var f=String.fromCharCode(i);if(f==="\\"||qt.test(f))return ln();k(u,"Unexpected character '"+f+"'")}function en(e,t){var r=n.slice(u,u+t);u+=t,Kt(e,r)}function tn(){var e="",t,i,s=u;for(;;){u>=r&&k(s,"Unterminated regular expression");var o=n.charAt(u);Ut.test(o)&&k(s,"Unterminated regular expression");if(!t){if(o==="[")i=!0;else if(o==="]"&&i)i=!1;else if(o==="/"&&!i)break;t=o==="\\"}else t=!1;++u}var e=n.slice(s,u);++u;var a=fn();return a&&!/^[gmsiy]*$/.test(a)&&k(s,"Invalid regexp flag"),Kt(A,new RegExp(e,a))}function nn(e,t){var r=u,i=0;for(;;){var s=n.charCodeAt(u),o;s>=97?o=s-97+10:s>=65?o=s-65+10:s>=48&&s<=57?o=s-48:o=Infinity;if(o>=e)break;++u,i=i*e+o}return u===r||t!=null&&u-r!==t?null:i}function rn(){u+=2;var e=nn(16);return e==null&&k(a+2,"Expected hexadecimal number"),Wt(n.charCodeAt(u))&&k(u,"Identifier directly after number"),Kt(L,e)}function sn(e){var t=u,r=e===".";!r&&nn(10)==null&&k(t,"Invalid number");if(r||n.charAt(u)==="."){var i=n.charAt(++u);(i==="-"||i==="+")&&++u,nn(10)===null&&e==="."&&k(t,"Invalid number"),r=!0}if(/e/i.test(n.charAt(u))){var i=n.charAt(++u);(i==="-"||i==="+")&&++u,nn(10)===null&&k(t,"Invalid number"),r=!0}Wt(n.charCodeAt(u))&&k(u,"Identifier directly after number");var s=n.slice(t,u),o;return r?o=parseFloat(s):e!=="0"||s.length===1?o=parseInt(s,10):/[89]/.test(s)||C?k(t,"Invalid number"):o=parseInt(s,8),Kt(L,o)}function on(e){u++;var t=[];for(;;){u>=r&&k(a,"Unterminated string constant");var i=n.charCodeAt(u);if(i===e)return++u,Kt(O,String.fromCharCode.apply(null,t));if(i===92){i=n.charCodeAt(++u);var s=/^[0-7]+/.exec(n.slice(u,u+3));s&&(s=s[0]);while(s&&parseInt(s,8)>255)s=s.slice(0,s.length-1);s==="0"&&(s=null),++u;if(s)C&&k(u-2,"Octal literal in strict mode"),t.push(parseInt(s,8)),u+=s.length-1;else switch(i){case 110:t.push(10);break;case 114:t.push(13);break;case 120:t.push(un(2));break;case 117:t.push(un(4));break;case 85:t.push(un(8));break;case 116:t.push(9);break;case 98:t.push(8);break;case 118:t.push(11);break;case 102:t.push(12);break;case 48:t.push(0);break;case 13:n.charCodeAt(u)===10&&++u;case 10:break;default:t.push(i)}}else(i===13||i===10||i===8232||i===8329)&&k(a,"Unterminated string constant"),i!==92&&t.push(i),++u}}function un(e){var t=nn(16,e);return t===null&&k(a,"Bad character escape sequence"),t}function fn(){an=!1;var e,t=!0,r=u;for(;;){var i=n.charCodeAt(u);if(Xt(i))an&&(e+=n.charAt(u)),++u;else{if(i!==92)break;an||(e=n.slice(r,u)),an=!0,n.charCodeAt(++u)!=117&&k(u,"Expecting Unicode escape sequence \\uXXXX"),++u;var s=un(4),o=String.fromCharCode(s);o||k(u-1,"Invalid Unicode escape"),(t?!Wt(s):!Xt(s))&&k(u-4,"Invalid Unicode escape"),e+=o}t=!1}return an?e:n.slice(r,u)}function ln(){var e=fn(),n=M;return an||(Bt(e)?n=it[e]:(t.forbidReserved&&(t.ecmaVersion===3?_t:Dt)(e)||C&&Pt(e))&&k(a,"The keyword '"+e+"' is reserved")),Kt(n,e)}function cn(){E=a,S=f,x=c,Zt()}function hn(e){C=e,u=S,Yt(),Zt()}function pn(){var e={type:null,start:a,end:null};return t.trackComments&&d&&(e.commentsBefore=d,d=null),t.locations&&(e.loc={start:l,end:null,source:i}),t.ranges&&(e.range=[a,0]),e}function dn(e){var n={type:null,start:e.start};return e.commentsBefore&&(n.commentsBefore=e.commentsBefore,e.commentsBefore=null),t.locations&&(n.loc={start:e.loc.start,end:null,source:e.loc.source}),t.ranges&&(n.range=[e.range[0],0]),n}function mn(e,n){return e.type=n,e.end=S,t.trackComments&&(v?(e.commentsAfter=v,v=null):vn&&vn.end===S&&(e.commentsAfter=vn.commentsAfter,vn.commentsAfter=null),vn=e),t.locations&&(e.loc.end=x),t.ranges&&(e.range[1]=S),e}function gn(e){return t.ecmaVersion>=5&&e.type==="ExpressionStatement"&&e.expression.type==="Literal"&&e.expression.value==="use strict"}function yn(e){if(h===e)return cn(),!0}function bn(){return h===_||h===at||!t.strictSemicolons&&Ut.test(n.slice(S,a))}function wn(){!yn(ht)&&!bn()&&Sn()}function En(e){h===e?cn():Sn()}function Sn(){k(a,"Unexpected token")}function xn(e){e.type!=="Identifier"&&e.type!=="MemberExpression"&&k(e.start,"Assigning to rvalue"),C&&e.type==="Identifier"&&Ht(e.name)&&k(e.start,"Assigning to "+e.name+" in strict mode")}function Tn(e){Jt(),E=S=u,t.locations&&(x=$t()),T=C=null,N=[],Zt();var n=e||pn(),r=!0;e||(n.body=[]);while(h!==_){var i=kn();n.body.push(i),r&&gn(i)&&hn(!0),r=!1}return mn(n,"Program")}function kn(){h===mt&&Zt(!0);var e=h,t=pn();switch(e){case D:case B:cn();var r=e===D;yn(ht)||bn()?t.label=null:h!==M?Sn():(t.label=$n(),wn());for(var i=0;it){var i=dn(e);i.left=e,i.operator=p,cn(),i.right=jn(Fn(n),r,n);var i=mn(i,/&&|\|\|/.test(i.operator)?"LogicalExpression":"BinaryExpression");return jn(i,t,n)}return e}function Fn(e){if(h.prefix){var t=pn(),n=h.isUpdate;return t.operator=p,t.prefix=!0,cn(),t.argument=Fn(e),n?xn(t.argument):C&&t.operator==="delete"&&t.argument.type==="Identifier"&&k(t.start,"Deleting local variable in strict mode"),mn(t,n?"UpdateExpression":"UnaryExpression")}var r=In();while(h.postfix&&!bn()){var t=dn(r);t.operator=p,t.prefix=!1,t.argument=r,xn(r),cn(),r=mn(t,"UpdateExpression")}return r}function In(){return qn(Rn())}function qn(e,t){if(yn(dt)){var n=dn(e);return n.object=e,n.property=$n(!0),n.computed=!1,qn(mn(n,"MemberExpression"),t)}if(yn(st)){var n=dn(e);return n.object=e,n.property=Dn(),n.computed=!0,En(ot),qn(mn(n,"MemberExpression"),t)}if(!t&&yn(ft)){var n=dn(e);return n.callee=e,n.arguments=Vn(lt,!1),qn(mn(n,"CallExpression"),t)}return e}function Rn(){switch(h){case Z:var e=pn();return cn(),mn(e,"ThisExpression");case M:return $n();case L:case O:case A:var e=pn();return e.value=p,cn(),mn(e,"Literal");case et:case tt:case nt:var e=pn();return e.value=h.atomValue,cn(),mn(e,"Literal");case ft:cn();var t=Dn();return En(lt),t;case st:var e=pn();return cn(),e.elements=Vn(ot,!0,!0),mn(e,"ArrayExpression");case ut:return zn();case z:var e=pn();return cn(),Xn(e,!1);case Y:return Un();default:Sn()}}function Un(){var e=pn();return cn(),e.callee=qn(Rn(!1),!0),yn(ft)?e.arguments=Vn(lt,!1):e.arguments=[],mn(e,"NewExpression")}function zn(){var e=pn(),n=!0,r=!1;e.properties=[],cn();while(!yn(at)){if(!n){En(ct);if(t.allowTrailingCommas&&yn(at))break}else n=!1;var i={key:Wn()},s=!1,o;yn(pt)?(i.value=Dn(!0),o=i.kind="init"):t.ecmaVersion>=5&&i.key.type==="Identifier"&&(i.key.name==="get"||i.key.name==="set")?(s=r=!0,o=i.kind=i.key.name,i.key=Wn(),!h===ft&&Sn(),i.value=Xn(pn(),!1)):Sn();if(i.key.type==="Identifier"&&(C||r))for(var u=0;u=0)for(var u=0;u3){n.sort(function(e,t){return t.length-e.length}),t+="switch(str.length){";for(var r=0;r=170&&qt.test(String.fromCharCode(e))}function Xt(e){return e<48?e===36:e<58?!0:e<65?!1:e<91?!0:e<97?e===95:e<123?!0:e>=170&&Rt.test(String.fromCharCode(e))}function Vt(){zt.lastIndex=b;var e=zt.exec(n);return e?e.index+e[0].length:n.length+1}function $t(){while(w<=u)++y,b=w,w=Vt();return{line:y,column:u-b}}function Jt(){y=1,u=b=0,w=Vt(),m=!0,g=null,Yt()}function Kt(e,n){f=u,t.locations&&(c=$t()),h=e,Yt(),p=n,v=g,m=e.beforeExpr}function Qt(){var e=n.indexOf("*/",u+=2);e===-1&&k(u-2,"Unterminated comment"),t.trackComments&&(g||(g=[])).push(n.slice(u,e)),u=e+2}function Gt(){var e=u,i=n.charCodeAt(u+=2);while(u8)++u;else if(e===32||e===160)++u;else{if(!(e>=5760&&jt.test(String.fromCharCode(e))))break;++u}}}function Zt(e){a=u,t.locations&&(l=$t()),d=g;if(e)return tn();if(u>=r)return Kt(_);var i=n.charCodeAt(u);if(Wt(i)||i===92)return ln();var s=n.charCodeAt(u+1);switch(i){case 46:if(s>=48&&s<=57)return sn(String.fromCharCode(i));return++u,Kt(dt);case 40:return++u,Kt(ft);case 41:return++u,Kt(lt);case 59:return++u,Kt(ht);case 44:return++u,Kt(ct);case 91:return++u,Kt(st);case 93:return++u,Kt(ot);case 123:return++u,Kt(ut);case 125:return++u,Kt(at);case 58:return++u,Kt(pt);case 63:return++u,Kt(vt);case 48:if(s===120||s===88)return rn();case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return sn(String.fromCharCode(i));case 34:case 39:return on(i);case 47:if(m)return++u,tn();if(s===61)return en(yt,2);return en(mt,1);case 37:case 42:if(s===61)return en(yt,2);return en(Ot,1);case 124:case 38:if(s===i)return en(i===124?St:xt,2);if(s===61)return en(yt,2);return en(i===124?Tt:Ct,1);case 94:if(s===61)return en(yt,2);return en(Nt,1);case 43:case 45:if(s===i)return en(wt,2);if(s===61)return en(yt,2);return en(bt,1);case 60:case 62:var o=1;if(s===i)return o=i===62&&n.charCodeAt(u+2)===62?3:2,n.charCodeAt(u+o)===61?en(yt,o+1):en(At,o);return s===61&&(o=n.charCodeAt(u+2)===61?3:2),en(Lt,o);case 61:case 33:if(s===61)return en(kt,n.charCodeAt(u+2)===61?3:2);return en(i===61?gt:Et,1);case 126:return en(Et,1)}var f=String.fromCharCode(i);if(f==="\\"||qt.test(f))return ln();k(u,"Unexpected character '"+f+"'")}function en(e,t){var r=n.slice(u,u+t);u+=t,Kt(e,r)}function tn(){var e="",t,i,s=u;for(;;){u>=r&&k(s,"Unterminated regular expression");var o=n.charAt(u);Ut.test(o)&&k(s,"Unterminated regular expression");if(!t){if(o==="[")i=!0;else if(o==="]"&&i)i=!1;else if(o==="/"&&!i)break;t=o==="\\"}else t=!1;++u}var e=n.slice(s,u);++u;var a=fn();return a&&!/^[gmsiy]*$/.test(a)&&k(s,"Invalid regexp flag"),Kt(A,new RegExp(e,a))}function nn(e,t){var r=u,i=0;for(;;){var s=n.charCodeAt(u),o;s>=97?o=s-97+10:s>=65?o=s-65+10:s>=48&&s<=57?o=s-48:o=Infinity;if(o>=e)break;++u,i=i*e+o}return u===r||t!=null&&u-r!==t?null:i}function rn(){u+=2;var e=nn(16);return e==null&&k(a+2,"Expected hexadecimal number"),Wt(n.charCodeAt(u))&&k(u,"Identifier directly after number"),Kt(L,e)}function sn(e){var t=u,r=e===".";!r&&nn(10)==null&&k(t,"Invalid number");if(r||n.charAt(u)==="."){var i=n.charAt(++u);(i==="-"||i==="+")&&++u,nn(10)===null&&e==="."&&k(t,"Invalid number"),r=!0}if(/e/i.test(n.charAt(u))){var i=n.charAt(++u);(i==="-"||i==="+")&&++u,nn(10)===null&&k(t,"Invalid number"),r=!0}Wt(n.charCodeAt(u))&&k(u,"Identifier directly after number");var s=n.slice(t,u),o;return r?o=parseFloat(s):e!=="0"||s.length===1?o=parseInt(s,10):/[89]/.test(s)||C?k(t,"Invalid number"):o=parseInt(s,8),Kt(L,o)}function on(e){u++;var t=[];for(;;){u>=r&&k(a,"Unterminated string constant");var i=n.charCodeAt(u);if(i===e)return++u,Kt(O,String.fromCharCode.apply(null,t));if(i===92){i=n.charCodeAt(++u);var s=/^[0-7]+/.exec(n.slice(u,u+3));s&&(s=s[0]);while(s&&parseInt(s,8)>255)s=s.slice(0,s.length-1);s==="0"&&(s=null),++u;if(s)C&&k(u-2,"Octal literal in strict mode"),t.push(parseInt(s,8)),u+=s.length-1;else switch(i){case 110:t.push(10);break;case 114:t.push(13);break;case 120:t.push(un(2));break;case 117:t.push(un(4));break;case 85:t.push(un(8));break;case 116:t.push(9);break;case 98:t.push(8);break;case 118:t.push(11);break;case 102:t.push(12);break;case 48:t.push(0);break;case 13:n.charCodeAt(u)===10&&++u;case 10:break;default:t.push(i)}}else(i===13||i===10||i===8232||i===8329)&&k(a,"Unterminated string constant"),i!==92&&t.push(i),++u}}function un(e){var t=nn(16,e);return t===null&&k(a,"Bad character escape sequence"),t}function fn(){an=!1;var e,t=!0,r=u;for(;;){var i=n.charCodeAt(u);if(Xt(i))an&&(e+=n.charAt(u)),++u;else{if(i!==92)break;an||(e=n.slice(r,u)),an=!0,n.charCodeAt(++u)!=117&&k(u,"Expecting Unicode escape sequence \\uXXXX"),++u;var s=un(4),o=String.fromCharCode(s);o||k(u-1,"Invalid Unicode escape"),(t?!Wt(s):!Xt(s))&&k(u-4,"Invalid Unicode escape"),e+=o}t=!1}return an?e:n.slice(r,u)}function ln(){var e=fn(),n=M;return an||(Bt(e)?n=it[e]:(t.forbidReserved&&(t.ecmaVersion===3?_t:Dt)(e)||C&&Pt(e))&&k(a,"The keyword '"+e+"' is reserved")),Kt(n,e)}function cn(){E=a,S=f,x=c,Zt()}function hn(e){C=e,u=S,Yt(),Zt()}function pn(){var e={type:null,start:a,end:null};return t.trackComments&&d&&(e.commentsBefore=d,d=null),t.locations&&(e.loc={start:l,end:null,source:i}),t.ranges&&(e.range=[a,0]),e}function dn(e){var n={type:null,start:e.start};return e.commentsBefore&&(n.commentsBefore=e.commentsBefore,e.commentsBefore=null),t.locations&&(n.loc={start:e.loc.start,end:null,source:e.loc.source}),t.ranges&&(n.range=[e.range[0],0]),n}function mn(e,n){return e.type=n,e.end=S,t.trackComments&&(v?(e.commentsAfter=v,v=null):vn&&vn.end===S&&vn.commentsAfter&&(e.commentsAfter=vn.commentsAfter,vn.commentsAfter=null),vn=e),t.locations&&(e.loc.end=x),t.ranges&&(e.range[1]=S),e}function gn(e){return t.ecmaVersion>=5&&e.type==="ExpressionStatement"&&e.expression.type==="Literal"&&e.expression.value==="use strict"}function yn(e){if(h===e)return cn(),!0}function bn(){return!t.strictSemicolons&&(h===_||h===at||Ut.test(n.slice(S,a)))}function wn(){!yn(ht)&&!bn()&&Sn()}function En(e){h===e?cn():Sn()}function Sn(){k(a,"Unexpected token")}function xn(e){e.type!=="Identifier"&&e.type!=="MemberExpression"&&k(e.start,"Assigning to rvalue"),C&&e.type==="Identifier"&&Ht(e.name)&&k(e.start,"Assigning to "+e.name+" in strict mode")}function Tn(e){Jt(),E=S=u,t.locations&&(x=$t()),T=C=null,N=[],Zt();var n=e||pn(),r=!0;e||(n.body=[]);while(h!==_){var i=kn();n.body.push(i),r&&gn(i)&&hn(!0),r=!1}return mn(n,"Program")}function kn(){h===mt&&Zt(!0);var e=h,t=pn();switch(e){case D:case B:cn();var r=e===D;yn(ht)||bn()?t.label=null:h!==M?Sn():(t.label=$n(),wn());for(var i=0;it){var i=dn(e);i.left=e,i.operator=p,cn(),i.right=jn(Fn(n),r,n);var i=mn(i,/&&|\|\|/.test(i.operator)?"LogicalExpression":"BinaryExpression");return jn(i,t,n)}return e}function Fn(e){if(h.prefix){var t=pn(),n=h.isUpdate;return t.operator=p,t.prefix=!0,cn(),t.argument=Fn(e),n?xn(t.argument):C&&t.operator==="delete"&&t.argument.type==="Identifier"&&k(t.start,"Deleting local variable in strict mode"),mn(t,n?"UpdateExpression":"UnaryExpression")}var r=In();while(h.postfix&&!bn()){var t=dn(r);t.operator=p,t.prefix=!1,t.argument=r,xn(r),cn(),r=mn(t,"UpdateExpression")}return r}function In(){return qn(Rn())}function qn(e,t){if(yn(dt)){var n=dn(e);return n.object=e,n.property=$n(!0),n.computed=!1,qn(mn(n,"MemberExpression"),t)}if(yn(st)){var n=dn(e);return n.object=e,n.property=Dn(),n.computed=!0,En(ot),qn(mn(n,"MemberExpression"),t)}if(!t&&yn(ft)){var n=dn(e);return n.callee=e,n.arguments=Vn(lt,!1),qn(mn(n,"CallExpression"),t)}return e}function Rn(){switch(h){case Z:var e=pn();return cn(),mn(e,"ThisExpression");case M:return $n();case L:case O:case A:var e=pn();return e.value=p,e.raw=n.slice(a,f),cn(),mn(e,"Literal");case et:case tt:case nt:var e=pn();return e.value=h.atomValue,cn(),mn(e,"Literal");case ft:cn();var t=Dn();return En(lt),t;case st:var e=pn();return cn(),e.elements=Vn(ot,!0,!0),mn(e,"ArrayExpression");case ut:return zn();case z:var e=pn();return cn(),Xn(e,!1);case Y:return Un();default:Sn()}}function Un(){var e=pn();return cn(),e.callee=qn(Rn(!1),!0),yn(ft)?e.arguments=Vn(lt,!1):e.arguments=[],mn(e,"NewExpression")}function zn(){var e=pn(),n=!0,r=!1;e.properties=[],cn();while(!yn(at)){if(!n){En(ct);if(t.allowTrailingCommas&&yn(at))break}else n=!1;var i={key:Wn()},s=!1,o;yn(pt)?(i.value=Dn(!0),o=i.kind="init"):t.ecmaVersion>=5&&i.key.type==="Identifier"&&(i.key.name==="get"||i.key.name==="set")?(s=r=!0,o=i.kind=i.key.name,i.key=Wn(),!h===ft&&Sn(),i.value=Xn(pn(),!1)):Sn();if(i.key.type==="Identifier"&&(C||r))for(var u=0;u=0)for(var u=0;u + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + 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 HOLDERS AND CONTRIBUTORS "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 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. +*//*jslint bitwise:true plusplus:true *//*global esprima:true, define:true, exports:true, window: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, parseExpression: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseLeftHandSideExpression: true, +parseStatement: true, parseSourceElement: true */(function(e,t){"use strict";typeof define=="function"&&define.amd?define(["exports"],t):typeof exports!="undefined"?t(exports):t(e.esprima={})})(this,function(e){"use strict";function y(e,t){if(!e)throw new Error("ASSERT: "+t)}function b(e,t){return a.slice(e,t)}function w(e){return"0123456789".indexOf(e)>=0}function E(e){return"0123456789abcdefABCDEF".indexOf(e)>=0}function S(e){return"01234567".indexOf(e)>=0}function x(e){return e===" "||e===" "||e===" "||e==="\f"||e===" "||e.charCodeAt(0)>=5760&&" ᠎              ".indexOf(e)>=0}function T(e){return e==="\n"||e==="\r"||e==="\u2028"||e==="\u2029"}function N(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierStart.test(e)}function C(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e>="0"&&e<="9"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierPart.test(e)}function k(e){return["class","enum","export","extends","import","super"].indexOf(e)>=0}function L(e){return["implements","interface","package","private","protected","public","static","yield","let"].indexOf(e)>=0}function A(e){return e==="eval"||e==="arguments"}function O(e){if(f&&L(e))return!0;switch(e.length){case 2:return e==="if"||e==="in"||e==="do";case 3:return e==="var"||e==="for"||e==="new"||e==="try"||e==="let";case 4:return e==="this"||e==="else"||e==="case"||e==="void"||e==="with"||e==="enum";case 5:return e==="while"||e==="break"||e==="catch"||e==="throw"||e==="const"||e==="yield"||e==="class"||e==="super";case 6:return e==="return"||e==="typeof"||e==="delete"||e==="switch"||e==="export"||e==="import";case 7:return e==="default"||e==="finally"||e==="extends";case 8:return e==="function"||e==="continue"||e==="debugger";case 10:return e==="instanceof";default:return!1}}function M(){var e,t,n;t=!1,n=!1;while(l=p&&X({},s.UnexpectedToken,"ILLEGAL")):(e=a[l++],l>=p&&X({},s.UnexpectedToken,"ILLEGAL"),e==="*"&&(e=a[l],e==="/"&&(++l,t=!1)));else if(e==="/"){e=a[l+1];if(e==="/")l+=2,n=!0;else{if(e!=="*")break;l+=2,t=!0,l>=p&&X({},s.UnexpectedToken,"ILLEGAL")}}else if(x(e))++l;else{if(!T(e))break;++l,e==="\r"&&a[l]==="\n"&&++l,++c,h=l}}}function _(e){var t,n,r,i=0;n=e==="u"?4:2;for(t=0;t"&&r===">"&&i===">"&&o==="=")return l+=4,{type:t.Punctuator,value:">>>=",lineNumber:c,lineStart:h,range:[e,l]};if(n==="="&&r==="="&&i==="=")return l+=3,{type:t.Punctuator,value:"===",lineNumber:c,lineStart:h,range:[e,l]};if(n==="!"&&r==="="&&i==="=")return l+=3,{type:t.Punctuator,value:"!==",lineNumber:c,lineStart:h,range:[e,l]};if(n===">"&&r===">"&&i===">")return l+=3,{type:t.Punctuator,value:">>>",lineNumber:c,lineStart:h,range:[e,l]};if(n==="<"&&r==="<"&&i==="=")return l+=3,{type:t.Punctuator,value:"<<=",lineNumber:c,lineStart:h,range:[e,l]};if(n===">"&&r===">"&&i==="=")return l+=3,{type:t.Punctuator,value:">>=",lineNumber:c,lineStart:h,range:[e,l]};if(n===r&&"+-<>&|".indexOf(n)>=0&&"+-<>&|".indexOf(r)>=0)return l+=2,{type:t.Punctuator,value:n+r,lineNumber:c,lineStart:h,range:[e,l]};if("<>=!+-*%&|^/".indexOf(n)>=0)return++l,r==="="&&(++l,n+=r),{type:t.Punctuator,value:n,lineNumber:c,lineStart:h,range:[e,l]};X({},s.UnexpectedToken,"ILLEGAL")}function j(){var e,n,r;r=a[l],y(w(r)||r===".","Numeric literal must start with a decimal digit or a decimal point"),n=l,e="";if(r!=="."){e=a[l++],r=a[l];if(e==="0"){if(r==="x"||r==="X"){e+=a[l++];while(l=p&&(r=""),X({},s.UnexpectedToken,"ILLEGAL")}return l=0&&l=p?{type:t.EOF,lineNumber:c,lineStart:h,range:[l,l]}:(e=a[l],N(e)?H():e==="."?w(a[l+1])?j():B():e==="'"||e==='"'?F():w(e)?j():B())}function U(){var e;return e=v,l=e.range[1],c=e.lineNumber,h=e.lineStart,v=R(),l=e.range[1],c=e.lineNumber,h=e.lineStart,e}function z(){var e,t,n;e=l,t=c,n=h,v=R(),l=e,c=t,h=n}function W(){var e,t,n,r;return e=l,t=c,n=h,M(),r=c!==t,l=e,c=t,h=n,r}function X(e,t){var n,r=Array.prototype.slice.call(arguments,2),i=t.replace(/%(\d)/g,function(e,t){return r[t]||""});throw typeof e.lineNumber=="number"?(n=new Error("Line "+e.lineNumber+": "+i),n.index=e.range[0],n.lineNumber=e.lineNumber,n.column=e.range[0]-h+1):(n=new Error("Line "+c+": "+i),n.index=l,n.lineNumber=c,n.column=l-h+1),n}function V(){try{X.apply(null,arguments)}catch(e){if(!g.errors)throw e;g.errors.push(e)}}function $(e){e.type===t.EOF&&X(e,s.UnexpectedEOS),e.type===t.NumericLiteral&&X(e,s.UnexpectedNumber),e.type===t.StringLiteral&&X(e,s.UnexpectedString),e.type===t.Identifier&&X(e,s.UnexpectedIdentifier);if(e.type===t.Keyword){if(k(e.value))X(e,s.UnexpectedReserved);else if(f&&L(e.value)){V(e,s.StrictReservedWord);return}X(e,s.UnexpectedToken,e.value)}X(e,s.UnexpectedToken,e.value)}function J(e){var n=U();(n.type!==t.Punctuator||n.value!==e)&&$(n)}function K(e){var n=U();(n.type!==t.Keyword||n.value!==e)&&$(n)}function Q(e){return v.type===t.Punctuator&&v.value===e}function G(e){return v.type===t.Keyword&&v.value===e}function Y(){var e;return v.type!==t.Punctuator?!1:(e=v.value,e==="="||e==="*="||e==="/="||e==="%="||e==="+="||e==="-="||e==="<<="||e===">>="||e===">>>="||e==="&="||e==="^="||e==="|=")}function Z(){var e;if(a[l]===";"){U();return}e=c,M();if(c!==e)return;if(Q(";")){U();return}v.type!==t.EOF&&!Q("}")&&$(v)}function et(e){return e.type===r.Identifier||e.type===r.MemberExpression}function tt(){var e=[];J("[");while(!Q("]"))Q(",")?(U(),e.push(null)):(e.push(Et()),Q("]")||J(","));return J("]"),d.createArrayExpression(e)}function nt(e,t){var n,r;return n=f,r=Jt(),t&&f&&A(e[0].name)&&V(t,s.StrictParamName),f=n,d.createFunctionExpression(null,e,[],r)}function rt(){var e=U();return e.type===t.StringLiteral||e.type===t.NumericLiteral?(f&&e.octal&&V(e,s.StrictOctalLiteral),d.createLiteral(e)):d.createIdentifier(e.value)}function it(){var e,n,r,i,s;e=v;if(e.type===t.Identifier)return r=rt(),e.value==="get"&&!Q(":")?(n=rt(),J("("),J(")"),i=nt([]),d.createProperty("get",n,i)):e.value==="set"&&!Q(":")?(n=rt(),J("("),e=v,e.type!==t.Identifier&&$(U()),s=[Nt()],J(")"),i=nt(s,e),d.createProperty("set",n,i)):(J(":"),i=Et(),d.createProperty("init",r,i));if(e.type!==t.EOF&&e.type!==t.Punctuator)return n=rt(),J(":"),i=Et(),d.createProperty("init",n,i);$(e)}function st(){var e=[],t,n,o,u={},a=String;J("{");while(!Q("}"))t=it(),t.key.type===r.Identifier?n=t.key.name:n=a(t.key.value),o=t.kind==="init"?i.Data:t.kind==="get"?i.Get:i.Set,Object.prototype.hasOwnProperty.call(u,n)?(u[n]===i.Data?f&&o===i.Data?V({},s.StrictDuplicateProperty):o!==i.Data&&V({},s.AccessorDataProperty):o===i.Data?V({},s.AccessorDataProperty):u[n]&o&&V({},s.AccessorGetSet),u[n]|=o):u[n]=o,e.push(t),Q("}")||J(",");return J("}"),d.createObjectExpression(e)}function ot(){var e;return J("("),e=St(),J(")"),e}function ut(){var e,n;e=v.type;if(e===t.Identifier)return d.createIdentifier(U().value);if(e===t.StringLiteral||e===t.NumericLiteral)return f&&v.octal&&V(v,s.StrictOctalLiteral),d.createLiteral(U());if(e===t.Keyword){if(G("this"))return U(),d.createThisExpression();if(G("function"))return Gt()}return e===t.BooleanLiteral?(n=U(),n.value=n.value==="true",d.createLiteral(n)):e===t.NullLiteral?(n=U(),n.value=null,d.createLiteral(n)):Q("[")?tt():Q("{")?st():Q("(")?ot():Q("/")||Q("/=")?d.createLiteral(I()):$(U())}function at(){var e=[];J("(");if(!Q(")"))while(l":case"<=":case">=":case"instanceof":r=7;break;case"in":r=n?7:0;break;case"<<":case">>":case">>>":r=8;break;case"+":case"-":r=9;break;case"*":case"/":case"%":r=11;break;default:}return r}function yt(e){var t=e.pop(),n=e.pop().value,r=e.pop();n==="||"||n==="&&"?e.push(d.createLogicalExpression(n,r,t)):e.push(d.createBinaryExpression(n,r,t))}function bt(){var e,t,n,r,i;r=m.allowIn,m.allowIn=!0,e=mt(),t=v,n=gt(t,r);if(n===0)return e;t.prec=n,U(),i=[e,t,mt()];while((n=gt(v,r))>0){while(i.length>2&&n<=i[i.length-2].prec)yt(i);t=U(),t.prec=n,i.push(t),i.push(mt())}while(i.length>1)yt(i);return m.allowIn=r,i[0]}function wt(){var e,t,n,r;return e=bt(),Q("?")&&(U(),t=m.allowIn,m.allowIn=!0,n=Et(),m.allowIn=t,J(":"),r=Et(),e=d.createConditionalExpression(e,n,r)),e}function Et(){var e,t,n;return e=v,t=wt(),Y()?(et(t)||X({},s.InvalidLHSInAssignment),f&&t.type===r.Identifier&&A(t.name)&&V(e,s.StrictLHSAssignment),e=U(),n=Et(),d.createAssignmentExpression(e.value,t,n)):t}function St(){var e=Et();if(Q(",")){e=d.createSequenceExpression([e]);while(l0&&g.comments[g.comments.length-1].range[1]>n)return;g.comments.push({type:e,value:t,range:[n,r],loc:i})}function nn(){var e,t,n,r,i,o;e="",i=!1,o=!1;while(l=p?(o=!1,e+=t,n.end={line:c,column:p-h},tn("Line",e,r,p,n)):e+=t;else if(i)T(t)?(t==="\r"&&a[l+1]==="\n"?(++l,e+="\r\n"):e+=t,++c,++l,h=l,l>=p&&X({},s.UnexpectedToken,"ILLEGAL")):(t=a[l++],l>=p&&X({},s.UnexpectedToken,"ILLEGAL"),e+=t,t==="*"&&(t=a[l],t==="/"&&(e=e.substr(0,e.length-1),i=!1,++l,n.end={line:c,column:l-h},tn("Block",e,r,l,n),e="")));else if(t==="/"){t=a[l+1];if(t==="/")n={start:{line:c,column:l-h}},r=l,l+=2,o=!0,l>=p&&(n.end={line:c,column:l-h},o=!1,tn("Line",e,r,l,n));else{if(t!=="*")break;r=l,l+=2,i=!0,n={start:{line:c,column:l-h-2}},l>=p&&X({},s.UnexpectedToken,"ILLEGAL")}}else if(x(t))++l;else{if(!T(t))break;++l,t==="\r"&&a[l]==="\n"&&++l,++c,h=l}}}function rn(){var e,t,n,r=[];for(e=0;e0&&(r=g.tokens[g.tokens.length-1],r.range[0]===e&&r.type==="Punctuator"&&(r.value==="/"||r.value==="/=")&&g.tokens.pop()),g.tokens.push({type:"RegularExpression",value:n.literal,range:[e,l],loc:t}),n}function un(){var e,t,n,r=[];for(e=0;e0?1:0,h=0,p=a.length,v=null,m={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1},g={},typeof t!="undefined"&&(g.range=typeof t.range=="boolean"&&t.range,g.loc=typeof t.loc=="boolean"&&t.loc,typeof t.tokens=="boolean"&&t.tokens&&(g.tokens=[]),typeof t.comment=="boolean"&&t.comment&&(g.comments=[]),typeof t.tolerant=="boolean"&&t.tolerant&&(g.errors=[])),p>0&&typeof a[0]=="undefined"&&(e instanceof String&&(a=e.valueOf()),typeof a[0]=="undefined"&&(a=mn(e))),dn();try{n=en(),typeof g.comments!="undefined"&&(rn(),n.comments=g.comments),typeof g.tokens!="undefined"&&(un(),n.tokens=g.tokens),typeof g.errors!="undefined"&&(n.errors=g.errors);if(g.range||g.loc)n.body=hn(n.body)}catch(i){throw i}finally{vn(),g={}}return n}var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g;t={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},n={},n[t.BooleanLiteral]="Boolean",n[t.EOF]="",n[t.Identifier]="Identifier",n[t.Keyword]="Keyword",n[t.NullLiteral]="Null",n[t.NumericLiteral]="Numeric",n[t.Punctuator]="Punctuator",n[t.StringLiteral]="String",r={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},i={Data:1,Get:2,Set:4},s={UnexpectedToken:"Unexpected token %0" +,UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictDelete:"Delete of an unqualified identifier in strict mode.",StrictDuplicateProperty:"Duplicate data property in object literal not allowed in strict mode",AccessorDataProperty:"Object literal may not have data and accessor property with the same name",AccessorGetSet:"Object literal may not have multiple get/set accessors with the same name",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictReservedWord:"Use of future reserved word in strict mode"},o={NonAsciiIdentifierStart:new RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々-〇〡-〩〱-〵〸-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]"),NonAsciiIdentifierPart:new RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮ̀-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁ҃-҇Ҋ-ԧԱ-Ֆՙա-և֑-ׇֽֿׁׂׅׄא-תװ-ײؐ-ؚؠ-٩ٮ-ۓە-ۜ۟-۪ۨ-ۼۿܐ-݊ݍ-ޱ߀-ߵߺࠀ-࠭ࡀ-࡛ࢠࢢ-ࢬࣤ-ࣾऀ-ॣ०-९ॱ-ॷॹ-ॿঁ-ঃঅ-ঌএঐও-নপ-রলশ-হ়-ৄেৈো-ৎৗড়ঢ়য়-ৣ০-ৱਁ-ਃਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹ਼ਾ-ੂੇੈੋ-੍ੑਖ਼-ੜਫ਼੦-ੵઁ-ઃઅ-ઍએ-ઑઓ-નપ-રલળવ-હ઼-ૅે-ૉો-્ૐૠ-ૣ૦-૯ଁ-ଃଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହ଼-ୄେୈୋ-୍ୖୗଡ଼ଢ଼ୟ-ୣ୦-୯ୱஂஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹா-ூெ-ைொ-்ௐௗ௦-௯ఁ-ఃఅ-ఌఎ-ఐఒ-నప-ళవ-హఽ-ౄె-ైొ-్ౕౖౘౙౠ-ౣ౦-౯ಂಃಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹ಼-ೄೆ-ೈೊ-್ೕೖೞೠ-ೣ೦-೯ೱೲംഃഅ-ഌഎ-ഐഒ-ഺഽ-ൄെ-ൈൊ-ൎൗൠ-ൣ൦-൯ൺ-ൿංඃඅ-ඖක-නඳ-රලව-ෆ්ා-ුූෘ-ෟෲෳก-ฺเ-๎๐-๙ກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ູົ-ຽເ-ໄໆ່-ໍ໐-໙ໜ-ໟༀ༘༙༠-༩༹༵༷༾-ཇཉ-ཬཱ-྄྆-ྗྙ-ྼ࿆က-၉ၐ-ႝႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚ፝-፟ᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-᜔ᜠ-᜴ᝀ-ᝓᝠ-ᝬᝮ-ᝰᝲᝳក-៓ៗៜ៝០-៩᠋-᠍᠐-᠙ᠠ-ᡷᢀ-ᢪᢰ-ᣵᤀ-ᤜᤠ-ᤫᤰ-᤻᥆-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉ᧐-᧙ᨀ-ᨛᨠ-ᩞ᩠-᩿᩼-᪉᪐-᪙ᪧᬀ-ᭋ᭐-᭙᭫-᭳ᮀ-᯳ᰀ-᰷᱀-᱉ᱍ-ᱽ᳐-᳔᳒-ᳶᴀ-ᷦ᷼-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼ‌‍‿⁀⁔ⁱⁿₐ-ₜ⃐-⃥⃜⃡-⃰ℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯ⵿-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⷠ-ⷿⸯ々-〇〡-〯〱-〵〸-〼ぁ-ゖ゙゚ゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘫꙀ-꙯ꙴ-꙽ꙿ-ꚗꚟ-꛱ꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠧꡀ-ꡳꢀ-꣄꣐-꣙꣠-ꣷꣻ꤀-꤭ꤰ-꥓ꥠ-ꥼꦀ-꧀ꧏ-꧙ꨀ-ꨶꩀ-ꩍ꩐-꩙ꩠ-ꩶꩺꩻꪀ-ꫂꫛ-ꫝꫠ-ꫯꫲ-꫶ꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯪ꯬꯭꯰-꯹가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻ︀-️︠-︦︳︴﹍-﹏ﹰ-ﹴﹶ-ﻼ0-9A-Z_a-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]")},typeof "esprima"[0]=="undefined"&&(b=function(t,n){return a.slice(t,n).join("")}),u={name:"SyntaxTree",createArrayExpression:function(e){return{type:r.ArrayExpression,elements:e}},createAssignmentExpression:function(e,t,n){return{type:r.AssignmentExpression,operator:e,left:t,right:n}},createBinaryExpression:function(e,t,n){return{type:r.BinaryExpression,operator:e,left:t,right:n}},createBlockStatement:function(e){return{type:r.BlockStatement,body:e}},createBreakStatement:function(e){return{type:r.BreakStatement,label:e}},createCallExpression:function(e,t){return{type:r.CallExpression,callee:e,arguments:t}},createCatchClause:function(e,t){return{type:r.CatchClause,param:e,body:t}},createConditionalExpression:function(e,t,n){return{type:r.ConditionalExpression,test:e,consequent:t,alternate:n}},createContinueStatement:function(e){return{type:r.ContinueStatement,label:e}},createDebuggerStatement:function(){return{type:r.DebuggerStatement}},createDoWhileStatement:function(e,t){return{type:r.DoWhileStatement,body:e,test:t}},createEmptyStatement:function(){return{type:r.EmptyStatement}},createExpressionStatement:function(e){return{type:r.ExpressionStatement,expression:e}},createForStatement:function(e,t,n,i){return{type:r.ForStatement,init:e,test:t,update:n,body:i}},createForInStatement:function(e,t,n){return{type:r.ForInStatement,left:e,right:t,body:n,each:!1}},createFunctionDeclaration:function(e,t,n,i){return{type:r.FunctionDeclaration,id:e,params:t,defaults:n,body:i,rest:null,generator:!1,expression:!1}},createFunctionExpression:function(e,t,n,i){return{type:r.FunctionExpression,id:e,params:t,defaults:n,body:i,rest:null,generator:!1,expression:!1}},createIdentifier:function(e){return{type:r.Identifier,name:e}},createIfStatement:function(e,t,n){return{type:r.IfStatement,test:e,consequent:t,alternate:n}},createLabeledStatement:function(e,t){return{type:r.LabeledStatement,label:e,body:t}},createLiteral:function(e){return{type:r.Literal,value:e.value,raw:b(e.range[0],e.range[1])}},createLogicalExpression:function(e,t,n){return{type:r.LogicalExpression,operator:e,left:t,right:n}},createMemberExpression:function(e,t,n){return{type:r.MemberExpression,computed:e==="[",object:t,property:n}},createNewExpression:function(e,t){return{type:r.NewExpression,callee:e,arguments:t}},createObjectExpression:function(e){return{type:r.ObjectExpression,properties:e}},createPostfixExpression:function(e,t){return{type:r.UpdateExpression,operator:e,argument:t,prefix:!1}},createProgram:function(e){return{type:r.Program,body:e}},createProperty:function(e,t,n){return{type:r.Property,key:t,value:n,kind:e}},createReturnStatement:function(e){return{type:r.ReturnStatement,argument:e}},createSequenceExpression:function(e){return{type:r.SequenceExpression,expressions:e}},createSwitchCase:function(e,t){return{type:r.SwitchCase,test:e,consequent:t}},createSwitchStatement:function(e,t){return{type:r.SwitchStatement,discriminant:e,cases:t}},createThisExpression:function(){return{type:r.ThisExpression}},createThrowStatement:function(e){return{type:r.ThrowStatement,argument:e}},createTryStatement:function(e,t,n,i){return{type:r.TryStatement,block:e,guardedHandlers:t,handlers:n,finalizer:i}},createUnaryExpression:function(e,t){return e==="++"||e==="--"?{type:r.UpdateExpression,operator:e,argument:t,prefix:!0}:{type:r.UnaryExpression,operator:e,argument:t}},createVariableDeclaration:function(e,t){return{type:r.VariableDeclaration,declarations:e,kind:t}},createVariableDeclarator:function(e,t){return{type:r.VariableDeclarator,id:e,init:t}},createWhileStatement:function(e,t){return{type:r.WhileStatement,test:e,body:t}},createWithStatement:function(e,t){return{type:r.WithStatement,object:e,body:t}}},e.version="1.1.0-dev",e.parse=yn,e.Syntax=function(){var e,t={};typeof Object.create=="function"&&(t=Object.create(null));for(e in r)r.hasOwnProperty(e)&&(t[e]=r[e]);return typeof Object.freeze=="function"&&Object.freeze(t),t}()}); \ No newline at end of file diff --git a/lib/esprima.js b/lib/esprima.js new file mode 100644 index 00000000..0340b1e2 --- /dev/null +++ b/lib/esprima.js @@ -0,0 +1,3809 @@ +/* + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + 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 HOLDERS AND CONTRIBUTORS "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 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. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, parseExpression: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseLeftHandSideExpression: true, +parseStatement: true, parseSourceElement: true */ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + Syntax, + PropertyKind, + Messages, + Regex, + SyntaxTreeDelegate, + source, + strict, + index, + lineNumber, + lineStart, + length, + delegate, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalReturn: 'Illegal return statement', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\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\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), + NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\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\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function sliceSource(from, to) { + return source.slice(from, to); + } + + if (typeof 'esprima'[0] === 'undefined') { + sliceSource = function sliceArraySource(from, to) { + return source.slice(from, to).join(''); + }; + } + + function isDecimalDigit(ch) { + return '0123456789'.indexOf(ch) >= 0; + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || + (ch === '\u000C') || (ch === '\u00A0') || + (ch.charCodeAt(0) >= 0x1680 && + '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029'); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === '$') || (ch === '_') || (ch === '\\') || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch)); + } + + function isIdentifierPart(ch) { + return (ch === '$') || (ch === '_') || (ch === '\\') || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || + ((ch >= '0') && (ch <= '9')) || + ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch)); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + return ['class', 'enum', 'export', 'extends', 'import', 'super']. + indexOf(id) >= 0; + } + + function isStrictModeReservedWord(id) { + return ['implements', 'interface', 'package', 'private', 'protected', + 'public', 'static', 'yield', 'let'].indexOf(id) >= 0; + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function skipComment() { + var ch, blockComment, lineComment; + + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch)) { + lineComment = false; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + ++index; + blockComment = false; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + index += 2; + lineComment = true; + } else if (ch === '*') { + index += 2; + blockComment = true; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function getEscapedIdentifier() { + var ch, id, restore, type; + + ch = id = source[index++]; + if (ch === '\\') { + if (source[index] !== 'u') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + if (ch === '\\' || !isIdentifierStart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id = ch; + } else { + index = restore; + id = 'u'; + } + } + + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += ch; + if (ch === '\\') { + id = id.substr(0, id.length - 1); + if (source[index] !== 'u') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + if (ch === '\\' || !isIdentifierPart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id += ch; + } else { + index = restore; + id += 'u'; + } + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source[index]; + if (ch === '\\') { + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return sliceSource(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + if (!isIdentifierStart(source[index])) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + id = (source[index] === '\\') ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + ch1 = source[index], + ch2, + ch3, + ch4; + + // Check for most common single-character punctuators. + + if (ch1 === '.' || ch1 === '(' || ch1 === ')' || ch1 === ';' || ch1 === ',' || + ch1 === '{' || ch1 === '}' || ch1 === '[' || ch1 === ']' || + ch1 === ':' || ch1 === '?' || ch1 === '~') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Peek more characters. + + ch2 = source[index + 1]; + ch3 = source[index + 2]; + ch4 = source[index + 3]; + + // 4-character punctuator: >>>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + if (ch4 === '=') { + index += 4; + return { + type: Token.Punctuator, + value: '>>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 3-character punctuators: === !== >>> <<= >>= + + if (ch1 === '=' && ch2 === '=' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '===', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '!' && ch2 === '=' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '!==', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + index += 3; + return { + type: Token.Punctuator, + value: '>>>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '<' && ch2 === '<' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '<<=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 2-character punctuators: <= >= == != ++ -- << >> && || + // += -= *= %= &= |= ^= /= + + if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { + if ('+-<>&|'.indexOf(ch2) >= 0) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + if (ch2 === '=') { + ++index; + ch1 += ch2; + } + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanNumericLiteral() { + var number, start, ch; + + ch = source[index]; + assert(isDecimalDigit(ch) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isHexDigit(ch)) { + break; + } + number += source[index++]; + } + + if (number.length <= 2) { + // only 0x + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + if (isOctalDigit(ch)) { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isOctalDigit(ch)) { + break; + } + number += source[index++]; + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: true, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // decimal number starts with '0' such as '09' is illegal. + if (isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } + + if (ch === '.') { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + + ch = source[index]; + if (isDecimalDigit(ch)) { + number += source[index++]; + while (index < length) { + ch = source[index]; + if (!isDecimalDigit(ch)) { + break; + } + number += source[index++]; + } + } else { + ch = 'character ' + ch; + if (index >= length) { + ch = ''; + } + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (index < length) { + ch = source[index]; + if (isIdentifierStart(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch)) { + switch (ch) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'u': + case 'x': + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\v'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch)) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanRegExp() { + var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + + lookahead = null; + skipComment(); + + start = index; + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + while (index < length) { + ch = source[index++]; + str += ch; + if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } else if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + pattern = str.substr(1, str.length - 2); + + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch)) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + } else { + str += '\\'; + } + } else { + flags += ch; + str += ch; + } + } + + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + + peek(); + + return { + literal: str, + value: value, + range: [start, index] + }; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advance() { + var ch; + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + range: [index, index] + }; + } + + ch = source[index]; + + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + if (ch === '.') { + // Dot (.) can also start a floating-point number, hence the need + // to check the next character. + if (isDecimalDigit(source[index + 1])) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + if (ch === '\'' || ch === '"') { + return scanStringLiteral(); + } + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + return scanPunctuator(); + } + + function lex() { + var token; + + token = lookahead; + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = advance(); + + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + return { + type: Syntax.BinaryExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createFunctionExpression: function (id, params, defaults, body) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: sliceSource(token.range[0], token.range[1]) + }; + }, + + createLogicalExpression: function (operator, left, right) { + return { + type: Syntax.LogicalExpression, + operator: operator, + left: left, + right: right + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + } + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + return args[index] || ''; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.range[0]; + error.lineNumber = token.lineNumber; + error.column = token.range[0] - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line; + + // Catch the very common case first. + if (source[index] === ';') { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + return; + } + + if (match(';')) { + lex(); + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = []; + + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else { + elements.push(parseAssignmentExpression()); + + if (!match(']')) { + expect(','); + } + } + } + + expect(']'); + + return delegate.createArrayExpression(elements); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(param, first) { + var previousStrict, body; + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (first && strict && isRestrictedWord(param[0].name)) { + throwErrorTolerant(first, Messages.StrictParamName); + } + strict = previousStrict; + return delegate.createFunctionExpression(null, param, [], body); + } + + function parseObjectPropertyKey() { + var token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseObjectProperty() { + var token, key, id, value, param; + + token = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + value = parsePropertyFunction([]); + return delegate.createProperty('get', key, value); + } + if (token.value === 'set' && !match(':')) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + if (token.type !== Token.Identifier) { + throwUnexpected(lex()); + } + param = [ parseVariableIdentifier() ]; + expect(')'); + value = parsePropertyFunction(param, token); + return delegate.createProperty('set', key, value); + } + expect(':'); + value = parseAssignmentExpression(); + return delegate.createProperty('init', id, value); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + throwUnexpected(token); + } else { + key = parseObjectPropertyKey(); + expect(':'); + value = parseAssignmentExpression(); + return delegate.createProperty('init', key, value); + } + } + + function parseObjectInitialiser() { + var properties = [], property, name, kind, map = {}, toString = String; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + if (Object.prototype.hasOwnProperty.call(map, name)) { + if (map[name] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[name] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[name] |= kind; + } else { + map[name] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return delegate.createObjectExpression(properties); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + expr = parseExpression(); + + expect(')'); + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token; + + type = lookahead.type; + + if (type === Token.Identifier) { + return delegate.createIdentifier(lex().value); + } + + if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(lex()); + } + + if (type === Token.Keyword) { + if (matchKeyword('this')) { + lex(); + return delegate.createThisExpression(); + } + + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + } + + if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + return delegate.createLiteral(token); + } + + if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + return delegate.createLiteral(token); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('/') || match('/=')) { + return delegate.createLiteral(scanRegExp()); + } + + return throwUnexpected(lex()); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = []; + + expect('('); + + if (!match(')')) { + while (index < length) { + args.push(parseAssignmentExpression()); + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseNonComputedProperty() { + var token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args; + + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return delegate.createNewExpression(callee, args); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(')) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + } else if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + } else { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } + } + + return expr; + } + + + function parseLeftHandSideExpression() { + var expr, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[')) { + if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + } else { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } + } + + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr = parseLeftHandSideExpressionAllowCall(), token; + + if (lookahead.type !== Token.Punctuator) { + return expr; + } + + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.createPostfixExpression(token.value, expr); + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + return parsePostfixExpression(); + } + + if (match('++') || match('--')) { + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + return delegate.createUnaryExpression(token.value, expr); + } + + if (match('+') || match('-') || match('~') || match('!')) { + token = lex(); + expr = parseUnaryExpression(); + return delegate.createUnaryExpression(token.value, expr); + } + + if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + return expr; + } + + return parsePostfixExpression(); + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + // Reduce: make a binary expression from the three topmost entries. + function reduceBinary(stack) { + var right = stack.pop(), + operator = stack.pop().value, + left = stack.pop(); + + + if (operator === '||' || operator === '&&') { + stack.push(delegate.createLogicalExpression(operator, left, right)); + } else { + stack.push(delegate.createBinaryExpression(operator, left, right)); + } + } + + function parseBinaryExpression() { + var expr, token, prec, previousAllowIn, stack; + + previousAllowIn = state.allowIn; + state.allowIn = true; + + expr = parseUnaryExpression(); + + token = lookahead; + prec = binaryPrecedence(token, previousAllowIn); + if (prec === 0) { + return expr; + } + token.prec = prec; + lex(); + + stack = [expr, token, parseUnaryExpression()]; + + while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) { + + // Reduce. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + reduceBinary(stack); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + stack.push(parseUnaryExpression()); + } + + // Final reduce to clean-up the stack. + while (stack.length > 1) { + reduceBinary(stack); + } + + state.allowIn = previousAllowIn; + return stack[0]; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate; + + expr = parseBinaryExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = delegate.createConditionalExpression(expr, consequent, alternate); + } + + return expr; + } + + // 11.13 Assignment Operators + + function parseAssignmentExpression() { + var token, left, right; + + token = lookahead; + left = parseConditionalExpression(); + + if (matchAssign()) { + // LeftHandSideExpression + if (!isLeftHandSide(left)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + // 11.13.1 + if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + token = lex(); + right = parseAssignmentExpression(); + return delegate.createAssignmentExpression(token.value, left, right); + } + + return left; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr = parseAssignmentExpression(); + + if (match(',')) { + expr = delegate.createSequenceExpression([ expr ]); + + while (index < length) { + if (!match(',')) { + break; + } + lex(); + expr.expressions.push(parseAssignmentExpression()); + } + + } + return expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block; + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseVariableDeclaration(kind) { + var id = parseVariableIdentifier(), + init = null; + + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + + if (kind === 'const') { + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return delegate.createVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + while (index < length) { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, kind); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + return delegate.createEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + consumeSemicolon(); + return delegate.createExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return delegate.createIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return delegate.createDoWhileStatement(body, test); + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return delegate.createWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token = lex(), + declarations = parseVariableDeclarationList(); + + return delegate.createVariableDeclaration(declarations, token.value); + } + + function parseForStatement() { + var init, test, update, left, right, body, oldInIteration; + + init = test = update = null; + + expectKeyword('for'); + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = true; + + if (init.declarations.length === 1 && matchKeyword('in')) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = true; + + if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isLeftHandSide(init)) { + throwError({}, Messages.InvalidLHSInForIn); + } + + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return (typeof left === 'undefined') ? + delegate.createForStatement(init, test, update, body) : + delegate.createForInStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var label = null; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source[index] === ';') { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement() { + var label = null; + + expectKeyword('break'); + + // Optimize the most common form: 'break;'. + if (source[index] === ';') { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement() { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source[index] === ' ') { + if (isIdentifierStart(source[index + 1])) { + argument = parseExpression(); + consumeSemicolon(); + return delegate.createReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return delegate.createReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return delegate.createReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return delegate.createWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, + consequent = [], + statement; + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + statement = parseStatement(); + if (typeof statement === 'undefined') { + break; + } + consequent.push(statement); + } + + return delegate.createSwitchCase(test, consequent); + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + if (match('}')) { + lex(); + return delegate.createSwitchStatement(discriminant); + } + + cases = []; + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return delegate.createSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return delegate.createThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body; + + expectKeyword('catch'); + + expect('('); + if (!match(')')) { + param = parseExpression(); + // 12.14.1 + if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + } + expect(')'); + body = parseBlock(); + return delegate.createCatchClause(param, body); + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return delegate.createTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return delegate.createDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody; + + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(); + case '{': + return parseBlock(); + case '(': + return parseExpressionStatement(); + default: + break; + } + } + + if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(); + case 'continue': + return parseContinueStatement(); + case 'debugger': + return parseDebuggerStatement(); + case 'do': + return parseDoWhileStatement(); + case 'for': + return parseForStatement(); + case 'function': + return parseFunctionDeclaration(); + case 'if': + return parseIfStatement(); + case 'return': + return parseReturnStatement(); + case 'switch': + return parseSwitchStatement(); + case 'throw': + return parseThrowStatement(); + case 'try': + return parseTryStatement(); + case 'var': + return parseVariableStatement(); + case 'while': + return parseWhileStatement(); + case 'with': + return parseWithStatement(); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[expr.name] = true; + labeledBody = parseStatement(); + delete state.labelSet[expr.name]; + return delegate.createLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return delegate.createExpressionStatement(expr); + } + + // 13 Function Definition + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; + + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + + return delegate.createBlockStatement(sourceElements); + } + + function parseParams(firstRestricted) { + var param, params = [], token, stricted, paramSet, message; + expect('('); + + if (!match(')')) { + paramSet = {}; + while (index < length) { + token = lookahead; + param = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + stricted = token; + message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + stricted = token; + message = Messages.StrictParamDupe; + } + } else if (!firstRestricted) { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + firstRestricted = token; + message = Messages.StrictParamDupe; + } + } + params.push(param); + paramSet[param.name] = true; + if (match(')')) { + break; + } + expect(','); + } + } + + expect(')'); + + return { + params: params, + stricted: stricted, + firstRestricted: firstRestricted, + message: message + }; + } + + function parseFunctionDeclaration() { + var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict; + + expectKeyword('function'); + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return delegate.createFunctionDeclaration(id, params, [], body); + } + + function parseFunctionExpression() { + var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict; + + expectKeyword('function'); + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && stricted) { + throwErrorTolerant(stricted, message); + } + strict = previousStrict; + + return delegate.createFunctionExpression(id, params, [], body); + } + + // 14 Program + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + default: + return parseStatement(); + } + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseProgram() { + var body; + strict = false; + peek(); + body = parseSourceElements(); + return delegate.createProgram(body); + } + + // The following functions are needed only when the option to preserve + // the comments is active. + + function addComment(type, value, start, end, loc) { + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (extra.comments.length > 0) { + if (extra.comments[extra.comments.length - 1].range[1] > start) { + return; + } + } + + extra.comments.push({ + type: type, + value: value, + range: [start, end], + loc: loc + }); + } + + function scanComment() { + var comment, ch, loc, start, blockComment, lineComment; + + comment = ''; + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch)) { + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + lineComment = false; + addComment('Line', comment, start, index - 1, loc); + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + comment = ''; + } else if (index >= length) { + lineComment = false; + comment += ch; + loc.end = { + line: lineNumber, + column: length - lineStart + }; + addComment('Line', comment, start, length, loc); + } else { + comment += ch; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + comment += '\r\n'; + } else { + comment += ch; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + comment += ch; + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + comment = comment.substr(0, comment.length - 1); + blockComment = false; + ++index; + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + comment = ''; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + start = index; + index += 2; + lineComment = true; + if (index >= length) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + lineComment = false; + addComment('Line', comment, start, index, loc); + } + } else if (ch === '*') { + start = index; + index += 2; + blockComment = true; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function filterCommentLocation() { + var i, entry, comment, comments = []; + + for (i = 0; i < extra.comments.length; ++i) { + entry = extra.comments[i]; + comment = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + comment.range = entry.range; + } + if (extra.loc) { + comment.loc = entry.loc; + } + comments.push(comment); + } + + extra.comments = comments; + } + + function collectToken() { + var start, loc, token, range, value; + + skipComment(); + start = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = extra.advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + range = [token.range[0], token.range[1]]; + value = sliceSource(token.range[0], token.range[1]); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: range, + loc: loc + }); + } + + return token; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = extra.scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + + return regex; + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function createLocationMarker() { + var marker = {}; + + marker.range = [index, index]; + marker.loc = { + start: { + line: lineNumber, + column: index - lineStart + }, + end: { + line: lineNumber, + column: index - lineStart + } + }; + + marker.end = function () { + this.range[1] = index; + this.loc.end.line = lineNumber; + this.loc.end.column = index - lineStart; + }; + + marker.applyGroup = function (node) { + if (extra.range) { + node.groupRange = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.groupLoc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + } + }; + + marker.apply = function (node) { + if (extra.range) { + node.range = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.loc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + } + }; + + return marker; + } + + function trackGroupExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + expect('('); + + expr = parseExpression(); + + expect(')'); + + marker.end(); + marker.applyGroup(expr); + + return expr; + } + + function trackLeftHandSideExpression() { + var marker, expr, property; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[')) { + if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + marker.end(); + marker.apply(expr); + } else { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function trackLeftHandSideExpressionAllowCall() { + var marker, expr, args, property; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(')) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + marker.end(); + marker.apply(expr); + } else if (match('[')) { + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); + marker.end(); + marker.apply(expr); + } else { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function filterGroup(node) { + var n, i, entry; + + n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; + for (i in node) { + if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { + entry = node[i]; + if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { + n[i] = entry; + } else { + n[i] = filterGroup(entry); + } + } + } + return n; + } + + function wrapTrackingFunction(range, loc) { + + return function (parseFunction) { + + function isBinary(node) { + return node.type === Syntax.LogicalExpression || + node.type === Syntax.BinaryExpression; + } + + function visit(node) { + var start, end; + + if (isBinary(node.left)) { + visit(node.left); + } + if (isBinary(node.right)) { + visit(node.right); + } + + if (range) { + if (node.left.groupRange || node.right.groupRange) { + start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; + end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; + node.range = [start, end]; + } else if (typeof node.range === 'undefined') { + start = node.left.range[0]; + end = node.right.range[1]; + node.range = [start, end]; + } + } + if (loc) { + if (node.left.groupLoc || node.right.groupLoc) { + start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; + end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; + node.loc = { + start: start, + end: end + }; + } else if (typeof node.loc === 'undefined') { + node.loc = { + start: node.left.loc.start, + end: node.right.loc.end + }; + } + } + } + + return function () { + var marker, node; + + skipComment(); + + marker = createLocationMarker(); + node = parseFunction.apply(null, arguments); + marker.end(); + + if (range && typeof node.range === 'undefined') { + marker.apply(node); + } + + if (loc && typeof node.loc === 'undefined') { + marker.apply(node); + } + + if (isBinary(node)) { + visit(node); + } + + return node; + }; + }; + } + + function patch() { + + var wrapTracking; + + if (extra.comments) { + extra.skipComment = skipComment; + skipComment = scanComment; + } + + if (extra.range || extra.loc) { + + extra.parseGroupExpression = parseGroupExpression; + extra.parseLeftHandSideExpression = parseLeftHandSideExpression; + extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; + parseGroupExpression = trackGroupExpression; + parseLeftHandSideExpression = trackLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; + + wrapTracking = wrapTrackingFunction(extra.range, extra.loc); + + extra.parseAssignmentExpression = parseAssignmentExpression; + extra.parseBinaryExpression = parseBinaryExpression; + extra.parseBlock = parseBlock; + extra.parseFunctionSourceElements = parseFunctionSourceElements; + extra.parseCatchClause = parseCatchClause; + extra.parseComputedMember = parseComputedMember; + extra.parseConditionalExpression = parseConditionalExpression; + extra.parseConstLetDeclaration = parseConstLetDeclaration; + extra.parseExpression = parseExpression; + extra.parseForVariableDeclaration = parseForVariableDeclaration; + extra.parseFunctionDeclaration = parseFunctionDeclaration; + extra.parseFunctionExpression = parseFunctionExpression; + extra.parseNewExpression = parseNewExpression; + extra.parseNonComputedProperty = parseNonComputedProperty; + extra.parseObjectProperty = parseObjectProperty; + extra.parseObjectPropertyKey = parseObjectPropertyKey; + extra.parsePostfixExpression = parsePostfixExpression; + extra.parsePrimaryExpression = parsePrimaryExpression; + extra.parseProgram = parseProgram; + extra.parsePropertyFunction = parsePropertyFunction; + extra.parseStatement = parseStatement; + extra.parseSwitchCase = parseSwitchCase; + extra.parseUnaryExpression = parseUnaryExpression; + extra.parseVariableDeclaration = parseVariableDeclaration; + extra.parseVariableIdentifier = parseVariableIdentifier; + + parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); + parseBinaryExpression = wrapTracking(extra.parseBinaryExpression); + parseBlock = wrapTracking(extra.parseBlock); + parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); + parseCatchClause = wrapTracking(extra.parseCatchClause); + parseComputedMember = wrapTracking(extra.parseComputedMember); + parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); + parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); + parseExpression = wrapTracking(extra.parseExpression); + parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); + parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); + parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); + parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); + parseNewExpression = wrapTracking(extra.parseNewExpression); + parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); + parseObjectProperty = wrapTracking(extra.parseObjectProperty); + parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); + parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); + parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); + parseProgram = wrapTracking(extra.parseProgram); + parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); + parseStatement = wrapTracking(extra.parseStatement); + parseSwitchCase = wrapTracking(extra.parseSwitchCase); + parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); + parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); + parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); + } + + if (typeof extra.tokens !== 'undefined') { + extra.advance = advance; + extra.scanRegExp = scanRegExp; + + advance = collectToken; + scanRegExp = collectRegex; + } + } + + function unpatch() { + if (typeof extra.skipComment === 'function') { + skipComment = extra.skipComment; + } + + if (extra.range || extra.loc) { + parseAssignmentExpression = extra.parseAssignmentExpression; + parseBinaryExpression = extra.parseBinaryExpression; + parseBlock = extra.parseBlock; + parseFunctionSourceElements = extra.parseFunctionSourceElements; + parseCatchClause = extra.parseCatchClause; + parseComputedMember = extra.parseComputedMember; + parseConditionalExpression = extra.parseConditionalExpression; + parseConstLetDeclaration = extra.parseConstLetDeclaration; + parseExpression = extra.parseExpression; + parseForVariableDeclaration = extra.parseForVariableDeclaration; + parseFunctionDeclaration = extra.parseFunctionDeclaration; + parseFunctionExpression = extra.parseFunctionExpression; + parseGroupExpression = extra.parseGroupExpression; + parseLeftHandSideExpression = extra.parseLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; + parseNewExpression = extra.parseNewExpression; + parseNonComputedProperty = extra.parseNonComputedProperty; + parseObjectProperty = extra.parseObjectProperty; + parseObjectPropertyKey = extra.parseObjectPropertyKey; + parsePrimaryExpression = extra.parsePrimaryExpression; + parsePostfixExpression = extra.parsePostfixExpression; + parseProgram = extra.parseProgram; + parsePropertyFunction = extra.parsePropertyFunction; + parseStatement = extra.parseStatement; + parseSwitchCase = extra.parseSwitchCase; + parseUnaryExpression = extra.parseUnaryExpression; + parseVariableDeclaration = extra.parseVariableDeclaration; + parseVariableIdentifier = extra.parseVariableIdentifier; + } + + if (typeof extra.scanRegExp === 'function') { + advance = extra.advance; + scanRegExp = extra.scanRegExp; + } + } + + function stringToArray(str) { + var length = str.length, + result = [], + i; + for (i = 0; i < length; ++i) { + result[i] = str.charAt(i); + } + return result; + } + + // This is used to modify the delegate. + + function extend(object, properties) { + var entry, result = {}; + + for (entry in object) { + if (object.hasOwnProperty(entry)) { + result[entry] = object[entry]; + } + } + + for (entry in properties) { + if (properties.hasOwnProperty(entry)) { + result[entry] = properties[entry]; + } + } + + return result; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + + // Force accessing the characters via an array. + if (typeof source[0] === 'undefined') { + source = stringToArray(code); + } + } + } + + patch(); + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + if (extra.range || extra.loc) { + program.body = filterGroup(program.body); + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + + return program; + } + + // Sync with package.json and component.json. + exports.version = '1.1.0-dev'; + + exports.parse = parse; + + // Deep copy. + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/src/core/PaperScript.js b/src/core/PaperScript.js index 194a96a2..e4dedba9 100644 --- a/src/core/PaperScript.js +++ b/src/core/PaperScript.js @@ -18,12 +18,17 @@ * @name PaperScript * @namespace */ + +/*#*/ if (options.parser == 'acorn') { +/*#*/ include('../../lib/acorn-min.js'); +/*#*/ } else { +/*#*/ include('../../lib/esprima-min.js'); +/*#*/ } + var PaperScript = this.PaperScript = new function() { -/*#*/ include('../../lib/parse-js-min.js'); + // Operators to overload - // Math Operators - - var operators = { + var binaryOperators = { '+': 'add', '-': 'subtract', '*': 'multiply', @@ -33,8 +38,18 @@ var PaperScript = this.PaperScript = new function() { '!=': 'equals' }; - function $eval(left, operator, right) { - var handler = operators[operator]; + var unaryOperators = { + '-': 'negate', + '+': null + }; + + // Use very short name for the binary operator (_$_) as well as the + // unary operator ($_), as operations will be replaced with then. + // The underscores stands for the values, and the $ for the operators. + + // Binary Operator Handler + function _$_(left, operator, right) { + var handler = binaryOperators[operator]; if (left && left[handler]) { var res = left[handler](right); return operator === '!=' ? !res : res; @@ -52,41 +67,21 @@ var PaperScript = this.PaperScript = new function() { } } - // Sign Operators - - var signOperators = { - '-': 'negate' - }; - - function $sign(operator, value) { - var handler = signOperators[operator]; - if (value && value[handler]) { + // Unary Operator Handler + function $_(operator, value) { + var handler = unaryOperators[operator]; + if (handler && value && value[handler]) return value[handler](); - } switch (operator) { case '+': return +value; case '-': return -value; default: - throw new Error('Implement Sign Operator: ' + operator); + throw new Error('Implement Unary Operator: ' + operator); } } // AST Helpers - function isDynamic(exp) { - var type = exp[0]; - return type != 'num' && type != 'string'; - } - - function handleOperator(operator, left, right) { - // Only replace operators with calls to $operator if the left hand side - // is potentially an object. - if (operators[operator] && isDynamic(left)) { - // Replace with call to $operator(left, operator, right): - return ['call', ['name', '$eval'], - [left, ['string', operator], right]]; - } - } /** * Compiles PaperScript code into JavaScript code. @@ -97,49 +92,111 @@ var PaperScript = this.PaperScript = new function() { * @return {String} The compiled PaperScript as JavaScript code. */ function compile(code) { - // Use parse-js to translate the code into a AST structure which is then - // walked and parsed for operators to overload. The resulting AST is - // translated back to code and evaluated. - var ast = parse_js.parse(code), - walker = parse_js.ast_walker(), - walk = walker.walk; + // Use Acorn or Esprima to translate the code into an AST structure + // which is then walked and parsed for operators to overload. + // Instead of modifying the AST and converting back to code, we directly + // change the source code based on the parser's range information, so we + // can preserve line-numbers in syntax errors and remove the need for + // Escodegen. - ast = walker.with_walkers({ - 'binary': function(operator, left, right) { - // Handle simple mathematical operators here: - return handleOperator(operator, left = walk(left), - right = walk(right)) - // Always return a new AST for this node, since we have - // processed left and right int he call above! - || [this[0], operator, left, right]; - }, + // Tracks code insertions so we can add their differences to the + // original offsets. + var insertions = []; - 'assign': function(operator, left, right) { - // Handle assignments like +=, -=, etc: - // Check if the assignment operator needs to be handled by paper - // if so, convert the assignment to a simple = and use result of - // of handleOperator on the right hand side. - var res = handleOperator(operator, left = walk(left), - right = walk(right)); - return res - ? [this[0], true, left, res] - // Always return a new AST for the same reason as in binary - : [this[0], operator, left, right]; - }, + // Converts an original offset to the one in the current state of the + // modified code. + function getOffset(offset) { + var start = offset; + // Add all insertions before this location together to calculate + // the current offset + for (var i = 0, l = insertions.length; i < l; i++) { + var insertion = insertions[i]; + if (insertion[0] >= offset) + break; + offset += insertion[1]; + } + return offset; + } - 'unary-prefix': function(operator, exp) { - if (signOperators[operator] && isDynamic(exp)) { - return ['call', ['name', '$sign'], - [['string', operator], walk(exp)]]; + // Returns the node's code as a string, taking insertions into account. + function getCode(node) { + return code.substring(getOffset(node.range[0]), + getOffset(node.range[1])); + } + + // Replaces the node's code with a new version and keeps insertions + // information up-to-date. + function replaceCode(node, str) { + var start = getOffset(node.range[0]), + end = getOffset(node.range[1]); + var insert = 0; + // Sort insertions by their offset, so getOffest() can do its thing + for (var i = insertions.length - 1; i >= 0; i--) { + if (start > insertions[i][0]) { + insert = i + 1; + break; } } - }, function() { - return walk(ast); - }); + insertions.splice(insert, 0, [start, str.length - end + start]); + code = code.substring(0, start) + str + code.substring(end); + } - return parse_js.gen_code(ast, { - beautify: true - }); + // Recursively walks the AST and replaces the code of certain nodes + function walkAst(node) { + for (var key in node) { + if (key === 'range') + continue; + var value = node[key]; + if (Array.isArray(value)) { + for (var i = 0, l = value.length; i < l; i++) + walkAst(value[i]); + } else if (Base.isObject(value)) { + walkAst(value); + } + } + switch (node.type) { + case 'BinaryExpression': + if (node.operator in binaryOperators + && node.left.type !== 'Literal') { + var left = getCode(node.left), + right = getCode(node.right); + replaceCode(node, '_$_(' + left + ', "' + node.operator + + '", ' + right + ')'); + } + break; + case 'AssignmentExpression': + if (/^.=$/.test(node.operator) + && node.left.type !== 'Literal') { + var left = getCode(node.left), + right = getCode(node.right); + replaceCode(node, left + ' = _$_(' + left + ', "' + + node.operator[0] + '", ' + right + ')'); + } + break; + case 'UpdateExpression': + if (!node.prefix) { + var arg = getCode(node.argument); + replaceCode(node, arg + ' = _$_(' + arg + ', "' + + node.operator[0] + '", 1)'); + } + break; + case 'UnaryExpression': + if (node.operator in unaryOperators + && node.argument.type !== 'Literal') { + var arg = getCode(node.argument); + replaceCode(node, '$_("' + node.operator + '", ' + + arg + ')'); + } + break; + } + } + // Now do the parsing magic +/*#*/ if (options.parser == 'acorn') { + walkAst(acorn.parse(code, { ranges: true })); +/*#*/ } else { + walkAst(esprima.parse(code, { range: true })); +/*#*/ } + return code; } /**