var errors = function() { function ParseError(pos, msgs) { this.msgs = [].concat(msgs) this.line = pos.line this.column = pos.column } ParseError.prototype.show = function() { return this.msgs.join(', ') + " at" + " line: " + this.line + " column: " + this.column } ParseError.prototype.combine = function(errs) { if (!'length' in errs) errs = [errs] return new CombinedError([this].concat(errs)) } function CombinedError(errs) { this.errs = errs ? errs : [] } CombinedError.prototype.combine = function(errs) { if (!'length' in errs) errs = [errs] this.errs = this.errs.concat(errs) } function unknown_error(pos) { return new ParseError(pos, "Unknown error") } function unexpect_error(pos, msg) { return new ParseError(pos, "Unexpected " + msg) } function expect_error(pos, msg) { return new ParseError(pos, "Expected " + msg) } function merge_errors() { var a0 = arguments[0] var ar = Array.prototype.slice.call(arguments, 1) return ar.length ? a0.combine(ar) : a0 } return { Parse: ParseError , unknown: unknown_error , unexpect: unexpect_error , expect: expect_error , merge: merge_errors }}() var p_string = function() { function Parse_String_State(str) { function Parse_State(pos, line, column) { this.pos = pos || 0 this.line = line || 1 this.column = column || 1 } Parse_State.prototype.str = str Parse_State.prototype.increment = function(c) { var newline = c == '\n' return new Parse_State(this.pos+1, newline?this.line+1:this.line, newline?1:this.column+1) } Parse_State.prototype.getToken = function() { return this.str[this.pos] } Parse_State.prototype.length = function() { return this.str.length } return Parse_State } function char(x) { return function(t) { return x == t }} function digit() { return function(x){ var cx = x.charCodeAt(0); return cx < 58 && cx > 47 }} function letter() { return function(x) { var cx = x.charCodeAt(0) return (cx < 91 && cx > 64) || (cx < 123 && cx > 96) }} function whitespace() { return function(x) { return x == ' ' || x == '\t' || x == '\r' || x == '\n' }} function control() { return function(x) { return x.charCodeAt(0) < 32 }} function run(p, input, cb) { var str_state = new (Parse_String_State(input))() function pok(x) { cb(null, x) } function perr(err) { cb(err) } p(str_state, pok, perr, pok, perr) } return { Parse_State: Parse_String_State , char: char , digit: digit , letter: letter , whitespace: whitespace , control: control , run: run }}() var combinators = function() { function always(x) { return function(state, cok, cerr, eok, eerr) { eok(x, state) }} // avoiding infinite recursions function wrap(f) { return function(x) { return function(state, cok, cerr, eok, eerr) { return f(x)(state, cok, cerr, eok, eerr) }}} function bind_2(p, f) { return function(state, cok, cerr, eok, eerr) { function pcok(item, state) { var q = f(item) q(state, cok, cerr, cok, cerr) } function peok(item, state) { wrap(f)(item)(state, cok, cerr, eok, eerr) } p(state, pcok, cerr, peok, eerr) }} function bind() { var ar = arguments, ari, arn = ar.length - 1 if (arn == 1) return bind_2(arguments[0], arguments[1]) var last = ar[arn] var res = new Array(arn), resi return function(state, cok, cerr, eok, eerr) { ari = resi = 0; bind(ar[ari++], function bind_arg2(x) { res[resi++] = x if (resi == arn) return last.apply(this, res) else return bind(ar[ari++], bind_arg2) }) (state, cok, cerr, eok, eerr)}} function next(p, q) { return bind(p, function() { return q }) } function nxtnxt() { var ar = Array.prototype.slice.call(arguments) return ar.reduceRight(function(p, c) { return next(c, p) }) } function never(err) { return function(state, cok, cerr, eok, eerr) { eerr(errors.unknown(state)) } } function either(p, q) { return function(state, cok, cerr, eok, eerr) { function p_eerr(err_from_p) { function q_eerr(err_from_q) { eerr(errors.merge(err_from_p, err_from_q)) } q(state, cok, cerr, eok, q_eerr) } p(state, cok, cerr, eok, p_eerr) } } function attempt(p) { return function(state, cok, cerr, eok, eerr) { p(state, cok, eerr, eok, eerr) }} function token(consume_p) { return function(state, cok, cerr, eok, eerr) { var t = state.getToken() if (!t) eerr(errors.unexpect(state, 'end of input')) else if (consume_p(t)) cok(t, state.increment(t)) else eerr(errors.unexpect(state, "token " + t)) } } function times(n, p) { if (n == 0) return always(null) return function (state, cok, cerr, eok, eerr) { var res = new Array(n) var resi = 0 function pcok(item, state) { function peok(item, state) { while(resi < n) res[resi++] = item cok(res, state) } res[resi++] = item if (resi < n) p(state, pcok, cerr, pcok, eerr) else if (resi == n) cok(res, state) } function peok(item, state) { while(resi < n) res[resi++] = item eok(res, state) } p(state, pcok, cerr, peok, eerr) } } function many(p) { function many_err() { throw new TypeError('`many` applied to parser that accepts an empty string') } function safe_p(state, cok, cerr, eok, eerr) { p(state, cok, cerr, many_err, eerr) } return either( bind(safe_p, wrap(many)(p), function(x, xs) { return always([x].concat(xs)) }) , always([])) } function many1(p) { return bind(p, many(p), function(x, xs) { return always([x].concat(xs) )})} function lookahead(p) { return function(state, cok, cerr, eok, eerr) { function ok(t) { eok(t, state) } p(state, ok, cerr, eok, eerr) } } function choice(first) { /* either + varargs */ var ar = Array.prototype.slice.call(arguments, 1) if (ar.length == 0 && !first) return never if (ar.length == 0 && first) return first return either(first, choice.apply(null, ar)) } function eof() { return function(state, cok, cerr, eok, eerr) { if (state.pos == state.length()) eok(null, state) else eerr(errors.expect(state, "end of input")) } } function between(open, close, p) { return bind(open, p, close, function(o, x, c) { return always(x) }) } return { always: always , bind: bind , next: next , nxtnxt: nxtnxt , never: never , wrap: wrap , either: either , attempt: attempt , many: many , many1: many1 , times: times , token: token , lookahead: lookahead , choice: choice , between: between , eof: eof }}() var funp = function() { // functional programming helpers, especially useful with token() function not(f) { return function(x) { return !f(x) }} function and(p, q) { return function(x) { return p(x) && q(x) }} function or(p, q) { /* todo more than 2 args */ if (arguments.length > 2) return Array.prototype.slice.call(arguments).reduce(function(p,q){return or(p,q)}) return function(x) { return p(x) || q(x) }} return { not: not , and: and , or: or }}() module.exports = { combinators: combinators , errors: errors , p_string: p_string , funp: funp }