UNPKG

cm-tarnation

Version:

An alternative parser for CodeMirror 6

109 lines 4.26 kB
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Wrapping } from "../../constants"; import { createID } from "../../util"; import { Node } from "../node"; import { Rule } from "./rule"; /** * A sort of {@link Rule}-like object that affects a {@link GrammarStack}. It * has `begin` and `end` properties which are {@link Rule}s that are used * for switching states. */ export class State { /** * @param repo - The {@link Repository} to add this state to. * @param state - The definition for this state. */ constructor(repo, state) { let type = state.type ?? createID(); let emit = (state.type && state.emit !== false) || state.autocomplete; // states handle nesting differently, so we don't want // to use the normal nesting behavior if (state.nest) { const nest = state.nest; delete state.nest; // don't pass to node this.inside = new Node(repo.id(), { type: `${type}_Nest${nest}`, nest }); } this.name = type; this.node = !emit ? Node.None : new Node(repo.id(), state); // prettier-ignore const begin = typeof state.begin === "string" ? repo.get(state.begin) : repo.add(state.begin); // prettier-ignore const end = typeof state.end === "string" ? repo.get(state.end) : repo.add(state.end); if (!(begin instanceof Rule) || !(end instanceof Rule)) { throw new Error(`Invalid state ${type}, rules not found or weren't rules`); } this.begin = begin; this.end = end; if (!this.inside) { if (state.inside) { if (state.inside === "loose") this.loose = true; else if (state.inside === "inherit") this.inside = null; else if (!Array.isArray(state.inside)) this.inside = repo.add(state.inside); else this.inside = repo.inside(state.inside); } else { this.inside = null; } } } /** * @param state - The current {@link GrammarState}. * @param str - The string to match. * @param pos - The position to start matching at. */ match(state, str, pos) { // loose mode, doesn't actually affect the stack if (this.loose) { const endMatched = this.end.match(state, str, pos); if (endMatched) return endMatched.wrap(this.node, Wrapping.END); const beginMatched = this.begin.match(state, str, pos); if (beginMatched) return beginMatched.wrap(this.node, Wrapping.BEGIN); return null; } else { let matched = this.begin.match(state, str, pos); if (!matched) return null; matched = matched.wrap(this.node, Wrapping.BEGIN); if (this.inside instanceof Node) { matched.push(this.inside, 1); state.stack.push(this.node, [], this); } else { const inside = this.inside ? this.inside : state.stack.rules; state.stack.push(this.node, inside, this); } return matched; } } /** * @param state - The current {@link GrammarState}. * @param str - The string to match. * @param pos - The position to start matching at. */ close(state, str, pos) { if (this.loose) throw new Error("Closing a loose state is not supported"); let matched = this.end.match(state, str, pos); if (!matched) return null; matched = matched.wrap(this.node, Wrapping.END); if (this.inside instanceof Node) matched.push(this.inside, -1); matched.state.stack.pop(); return matched; } } //# sourceMappingURL=state.js.map