UNPKG

tell-me-when

Version:
218 lines (208 loc) 5.67 kB
import { ParseNode } from "./ParseNode.mjs"; export 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 : new TokenNode(factor); } /** * Matches the given string or regular expression */ static token(token) { return new TokenNode(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)); } } export class GrammarNodeRef extends GrammarNode { constructor(ref) { super(); this.ref = ref; } parse(state) { return this.ref().parse(state); } } export class TokenNode extends GrammarNode { constructor(token) { super(); this.token = token; } parse(state) { const match = state.match(this.token); if (match) { state.index = match.index + match[0].length; return new ParseNode(undefined, match.index, state.index); } return ParseNode.error(state.index); } } export class MaybeNode extends GrammarNode { constructor(node) { super(); this.node = node; } parse(state) { const parsed = this.node.parse(state); return parsed.isError ? ParseNode.empty(state.index) : parsed; } } export 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(undefined, startIndex, state.index, children); } } export 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.error(startIndex); } } export class LongestOfNode extends GrammarNode { options; constructor(...options) { super(); this.options = options; } parse(state) { const startIndex = state.index; let best = 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; } } export 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(this.name, startIndex, state.index, children); } } export 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.error(index); state.index = index; return ParseNode.empty(index); } } export 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); } } //# sourceMappingURL=GrammarNode.mjs.map