UNPKG

tell-me-when

Version:
251 lines (240 loc) 6.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StringTokenNode = exports.RepeatNode = exports.RegExpNode = exports.ParseAsNode = exports.OrNode = exports.NegativeLookaheadNode = exports.MaybeNode = exports.LongestOfNode = exports.GroupNode = exports.GrammarNodeRef = exports.GrammarNode = void 0; var _ParseNode = require("./ParseNode.js"); class GrammarNode { parseAs(parseAs) { return new ParseAsNode(this, parseAs); } /** * Matches this node once or zero times */ maybe() { return new MaybeNode(this); } /** * Matches this node or the alternate node */ or(alternate) { return new OrNode(this, alternate); } /** * Matches one of the given nodes. The first option to parse successfully wins */ static oneOf(...options) { return new OrNode(...options.map(GrammarNode.toGrammarNode)); } /** * Matches one of the given nodes. Tries all of the options, and the one that * successfully parses the farthest in the input wins */ static longestOf(...options) { return new LongestOfNode(...options.map(GrammarNode.toGrammarNode)); } /** * Matches this node repeated the given number of times */ /** * Matches this node repeated between min and max (inclusive) times */ repeat(countOrMin, max) { return new RepeatNode(this, max != null ? [countOrMin, max] : countOrMin); } static toGrammarNode(factor) { return typeof factor === 'function' ? new GrammarNodeRef(factor) : factor instanceof GrammarNode ? factor : GrammarNode.token(factor); } /** * Matches the given string or regular expression */ static token(token) { return token instanceof RegExp ? new RegExpNode(token) : new StringTokenNode(token); } /** * Matches the given nodes in sequence */ static group(...sequence) { return new GroupNode(undefined, ...sequence.map(GrammarNode.toGrammarNode)); } /** * Creates a named group that matches the given nodes in sequence. * Same as {@link group} but the {@link ParseNode} returned by {@link parse} * will have the given name. */ static named(name, ...sequence) { return new GroupNode(name, ...sequence.map(GrammarNode.toGrammarNode)); } static negativeLookahead(...sequence) { return new NegativeLookaheadNode(sequence.length === 1 ? GrammarNode.toGrammarNode(sequence[0]) : GrammarNode.group(...sequence)); } } exports.GrammarNode = GrammarNode; class GrammarNodeRef extends GrammarNode { constructor(ref) { super(); this.ref = ref; } parse(state) { return this.ref().parse(state); } } exports.GrammarNodeRef = GrammarNodeRef; class StringTokenNode extends GrammarNode { constructor(token) { super(); this.token = token; this.token = this.token.toLowerCase(); } parse(state) { const start = state.index; if (state.testLowerCase(this.token)) { return new _ParseNode.ParseNode(undefined, start, state.index); } return _ParseNode.ParseNode.error(start); } } exports.StringTokenNode = StringTokenNode; class RegExpNode extends GrammarNode { constructor(token) { super(); this.token = token; if (!token.sticky) { this.token = new RegExp(token.source, `${token.flags}y`); } } parse(state) { const start = state.index; if (state.testRegex(this.token)) { return new _ParseNode.ParseNode(undefined, start, state.index); } return _ParseNode.ParseNode.error(start); } } exports.RegExpNode = RegExpNode; class MaybeNode extends GrammarNode { constructor(node) { super(); this.node = node; } parse(state) { const parsed = this.node.parse(state); return parsed.isError ? _ParseNode.ParseNode.empty(state.index) : parsed; } } exports.MaybeNode = MaybeNode; class RepeatNode extends GrammarNode { constructor(node, count) { super(); this.node = node; this.count = count; } parse(state) { const startIndex = state.index; const children = []; for (let i = 0; i < (Array.isArray(this.count) ? this.count[1] : this.count); i++) { const parsed = this.node.parse(state); if (parsed.isError) { if (i < (Array.isArray(this.count) ? this.count[0] : this.count)) { state.index = startIndex; return parsed; } break; } if (!parsed.isEmpty) children.push(parsed); } return new _ParseNode.ParseNode(undefined, startIndex, state.index, children); } } exports.RepeatNode = RepeatNode; class OrNode extends GrammarNode { options; constructor(...options) { super(); this.options = options; } parse(state) { const startIndex = state.index; for (const option of this.options) { const parsed = option.parse(state); if (!parsed.isError) return parsed; } state.index = startIndex; return _ParseNode.ParseNode.error(startIndex); } } exports.OrNode = OrNode; class LongestOfNode extends GrammarNode { options; constructor(...options) { super(); this.options = options; } parse(state) { const startIndex = state.index; let best = _ParseNode.ParseNode.error(startIndex); for (const option of this.options) { state.index = startIndex; const parsed = option.parse(state); if (!parsed.isError && (best.isError || parsed.to > best.to)) { best = parsed; if (parsed.to === state.end) break; } } state.index = best.isError ? startIndex : best.to; return best; } } exports.LongestOfNode = LongestOfNode; class GroupNode extends GrammarNode { factors; constructor(name, ...factors) { super(); this.name = name; this.factors = factors; } parse(state) { const startIndex = state.index; const children = []; for (const factor of this.factors) { const parsed = factor.parse(state); if (parsed.isError) { state.index = startIndex; return parsed; } if (!parsed.isEmpty) children.push(parsed); } return new _ParseNode.ParseNode(this.name, startIndex, state.index, children); } } exports.GroupNode = GroupNode; class NegativeLookaheadNode extends GrammarNode { constructor(node) { super(); this.node = node; } parse(state) { const { index } = state; const parsed = this.node.parse(state); if (!parsed.isError) return _ParseNode.ParseNode.error(index); state.index = index; return _ParseNode.ParseNode.empty(index); } } exports.NegativeLookaheadNode = NegativeLookaheadNode; class ParseAsNode extends GrammarNode { constructor(node, parseAsClass) { super(); this.node = node; this.parseAsClass = parseAsClass; } parse(state) { const parsed = this.node.parse(state); if (parsed.isError) return parsed; return new this.parseAsClass(parsed); } } exports.ParseAsNode = ParseAsNode; //# sourceMappingURL=GrammarNode.js.map