cm-tarnation
Version:
An alternative parser for CodeMirror 6
103 lines • 3.67 kB
JavaScript
/* 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 { TreeBuffer } from "@lezer/common";
import { CHUNK_ARRAY_INTERVAL } from "../constants";
export class Chunk {
constructor(pos, state) {
this.from = pos;
this.to = pos;
this.length = 0;
this.state = state;
this.tokens = new Int16Array(CHUNK_ARRAY_INTERVAL);
this.size = 0;
this.open = null;
this.close = null;
}
offset(offset) {
this.from += offset;
this.to = this.from + this.length;
}
add(id, from, to) {
this.tree = undefined;
if (to > this.to) {
this.to = to;
this.length = to - this.from;
}
// make token relative to chunk position
from -= this.from;
to -= this.from;
if (id !== null) {
// resize token array if needed
if (this.size * 3 + 3 > this.tokens.length) {
const old = this.tokens;
this.tokens = new Int16Array(this.tokens.length + CHUNK_ARRAY_INTERVAL);
this.tokens.set(old);
}
const idx = this.size * 3;
this.tokens[idx] = id;
this.tokens[idx + 1] = from;
this.tokens[idx + 2] = to;
this.size++;
}
}
pushOpen(...ids) {
this.tree = undefined;
this.open ??= [];
this.open.push(...ids);
}
pushClose(...ids) {
this.tree = undefined;
this.close ??= [];
this.close.push(...ids);
}
tryForTree(nodeSet) {
if (this.tree)
return this.tree;
if (this.size <= 1)
return null;
if (this.open || this.close) {
if (!(this.open && this.close))
return null;
if (this.open.length !== this.close.length)
return null;
const open = this.open.slice().reverse();
const close = this.close;
for (let i = 0; i < open.length; i++) {
if (open[i] !== close[i])
return null;
}
}
// if we're here, we can make a tree buffer out of this chunk
const buffer = [];
const total = this.size * 4 + (this.open?.length ?? 0) * 4;
if (this.open) {
for (let i = this.open.length - 1; i >= 0; i--) {
buffer.push(this.open[i], 0, this.length, total);
}
}
for (let i = 0; i < this.size; i++) {
buffer.push(this.tokens[i * 3], this.tokens[i * 3 + 1], this.tokens[i * 3 + 2], buffer.length + 4);
}
const tree = new TreeBuffer(new Uint16Array(buffer), this.length, nodeSet);
this.tree = tree;
return tree;
}
/**
* Determines if a grammar's state (and parse position) is compatible
* with reusing this node. This is only a safe determination if it is
* made _after_ the changed range of the document.
*
* @param state - The state to compare against.
* @param pos - The position to compare against.
* @param offset - The edit offset, to correct for chunk position differences.
*/
isReusable(state, pos, offset = 0) {
if (this.from + offset !== pos)
return false;
if (!state.equals(this.state))
return false;
return true;
}
}
//# sourceMappingURL=chunk.js.map