UNPKG

@masala/parser

Version:
418 lines (342 loc) 15.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /* * Parsec * https://github.com/d-plaindoux/parsec * * Copyright (c) 2016 Didier Plaindoux * Licensed under the LGPL2 license. */ /* * Parsec: Direct Style Monadic Parser Combinators For The Real World * * http://research.microsoft.com/en-us/um/people/daan/download/papers/parsec-paper.pdf */ exports.eos = eos; var _index = require('../stream/index'); var _index2 = _interopRequireDefault(_index); var _option = require('../data/option'); var _option2 = _interopRequireDefault(_option); var _response = require('./response'); var _response2 = _interopRequireDefault(_response); var _unit = require('../data/unit'); var _unit2 = _interopRequireDefault(_unit); var _tuple = require('../data/tuple'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Parser class */ var Parser = function () { // (Stream 'c -> number -> Response 'a 'c) -> Parser 'a 'c function Parser(parse) { _classCallCheck(this, Parser); this.parse = parse.bind(this); } _createClass(Parser, [{ key: 'val', value: function val(text) { return this.parse(_index2.default.ofString(text)).value; } // Parser 'a 'c => ('a -> Parser 'b 'c) -> Parser 'b 'c }, { key: 'flatMap', value: function flatMap(f) { return bind(this, f); } // Parser 'a 'c => ('a -> 'b) -> Parser 'b 'c }, { key: 'map', value: function map(f) { var self = this; return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return self.parse(input, index).map(f); }); } // Parser 'a 'c => ('a -> boolean) -> Parser 'a 'c }, { key: 'filter', value: function filter(p) { var self = this; return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return self.parse(input, index).filter(p); }); } // Parser 'a 'c => Comparable 'a -> Parser 'a 'c }, { key: 'match', value: function match(v) { return this.filter(function (a) { return a === v; }); } // Parser 'a 'c => Parser 'b 'c -> Parser ('a,'b) 'c // Parser 'a 'c => Parser 'b 'c -> Parser ('a,'b) 'c }, { key: 'then', value: function then(p) { return this.flatMap(function (a) { return p.map(function (b) { return new _tuple.Tuple([]).append(a).append(b); }); }); } }, { key: 'single', value: function single() { return this.map(function (tuple) { return tuple.single(); }); } }, { key: 'last', value: function last() { return this.map(function (tuple) { return tuple.last(); }); } }, { key: 'first', value: function first() { return this.map(function (tuple) { return tuple.first(); }); } // Should be called only on ListParser ; Always returns an array }, { key: 'array', value: function array() { return this.map(function (value) { if (!(0, _tuple.isTuple)(value)) { throw 'array() is called only on TupleParser'; } return value.array(); }); } }, { key: 'thenEos', value: function thenEos() { return this.then(eos().drop()); } }, { key: 'eos', value: function eos() { var _this = this; return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return _this.parse(input, index).fold(function (accept) { return input.endOfStream(accept.offset) ? _response2.default.accept(accept.value, accept.input, accept.offset, true) : _response2.default.reject(accept.input, accept.offset, accept.consumed); }, function (reject) { return _response2.default.reject(reject.input, reject.offset, reject.consumed); }); }); } }, { key: 'concat', value: function concat(p) { return this.then(p); } }, { key: 'drop', value: function drop() { return this.map(function () { return _tuple.NEUTRAL; }); } // Parser 'a 'c => Parser 'b 'c -> Parser 'a 'c }, { key: 'thenLeft', value: function thenLeft(p) { return this.then(p.drop()); } // Parser 'a 'c => Parser 'b 'c -> Parser 'b 'c }, { key: 'thenRight', value: function thenRight(p) { return this.drop().then(p); } // Parser 'a 'c => 'b -> Parser 'b 'c }, { key: 'returns', value: function returns(v) { return this.drop().map(function () { return v; }); } // Parser 'a 'c -> Parser 'a 'c }, { key: 'or', value: function or(p) { return choice(this, p); } /** * Must be used with F.layer() * @param p * @returns {Parser} */ }, { key: 'and', value: function and(p) { return both(this, p); } // Parser 'a 'c => unit -> Parser (Option 'a) 'c }, { key: 'opt', value: function opt() { return this.map(_option2.default.some).or(returns(_option2.default.none())); } // Parser 'a 'c => unit -> Parser (List 'a) 'c }, { key: 'rep', value: function rep() { return repeatable(this, function () { return true; }, function (l) { return l !== 0; }); } // Parser 'a 'c => number -> Parser (List 'a) 'c }, { key: 'occurrence', value: function occurrence(_occurrence) { return repeatable(this, function (l) { return l < _occurrence; }, function (l) { return l === _occurrence; }); } // Parser 'a 'c => unit -> Parser (List 'a) 'c }, { key: 'optrep', value: function optrep() { return repeatable(this, function () { return true; }, function () { return true; }); } // Parser 'a 'c => Parser 'b 'a -> Parser 'b 'c }, { key: 'chain', value: function chain(p) { var self = this; return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return p.parse(_index2.default.buffered(_index2.default.ofParser(self, input)), index); }); } /** * Prints a hint if the parser enters in this step * @param hint * @returns the equivalent Parser */ // TODO: set details default at false; check tests }, { key: 'debug', value: function debug(hint) { var details = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var f = function f(p) { if (details) { console.log('[debug] : ', hint, p); } else { console.log('[debug] : ', hint); } return p; }; return this.map(f); } }]); return Parser; }(); // Response 'a 'c -> ('a -> Parser 'b 'c) -> Response 'b 'c exports.default = Parser; function bindAccepted(accept_a, f) { return f(accept_a.value).parse(accept_a.input, accept_a.offset).fold(function (accept_b) { return _response2.default.accept(accept_b.value, accept_b.input, accept_b.offset, accept_a.consumed || accept_b.consumed); }, function (reject_b) { return _response2.default.reject(reject_b.input, reject_b.offset, accept_a.consumed || reject_b.consumed); }); } // Parser 'a 'c -> ('a -> Parser 'b 'c) -> Parser 'b 'c function bind(self, f) { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return self.parse(input, index).fold(function (accept_a) { return bindAccepted(accept_a, f); }, function (reject_a) { return reject_a; }); }); } // Parser 'a 'c -> Parser 'a 'c -> Parser 'a 'c // TODO logger representing which choice is made function choice(self, f) { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return self.parse(input, index).fold(function (accept) { return accept; }, function (reject) { return reject.consumed ? reject : f.parse(input, index); }); }); } // Parser 'a 'c -> Parser 'a 'c -> Parser 'a 'c function both(self, f) { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return self.parse(input, index).fold(function (accept) { return f.parse(input, index).map(function (r) { return accept.value.append(r); }); }, function (reject) { return reject; }); }); } // Parser 'a 'c -> unit -> Parser (List 'a) 'c function repeatable(self, occurrences, accept) { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var consumed = false, value = new _tuple.Tuple([]), offset = index, current = self.parse(input, index), occurrence = 0; while (current.isAccepted() && occurrences(occurrence)) { occurrence += 1; value = value.append(current.value); consumed = consumed || current.consumed; offset = current.offset; current = self.parse(input, current.offset); } if (accept(occurrence)) { return _response2.default.accept(value, input, offset, consumed); } return _response2.default.reject(input, offset, consumed); }); } /* * Builders */ function returns(v) { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return _response2.default.accept(v, input, index, false); }); } // unit -> Parser unit 'c function eos() { return new Parser(function (input) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; if (input.endOfStream(index)) { return _response2.default.accept(_unit2.default, input, index, false); } else { return _response2.default.reject(input, index, false); } }); } //# sourceMappingURL=parser.js.map