@masala/parser
Version:
255 lines (209 loc) • 8.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GenLex = exports.Token = exports.TokenDefinition = undefined;
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; }; }();
exports.getMathGenLex = getMathGenLex;
var _response = require("../parsec/response");
var _response2 = _interopRequireDefault(_response);
var _parsec = require("../parsec");
var _unit = require("../data/unit");
var _unit2 = _interopRequireDefault(_unit);
var _option = require("../data/option");
var _option2 = _interopRequireDefault(_option);
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"); } }
var TokenDefinition =
// value will be determined at runtime while parsing
exports.TokenDefinition = function TokenDefinition(parser, name, precedence) {
_classCallCheck(this, TokenDefinition);
this.parser = parser;
this.name = name;
this.precedence = precedence;
};
// a Token object is instantiated at runtime, with a value given by the parsed text
var Token = exports.Token = function () {
function Token(name, value) {
_classCallCheck(this, Token);
this.name = name;
this.value = value;
}
_createClass(Token, [{
key: "accept",
value: function accept(name) {
// TODO logger console.log('accepting', name, this.name===name, this.value);
return this.name === name ? _option2.default.some(this.value) : _option2.default.none();
}
}]);
return Token;
}();
var GenLex = exports.GenLex = function () {
function GenLex() {
_classCallCheck(this, GenLex);
this.spaces = defaultSpaces();
// definitions keep trace of all: parser, precedence and name
this.definitions = [];
// get a token, but not directly its precedence
this.tokensMap = {};
}
_createClass(GenLex, [{
key: "tokenize",
value: function tokenize(parser, name) {
var precedence = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
if (typeof parser === 'string') {
if (name === undefined) {
name = parser;
}
return this.tokenize(_parsec.C.string(parser), name, precedence);
}
var definition = new TokenDefinition(parser, name, precedence);
this.definitions.push(definition);
// probably a bad name
var token = literal(function (token) {
return token.accept(name);
}, name);
this.tokensMap[name] = token;
return token;
}
}, {
key: "keywords",
value: function keywords(keys) {
var _this = this;
var precedence = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
return keys.reduce(function (acc, key) {
return acc.concat(_this.tokenize(key, key, precedence));
}, []);
}
}, {
key: "setSeparators",
value: function setSeparators(spacesCharacters) {
if (typeof spacesCharacters !== 'string') {
throw "setSeparators needs a string as separators, such as ' \r\n\f\t' ;" + " use setSeparatorsParser to declare a parser";
}
this.spaces = _parsec.C.charIn(spacesCharacters).map(function () {
return _unit2.default;
});
}
/**
* Set separator Parser. It's up to the parser to accept or not
* optional repetition
* @param spacesParser
*/
}, {
key: "setSeparatorsParser",
value: function setSeparatorsParser(spacesParser) {
this.spaces = spacesParser.map(function () {
return _unit2.default;
});
}
}, {
key: "updatePrecedence",
value: function updatePrecedence(tokenName, precedence) {
this.definitions.find(function (def) {
return def.name === tokenName;
}).precedence = precedence;
}
}, {
key: "buildTokenizer",
value: function buildTokenizer() {
var token = this.findTokenByPrecedence();
return this.spaces.optrep().drop().then(token).then(this.spaces.optrep().drop()).single();
}
}, {
key: "use",
value: function use(grammar) {
return this.buildTokenizer().chain(grammar);
}
}, {
key: "findTokenByPrecedence",
value: function findTokenByPrecedence() {
var sortedDefinitions = this.definitions.sort(function (d1, d2) {
return d2.precedence - d1.precedence;
});
return sortedDefinitions.reduce(function (combinator, definition) {
return _parsec.F.try(getTokenParser(definition))
// .or (F.error('no match for '+definition.name))
.or(combinator);
}, _parsec.F.error());
}
}, {
key: "remove",
value: function remove(tokenName) {
// find definitions
this.definitions = this.definitions.filter(function (d) {
return d.name !== tokenName;
});
delete this.tokensMap[tokenName];
}
// type: { [key: string]: Parser }
}, {
key: "tokens",
value: function tokens() {
return this.tokensMap;
}
}, {
key: "get",
value: function get(tokenName) {
return this.tokensMap[tokenName];
}
}]);
return GenLex;
}();
function getTokenParser(def) {
return def.parser.map(function (value) {
return new Token(def.name, value);
});
}
// name is for easier debugging
// eslint-disable-next-line
function literal(tokenize, name) {
return _parsec.F.parse(function (input, index) {
// TODO logger console.log('testing ', {name, input:input.get(index), index});
// console.log('trying ', {index, name});
return input.get(index)
// FIXME= value is the token, token is the value
.map(function (value) {
/* TODO: keep for logger
let token = value;
try {
console.log('in map', {value, name, index});
console.log('tokenizing', tokenize(token));
} catch (e) {
console.error('failed', e)
}*/
return tokenize(value).map(function (token) {
// TODO logger console.log('accept with ', name, index);
//console.log('accept:', token,index, input.location(index));
return _response2.default.accept(token, input, index + 1, true);
}).orLazyElse(function () {
// TODO logger console.log('lazyElse failed with ', name, index);
// console.log('reject:',index, input.source.offsets[index],input,'>>>', value,
// input.location(index));
return _response2.default.reject(input, index, false);
});
}).lazyRecoverWith(function () {
// TODO logger console.log('failed with ', name, index);
//console.log('lazyRecover with offset:', input.location(index));
return _response2.default.reject(input, index, false);
});
});
}
function defaultSpaces() {
return _parsec.C.charIn(' \r\n\f\t').map(function () {
return _unit2.default;
});
}
function getMathGenLex() {
var basicGenlex = new GenLex();
// We try first to have digits
basicGenlex.tokenize(_parsec.N.number(), 'number', 1100);
basicGenlex.tokenize(_parsec.C.char('+'), 'plus', 1000);
basicGenlex.tokenize(_parsec.C.char('-'), 'minus', 1000);
basicGenlex.tokenize(_parsec.C.char('*'), 'mult', 800);
basicGenlex.tokenize(_parsec.C.char('/'), 'div', 800);
basicGenlex.tokenize(_parsec.C.char('('), 'open', 1000);
basicGenlex.tokenize(_parsec.C.char(')'), 'close', 1000);
return basicGenlex;
}
//# sourceMappingURL=genlex.js.map