@gdquest/gd-exercise
Version:
Core package that handles logic for the GDExercise project.
1,515 lines (1,512 loc) • 127 kB
JavaScript
import {
DefaultBufferLength,
IterMode,
NodeProp,
NodeSet,
NodeType,
Parser,
Tree,
styleTags,
tags
} from "./chunk-RHPUBFPS.mjs";
import "./chunk-MJPHVYKR.mjs";
// ../codemirror-gdscript/dist/index.mjs
import {
foldNodeProp,
foldInside,
indentNodeProp,
LRLanguage,
LanguageSupport
} from "@codemirror/language";
// ../../node_modules/.pnpm/@lezer+lr@1.3.9/node_modules/@lezer/lr/dist/index.js
var Stack = class _Stack {
/// @internal
constructor(p, stack, state, reducePos, pos, score, buffer, bufferBase, curContext, lookAhead = 0, parent) {
this.p = p;
this.stack = stack;
this.state = state;
this.reducePos = reducePos;
this.pos = pos;
this.score = score;
this.buffer = buffer;
this.bufferBase = bufferBase;
this.curContext = curContext;
this.lookAhead = lookAhead;
this.parent = parent;
}
/// @internal
toString() {
return `[${this.stack.filter((_, i) => i % 3 == 0).concat(this.state)}]@${this.pos}${this.score ? "!" + this.score : ""}`;
}
// Start an empty stack
/// @internal
static start(p, state, pos = 0) {
let cx = p.parser.context;
return new _Stack(p, [], state, pos, pos, 0, [], 0, cx ? new StackContext(cx, cx.start) : null, 0, null);
}
/// The stack's current [context](#lr.ContextTracker) value, if
/// any. Its type will depend on the context tracker's type
/// parameter, or it will be `null` if there is no context
/// tracker.
get context() {
return this.curContext ? this.curContext.context : null;
}
// Push a state onto the stack, tracking its start position as well
// as the buffer base at that point.
/// @internal
pushState(state, start) {
this.stack.push(this.state, start, this.bufferBase + this.buffer.length);
this.state = state;
}
// Apply a reduce action
/// @internal
reduce(action) {
var _a;
let depth = action >> 19, type = action & 65535;
let { parser: parser2 } = this.p;
let dPrec = parser2.dynamicPrecedence(type);
if (dPrec)
this.score += dPrec;
if (depth == 0) {
this.pushState(parser2.getGoto(this.state, type, true), this.reducePos);
if (type < parser2.minRepeatTerm)
this.storeNode(type, this.reducePos, this.reducePos, 4, true);
this.reduceContext(type, this.reducePos);
return;
}
let base = this.stack.length - (depth - 1) * 3 - (action & 262144 ? 6 : 0);
let start = base ? this.stack[base - 2] : this.p.ranges[0].from, size = this.reducePos - start;
if (size >= 2e3 && !((_a = this.p.parser.nodeSet.types[type]) === null || _a === void 0 ? void 0 : _a.isAnonymous)) {
if (start == this.p.lastBigReductionStart) {
this.p.bigReductionCount++;
this.p.lastBigReductionSize = size;
} else if (this.p.lastBigReductionSize < size) {
this.p.bigReductionCount = 1;
this.p.lastBigReductionStart = start;
this.p.lastBigReductionSize = size;
}
}
let bufferBase = base ? this.stack[base - 1] : 0, count = this.bufferBase + this.buffer.length - bufferBase;
if (type < parser2.minRepeatTerm || action & 131072) {
let pos = parser2.stateFlag(
this.state,
1
/* StateFlag.Skipped */
) ? this.pos : this.reducePos;
this.storeNode(type, start, pos, count + 4, true);
}
if (action & 262144) {
this.state = this.stack[base];
} else {
let baseStateID = this.stack[base - 3];
this.state = parser2.getGoto(baseStateID, type, true);
}
while (this.stack.length > base)
this.stack.pop();
this.reduceContext(type, start);
}
// Shift a value into the buffer
/// @internal
storeNode(term, start, end, size = 4, isReduce = false) {
if (term == 0 && (!this.stack.length || this.stack[this.stack.length - 1] < this.buffer.length + this.bufferBase)) {
let cur = this, top = this.buffer.length;
if (top == 0 && cur.parent) {
top = cur.bufferBase - cur.parent.bufferBase;
cur = cur.parent;
}
if (top > 0 && cur.buffer[top - 4] == 0 && cur.buffer[top - 1] > -1) {
if (start == end)
return;
if (cur.buffer[top - 2] >= start) {
cur.buffer[top - 2] = end;
return;
}
}
}
if (!isReduce || this.pos == end) {
this.buffer.push(term, start, end, size);
} else {
let index = this.buffer.length;
if (index > 0 && this.buffer[index - 4] != 0)
while (index > 0 && this.buffer[index - 2] > end) {
this.buffer[index] = this.buffer[index - 4];
this.buffer[index + 1] = this.buffer[index - 3];
this.buffer[index + 2] = this.buffer[index - 2];
this.buffer[index + 3] = this.buffer[index - 1];
index -= 4;
if (size > 4)
size -= 4;
}
this.buffer[index] = term;
this.buffer[index + 1] = start;
this.buffer[index + 2] = end;
this.buffer[index + 3] = size;
}
}
// Apply a shift action
/// @internal
shift(action, next, nextEnd) {
let start = this.pos;
if (action & 131072) {
this.pushState(action & 65535, this.pos);
} else if ((action & 262144) == 0) {
let nextState = action, { parser: parser2 } = this.p;
if (nextEnd > this.pos || next <= parser2.maxNode) {
this.pos = nextEnd;
if (!parser2.stateFlag(
nextState,
1
/* StateFlag.Skipped */
))
this.reducePos = nextEnd;
}
this.pushState(nextState, start);
this.shiftContext(next, start);
if (next <= parser2.maxNode)
this.buffer.push(next, start, nextEnd, 4);
} else {
this.pos = nextEnd;
this.shiftContext(next, start);
if (next <= this.p.parser.maxNode)
this.buffer.push(next, start, nextEnd, 4);
}
}
// Apply an action
/// @internal
apply(action, next, nextEnd) {
if (action & 65536)
this.reduce(action);
else
this.shift(action, next, nextEnd);
}
// Add a prebuilt (reused) node into the buffer.
/// @internal
useNode(value, next) {
let index = this.p.reused.length - 1;
if (index < 0 || this.p.reused[index] != value) {
this.p.reused.push(value);
index++;
}
let start = this.pos;
this.reducePos = this.pos = start + value.length;
this.pushState(next, start);
this.buffer.push(
index,
start,
this.reducePos,
-1
/* size == -1 means this is a reused value */
);
if (this.curContext)
this.updateContext(this.curContext.tracker.reuse(this.curContext.context, value, this, this.p.stream.reset(this.pos - value.length)));
}
// Split the stack. Due to the buffer sharing and the fact
// that `this.stack` tends to stay quite shallow, this isn't very
// expensive.
/// @internal
split() {
let parent = this;
let off = parent.buffer.length;
while (off > 0 && parent.buffer[off - 2] > parent.reducePos)
off -= 4;
let buffer = parent.buffer.slice(off), base = parent.bufferBase + off;
while (parent && base == parent.bufferBase)
parent = parent.parent;
return new _Stack(this.p, this.stack.slice(), this.state, this.reducePos, this.pos, this.score, buffer, base, this.curContext, this.lookAhead, parent);
}
// Try to recover from an error by 'deleting' (ignoring) one token.
/// @internal
recoverByDelete(next, nextEnd) {
let isNode = next <= this.p.parser.maxNode;
if (isNode)
this.storeNode(next, this.pos, nextEnd, 4);
this.storeNode(0, this.pos, nextEnd, isNode ? 8 : 4);
this.pos = this.reducePos = nextEnd;
this.score -= 190;
}
/// Check if the given term would be able to be shifted (optionally
/// after some reductions) on this stack. This can be useful for
/// external tokenizers that want to make sure they only provide a
/// given token when it applies.
canShift(term) {
for (let sim = new SimulatedStack(this); ; ) {
let action = this.p.parser.stateSlot(
sim.state,
4
/* ParseState.DefaultReduce */
) || this.p.parser.hasAction(sim.state, term);
if (action == 0)
return false;
if ((action & 65536) == 0)
return true;
sim.reduce(action);
}
}
// Apply up to Recover.MaxNext recovery actions that conceptually
// inserts some missing token or rule.
/// @internal
recoverByInsert(next) {
if (this.stack.length >= 300)
return [];
let nextStates = this.p.parser.nextStates(this.state);
if (nextStates.length > 4 << 1 || this.stack.length >= 120) {
let best = [];
for (let i = 0, s; i < nextStates.length; i += 2) {
if ((s = nextStates[i + 1]) != this.state && this.p.parser.hasAction(s, next))
best.push(nextStates[i], s);
}
if (this.stack.length < 120)
for (let i = 0; best.length < 4 << 1 && i < nextStates.length; i += 2) {
let s = nextStates[i + 1];
if (!best.some((v, i2) => i2 & 1 && v == s))
best.push(nextStates[i], s);
}
nextStates = best;
}
let result = [];
for (let i = 0; i < nextStates.length && result.length < 4; i += 2) {
let s = nextStates[i + 1];
if (s == this.state)
continue;
let stack = this.split();
stack.pushState(s, this.pos);
stack.storeNode(0, stack.pos, stack.pos, 4, true);
stack.shiftContext(nextStates[i], this.pos);
stack.score -= 200;
result.push(stack);
}
return result;
}
// Force a reduce, if possible. Return false if that can't
// be done.
/// @internal
forceReduce() {
let { parser: parser2 } = this.p;
let reduce = parser2.stateSlot(
this.state,
5
/* ParseState.ForcedReduce */
);
if ((reduce & 65536) == 0)
return false;
if (!parser2.validAction(this.state, reduce)) {
let depth = reduce >> 19, term = reduce & 65535;
let target = this.stack.length - depth * 3;
if (target < 0 || parser2.getGoto(this.stack[target], term, false) < 0) {
let backup = this.findForcedReduction();
if (backup == null)
return false;
reduce = backup;
}
this.storeNode(0, this.pos, this.pos, 4, true);
this.score -= 100;
}
this.reducePos = this.pos;
this.reduce(reduce);
return true;
}
/// Try to scan through the automaton to find some kind of reduction
/// that can be applied. Used when the regular ForcedReduce field
/// isn't a valid action. @internal
findForcedReduction() {
let { parser: parser2 } = this.p, seen = [];
let explore = (state, depth) => {
if (seen.includes(state))
return;
seen.push(state);
return parser2.allActions(state, (action) => {
if (action & (262144 | 131072))
;
else if (action & 65536) {
let rDepth = (action >> 19) - depth;
if (rDepth > 1) {
let term = action & 65535, target = this.stack.length - rDepth * 3;
if (target >= 0 && parser2.getGoto(this.stack[target], term, false) >= 0)
return rDepth << 19 | 65536 | term;
}
} else {
let found = explore(action, depth + 1);
if (found != null)
return found;
}
});
};
return explore(this.state, 0);
}
/// @internal
forceAll() {
while (!this.p.parser.stateFlag(
this.state,
2
/* StateFlag.Accepting */
)) {
if (!this.forceReduce()) {
this.storeNode(0, this.pos, this.pos, 4, true);
break;
}
}
return this;
}
/// Check whether this state has no further actions (assumed to be a direct descendant of the
/// top state, since any other states must be able to continue
/// somehow). @internal
get deadEnd() {
if (this.stack.length != 3)
return false;
let { parser: parser2 } = this.p;
return parser2.data[parser2.stateSlot(
this.state,
1
/* ParseState.Actions */
)] == 65535 && !parser2.stateSlot(
this.state,
4
/* ParseState.DefaultReduce */
);
}
/// Restart the stack (put it back in its start state). Only safe
/// when this.stack.length == 3 (state is directly below the top
/// state). @internal
restart() {
this.state = this.stack[0];
this.stack.length = 0;
}
/// @internal
sameState(other) {
if (this.state != other.state || this.stack.length != other.stack.length)
return false;
for (let i = 0; i < this.stack.length; i += 3)
if (this.stack[i] != other.stack[i])
return false;
return true;
}
/// Get the parser used by this stack.
get parser() {
return this.p.parser;
}
/// Test whether a given dialect (by numeric ID, as exported from
/// the terms file) is enabled.
dialectEnabled(dialectID) {
return this.p.parser.dialect.flags[dialectID];
}
shiftContext(term, start) {
if (this.curContext)
this.updateContext(this.curContext.tracker.shift(this.curContext.context, term, this, this.p.stream.reset(start)));
}
reduceContext(term, start) {
if (this.curContext)
this.updateContext(this.curContext.tracker.reduce(this.curContext.context, term, this, this.p.stream.reset(start)));
}
/// @internal
emitContext() {
let last = this.buffer.length - 1;
if (last < 0 || this.buffer[last] != -3)
this.buffer.push(this.curContext.hash, this.pos, this.pos, -3);
}
/// @internal
emitLookAhead() {
let last = this.buffer.length - 1;
if (last < 0 || this.buffer[last] != -4)
this.buffer.push(this.lookAhead, this.pos, this.pos, -4);
}
updateContext(context) {
if (context != this.curContext.context) {
let newCx = new StackContext(this.curContext.tracker, context);
if (newCx.hash != this.curContext.hash)
this.emitContext();
this.curContext = newCx;
}
}
/// @internal
setLookAhead(lookAhead) {
if (lookAhead > this.lookAhead) {
this.emitLookAhead();
this.lookAhead = lookAhead;
}
}
/// @internal
close() {
if (this.curContext && this.curContext.tracker.strict)
this.emitContext();
if (this.lookAhead > 0)
this.emitLookAhead();
}
};
var StackContext = class {
constructor(tracker, context) {
this.tracker = tracker;
this.context = context;
this.hash = tracker.strict ? tracker.hash(context) : 0;
}
};
var Recover;
(function(Recover2) {
Recover2[Recover2["Insert"] = 200] = "Insert";
Recover2[Recover2["Delete"] = 190] = "Delete";
Recover2[Recover2["Reduce"] = 100] = "Reduce";
Recover2[Recover2["MaxNext"] = 4] = "MaxNext";
Recover2[Recover2["MaxInsertStackDepth"] = 300] = "MaxInsertStackDepth";
Recover2[Recover2["DampenInsertStackDepth"] = 120] = "DampenInsertStackDepth";
Recover2[Recover2["MinBigReduction"] = 2e3] = "MinBigReduction";
})(Recover || (Recover = {}));
var SimulatedStack = class {
constructor(start) {
this.start = start;
this.state = start.state;
this.stack = start.stack;
this.base = this.stack.length;
}
reduce(action) {
let term = action & 65535, depth = action >> 19;
if (depth == 0) {
if (this.stack == this.start.stack)
this.stack = this.stack.slice();
this.stack.push(this.state, 0, 0);
this.base += 3;
} else {
this.base -= (depth - 1) * 3;
}
let goto = this.start.p.parser.getGoto(this.stack[this.base - 3], term, true);
this.state = goto;
}
};
var StackBufferCursor = class _StackBufferCursor {
constructor(stack, pos, index) {
this.stack = stack;
this.pos = pos;
this.index = index;
this.buffer = stack.buffer;
if (this.index == 0)
this.maybeNext();
}
static create(stack, pos = stack.bufferBase + stack.buffer.length) {
return new _StackBufferCursor(stack, pos, pos - stack.bufferBase);
}
maybeNext() {
let next = this.stack.parent;
if (next != null) {
this.index = this.stack.bufferBase - next.bufferBase;
this.stack = next;
this.buffer = next.buffer;
}
}
get id() {
return this.buffer[this.index - 4];
}
get start() {
return this.buffer[this.index - 3];
}
get end() {
return this.buffer[this.index - 2];
}
get size() {
return this.buffer[this.index - 1];
}
next() {
this.index -= 4;
this.pos -= 4;
if (this.index == 0)
this.maybeNext();
}
fork() {
return new _StackBufferCursor(this.stack, this.pos, this.index);
}
};
function decodeArray(input, Type = Uint16Array) {
if (typeof input != "string")
return input;
let array = null;
for (let pos = 0, out = 0; pos < input.length; ) {
let value = 0;
for (; ; ) {
let next = input.charCodeAt(pos++), stop = false;
if (next == 126) {
value = 65535;
break;
}
if (next >= 92)
next--;
if (next >= 34)
next--;
let digit = next - 32;
if (digit >= 46) {
digit -= 46;
stop = true;
}
value += digit;
if (stop)
break;
value *= 46;
}
if (array)
array[out++] = value;
else
array = new Type(value);
}
return array;
}
var CachedToken = class {
constructor() {
this.start = -1;
this.value = -1;
this.end = -1;
this.extended = -1;
this.lookAhead = 0;
this.mask = 0;
this.context = 0;
}
};
var nullToken = new CachedToken();
var InputStream = class {
/// @internal
constructor(input, ranges) {
this.input = input;
this.ranges = ranges;
this.chunk = "";
this.chunkOff = 0;
this.chunk2 = "";
this.chunk2Pos = 0;
this.next = -1;
this.token = nullToken;
this.rangeIndex = 0;
this.pos = this.chunkPos = ranges[0].from;
this.range = ranges[0];
this.end = ranges[ranges.length - 1].to;
this.readNext();
}
/// @internal
resolveOffset(offset, assoc) {
let range = this.range, index = this.rangeIndex;
let pos = this.pos + offset;
while (pos < range.from) {
if (!index)
return null;
let next = this.ranges[--index];
pos -= range.from - next.to;
range = next;
}
while (assoc < 0 ? pos > range.to : pos >= range.to) {
if (index == this.ranges.length - 1)
return null;
let next = this.ranges[++index];
pos += next.from - range.to;
range = next;
}
return pos;
}
/// @internal
clipPos(pos) {
if (pos >= this.range.from && pos < this.range.to)
return pos;
for (let range of this.ranges)
if (range.to > pos)
return Math.max(pos, range.from);
return this.end;
}
/// Look at a code unit near the stream position. `.peek(0)` equals
/// `.next`, `.peek(-1)` gives you the previous character, and so
/// on.
///
/// Note that looking around during tokenizing creates dependencies
/// on potentially far-away content, which may reduce the
/// effectiveness incremental parsing—when looking forward—or even
/// cause invalid reparses when looking backward more than 25 code
/// units, since the library does not track lookbehind.
peek(offset) {
let idx = this.chunkOff + offset, pos, result;
if (idx >= 0 && idx < this.chunk.length) {
pos = this.pos + offset;
result = this.chunk.charCodeAt(idx);
} else {
let resolved = this.resolveOffset(offset, 1);
if (resolved == null)
return -1;
pos = resolved;
if (pos >= this.chunk2Pos && pos < this.chunk2Pos + this.chunk2.length) {
result = this.chunk2.charCodeAt(pos - this.chunk2Pos);
} else {
let i = this.rangeIndex, range = this.range;
while (range.to <= pos)
range = this.ranges[++i];
this.chunk2 = this.input.chunk(this.chunk2Pos = pos);
if (pos + this.chunk2.length > range.to)
this.chunk2 = this.chunk2.slice(0, range.to - pos);
result = this.chunk2.charCodeAt(0);
}
}
if (pos >= this.token.lookAhead)
this.token.lookAhead = pos + 1;
return result;
}
/// Accept a token. By default, the end of the token is set to the
/// current stream position, but you can pass an offset (relative to
/// the stream position) to change that.
acceptToken(token, endOffset = 0) {
let end = endOffset ? this.resolveOffset(endOffset, -1) : this.pos;
if (end == null || end < this.token.start)
throw new RangeError("Token end out of bounds");
this.token.value = token;
this.token.end = end;
}
getChunk() {
if (this.pos >= this.chunk2Pos && this.pos < this.chunk2Pos + this.chunk2.length) {
let { chunk, chunkPos } = this;
this.chunk = this.chunk2;
this.chunkPos = this.chunk2Pos;
this.chunk2 = chunk;
this.chunk2Pos = chunkPos;
this.chunkOff = this.pos - this.chunkPos;
} else {
this.chunk2 = this.chunk;
this.chunk2Pos = this.chunkPos;
let nextChunk = this.input.chunk(this.pos);
let end = this.pos + nextChunk.length;
this.chunk = end > this.range.to ? nextChunk.slice(0, this.range.to - this.pos) : nextChunk;
this.chunkPos = this.pos;
this.chunkOff = 0;
}
}
readNext() {
if (this.chunkOff >= this.chunk.length) {
this.getChunk();
if (this.chunkOff == this.chunk.length)
return this.next = -1;
}
return this.next = this.chunk.charCodeAt(this.chunkOff);
}
/// Move the stream forward N (defaults to 1) code units. Returns
/// the new value of [`next`](#lr.InputStream.next).
advance(n = 1) {
this.chunkOff += n;
while (this.pos + n >= this.range.to) {
if (this.rangeIndex == this.ranges.length - 1)
return this.setDone();
n -= this.range.to - this.pos;
this.range = this.ranges[++this.rangeIndex];
this.pos = this.range.from;
}
this.pos += n;
if (this.pos >= this.token.lookAhead)
this.token.lookAhead = this.pos + 1;
return this.readNext();
}
setDone() {
this.pos = this.chunkPos = this.end;
this.range = this.ranges[this.rangeIndex = this.ranges.length - 1];
this.chunk = "";
return this.next = -1;
}
/// @internal
reset(pos, token) {
if (token) {
this.token = token;
token.start = pos;
token.lookAhead = pos + 1;
token.value = token.extended = -1;
} else {
this.token = nullToken;
}
if (this.pos != pos) {
this.pos = pos;
if (pos == this.end) {
this.setDone();
return this;
}
while (pos < this.range.from)
this.range = this.ranges[--this.rangeIndex];
while (pos >= this.range.to)
this.range = this.ranges[++this.rangeIndex];
if (pos >= this.chunkPos && pos < this.chunkPos + this.chunk.length) {
this.chunkOff = pos - this.chunkPos;
} else {
this.chunk = "";
this.chunkOff = 0;
}
this.readNext();
}
return this;
}
/// @internal
read(from, to) {
if (from >= this.chunkPos && to <= this.chunkPos + this.chunk.length)
return this.chunk.slice(from - this.chunkPos, to - this.chunkPos);
if (from >= this.chunk2Pos && to <= this.chunk2Pos + this.chunk2.length)
return this.chunk2.slice(from - this.chunk2Pos, to - this.chunk2Pos);
if (from >= this.range.from && to <= this.range.to)
return this.input.read(from, to);
let result = "";
for (let r of this.ranges) {
if (r.from >= to)
break;
if (r.to > from)
result += this.input.read(Math.max(r.from, from), Math.min(r.to, to));
}
return result;
}
};
var TokenGroup = class {
constructor(data, id2) {
this.data = data;
this.id = id2;
}
token(input, stack) {
let { parser: parser2 } = stack.p;
readToken(this.data, input, stack, this.id, parser2.data, parser2.tokenPrecTable);
}
};
TokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false;
var LocalTokenGroup = class {
constructor(data, precTable, elseToken) {
this.precTable = precTable;
this.elseToken = elseToken;
this.data = typeof data == "string" ? decodeArray(data) : data;
}
token(input, stack) {
let start = input.pos, skipped = 0;
for (; ; ) {
let atEof = input.next < 0, nextPos = input.resolveOffset(1, 1);
readToken(this.data, input, stack, 0, this.data, this.precTable);
if (input.token.value > -1)
break;
if (this.elseToken == null)
return;
if (!atEof)
skipped++;
if (nextPos == null)
break;
input.reset(nextPos, input.token);
}
if (skipped) {
input.reset(start, input.token);
input.acceptToken(this.elseToken, skipped);
}
}
};
LocalTokenGroup.prototype.contextual = TokenGroup.prototype.fallback = TokenGroup.prototype.extend = false;
var ExternalTokenizer = class {
/// Create a tokenizer. The first argument is the function that,
/// given an input stream, scans for the types of tokens it
/// recognizes at the stream's position, and calls
/// [`acceptToken`](#lr.InputStream.acceptToken) when it finds
/// one.
constructor(token, options = {}) {
this.token = token;
this.contextual = !!options.contextual;
this.fallback = !!options.fallback;
this.extend = !!options.extend;
}
};
function readToken(data, input, stack, group, precTable, precOffset) {
let state = 0, groupMask = 1 << group, { dialect } = stack.p.parser;
scan:
for (; ; ) {
if ((groupMask & data[state]) == 0)
break;
let accEnd = data[state + 1];
for (let i = state + 3; i < accEnd; i += 2)
if ((data[i + 1] & groupMask) > 0) {
let term = data[i];
if (dialect.allows(term) && (input.token.value == -1 || input.token.value == term || overrides(term, input.token.value, precTable, precOffset))) {
input.acceptToken(term);
break;
}
}
let next = input.next, low = 0, high = data[state + 2];
if (input.next < 0 && high > low && data[accEnd + high * 3 - 3] == 65535 && data[accEnd + high * 3 - 3] == 65535) {
state = data[accEnd + high * 3 - 1];
continue scan;
}
for (; low < high; ) {
let mid = low + high >> 1;
let index = accEnd + mid + (mid << 1);
let from = data[index], to = data[index + 1] || 65536;
if (next < from)
high = mid;
else if (next >= to)
low = mid + 1;
else {
state = data[index + 2];
input.advance();
continue scan;
}
}
break;
}
}
function findOffset(data, start, term) {
for (let i = start, next; (next = data[i]) != 65535; i++)
if (next == term)
return i - start;
return -1;
}
function overrides(token, prev, tableData, tableOffset) {
let iPrev = findOffset(tableData, tableOffset, prev);
return iPrev < 0 || findOffset(tableData, tableOffset, token) < iPrev;
}
var verbose = typeof process != "undefined" && process.env && /\bparse\b/.test(process.env.LOG);
var stackIDs = null;
var Safety;
(function(Safety2) {
Safety2[Safety2["Margin"] = 25] = "Margin";
})(Safety || (Safety = {}));
function cutAt(tree, pos, side) {
let cursor = tree.cursor(IterMode.IncludeAnonymous);
cursor.moveTo(pos);
for (; ; ) {
if (!(side < 0 ? cursor.childBefore(pos) : cursor.childAfter(pos)))
for (; ; ) {
if ((side < 0 ? cursor.to < pos : cursor.from > pos) && !cursor.type.isError)
return side < 0 ? Math.max(0, Math.min(
cursor.to - 1,
pos - 25
/* Safety.Margin */
)) : Math.min(tree.length, Math.max(
cursor.from + 1,
pos + 25
/* Safety.Margin */
));
if (side < 0 ? cursor.prevSibling() : cursor.nextSibling())
break;
if (!cursor.parent())
return side < 0 ? 0 : tree.length;
}
}
}
var FragmentCursor = class {
constructor(fragments, nodeSet) {
this.fragments = fragments;
this.nodeSet = nodeSet;
this.i = 0;
this.fragment = null;
this.safeFrom = -1;
this.safeTo = -1;
this.trees = [];
this.start = [];
this.index = [];
this.nextFragment();
}
nextFragment() {
let fr = this.fragment = this.i == this.fragments.length ? null : this.fragments[this.i++];
if (fr) {
this.safeFrom = fr.openStart ? cutAt(fr.tree, fr.from + fr.offset, 1) - fr.offset : fr.from;
this.safeTo = fr.openEnd ? cutAt(fr.tree, fr.to + fr.offset, -1) - fr.offset : fr.to;
while (this.trees.length) {
this.trees.pop();
this.start.pop();
this.index.pop();
}
this.trees.push(fr.tree);
this.start.push(-fr.offset);
this.index.push(0);
this.nextStart = this.safeFrom;
} else {
this.nextStart = 1e9;
}
}
// `pos` must be >= any previously given `pos` for this cursor
nodeAt(pos) {
if (pos < this.nextStart)
return null;
while (this.fragment && this.safeTo <= pos)
this.nextFragment();
if (!this.fragment)
return null;
for (; ; ) {
let last = this.trees.length - 1;
if (last < 0) {
this.nextFragment();
return null;
}
let top = this.trees[last], index = this.index[last];
if (index == top.children.length) {
this.trees.pop();
this.start.pop();
this.index.pop();
continue;
}
let next = top.children[index];
let start = this.start[last] + top.positions[index];
if (start > pos) {
this.nextStart = start;
return null;
}
if (next instanceof Tree) {
if (start == pos) {
if (start < this.safeFrom)
return null;
let end = start + next.length;
if (end <= this.safeTo) {
let lookAhead = next.prop(NodeProp.lookAhead);
if (!lookAhead || end + lookAhead < this.fragment.to)
return next;
}
}
this.index[last]++;
if (start + next.length >= Math.max(this.safeFrom, pos)) {
this.trees.push(next);
this.start.push(start);
this.index.push(0);
}
} else {
this.index[last]++;
this.nextStart = start + next.length;
}
}
}
};
var TokenCache = class {
constructor(parser2, stream) {
this.stream = stream;
this.tokens = [];
this.mainToken = null;
this.actions = [];
this.tokens = parser2.tokenizers.map((_) => new CachedToken());
}
getActions(stack) {
let actionIndex = 0;
let main = null;
let { parser: parser2 } = stack.p, { tokenizers } = parser2;
let mask = parser2.stateSlot(
stack.state,
3
/* ParseState.TokenizerMask */
);
let context = stack.curContext ? stack.curContext.hash : 0;
let lookAhead = 0;
for (let i = 0; i < tokenizers.length; i++) {
if ((1 << i & mask) == 0)
continue;
let tokenizer = tokenizers[i], token = this.tokens[i];
if (main && !tokenizer.fallback)
continue;
if (tokenizer.contextual || token.start != stack.pos || token.mask != mask || token.context != context) {
this.updateCachedToken(token, tokenizer, stack);
token.mask = mask;
token.context = context;
}
if (token.lookAhead > token.end + 25)
lookAhead = Math.max(token.lookAhead, lookAhead);
if (token.value != 0) {
let startIndex = actionIndex;
if (token.extended > -1)
actionIndex = this.addActions(stack, token.extended, token.end, actionIndex);
actionIndex = this.addActions(stack, token.value, token.end, actionIndex);
if (!tokenizer.extend) {
main = token;
if (actionIndex > startIndex)
break;
}
}
}
while (this.actions.length > actionIndex)
this.actions.pop();
if (lookAhead)
stack.setLookAhead(lookAhead);
if (!main && stack.pos == this.stream.end) {
main = new CachedToken();
main.value = stack.p.parser.eofTerm;
main.start = main.end = stack.pos;
actionIndex = this.addActions(stack, main.value, main.end, actionIndex);
}
this.mainToken = main;
return this.actions;
}
getMainToken(stack) {
if (this.mainToken)
return this.mainToken;
let main = new CachedToken(), { pos, p } = stack;
main.start = pos;
main.end = Math.min(pos + 1, p.stream.end);
main.value = pos == p.stream.end ? p.parser.eofTerm : 0;
return main;
}
updateCachedToken(token, tokenizer, stack) {
let start = this.stream.clipPos(stack.pos);
tokenizer.token(this.stream.reset(start, token), stack);
if (token.value > -1) {
let { parser: parser2 } = stack.p;
for (let i = 0; i < parser2.specialized.length; i++)
if (parser2.specialized[i] == token.value) {
let result = parser2.specializers[i](this.stream.read(token.start, token.end), stack);
if (result >= 0 && stack.p.parser.dialect.allows(result >> 1)) {
if ((result & 1) == 0)
token.value = result >> 1;
else
token.extended = result >> 1;
break;
}
}
} else {
token.value = 0;
token.end = this.stream.clipPos(start + 1);
}
}
putAction(action, token, end, index) {
for (let i = 0; i < index; i += 3)
if (this.actions[i] == action)
return index;
this.actions[index++] = action;
this.actions[index++] = token;
this.actions[index++] = end;
return index;
}
addActions(stack, token, end, index) {
let { state } = stack, { parser: parser2 } = stack.p, { data } = parser2;
for (let set = 0; set < 2; set++) {
for (let i = parser2.stateSlot(
state,
set ? 2 : 1
/* ParseState.Actions */
); ; i += 3) {
if (data[i] == 65535) {
if (data[i + 1] == 1) {
i = pair(data, i + 2);
} else {
if (index == 0 && data[i + 1] == 2)
index = this.putAction(pair(data, i + 2), token, end, index);
break;
}
}
if (data[i] == token)
index = this.putAction(pair(data, i + 1), token, end, index);
}
}
return index;
}
};
var Rec;
(function(Rec2) {
Rec2[Rec2["Distance"] = 5] = "Distance";
Rec2[Rec2["MaxRemainingPerStep"] = 3] = "MaxRemainingPerStep";
Rec2[Rec2["MinBufferLengthPrune"] = 500] = "MinBufferLengthPrune";
Rec2[Rec2["ForceReduceLimit"] = 10] = "ForceReduceLimit";
Rec2[Rec2["CutDepth"] = 15e3] = "CutDepth";
Rec2[Rec2["CutTo"] = 9e3] = "CutTo";
Rec2[Rec2["MaxLeftAssociativeReductionCount"] = 300] = "MaxLeftAssociativeReductionCount";
Rec2[Rec2["MaxStackCount"] = 12] = "MaxStackCount";
})(Rec || (Rec = {}));
var Parse = class {
constructor(parser2, input, fragments, ranges) {
this.parser = parser2;
this.input = input;
this.ranges = ranges;
this.recovering = 0;
this.nextStackID = 9812;
this.minStackPos = 0;
this.reused = [];
this.stoppedAt = null;
this.lastBigReductionStart = -1;
this.lastBigReductionSize = 0;
this.bigReductionCount = 0;
this.stream = new InputStream(input, ranges);
this.tokens = new TokenCache(parser2, this.stream);
this.topTerm = parser2.top[1];
let { from } = ranges[0];
this.stacks = [Stack.start(this, parser2.top[0], from)];
this.fragments = fragments.length && this.stream.end - from > parser2.bufferLength * 4 ? new FragmentCursor(fragments, parser2.nodeSet) : null;
}
get parsedPos() {
return this.minStackPos;
}
// Move the parser forward. This will process all parse stacks at
// `this.pos` and try to advance them to a further position. If no
// stack for such a position is found, it'll start error-recovery.
//
// When the parse is finished, this will return a syntax tree. When
// not, it returns `null`.
advance() {
let stacks = this.stacks, pos = this.minStackPos;
let newStacks = this.stacks = [];
let stopped, stoppedTokens;
if (this.bigReductionCount > 300 && stacks.length == 1) {
let [s] = stacks;
while (s.forceReduce() && s.stack.length && s.stack[s.stack.length - 2] >= this.lastBigReductionStart) {
}
this.bigReductionCount = this.lastBigReductionSize = 0;
}
for (let i = 0; i < stacks.length; i++) {
let stack = stacks[i];
for (; ; ) {
this.tokens.mainToken = null;
if (stack.pos > pos) {
newStacks.push(stack);
} else if (this.advanceStack(stack, newStacks, stacks)) {
continue;
} else {
if (!stopped) {
stopped = [];
stoppedTokens = [];
}
stopped.push(stack);
let tok = this.tokens.getMainToken(stack);
stoppedTokens.push(tok.value, tok.end);
}
break;
}
}
if (!newStacks.length) {
let finished = stopped && findFinished(stopped);
if (finished)
return this.stackToTree(finished);
if (this.parser.strict) {
if (verbose && stopped)
console.log("Stuck with token " + (this.tokens.mainToken ? this.parser.getName(this.tokens.mainToken.value) : "none"));
throw new SyntaxError("No parse at " + pos);
}
if (!this.recovering)
this.recovering = 5;
}
if (this.recovering && stopped) {
let finished = this.stoppedAt != null && stopped[0].pos > this.stoppedAt ? stopped[0] : this.runRecovery(stopped, stoppedTokens, newStacks);
if (finished)
return this.stackToTree(finished.forceAll());
}
if (this.recovering) {
let maxRemaining = this.recovering == 1 ? 1 : this.recovering * 3;
if (newStacks.length > maxRemaining) {
newStacks.sort((a, b) => b.score - a.score);
while (newStacks.length > maxRemaining)
newStacks.pop();
}
if (newStacks.some((s) => s.reducePos > pos))
this.recovering--;
} else if (newStacks.length > 1) {
outer:
for (let i = 0; i < newStacks.length - 1; i++) {
let stack = newStacks[i];
for (let j = i + 1; j < newStacks.length; j++) {
let other = newStacks[j];
if (stack.sameState(other) || stack.buffer.length > 500 && other.buffer.length > 500) {
if ((stack.score - other.score || stack.buffer.length - other.buffer.length) > 0) {
newStacks.splice(j--, 1);
} else {
newStacks.splice(i--, 1);
continue outer;
}
}
}
}
if (newStacks.length > 12)
newStacks.splice(
12,
newStacks.length - 12
/* Rec.MaxStackCount */
);
}
this.minStackPos = newStacks[0].pos;
for (let i = 1; i < newStacks.length; i++)
if (newStacks[i].pos < this.minStackPos)
this.minStackPos = newStacks[i].pos;
return null;
}
stopAt(pos) {
if (this.stoppedAt != null && this.stoppedAt < pos)
throw new RangeError("Can't move stoppedAt forward");
this.stoppedAt = pos;
}
// Returns an updated version of the given stack, or null if the
// stack can't advance normally. When `split` and `stacks` are
// given, stacks split off by ambiguous operations will be pushed to
// `split`, or added to `stacks` if they move `pos` forward.
advanceStack(stack, stacks, split) {
let start = stack.pos, { parser: parser2 } = this;
let base = verbose ? this.stackID(stack) + " -> " : "";
if (this.stoppedAt != null && start > this.stoppedAt)
return stack.forceReduce() ? stack : null;
if (this.fragments) {
let strictCx = stack.curContext && stack.curContext.tracker.strict, cxHash = strictCx ? stack.curContext.hash : 0;
for (let cached = this.fragments.nodeAt(start); cached; ) {
let match = this.parser.nodeSet.types[cached.type.id] == cached.type ? parser2.getGoto(stack.state, cached.type.id) : -1;
if (match > -1 && cached.length && (!strictCx || (cached.prop(NodeProp.contextHash) || 0) == cxHash)) {
stack.useNode(cached, match);
if (verbose)
console.log(base + this.stackID(stack) + ` (via reuse of ${parser2.getName(cached.type.id)})`);
return true;
}
if (!(cached instanceof Tree) || cached.children.length == 0 || cached.positions[0] > 0)
break;
let inner = cached.children[0];
if (inner instanceof Tree && cached.positions[0] == 0)
cached = inner;
else
break;
}
}
let defaultReduce = parser2.stateSlot(
stack.state,
4
/* ParseState.DefaultReduce */
);
if (defaultReduce > 0) {
stack.reduce(defaultReduce);
if (verbose)
console.log(base + this.stackID(stack) + ` (via always-reduce ${parser2.getName(
defaultReduce & 65535
/* Action.ValueMask */
)})`);
return true;
}
if (stack.stack.length >= 15e3) {
while (stack.stack.length > 9e3 && stack.forceReduce()) {
}
}
let actions = this.tokens.getActions(stack);
for (let i = 0; i < actions.length; ) {
let action = actions[i++], term = actions[i++], end = actions[i++];
let last = i == actions.length || !split;
let localStack = last ? stack : stack.split();
localStack.apply(action, term, end);
if (verbose)
console.log(base + this.stackID(localStack) + ` (via ${(action & 65536) == 0 ? "shift" : `reduce of ${parser2.getName(
action & 65535
/* Action.ValueMask */
)}`} for ${parser2.getName(term)} @ ${start}${localStack == stack ? "" : ", split"})`);
if (last)
return true;
else if (localStack.pos > start)
stacks.push(localStack);
else
split.push(localStack);
}
return false;
}
// Advance a given stack forward as far as it will go. Returns the
// (possibly updated) stack if it got stuck, or null if it moved
// forward and was given to `pushStackDedup`.
advanceFully(stack, newStacks) {
let pos = stack.pos;
for (; ; ) {
if (!this.advanceStack(stack, null, null))
return false;
if (stack.pos > pos) {
pushStackDedup(stack, newStacks);
return true;
}
}
}
runRecovery(stacks, tokens, newStacks) {
let finished = null, restarted = false;
for (let i = 0; i < stacks.length; i++) {
let stack = stacks[i], token = tokens[i << 1], tokenEnd = tokens[(i << 1) + 1];
let base = verbose ? this.stackID(stack) + " -> " : "";
if (stack.deadEnd) {
if (restarted)
continue;
restarted = true;
stack.restart();
if (verbose)
console.log(base + this.stackID(stack) + " (restarted)");
let done = this.advanceFully(stack, newStacks);
if (done)
continue;
}
let force = stack.split(), forceBase = base;
for (let j = 0; force.forceReduce() && j < 10; j++) {
if (verbose)
console.log(forceBase + this.stackID(force) + " (via force-reduce)");
let done = this.advanceFully(force, newStacks);
if (done)
break;
if (verbose)
forceBase = this.stackID(force) + " -> ";
}
for (let insert of stack.recoverByInsert(token)) {
if (verbose)
console.log(base + this.stackID(insert) + " (via recover-insert)");
this.advanceFully(insert, newStacks);
}
if (this.stream.end > stack.pos) {
if (tokenEnd == stack.pos) {
tokenEnd++;
token = 0;
}
stack.recoverByDelete(token, tokenEnd);
if (verbose)
console.log(base + this.stackID(stack) + ` (via recover-delete ${this.parser.getName(token)})`);
pushStackDedup(stack, newStacks);
} else if (!finished || finished.score < stack.score) {
finished = stack;
}
}
return finished;
}
// Convert the stack's buffer to a syntax tree.
stackToTree(stack) {
stack.close();
return Tree.build({
buffer: StackBufferCursor.create(stack),
nodeSet: this.parser.nodeSet,
topID: this.topTerm,
maxBufferLength: this.parser.bufferLength,
reused: this.reused,
start: this.ranges[0].from,
length: stack.pos - this.ranges[0].from,
minRepeatType: this.parser.minRepeatTerm
});
}
stackID(stack) {
let id2 = (stackIDs || (stackIDs = /* @__PURE__ */ new WeakMap())).get(stack);
if (!id2)
stackIDs.set(stack, id2 = String.fromCodePoint(this.nextStackID++));
return id2 + stack;
}
};
function pushStackDedup(stack, newStacks) {
for (let i = 0; i < newStacks.length; i++) {
let other = newStacks[i];
if (other.pos == stack.pos && other.sameState(stack)) {
if (newStacks[i].score < stack.score)
newStacks[i] = stack;
return;
}
}
newStacks.push(stack);
}
var Dialect = class {
constructor(source, flags, disabled) {
this.source = source;
this.flags = flags;
this.disabled = disabled;
}
allows(term) {
return !this.disabled || this.disabled[term] == 0;
}
};
var id = (x) => x;
var ContextTracker = class {
/// Define a context tracker.
constructor(spec) {
this.start = spec.start;
this.shift = spec.shift || id;
this.reduce = spec.reduce || id;
this.reuse = spec.reuse || id;
this.hash = spec.hash || (() => 0);
this.strict = spec.strict !== false;
}
};
var LRParser = class _LRParser extends Parser {
/// @internal
constructor(spec) {
super();
this.wrappers = [];
if (spec.version != 14)
throw new RangeError(`Parser version (${spec.version}) doesn't match runtime version (${14})`);
let nodeNames = spec.nodeNames.split(" ");
this.minRepeatTerm = nodeNames.length;
for (let i = 0; i < spec.repeatNodeCount; i++)
nodeNames.push("");
let topTerms = Object.keys(spec.topRules).map((r) => spec.topRules[r][1]);
let nodeProps = [];
for (let i = 0; i < nodeNames.length; i++)
nodeProps.push([]);
function setProp(nodeID, prop, value) {
nodeProps[nodeID].push([prop, prop.deserialize(String(value))]);
}
if (spec.nodeProps)
for (let propSpec of spec.nodeProps) {
let prop = propSpec[0];
if (typeof prop == "string")
prop = NodeProp[prop];
for (let i = 1; i < propSpec.length; ) {
let next = propSpec[i++];
if (next >= 0) {
setProp(next, prop, propSpec[i++]);
} else {
let value = propSpec[i + -next];
for (let j = -next; j > 0; j--)
setProp(propSpec[i++], prop, value);
i++;
}
}
}
this.nodeSet = new NodeSet(nodeNames.map((name, i) => NodeType.define({
name: i >= this.minRepeatTerm ? void 0 : name,
id: i,
props: nodeProps[i],
top: topTerms.indexOf(i) > -1,
error: i == 0,
skipped: spec.skippedNodes && spec.skippedNodes.indexOf(i) > -1
})));
if (spec.propSources)
this.nodeSet = this.nodeSet.extend(...spec.propSources);
this.strict = false;
this.bufferLength = DefaultBufferLength;
let tokenArray = decodeArray(spec.tokenData);
this.context = spec.context;
this.specializerSpecs = spec.specialized || [];
this.specialized = new Uint16Array(this.specializerSpecs.length);
for (let i = 0; i < this.specializerSpecs.length; i++)
this.specialized[i] = this.specializerSpecs[i].term;
this.specializers = this.specializerSpecs.map(getSpecializer);
this.states = decodeArray(spec.states, Uint32Array);
this.data = decodeArray(spec.stateData);
this.goto = decodeArray(spec.goto);
this.maxTerm = spec.maxTerm;
this.tokenizers = spec.tokenizers.map((value) => typeof value == "number" ? new TokenGroup(tokenArray, value) : value);
this.topRules = spec.topRules;
this.dialects = spec.dialects || {};
this.dynamicPrecedences = spec.dynamicPrecedences || null;
this.tokenPrecTable = spec.tokenPrec;
this.termNames = spec.termNames || null;
this.maxNode = this.nodeSet.types.length - 1;
this.dialect = this.parseDialect();
this.top = this.topRules[Object.keys(this.topRules)[0]];
}
createParse(input, fragments, ranges) {
let parse = new Parse(this, input, fragments, ranges);
for (let w of this.wrappers)
parse = w(parse, input, fragments, ranges);
return parse;
}
/// Get a goto table entry @internal
getGoto(state, term, loose = false) {
let table = this.goto;
if (term >= table[0])
return -1;
for (let pos = table[term + 1]; ; ) {
let groupTag = table[pos++], last = groupTag & 1;
let target = table[pos++];
if (last && loose)
return target;
for (let end = pos + (groupTag >> 1); pos < end; pos++)
if (table[pos] == state)
return target;
if (last)
return -1;
}
}
/// Check if this state has an action for a given terminal @internal
hasAction(state, terminal) {
let data = this.data;
for (let set = 0; set < 2; set++) {
for (let i = this.stateSlot(
state,
set ? 2 : 1
/* ParseState.Actions */
), next; ; i += 3) {
if ((next = data[i]) == 65535) {
if (data[i + 1] == 1)
next = data[i = pair(data, i + 2)];
else if (data[i + 1] == 2)
return pair(data, i + 2);
else
break;
}
if (next == terminal || next == 0)
return pair(data, i + 1);
}
}
return 0;
}
/// @internal
stateSlot(state, slot) {
return this.states[state * 6 + slot];
}
/// @internal
stateFlag(state, flag) {
return (this.stateSlot(
state,
0
/* ParseState.Flags */
) & flag) > 0;
}