peasy
Version:
an easy but powerful parser
396 lines (382 loc) • 12.6 kB
JavaScript
var exports, module, require;
(function(require, exports, module) {var ts;if (typeof window === 'object') { ts = twoside('peasy/samples/arithmatic2.js'), require = ts.require, exports = ts.exports, module = ts.module;} // wrap line by gulp-twoside for providing twoside module;
/*https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
Precedence Operator type Associativity Individual operators
1 new right-to-left new
2 function call left-to-right ()
property access left-to-right .
left-to-right []
3 ++ n/a --
4 right-to-left ! ~ + - typeof void delete
5 * / % //
6 + -
7 << >> >>>
8 < <= > >= in instanceof
9 == != === !==
10 bitwise-and left-to-right &
11 bitwise-xor left-to-right ^
12 bitwise-or left-to-right |
13 logical-and left-to-right &&
14 logical-or left-to-right ||
15 condition right-to-left ?:
16 yield right-to-left yield
17 assignment right-to-left = += -= *= /= %= <<= >>= >>>= &= ^= |=
18 comma left-to-right ,
*/
var Parser, StateMachine, charset, identifierCharSet, identifierChars, in_, letterDigits, peasy, _in_,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
peasy = require("../peasy");
StateMachine = require("./statemachine").StateMachine;
in_ = peasy.in_, charset = peasy.charset, letterDigits = peasy.letterDigits;
_in_ = in_;
identifierChars = '$_' + letterDigits;
identifierCharSet = charset(identifierChars);
exports.Parser = Parser = (function(_super) {
__extends(Parser, _super);
function Parser() {
var addassign, assign, assignExpr, assignExpr_, assignOperator, atom, attr, binaryOpItems, binaryOpPriorityMap, binaryOperator, binarysm, bitandassign, bitnot, bitorassign, bitxorassign, bracketExpr, bracketExpr1, callPropExpr, callPropTail, char, colon, comma, condition, dec, delete_, divassign, dot, dotIdentifier, eoi, error, expect, expr, expression, expression_, headAtom, headExpr, identifier, idivassign, inc, incDec, lbracket, list, literal, logicOrExpr, lpar, lshiftassign, memo, modassign, mulassign, myop, negative, newExpr, new_, not1, not_, number, orBinary, orp, param, paramExpr, paren, paren1, parenExpr, posNeg, positive, prefixExpr, property, question, rbracket, rec, rpar, rshiftassign, self, simpleExpr, spaces, string, subassign, suffixExpr, typeof_, unaryExpr, unaryOp, unaryTail, void_, wrap, wrapColon, wrapDot, wrapQuestion, zrshiftassign, _ref;
Parser.__super__.constructor.apply(this, arguments);
_ref = self = this, orp = _ref.orp, list = _ref.list, rec = _ref.rec, memo = _ref.memo, wrap = _ref.wrap, char = _ref.char, literal = _ref.literal, spaces = _ref.spaces, eoi = _ref.eoi, identifier = _ref.identifier;
number = function() {
var base, c, cur, start, text;
text = self.data;
start = cur = self.cur;
base = 10;
c = text[cur];
if (c === '+' || c === '-') {
cur++;
}
if (text[cur] === '0') {
c = text[++cur];
if (c === 'x' || c === 'X') {
base = 16;
cur++;
}
}
if (base === 16) {
while (c = text[cur]) {
if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))) {
self.cur = cur;
return text.slice(start, cur);
}
cur++;
}
}
while (c = text[cur]) {
if (!(('0' <= c && c <= '9'))) {
break;
}
cur++;
}
if (text[cur] === '.') {
cur++;
while (c = text[cur]) {
if (!(('0' <= c && c <= '9'))) {
break;
}
cur++;
}
if (text[cur - 1] === '.' && (c = text[cur - 2]) && !(('0' <= c && c <= '9'))) {
return;
}
}
c = text[cur];
if (c === 'E' || c === 'e') {
cur++;
while (c = text[cur]) {
if (!(('0' <= c && c <= '9'))) {
break;
}
cur++;
}
if ((c = text[cur - 1]) && (c === 'E' || c === 'e')) {
return;
}
}
self.cur = cur;
return text.slice(start, cur);
};
string = function() {
var c, cur, quote, result, text;
text = self.data;
cur = self.cur;
c = text[cur];
if (c === '"' || c === "'") {
quote = c;
} else {
return;
}
result = '';
cur++;
while (1) {
c = text[cur];
if (c === '\\') {
result += text[cur + 1];
cur += 2;
} else if (c === quote) {
self.cur = cur + 1;
return quote + result + quote;
} else if (!c) {
error('expect ' + quote);
} else {
result += c;
cur++;
}
}
};
question = char('?');
colon = char(':');
comma = char(',');
dot = char('.');
lpar = char('(');
rpar = char(')');
lbracket = char('[');
rbracket = char(']');
myop = function(op) {
var opFn;
if (op.length === 1) {
opFn = char(op);
} else {
opFn = literal(op);
}
if (_in_(op[0], identifierCharSet)) {
return function() {
return spaces() && (op = opFn()) && spaces() && !_in_(data[self.cur], identifierCharSet) && ' ' + op + ' ';
};
} else {
return function() {
return spaces() && (op = opFn()) && spaces() && op;
};
}
};
posNeg = function(op) {
var opFn;
opFn = char(op);
return function() {
var c;
return spaces() && (op = opFn()) && (c = self.data[self.cur]) && c !== '.' && !(('0' <= c && c <= '9')) && spaces() && op;
};
};
positive = posNeg('+');
negative = posNeg('-');
new_ = myop('new');
inc = myop('++');
dec = myop('--');
not1 = orp(myop('!'), myop('not'));
not_ = function() {
return not1();
};
bitnot = myop('~');
typeof_ = myop('typeof');
void_ = myop('void');
delete_ = myop('delete');
unaryOp = orp(not_, bitnot, positive, negative, typeof_, void_);
comma = myop(',');
assign = myop('=');
addassign = myop('+=');
subassign = myop('-=');
mulassign = myop('*=');
divassign = myop('/=');
modassign = myop('%=');
idivassign = myop('//=');
rshiftassign = myop('>>=');
lshiftassign = myop('<<=');
zrshiftassign = myop('>>>=');
bitandassign = myop('&=');
bitxorassign = myop('^=');
bitorassign = myop('|=');
error = function(msg) {
throw self.data.slice(self.cur - 20, +(self.cur + 20) + 1 || 9e9) + ' ' + self.cur + ': ' + msg;
};
expect = function(fn, msg) {
return fn() || error(msg);
};
incDec = orp(inc, dec);
prefixExpr = function() {
var op, x;
return (op = incDec()) && (x = headExpr()) && op + x;
};
suffixExpr = function() {
var op, x;
return (x = headExpr()) && (op = incDec()) && x + op;
};
paren = function(item, left, right, msg) {
if (left == null) {
left = lpar;
}
if (right == null) {
right = rpar;
}
if (msg == null) {
msg = 'expect ) to match (';
}
if ((typeof item) === 'string') {
left = self.literal(item);
}
if ((typeof left) === 'string') {
left = self.literal(left);
}
if ((typeof right) === 'string') {
right = self.literal(right);
}
return function() {
var start, x;
start = self.cur;
return left() && (x = item()) && expect(right, msg + ' at: ' + start) && x;
};
};
paren1 = paren(function() {
var x;
return spaces() && (x = expression()) && spaces() && x;
});
parenExpr = memo(function() {
var x;
return (x = paren1()) && '(' + x + ')';
});
atom = memo(orp(parenExpr, number, string, identifier));
newExpr = function() {
var x;
return new_() && (x = callProp()) && 'new ' + x;
};
unaryTail = orp(prefixExpr, suffixExpr, atom);
unaryExpr = function() {
var op, x;
return (op = unaryOp()) && (x = unaryTail()) && op + x;
};
bracketExpr1 = wrap(paren(wrap(function() {
return commaExpr();
}), lbracket, rbracket, 'expect ] to match ['));
bracketExpr = function() {
var x;
return (x = bracketExpr1()) && '[' + x + ']';
};
wrapDot = wrap(dot);
dotIdentifier = function() {
var id;
return wrapDot() && (id = expect(identifier, 'expect identifier')) && '.' + id;
};
attr = orp(bracketExpr, dotIdentifier);
param = paren(function() {
var x;
return (spaces() && (x = expression()) && spaces() && expect(rpar, 'expect )')) || ' ';
});
paramExpr = memo(function() {
var x;
return (x = param()) && '(' + x + ')';
});
callPropTail = orp(paramExpr, attr);
callPropExpr = rec(function() {
var e, h;
return (h = headExpr()) && (((e = callPropTail()) && h + e) || h);
});
property = rec(function() {
var e, h;
return (h = headExpr()) && (((e = attr()) && h + e) || h);
});
headAtom = memo(orp(parenExpr, identifier));
headExpr = memo(orp(callPropExpr, headAtom));
simpleExpr = memo(orp(unaryExpr, prefixExpr, suffixExpr, callPropExpr, newExpr, atom));
binaryOpPriorityMap = {
5: ['*', '/', '//', '%'],
6: ['+', '-'],
7: ['<<', '>>', '>>>'],
8: ['<', '<=', '>', '>=', 'in ', 'in\t', 'instanceof ', 'instanceof\t'],
9: ['==', '!=', '==', '==='],
10: ['&'],
11: ['|'],
12: ['^'],
13: ['&&'],
14: ['||'],
17: [',']
};
binaryOpItems = [];
(function() {
var k, op, ops, _results;
_results = [];
for (k in binaryOpPriorityMap) {
ops = binaryOpPriorityMap[k];
_results.push((function() {
var _i, _len, _results1;
_results1 = [];
for (_i = 0, _len = ops.length; _i < _len; _i++) {
op = ops[_i];
_results1.push(binaryOpItems.push([
op, {
text: op,
pri: parseInt(k)
}
]));
}
return _results1;
})());
}
return _results;
})();
binarysm = new StateMachine(binaryOpItems);
binaryOperator = memo(function() {
var m;
m = binarysm.match(self.data, self.cur);
if (m[0]) {
self.cur = m[1];
return m[0];
}
});
expr = function(n) {
var binary;
return binary = rec(function() {
var beforeOp, fn, op, x, y, _ref1;
if (x = binary()) {
beforeOp = self.cur;
if ((op = binaryOperator()) && ((n >= (_ref1 = op.pri) && _ref1 >= x.pri)) && (fn = expr(op.pri)) && (y = fn())) {
return {
text: x.text + op.text + y.text,
pri: op.pri
};
} else {
self.cur = beforeOp;
return x;
}
} else if (x = simpleExpr()) {
return {
text: x,
pri: 4
};
}
});
};
orBinary = expr(15);
logicOrExpr = function() {
var x;
return (x = orBinary()) && x.text;
};
wrapQuestion = wrap(question);
wrapColon = wrap(colon);
condition = function() {
var x, y, z;
return (x = logicOrExpr()) && ((wrapQuestion() && (y = assignExpr()) && expect(wrapColon, 'expect :') && (z = assignExpr()) && x + '? ' + y + ': ' + z) || x);
};
assignOperator = orp(assign, addassign, subassign, mulassign, divassign, modassign, idivassign, rshiftassign, lshiftassign, zrshiftassign, bitandassign, bitxorassign, bitorassign);
assignExpr_ = function() {
var e, op, v;
if ((v = property()) && (op = assignOperator())) {
return (e = expect(assignExpr, 'expect the right hand side of assign.')) && v + op + e;
}
};
assignExpr = orp(assignExpr_, condition);
expression_ = list(assignExpr, wrap(comma));
expression = function() {
var x;
x = expression_();
if (x) {
return x.join(',');
}
};
this.root = function() {
var x;
return (x = expression()) && expect(eoi, 'expect end of input') && x;
};
}
return Parser;
})(peasy.Parser);
})(require, exports, module);// wrap line by gulp-twoside