parser-combinator
Version:
Parser combinators
315 lines (251 loc) • 12.7 kB
JavaScript
;
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
*/
var _index = require('../stream/index');
var _index2 = _interopRequireDefault(_index);
var _option = require('../data/option');
var _option2 = _interopRequireDefault(_option);
var _list = require('../data/list');
var _list2 = _interopRequireDefault(_list);
var _response = require('./response');
var _response2 = _interopRequireDefault(_response);
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;
}
// Parser 'a 'c => ('a -> Parser 'b 'c) -> Parser 'b 'c
_createClass(Parser, [{
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
}, {
key: 'then',
value: function then(p) {
return this.flatmap(function (a) {
return p.map(function (b) {
var result = (0, _list2.default)(a).append((0, _list2.default)(b)).array();
if (result.length == 1) {
return result[0];
} else {
return result;
}
});
});
}
}, {
key: 'concat',
value: function concat(p) {
return this.then(p);
}
}, {
key: 'drop',
value: function drop() {
return this.map(function (item) {
return [];
});
}
// 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: 'thenReturns',
value: function thenReturns(v) {
return this.thenRight(returns(v));
}
// Parser 'a 'c -> Parser 'a 'c
}, {
key: 'or',
value: function or(p) {
return choice(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
*/
}, {
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(accept_a.input.location(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
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 -> 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 = (0, _list2.default)(),
offset = index,
current = self.parse(input, index),
occurrence = 0;
while (current.isAccepted() && occurrences(occurrence)) {
occurrence += 1;
value = value.append((0, _list2.default)(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(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);
});
}
//# sourceMappingURL=parser.js.map