Comparing version 0.2.8 to 0.2.9
@@ -1,2 +0,2 @@ | ||
// JavaScript Expression Parser (JSEP) 0.2.8 | ||
// JavaScript Expression Parser (JSEP) 0.2.9 | ||
// JSEP may be freely distributed under the MIT License | ||
@@ -22,3 +22,24 @@ // http://jsep.from.so/ | ||
LOGICAL_EXP = 'LogicalExpression', | ||
CONDITIONAL_EXP = 'ConditionalExpression', | ||
ARRAY_EXP = 'Array', | ||
PERIOD_CODE = 46, // '.' | ||
COMMA_CODE = 44, // ',' | ||
SQUOTE_CODE = 39, // single quote | ||
DQUOTE_CODE = 34, // double quotes | ||
OPAREN_CODE = 40, // ( | ||
CPAREN_CODE = 41, // ) | ||
OBRACK_CODE = 91, // [ | ||
CBRACK_CODE = 93, // ] | ||
QUMARK_CODE = 63, // ? | ||
SEMCOL_CODE = 59, // ; | ||
COLON_CODE = 58, // : | ||
throwError = function(message, index) { | ||
var error = new Error(message + ' at character ' + index); | ||
error.index = index; | ||
error.dedscription = message; | ||
throw error; | ||
}, | ||
// Operations | ||
@@ -117,2 +138,36 @@ // ---------- | ||
}, | ||
// The main parsing function. Much of this code is dedicated to ternary expressions | ||
gobbleExpression = function() { | ||
var test = gobbleBinaryExpression(), | ||
consequent, alternate; | ||
gobbleSpaces(); | ||
// Ternary expression: test ? consequent : alternate | ||
if(exprICode(index) === QUMARK_CODE) { | ||
index++; | ||
consequent = gobbleExpression(); | ||
if(!consequent) { | ||
throwError('Expected expression', index); | ||
} | ||
gobbleSpaces(); | ||
if(exprICode(index) === COLON_CODE) { | ||
index++; | ||
alternate = gobbleExpression(); | ||
if(!alternate) { | ||
throwError('Expected expression', index); | ||
} | ||
return { | ||
type: CONDITIONAL_EXP, | ||
test: test, | ||
consequent: consequent, | ||
alternate: alternate | ||
}; | ||
} else { | ||
throwError('Expected :', index); | ||
} | ||
} else { | ||
return test; | ||
} | ||
}, | ||
@@ -138,3 +193,3 @@ // Search for the operation portion of the string (e.g. `+`, `===`) | ||
// e.g. `1`, `1+2`, `a+(b*2)-Math.sqrt(2)` | ||
gobbleExpression = function() { | ||
gobbleBinaryExpression = function() { | ||
var ch_i, node, biop, prec, stack, biop_info, left, right, i; | ||
@@ -158,3 +213,3 @@ | ||
if(!right) { | ||
throw new Error("Expected expression after " + biop + " at character " + index); | ||
throwError("Expected expression after " + biop, index); | ||
} | ||
@@ -183,6 +238,5 @@ stack = [left, biop_info, right]; | ||
if(!node) { | ||
throw new Error("Expected expression after " + biop + " at character " + index); | ||
throwError("Expected expression after " + biop, index); | ||
} | ||
stack.push(biop_info); | ||
stack.push(node); | ||
stack.push(biop_info, node); | ||
} | ||
@@ -196,3 +250,2 @@ | ||
} | ||
return node; | ||
@@ -209,14 +262,11 @@ }, | ||
if(isDecimalDigit(ch) || ch === 46) { | ||
if(isDecimalDigit(ch) || ch === PERIOD_CODE) { | ||
// Char code 46 is a dot `.` which can start off a numeric literal | ||
return gobbleNumericLiteral(); | ||
} else if(ch === 39 || ch === 34) { | ||
} else if(ch === SQUOTE_CODE || ch === DQUOTE_CODE) { | ||
// Single or double quotes | ||
return gobbleStringLiteral(); | ||
} else if(isIdentifierStart(ch)) { | ||
} else if(isIdentifierStart(ch) || ch === OPAREN_CODE) { // open parenthesis | ||
// `foo`, `bar.baz` | ||
return gobbleVariable(); | ||
} else if(ch === 40) { | ||
// Open parentheses | ||
return gobbleGroup(); | ||
} else { | ||
@@ -244,3 +294,3 @@ to_check = expr.substr(index, max_unop_len); | ||
gobbleNumericLiteral = function() { | ||
var number = ''; | ||
var number = '', ch; | ||
while(isDecimalDigit(exprICode(index))) { | ||
@@ -250,3 +300,3 @@ number += exprI(index++); | ||
if(exprI(index) === '.') { // can start with a decimal marker | ||
if(exprICode(index) === PERIOD_CODE) { // can start with a decimal marker | ||
number += exprI(index++); | ||
@@ -259,5 +309,7 @@ | ||
if(exprI(index) === 'e' || exprI(index) === 'E') { // exponent marker | ||
ch = exprI(index); | ||
if(ch === 'e' || ch === 'E') { // exponent marker | ||
number += exprI(index++); | ||
if(exprI(index) === '+' || exprI(index) === '-') { // exponent sign | ||
ch = exprI(index); | ||
if(ch === '+' || ch === '-') { // exponent sign | ||
number += exprI(index++); | ||
@@ -269,4 +321,3 @@ } | ||
if(!isDecimalDigit(exprICode(index-1)) ) { | ||
throw new Error('Expected exponent (' + | ||
number + exprI(index) + ') at character ' + index); | ||
throwError('Expected exponent (' + number + exprI(index) + ')', index); | ||
} | ||
@@ -278,4 +329,4 @@ } | ||
if(isIdentifierStart(exprICode(index))) { | ||
throw new Error('Variable names cannot start with a number (' + | ||
number + exprI(index) + ') at character ' + index); | ||
throwError( 'Variable names cannot start with a number (' + | ||
number + exprI(index) + ')', index); | ||
} | ||
@@ -317,3 +368,3 @@ | ||
if(!closed) { | ||
throw new Error('Unclosed quote after "'+str+'"'); | ||
throwError('Unclosed quote after "'+str+'"', index); | ||
} | ||
@@ -338,3 +389,3 @@ | ||
} else { | ||
throw new Error('Unexpected ' + exprI(index) + 'at character ' + index); | ||
throwError('Unexpected ' + exprI(index), index); | ||
} | ||
@@ -368,14 +419,16 @@ | ||
// Gobbles a list of arguments within the context of a function call. This function | ||
// also assumes that the `(` has already been gobbled. | ||
// e.g. `foo(bar, baz)` or `my_func()` | ||
gobbleArguments = function() { | ||
// Gobbles a list of arguments within the context of a function call | ||
// or array literal. This function also assumes that the opening character | ||
// `(` or `[` has already been gobbled, and gobbles expressions and commas | ||
// until the terminator character `)` or `]` is encountered. | ||
// e.g. `foo(bar, baz)`, `my_func()`, or `[bar, baz]` | ||
gobbleArguments = function(termination) { | ||
var ch_i, args = [], node; | ||
while(index < length) { | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
if(ch_i === ')') { // done parsing | ||
ch_i = exprICode(index); | ||
if(ch_i === termination) { // done parsing | ||
index++; | ||
break; | ||
} else if (ch_i === ',') { // between expressions | ||
} else if (ch_i === COMMA_CODE) { // between expressions | ||
index++; | ||
@@ -385,3 +438,3 @@ } else { | ||
if(!node || node.type === COMPOUND) { | ||
throw new Error('Expected comma at character ' + index); | ||
throwError('Expected comma', index); | ||
} | ||
@@ -399,9 +452,15 @@ args.push(node); | ||
gobbleVariable = function() { | ||
var ch_i, node, old_index; | ||
node = gobbleIdentifier(); | ||
var ch_i, node; | ||
ch_i = exprICode(index); | ||
if(ch_i === OPAREN_CODE) { | ||
node = gobbleGroup(); | ||
} else { | ||
node = gobbleIdentifier(); | ||
} | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
while(ch_i === '.' || ch_i === '[' || ch_i === '(') { | ||
if(ch_i === '.') { | ||
index++; | ||
ch_i = exprICode(index); | ||
while(ch_i === PERIOD_CODE || ch_i === OBRACK_CODE || ch_i === OPAREN_CODE) { | ||
index++; | ||
if(ch_i === PERIOD_CODE) { | ||
gobbleSpaces(); | ||
@@ -414,5 +473,3 @@ node = { | ||
}; | ||
} else if(ch_i === '[') { | ||
old_index = index; | ||
index++; | ||
} else if(ch_i === OBRACK_CODE) { | ||
node = { | ||
@@ -425,14 +482,12 @@ type: MEMBER_EXP, | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
if(ch_i !== ']') { | ||
throw new Error('Unclosed [ at character ' + index); | ||
ch_i = exprICode(index); | ||
if(ch_i !== CBRACK_CODE) { | ||
throwError('Unclosed [', index); | ||
} | ||
index++; | ||
gobbleSpaces(); | ||
} else if(ch_i === '(') { | ||
} else if(ch_i === OPAREN_CODE) { | ||
// A function call is being made; gobble all the arguments | ||
index++; | ||
node = { | ||
type: CALL_EXP, | ||
'arguments': gobbleArguments(), | ||
'arguments': gobbleArguments(CPAREN_CODE), | ||
callee: node | ||
@@ -442,3 +497,3 @@ }; | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
ch_i = exprICode(index); | ||
} | ||
@@ -457,18 +512,32 @@ return node; | ||
gobbleSpaces(); | ||
if(exprI(index) === ')') { | ||
if(exprICode(index) === CPAREN_CODE) { | ||
index++; | ||
return node; | ||
} else { | ||
throw new Error('Unclosed ( at character ' + index); | ||
throwError('Unclosed (', index); | ||
} | ||
}, | ||
// Responsible for parsing Array literals `[1, 2, 3]` | ||
// This function assumes that it needs to gobble the opening bracket | ||
// and then tries to gobble the expressions as arguments. | ||
gobbleArray = function() { | ||
index++; | ||
return { | ||
type: ARRAY_EXP, | ||
body: gobbleArguments(CBRACK_CODE) | ||
}; | ||
}, | ||
nodes = [], ch_i, node; | ||
while(index < length) { | ||
ch_i = exprI(index); | ||
ch_i = exprICode(index); | ||
// Expressions can be separated by semicolons, commas, or just inferred without any | ||
// separators | ||
if(ch_i === ';' || ch_i ===',') { | ||
if(ch_i === SEMCOL_CODE || ch_i === COMMA_CODE) { | ||
index++; // ignore separators | ||
} else if (ch_i === OBRACK_CODE && (node = gobbleArray())) { | ||
nodes.push(node); | ||
} else { | ||
@@ -481,3 +550,3 @@ // Try to gobble each expression individually | ||
} else if(index < length) { | ||
throw new Error("Unexpected '"+exprI(index)+"' at character " + index); | ||
throwError('Unexpected "' + exprI(index) + '"', index); | ||
} | ||
@@ -499,3 +568,3 @@ } | ||
// To be filled in by the template | ||
jsep.version = '0.2.8'; | ||
jsep.version = '0.2.9'; | ||
jsep.toString = function() { return 'JavaScript Expression Parser (JSEP) v' + jsep.version; }; | ||
@@ -502,0 +571,0 @@ |
@@ -1,3 +0,3 @@ | ||
/* jsep v0.2.8 (http://jsep.from.so/) */ | ||
!function(a){"use strict";var b="Compound",c="Identifier",d="MemberExpression",e="Literal",f="ThisExpression",g="CallExpression",h="UnaryExpression",i="BinaryExpression",j="LogicalExpression",k=!0,l={"-":k,"!":k,"~":k,"+":k},m={"||":1,"&&":2,"|":3,"^":4,"&":5,"==":6,"!=":6,"===":6,"!==":6,"<":7,">":7,"<=":7,">=":7,"<<":8,">>":8,">>>":8,"+":9,"-":9,"*":10,"/":10,"%":10},n=function(a){var b,c=0;for(var d in a)(b=d.length)>c&&a.hasOwnProperty(d)&&(c=b);return c},o=n(l),p=n(m),q={"true":!0,"false":!1,"null":null},r="this",s=function(a){return m[a]||0},t=function(a,b,c){var d="||"===a||"&&"===a?j:i;return{type:d,operator:a,left:b,right:c}},u=function(a){return a>=48&&57>=a},v=function(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a},w=function(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a},x=function(a){for(var i,j,k=0,n=a.charAt,x=a.charCodeAt,y=function(b){return n.call(a,b)},z=function(b){return x.call(a,b)},A=a.length,B=function(){for(var a=z(k);32===a||9===a;)a=z(++k)},C=function(){B();for(var b=a.substr(k,p),c=b.length;c>0;){if(m.hasOwnProperty(b))return k+=c,b;b=b.substr(0,--c)}return!1},D=function(){var a,b,c,d,e,f,g,h;if(f=E(),b=C(),!b)return f;if(e={value:b,prec:s(b)},g=E(),!g)throw new Error("Expected expression after "+b+" at character "+k);for(d=[f,e,g];(b=C())&&(c=s(b),0!==c);){for(e={value:b,prec:c};d.length>2&&c<=d[d.length-2].prec;)g=d.pop(),b=d.pop().value,f=d.pop(),a=t(b,f,g),d.push(a);if(a=E(),!a)throw new Error("Expected expression after "+b+" at character "+k);d.push(e),d.push(a)}for(h=d.length-1,a=d[h];h>1;)a=t(d[h-1].value,d[h-2],a),h-=2;return a},E=function(){var b,c,d;if(B(),b=z(k),u(b)||46===b)return F();if(39===b||34===b)return G();if(v(b))return J();if(40===b)return K();for(c=a.substr(k,o),d=c.length;d>0;){if(l.hasOwnProperty(c))return k+=d,{type:h,operator:c,argument:E(),prefix:!0};c=c.substr(0,--d)}return!1},F=function(){for(var a="";u(z(k));)a+=y(k++);if("."===y(k))for(a+=y(k++);u(z(k));)a+=y(k++);if("e"===y(k)||"E"===y(k)){for(a+=y(k++),("+"===y(k)||"-"===y(k))&&(a+=y(k++));u(z(k));)a+=y(k++);if(!u(z(k-1)))throw new Error("Expected exponent ("+a+y(k)+") at character "+k)}if(v(z(k)))throw new Error("Variable names cannot start with a number ("+a+y(k)+") at character "+k);return{type:e,value:parseFloat(a),raw:a}},G=function(){for(var a,b="",c=y(k++),d=!1;A>k;){if(a=y(k++),a===c){d=!0;break}if("\\"===a)switch(a=y(k++)){case"n":b+="\n";break;case"r":b+="\r";break;case"t":b+=" ";break;case"b":b+="\b";break;case"f":b+="\f";break;case"v":b+=""}else b+=a}if(!d)throw new Error('Unclosed quote after "'+b+'"');return{type:e,value:b,raw:c+b+c}},H=function(){var b,d=z(k),g=k;if(!v(d))throw new Error("Unexpected "+y(k)+"at character "+k);for(k++;A>k&&(d=z(k),w(d));)k++;return b=a.slice(g,k),q.hasOwnProperty(b)?{type:e,value:q[b],raw:b}:b===r?{type:f}:{type:c,name:b}},I=function(){for(var a,c,d=[];A>k;){if(B(),a=y(k),")"===a){k++;break}if(","===a)k++;else{if(c=D(),!c||c.type===b)throw new Error("Expected comma at character "+k);d.push(c)}}return d},J=function(){var a,b,c;for(b=H(),B(),a=y(k);"."===a||"["===a||"("===a;){if("."===a)k++,B(),b={type:d,computed:!1,object:b,property:H()};else if("["===a){if(c=k,k++,b={type:d,computed:!0,object:b,property:D()},B(),a=y(k),"]"!==a)throw new Error("Unclosed [ at character "+k);k++,B()}else"("===a&&(k++,b={type:g,arguments:I(),callee:b});B(),a=y(k)}return b},K=function(){k++;var a=D();if(B(),")"===y(k))return k++,a;throw new Error("Unclosed ( at character "+k)},L=[];A>k;)if(i=y(k),";"===i||","===i)k++;else if(j=D())L.push(j);else if(A>k)throw new Error("Unexpected '"+y(k)+"' at character "+k);return 1===L.length?L[0]:{type:b,body:L}};if(x.version="0.2.8",x.toString=function(){return"JavaScript Expression Parser (JSEP) v"+x.version},x.addUnaryOp=function(a){return l[a]=k,this},x.addBinaryOp=function(a,b){return p=Math.max(a.length,p),m[a]=b,this},x.removeUnaryOp=function(a){return delete l[a],a.length===o&&(o=n(l)),this},x.removeBinaryOp=function(a){return delete m[a],a.length===p&&(p=n(m)),this},"undefined"==typeof exports){var y=a.jsep;a.jsep=x,x.noConflict=function(){return a.jsep===x&&(a.jsep=y),x}}else"undefined"!=typeof module&&module.exports?exports=module.exports=x:exports.parse=x}(this); | ||
/* jsep v0.2.9 (http://jsep.from.so/) */ | ||
!function(a){"use strict";var b="Compound",c="Identifier",d="MemberExpression",e="Literal",f="ThisExpression",g="CallExpression",h="UnaryExpression",i="BinaryExpression",j="LogicalExpression",k="ConditionalExpression",l="Array",m=46,n=44,o=39,p=34,q=40,r=41,s=91,t=93,u=63,v=59,w=58,x=function(a,b){var c=new Error(a+" at character "+b);throw c.index=b,c.dedscription=a,c},y=!0,z={"-":y,"!":y,"~":y,"+":y},A={"||":1,"&&":2,"|":3,"^":4,"&":5,"==":6,"!=":6,"===":6,"!==":6,"<":7,">":7,"<=":7,">=":7,"<<":8,">>":8,">>>":8,"+":9,"-":9,"*":10,"/":10,"%":10},B=function(a){var b,c=0;for(var d in a)(b=d.length)>c&&a.hasOwnProperty(d)&&(c=b);return c},C=B(z),D=B(A),E={"true":!0,"false":!1,"null":null},F="this",G=function(a){return A[a]||0},H=function(a,b,c){var d="||"===a||"&&"===a?j:i;return{type:d,operator:a,left:b,right:c}},I=function(a){return a>=48&&57>=a},J=function(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a},K=function(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a},L=function(a){for(var i,j,y=0,B=a.charAt,L=a.charCodeAt,M=function(b){return B.call(a,b)},N=function(b){return L.call(a,b)},O=a.length,P=function(){for(var a=N(y);32===a||9===a;)a=N(++y)},Q=function(){var a,b,c=S();return P(),N(y)!==u?c:(y++,a=Q(),a||x("Expected expression",y),P(),N(y)===w?(y++,b=Q(),b||x("Expected expression",y),{type:k,test:c,consequent:a,alternate:b}):(x("Expected :",y),void 0))},R=function(){P();for(var b=a.substr(y,D),c=b.length;c>0;){if(A.hasOwnProperty(b))return y+=c,b;b=b.substr(0,--c)}return!1},S=function(){var a,b,c,d,e,f,g,h;if(f=T(),b=R(),!b)return f;for(e={value:b,prec:G(b)},g=T(),g||x("Expected expression after "+b,y),d=[f,e,g];(b=R())&&(c=G(b),0!==c);){for(e={value:b,prec:c};d.length>2&&c<=d[d.length-2].prec;)g=d.pop(),b=d.pop().value,f=d.pop(),a=H(b,f,g),d.push(a);a=T(),a||x("Expected expression after "+b,y),d.push(e,a)}for(h=d.length-1,a=d[h];h>1;)a=H(d[h-1].value,d[h-2],a),h-=2;return a},T=function(){var b,c,d;if(P(),b=N(y),I(b)||b===m)return U();if(b===o||b===p)return V();if(J(b)||b===q)return Y();for(c=a.substr(y,C),d=c.length;d>0;){if(z.hasOwnProperty(c))return y+=d,{type:h,operator:c,argument:T(),prefix:!0};c=c.substr(0,--d)}return!1},U=function(){for(var a,b="";I(N(y));)b+=M(y++);if(N(y)===m)for(b+=M(y++);I(N(y));)b+=M(y++);if(a=M(y),"e"===a||"E"===a){for(b+=M(y++),a=M(y),("+"===a||"-"===a)&&(b+=M(y++));I(N(y));)b+=M(y++);I(N(y-1))||x("Expected exponent ("+b+M(y)+")",y)}return J(N(y))&&x("Variable names cannot start with a number ("+b+M(y)+")",y),{type:e,value:parseFloat(b),raw:b}},V=function(){for(var a,b="",c=M(y++),d=!1;O>y;){if(a=M(y++),a===c){d=!0;break}if("\\"===a)switch(a=M(y++)){case"n":b+="\n";break;case"r":b+="\r";break;case"t":b+=" ";break;case"b":b+="\b";break;case"f":b+="\f";break;case"v":b+=""}else b+=a}return d||x('Unclosed quote after "'+b+'"',y),{type:e,value:b,raw:c+b+c}},W=function(){var b,d=N(y),g=y;for(J(d)?y++:x("Unexpected "+M(y),y);O>y&&(d=N(y),K(d));)y++;return b=a.slice(g,y),E.hasOwnProperty(b)?{type:e,value:E[b],raw:b}:b===F?{type:f}:{type:c,name:b}},X=function(a){for(var c,d,e=[];O>y;){if(P(),c=N(y),c===a){y++;break}c===n?y++:(d=Q(),d&&d.type!==b||x("Expected comma",y),e.push(d))}return e},Y=function(){var a,b;for(a=N(y),b=a===q?Z():W(),P(),a=N(y);a===m||a===s||a===q;)y++,a===m?(P(),b={type:d,computed:!1,object:b,property:W()}):a===s?(b={type:d,computed:!0,object:b,property:Q()},P(),a=N(y),a!==t&&x("Unclosed [",y),y++):a===q&&(b={type:g,arguments:X(r),callee:b}),P(),a=N(y);return b},Z=function(){y++;var a=Q();return P(),N(y)===r?(y++,a):(x("Unclosed (",y),void 0)},$=function(){return y++,{type:l,body:X(t)}},_=[];O>y;)i=N(y),i===v||i===n?y++:i===s&&(j=$())?_.push(j):(j=Q())?_.push(j):O>y&&x('Unexpected "'+M(y)+'"',y);return 1===_.length?_[0]:{type:b,body:_}};if(L.version="0.2.9",L.toString=function(){return"JavaScript Expression Parser (JSEP) v"+L.version},L.addUnaryOp=function(a){return z[a]=y,this},L.addBinaryOp=function(a,b){return D=Math.max(a.length,D),A[a]=b,this},L.removeUnaryOp=function(a){return delete z[a],a.length===C&&(C=B(z)),this},L.removeBinaryOp=function(a){return delete A[a],a.length===D&&(D=B(A)),this},"undefined"==typeof exports){var M=a.jsep;a.jsep=L,L.noConflict=function(){return a.jsep===L&&(a.jsep=M),L}}else"undefined"!=typeof module&&module.exports?exports=module.exports=L:exports.parse=L}(this); | ||
//# sourceMappingURL=jsep.min.js.map |
{ | ||
"name": "jsep", | ||
"version": "0.2.8", | ||
"version": "0.2.9", | ||
"description": "a tiny JavaScript expression parser", | ||
@@ -29,3 +29,5 @@ "author": "Stephen Oney <swloney@gmail.com> (http://from.so/)", | ||
}, | ||
"engines": {"node": ">= 0.4.7"} | ||
"engines": {"node": ">= 0.4.7"}, | ||
"directories": {"test": "test"}, | ||
"scripts": {"test": "grunt test"} | ||
} |
173
src/jsep.js
@@ -22,3 +22,24 @@ // JavaScript Expression Parser (JSEP) <%= version %> | ||
LOGICAL_EXP = 'LogicalExpression', | ||
CONDITIONAL_EXP = 'ConditionalExpression', | ||
ARRAY_EXP = 'Array', | ||
PERIOD_CODE = 46, // '.' | ||
COMMA_CODE = 44, // ',' | ||
SQUOTE_CODE = 39, // single quote | ||
DQUOTE_CODE = 34, // double quotes | ||
OPAREN_CODE = 40, // ( | ||
CPAREN_CODE = 41, // ) | ||
OBRACK_CODE = 91, // [ | ||
CBRACK_CODE = 93, // ] | ||
QUMARK_CODE = 63, // ? | ||
SEMCOL_CODE = 59, // ; | ||
COLON_CODE = 58, // : | ||
throwError = function(message, index) { | ||
var error = new Error(message + ' at character ' + index); | ||
error.index = index; | ||
error.dedscription = message; | ||
throw error; | ||
}, | ||
// Operations | ||
@@ -117,2 +138,36 @@ // ---------- | ||
}, | ||
// The main parsing function. Much of this code is dedicated to ternary expressions | ||
gobbleExpression = function() { | ||
var test = gobbleBinaryExpression(), | ||
consequent, alternate; | ||
gobbleSpaces(); | ||
// Ternary expression: test ? consequent : alternate | ||
if(exprICode(index) === QUMARK_CODE) { | ||
index++; | ||
consequent = gobbleExpression(); | ||
if(!consequent) { | ||
throwError('Expected expression', index); | ||
} | ||
gobbleSpaces(); | ||
if(exprICode(index) === COLON_CODE) { | ||
index++; | ||
alternate = gobbleExpression(); | ||
if(!alternate) { | ||
throwError('Expected expression', index); | ||
} | ||
return { | ||
type: CONDITIONAL_EXP, | ||
test: test, | ||
consequent: consequent, | ||
alternate: alternate | ||
}; | ||
} else { | ||
throwError('Expected :', index); | ||
} | ||
} else { | ||
return test; | ||
} | ||
}, | ||
@@ -138,3 +193,3 @@ // Search for the operation portion of the string (e.g. `+`, `===`) | ||
// e.g. `1`, `1+2`, `a+(b*2)-Math.sqrt(2)` | ||
gobbleExpression = function() { | ||
gobbleBinaryExpression = function() { | ||
var ch_i, node, biop, prec, stack, biop_info, left, right, i; | ||
@@ -158,3 +213,3 @@ | ||
if(!right) { | ||
throw new Error("Expected expression after " + biop + " at character " + index); | ||
throwError("Expected expression after " + biop, index); | ||
} | ||
@@ -183,6 +238,5 @@ stack = [left, biop_info, right]; | ||
if(!node) { | ||
throw new Error("Expected expression after " + biop + " at character " + index); | ||
throwError("Expected expression after " + biop, index); | ||
} | ||
stack.push(biop_info); | ||
stack.push(node); | ||
stack.push(biop_info, node); | ||
} | ||
@@ -196,3 +250,2 @@ | ||
} | ||
return node; | ||
@@ -209,14 +262,11 @@ }, | ||
if(isDecimalDigit(ch) || ch === 46) { | ||
if(isDecimalDigit(ch) || ch === PERIOD_CODE) { | ||
// Char code 46 is a dot `.` which can start off a numeric literal | ||
return gobbleNumericLiteral(); | ||
} else if(ch === 39 || ch === 34) { | ||
} else if(ch === SQUOTE_CODE || ch === DQUOTE_CODE) { | ||
// Single or double quotes | ||
return gobbleStringLiteral(); | ||
} else if(isIdentifierStart(ch)) { | ||
} else if(isIdentifierStart(ch) || ch === OPAREN_CODE) { // open parenthesis | ||
// `foo`, `bar.baz` | ||
return gobbleVariable(); | ||
} else if(ch === 40) { | ||
// Open parentheses | ||
return gobbleGroup(); | ||
} else { | ||
@@ -244,3 +294,3 @@ to_check = expr.substr(index, max_unop_len); | ||
gobbleNumericLiteral = function() { | ||
var number = ''; | ||
var number = '', ch; | ||
while(isDecimalDigit(exprICode(index))) { | ||
@@ -250,3 +300,3 @@ number += exprI(index++); | ||
if(exprI(index) === '.') { // can start with a decimal marker | ||
if(exprICode(index) === PERIOD_CODE) { // can start with a decimal marker | ||
number += exprI(index++); | ||
@@ -259,5 +309,7 @@ | ||
if(exprI(index) === 'e' || exprI(index) === 'E') { // exponent marker | ||
ch = exprI(index); | ||
if(ch === 'e' || ch === 'E') { // exponent marker | ||
number += exprI(index++); | ||
if(exprI(index) === '+' || exprI(index) === '-') { // exponent sign | ||
ch = exprI(index); | ||
if(ch === '+' || ch === '-') { // exponent sign | ||
number += exprI(index++); | ||
@@ -269,4 +321,3 @@ } | ||
if(!isDecimalDigit(exprICode(index-1)) ) { | ||
throw new Error('Expected exponent (' + | ||
number + exprI(index) + ') at character ' + index); | ||
throwError('Expected exponent (' + number + exprI(index) + ')', index); | ||
} | ||
@@ -278,4 +329,4 @@ } | ||
if(isIdentifierStart(exprICode(index))) { | ||
throw new Error('Variable names cannot start with a number (' + | ||
number + exprI(index) + ') at character ' + index); | ||
throwError( 'Variable names cannot start with a number (' + | ||
number + exprI(index) + ')', index); | ||
} | ||
@@ -317,3 +368,3 @@ | ||
if(!closed) { | ||
throw new Error('Unclosed quote after "'+str+'"'); | ||
throwError('Unclosed quote after "'+str+'"', index); | ||
} | ||
@@ -338,3 +389,3 @@ | ||
} else { | ||
throw new Error('Unexpected ' + exprI(index) + 'at character ' + index); | ||
throwError('Unexpected ' + exprI(index), index); | ||
} | ||
@@ -368,14 +419,16 @@ | ||
// Gobbles a list of arguments within the context of a function call. This function | ||
// also assumes that the `(` has already been gobbled. | ||
// e.g. `foo(bar, baz)` or `my_func()` | ||
gobbleArguments = function() { | ||
// Gobbles a list of arguments within the context of a function call | ||
// or array literal. This function also assumes that the opening character | ||
// `(` or `[` has already been gobbled, and gobbles expressions and commas | ||
// until the terminator character `)` or `]` is encountered. | ||
// e.g. `foo(bar, baz)`, `my_func()`, or `[bar, baz]` | ||
gobbleArguments = function(termination) { | ||
var ch_i, args = [], node; | ||
while(index < length) { | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
if(ch_i === ')') { // done parsing | ||
ch_i = exprICode(index); | ||
if(ch_i === termination) { // done parsing | ||
index++; | ||
break; | ||
} else if (ch_i === ',') { // between expressions | ||
} else if (ch_i === COMMA_CODE) { // between expressions | ||
index++; | ||
@@ -385,3 +438,3 @@ } else { | ||
if(!node || node.type === COMPOUND) { | ||
throw new Error('Expected comma at character ' + index); | ||
throwError('Expected comma', index); | ||
} | ||
@@ -399,9 +452,15 @@ args.push(node); | ||
gobbleVariable = function() { | ||
var ch_i, node, old_index; | ||
node = gobbleIdentifier(); | ||
var ch_i, node; | ||
ch_i = exprICode(index); | ||
if(ch_i === OPAREN_CODE) { | ||
node = gobbleGroup(); | ||
} else { | ||
node = gobbleIdentifier(); | ||
} | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
while(ch_i === '.' || ch_i === '[' || ch_i === '(') { | ||
if(ch_i === '.') { | ||
index++; | ||
ch_i = exprICode(index); | ||
while(ch_i === PERIOD_CODE || ch_i === OBRACK_CODE || ch_i === OPAREN_CODE) { | ||
index++; | ||
if(ch_i === PERIOD_CODE) { | ||
gobbleSpaces(); | ||
@@ -414,5 +473,3 @@ node = { | ||
}; | ||
} else if(ch_i === '[') { | ||
old_index = index; | ||
index++; | ||
} else if(ch_i === OBRACK_CODE) { | ||
node = { | ||
@@ -425,14 +482,12 @@ type: MEMBER_EXP, | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
if(ch_i !== ']') { | ||
throw new Error('Unclosed [ at character ' + index); | ||
ch_i = exprICode(index); | ||
if(ch_i !== CBRACK_CODE) { | ||
throwError('Unclosed [', index); | ||
} | ||
index++; | ||
gobbleSpaces(); | ||
} else if(ch_i === '(') { | ||
} else if(ch_i === OPAREN_CODE) { | ||
// A function call is being made; gobble all the arguments | ||
index++; | ||
node = { | ||
type: CALL_EXP, | ||
'arguments': gobbleArguments(), | ||
'arguments': gobbleArguments(CPAREN_CODE), | ||
callee: node | ||
@@ -442,3 +497,3 @@ }; | ||
gobbleSpaces(); | ||
ch_i = exprI(index); | ||
ch_i = exprICode(index); | ||
} | ||
@@ -457,18 +512,32 @@ return node; | ||
gobbleSpaces(); | ||
if(exprI(index) === ')') { | ||
if(exprICode(index) === CPAREN_CODE) { | ||
index++; | ||
return node; | ||
} else { | ||
throw new Error('Unclosed ( at character ' + index); | ||
throwError('Unclosed (', index); | ||
} | ||
}, | ||
// Responsible for parsing Array literals `[1, 2, 3]` | ||
// This function assumes that it needs to gobble the opening bracket | ||
// and then tries to gobble the expressions as arguments. | ||
gobbleArray = function() { | ||
index++; | ||
return { | ||
type: ARRAY_EXP, | ||
body: gobbleArguments(CBRACK_CODE) | ||
}; | ||
}, | ||
nodes = [], ch_i, node; | ||
while(index < length) { | ||
ch_i = exprI(index); | ||
ch_i = exprICode(index); | ||
// Expressions can be separated by semicolons, commas, or just inferred without any | ||
// separators | ||
if(ch_i === ';' || ch_i ===',') { | ||
if(ch_i === SEMCOL_CODE || ch_i === COMMA_CODE) { | ||
index++; // ignore separators | ||
} else if (ch_i === OBRACK_CODE && (node = gobbleArray())) { | ||
nodes.push(node); | ||
} else { | ||
@@ -481,3 +550,3 @@ // Try to gobble each expression individually | ||
} else if(index < length) { | ||
throw new Error("Unexpected '"+exprI(index)+"' at character " + index); | ||
throwError('Unexpected "' + exprI(index) + '"', index); | ||
} | ||
@@ -484,0 +553,0 @@ } |
@@ -29,3 +29,3 @@ (function() { | ||
var filter_props = function(larger, smaller) { | ||
var rv = {}; | ||
var rv = (typeof larger.length === 'number') ? [] : {}; | ||
var prop_val; | ||
@@ -78,2 +78,11 @@ for(var prop_name in smaller) { | ||
test('Arrays', function() { | ||
test_parser("[]", {type: 'Array', body: []}); | ||
test_parser("[a]", { | ||
type: 'Array', | ||
body: [{type: 'Identifier', name: 'a'}] | ||
}); | ||
}); | ||
test('Ops', function() { | ||
@@ -108,7 +117,15 @@ test_op_expession("1"); | ||
"$foo[ bar][ baz] (a, bb , c ) .other12 ['lawl'][12]", | ||
"(a(b(c[!d]).e).f+'hi'==2) === true" | ||
"(a(b(c[!d]).e).f+'hi'==2) === true", | ||
"(Object.variable.toLowerCase()).length == 3", | ||
"(Object.variable.toLowerCase()) . length == 3" | ||
]).map(esprima_comparison_test); | ||
}); | ||
test('Ternary', function() { | ||
var val = jsep('a ? b : c'); | ||
equal(val.type, 'ConditionalExpression'); | ||
val = jsep('a||b ? c : d'); | ||
equal(val.type, 'ConditionalExpression'); | ||
}); | ||
}()); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 8 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
671465
28
7846
8