1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816 |
- // FIXME profile adding a per-Tree TreeNode cache, validating it by
- // parent pointer
- /// The default maximum length of a `TreeBuffer` node (1024).
- const DefaultBufferLength = 1024;
- let nextPropID = 0;
- class Range {
- constructor(from, to) {
- this.from = from;
- this.to = to;
- }
- }
- /// Each [node type](#common.NodeType) or [individual tree](#common.Tree)
- /// can have metadata associated with it in props. Instances of this
- /// class represent prop names.
- class NodeProp {
- /// Create a new node prop type.
- constructor(config = {}) {
- this.id = nextPropID++;
- this.perNode = !!config.perNode;
- this.deserialize = config.deserialize || (() => {
- throw new Error("This node type doesn't define a deserialize function");
- });
- }
- /// This is meant to be used with
- /// [`NodeSet.extend`](#common.NodeSet.extend) or
- /// [`LRParser.configure`](#lr.ParserConfig.props) to compute
- /// prop values for each node type in the set. Takes a [match
- /// object](#common.NodeType^match) or function that returns undefined
- /// if the node type doesn't get this prop, and the prop's value if
- /// it does.
- add(match) {
- if (this.perNode)
- throw new RangeError("Can't add per-node props to node types");
- if (typeof match != "function")
- match = NodeType.match(match);
- return (type) => {
- let result = match(type);
- return result === undefined ? null : [this, result];
- };
- }
- }
- /// Prop that is used to describe matching delimiters. For opening
- /// delimiters, this holds an array of node names (written as a
- /// space-separated string when declaring this prop in a grammar)
- /// for the node types of closing delimiters that match it.
- NodeProp.closedBy = new NodeProp({ deserialize: str => str.split(" ") });
- /// The inverse of [`closedBy`](#common.NodeProp^closedBy). This is
- /// attached to closing delimiters, holding an array of node names
- /// of types of matching opening delimiters.
- NodeProp.openedBy = new NodeProp({ deserialize: str => str.split(" ") });
- /// Used to assign node types to groups (for example, all node
- /// types that represent an expression could be tagged with an
- /// `"Expression"` group).
- NodeProp.group = new NodeProp({ deserialize: str => str.split(" ") });
- /// The hash of the [context](#lr.ContextTracker.constructor)
- /// that the node was parsed in, if any. Used to limit reuse of
- /// contextual nodes.
- NodeProp.contextHash = new NodeProp({ perNode: true });
- /// The distance beyond the end of the node that the tokenizer
- /// looked ahead for any of the tokens inside the node. (The LR
- /// parser only stores this when it is larger than 25, for
- /// efficiency reasons.)
- NodeProp.lookAhead = new NodeProp({ perNode: true });
- /// This per-node prop is used to replace a given node, or part of a
- /// node, with another tree. This is useful to include trees from
- /// different languages.
- NodeProp.mounted = new NodeProp({ perNode: true });
- /// A mounted tree, which can be [stored](#common.NodeProp^mounted) on
- /// a tree node to indicate that parts of its content are
- /// represented by another tree.
- class MountedTree {
- constructor(
- /// The inner tree.
- tree,
- /// If this is null, this tree replaces the entire node (it will
- /// be included in the regular iteration instead of its host
- /// node). If not, only the given ranges are considered to be
- /// covered by this tree. This is used for trees that are mixed in
- /// a way that isn't strictly hierarchical. Such mounted trees are
- /// only entered by [`resolveInner`](#common.Tree.resolveInner)
- /// and [`enter`](#common.SyntaxNode.enter).
- overlay,
- /// The parser used to create this subtree.
- parser) {
- this.tree = tree;
- this.overlay = overlay;
- this.parser = parser;
- }
- }
- const noProps = Object.create(null);
- /// Each node in a syntax tree has a node type associated with it.
- class NodeType {
- /// @internal
- constructor(
- /// The name of the node type. Not necessarily unique, but if the
- /// grammar was written properly, different node types with the
- /// same name within a node set should play the same semantic
- /// role.
- name,
- /// @internal
- props,
- /// The id of this node in its set. Corresponds to the term ids
- /// used in the parser.
- id,
- /// @internal
- flags = 0) {
- this.name = name;
- this.props = props;
- this.id = id;
- this.flags = flags;
- }
- static define(spec) {
- let props = spec.props && spec.props.length ? Object.create(null) : noProps;
- let flags = (spec.top ? 1 /* Top */ : 0) | (spec.skipped ? 2 /* Skipped */ : 0) |
- (spec.error ? 4 /* Error */ : 0) | (spec.name == null ? 8 /* Anonymous */ : 0);
- let type = new NodeType(spec.name || "", props, spec.id, flags);
- if (spec.props)
- for (let src of spec.props) {
- if (!Array.isArray(src))
- src = src(type);
- if (src) {
- if (src[0].perNode)
- throw new RangeError("Can't store a per-node prop on a node type");
- props[src[0].id] = src[1];
- }
- }
- return type;
- }
- /// Retrieves a node prop for this type. Will return `undefined` if
- /// the prop isn't present on this node.
- prop(prop) { return this.props[prop.id]; }
- /// True when this is the top node of a grammar.
- get isTop() { return (this.flags & 1 /* Top */) > 0; }
- /// True when this node is produced by a skip rule.
- get isSkipped() { return (this.flags & 2 /* Skipped */) > 0; }
- /// Indicates whether this is an error node.
- get isError() { return (this.flags & 4 /* Error */) > 0; }
- /// When true, this node type doesn't correspond to a user-declared
- /// named node, for example because it is used to cache repetition.
- get isAnonymous() { return (this.flags & 8 /* Anonymous */) > 0; }
- /// Returns true when this node's name or one of its
- /// [groups](#common.NodeProp^group) matches the given string.
- is(name) {
- if (typeof name == 'string') {
- if (this.name == name)
- return true;
- let group = this.prop(NodeProp.group);
- return group ? group.indexOf(name) > -1 : false;
- }
- return this.id == name;
- }
- /// Create a function from node types to arbitrary values by
- /// specifying an object whose property names are node or
- /// [group](#common.NodeProp^group) names. Often useful with
- /// [`NodeProp.add`](#common.NodeProp.add). You can put multiple
- /// names, separated by spaces, in a single property name to map
- /// multiple node names to a single value.
- static match(map) {
- let direct = Object.create(null);
- for (let prop in map)
- for (let name of prop.split(" "))
- direct[name] = map[prop];
- return (node) => {
- for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) {
- let found = direct[i < 0 ? node.name : groups[i]];
- if (found)
- return found;
- }
- };
- }
- }
- /// An empty dummy node type to use when no actual type is available.
- NodeType.none = new NodeType("", Object.create(null), 0, 8 /* Anonymous */);
- /// A node set holds a collection of node types. It is used to
- /// compactly represent trees by storing their type ids, rather than a
- /// full pointer to the type object, in a numeric array. Each parser
- /// [has](#lr.LRParser.nodeSet) a node set, and [tree
- /// buffers](#common.TreeBuffer) can only store collections of nodes
- /// from the same set. A set can have a maximum of 2**16 (65536) node
- /// types in it, so that the ids fit into 16-bit typed array slots.
- class NodeSet {
- /// Create a set with the given types. The `id` property of each
- /// type should correspond to its position within the array.
- constructor(
- /// The node types in this set, by id.
- types) {
- this.types = types;
- for (let i = 0; i < types.length; i++)
- if (types[i].id != i)
- throw new RangeError("Node type ids should correspond to array positions when creating a node set");
- }
- /// Create a copy of this set with some node properties added. The
- /// arguments to this method should be created with
- /// [`NodeProp.add`](#common.NodeProp.add).
- extend(...props) {
- let newTypes = [];
- for (let type of this.types) {
- let newProps = null;
- for (let source of props) {
- let add = source(type);
- if (add) {
- if (!newProps)
- newProps = Object.assign({}, type.props);
- newProps[add[0].id] = add[1];
- }
- }
- newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type);
- }
- return new NodeSet(newTypes);
- }
- }
- const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap();
- /// Options that control iteration. Can be combined with the `|`
- /// operator to enable multiple ones.
- var IterMode;
- (function (IterMode) {
- /// When enabled, iteration will only visit [`Tree`](#common.Tree)
- /// objects, not nodes packed into
- /// [`TreeBuffer`](#common.TreeBuffer)s.
- IterMode[IterMode["ExcludeBuffers"] = 1] = "ExcludeBuffers";
- /// Enable this to make iteration include anonymous nodes (such as
- /// the nodes that wrap repeated grammar constructs into a balanced
- /// tree).
- IterMode[IterMode["IncludeAnonymous"] = 2] = "IncludeAnonymous";
- /// By default, regular [mounted](#common.NodeProp^mounted) nodes
- /// replace their base node in iteration. Enable this to ignore them
- /// instead.
- IterMode[IterMode["IgnoreMounts"] = 4] = "IgnoreMounts";
- /// This option only applies in
- /// [`enter`](#common.SyntaxNode.enter)-style methods. It tells the
- /// library to not enter mounted overlays if one covers the given
- /// position.
- IterMode[IterMode["IgnoreOverlays"] = 8] = "IgnoreOverlays";
- })(IterMode || (IterMode = {}));
- /// A piece of syntax tree. There are two ways to approach these
- /// trees: the way they are actually stored in memory, and the
- /// convenient way.
- ///
- /// Syntax trees are stored as a tree of `Tree` and `TreeBuffer`
- /// objects. By packing detail information into `TreeBuffer` leaf
- /// nodes, the representation is made a lot more memory-efficient.
- ///
- /// However, when you want to actually work with tree nodes, this
- /// representation is very awkward, so most client code will want to
- /// use the [`TreeCursor`](#common.TreeCursor) or
- /// [`SyntaxNode`](#common.SyntaxNode) interface instead, which provides
- /// a view on some part of this data structure, and can be used to
- /// move around to adjacent nodes.
- class Tree {
- /// Construct a new tree. See also [`Tree.build`](#common.Tree^build).
- constructor(
- /// The type of the top node.
- type,
- /// This node's child nodes.
- children,
- /// The positions (offsets relative to the start of this tree) of
- /// the children.
- positions,
- /// The total length of this tree
- length,
- /// Per-node [node props](#common.NodeProp) to associate with this node.
- props) {
- this.type = type;
- this.children = children;
- this.positions = positions;
- this.length = length;
- /// @internal
- this.props = null;
- if (props && props.length) {
- this.props = Object.create(null);
- for (let [prop, value] of props)
- this.props[typeof prop == "number" ? prop : prop.id] = value;
- }
- }
- /// @internal
- toString() {
- let mounted = this.prop(NodeProp.mounted);
- if (mounted && !mounted.overlay)
- return mounted.tree.toString();
- let children = "";
- for (let ch of this.children) {
- let str = ch.toString();
- if (str) {
- if (children)
- children += ",";
- children += str;
- }
- }
- return !this.type.name ? children :
- (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) +
- (children.length ? "(" + children + ")" : "");
- }
- /// Get a [tree cursor](#common.TreeCursor) positioned at the top of
- /// the tree. Mode can be used to [control](#common.IterMode) which
- /// nodes the cursor visits.
- cursor(mode = 0) {
- return new TreeCursor(this.topNode, mode);
- }
- /// Get a [tree cursor](#common.TreeCursor) pointing into this tree
- /// at the given position and side (see
- /// [`moveTo`](#common.TreeCursor.moveTo).
- cursorAt(pos, side = 0, mode = 0) {
- let scope = CachedNode.get(this) || this.topNode;
- let cursor = new TreeCursor(scope);
- cursor.moveTo(pos, side);
- CachedNode.set(this, cursor._tree);
- return cursor;
- }
- /// Get a [syntax node](#common.SyntaxNode) object for the top of the
- /// tree.
- get topNode() {
- return new TreeNode(this, 0, 0, null);
- }
- /// Get the [syntax node](#common.SyntaxNode) at the given position.
- /// If `side` is -1, this will move into nodes that end at the
- /// position. If 1, it'll move into nodes that start at the
- /// position. With 0, it'll only enter nodes that cover the position
- /// from both sides.
- resolve(pos, side = 0) {
- let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false);
- CachedNode.set(this, node);
- return node;
- }
- /// Like [`resolve`](#common.Tree.resolve), but will enter
- /// [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node
- /// pointing into the innermost overlaid tree at the given position
- /// (with parent links going through all parent structure, including
- /// the host trees).
- resolveInner(pos, side = 0) {
- let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true);
- CachedInnerNode.set(this, node);
- return node;
- }
- /// Iterate over the tree and its children, calling `enter` for any
- /// node that touches the `from`/`to` region (if given) before
- /// running over such a node's children, and `leave` (if given) when
- /// leaving the node. When `enter` returns `false`, that node will
- /// not have its children iterated over (or `leave` called).
- iterate(spec) {
- let { enter, leave, from = 0, to = this.length } = spec;
- for (let c = this.cursor((spec.mode || 0) | IterMode.IncludeAnonymous);;) {
- let entered = false;
- if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c) !== false)) {
- if (c.firstChild())
- continue;
- entered = true;
- }
- for (;;) {
- if (entered && leave && !c.type.isAnonymous)
- leave(c);
- if (c.nextSibling())
- break;
- if (!c.parent())
- return;
- entered = true;
- }
- }
- }
- /// Get the value of the given [node prop](#common.NodeProp) for this
- /// node. Works with both per-node and per-type props.
- prop(prop) {
- return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : undefined;
- }
- /// Returns the node's [per-node props](#common.NodeProp.perNode) in a
- /// format that can be passed to the [`Tree`](#common.Tree)
- /// constructor.
- get propValues() {
- let result = [];
- if (this.props)
- for (let id in this.props)
- result.push([+id, this.props[id]]);
- return result;
- }
- /// Balance the direct children of this tree, producing a copy of
- /// which may have children grouped into subtrees with type
- /// [`NodeType.none`](#common.NodeType^none).
- balance(config = {}) {
- return this.children.length <= 8 /* BranchFactor */ ? this :
- balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length)));
- }
- /// Build a tree from a postfix-ordered buffer of node information,
- /// or a cursor over such a buffer.
- static build(data) { return buildTree(data); }
- }
- /// The empty tree
- Tree.empty = new Tree(NodeType.none, [], [], 0);
- class FlatBufferCursor {
- constructor(buffer, index) {
- this.buffer = buffer;
- this.index = index;
- }
- 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]; }
- get pos() { return this.index; }
- next() { this.index -= 4; }
- fork() { return new FlatBufferCursor(this.buffer, this.index); }
- }
- /// Tree buffers contain (type, start, end, endIndex) quads for each
- /// node. In such a buffer, nodes are stored in prefix order (parents
- /// before children, with the endIndex of the parent indicating which
- /// children belong to it)
- class TreeBuffer {
- /// Create a tree buffer.
- constructor(
- /// The buffer's content.
- buffer,
- /// The total length of the group of nodes in the buffer.
- length,
- /// The node set used in this buffer.
- set) {
- this.buffer = buffer;
- this.length = length;
- this.set = set;
- }
- /// @internal
- get type() { return NodeType.none; }
- /// @internal
- toString() {
- let result = [];
- for (let index = 0; index < this.buffer.length;) {
- result.push(this.childString(index));
- index = this.buffer[index + 3];
- }
- return result.join(",");
- }
- /// @internal
- childString(index) {
- let id = this.buffer[index], endIndex = this.buffer[index + 3];
- let type = this.set.types[id], result = type.name;
- if (/\W/.test(result) && !type.isError)
- result = JSON.stringify(result);
- index += 4;
- if (endIndex == index)
- return result;
- let children = [];
- while (index < endIndex) {
- children.push(this.childString(index));
- index = this.buffer[index + 3];
- }
- return result + "(" + children.join(",") + ")";
- }
- /// @internal
- findChild(startIndex, endIndex, dir, pos, side) {
- let { buffer } = this, pick = -1;
- for (let i = startIndex; i != endIndex; i = buffer[i + 3]) {
- if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) {
- pick = i;
- if (dir > 0)
- break;
- }
- }
- return pick;
- }
- /// @internal
- slice(startI, endI, from, to) {
- let b = this.buffer;
- let copy = new Uint16Array(endI - startI);
- for (let i = startI, j = 0; i < endI;) {
- copy[j++] = b[i++];
- copy[j++] = b[i++] - from;
- copy[j++] = b[i++] - from;
- copy[j++] = b[i++] - startI;
- }
- return new TreeBuffer(copy, to - from, this.set);
- }
- }
- function checkSide(side, pos, from, to) {
- switch (side) {
- case -2 /* Before */: return from < pos;
- case -1 /* AtOrBefore */: return to >= pos && from < pos;
- case 0 /* Around */: return from < pos && to > pos;
- case 1 /* AtOrAfter */: return from <= pos && to > pos;
- case 2 /* After */: return to > pos;
- case 4 /* DontCare */: return true;
- }
- }
- function enterUnfinishedNodesBefore(node, pos) {
- let scan = node.childBefore(pos);
- while (scan) {
- let last = scan.lastChild;
- if (!last || last.to != scan.to)
- break;
- if (last.type.isError && last.from == last.to) {
- node = scan;
- scan = last.prevSibling;
- }
- else {
- scan = last;
- }
- }
- return node;
- }
- function resolveNode(node, pos, side, overlays) {
- var _a;
- // Move up to a node that actually holds the position, if possible
- while (node.from == node.to ||
- (side < 1 ? node.from >= pos : node.from > pos) ||
- (side > -1 ? node.to <= pos : node.to < pos)) {
- let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent;
- if (!parent)
- return node;
- node = parent;
- }
- let mode = overlays ? 0 : IterMode.IgnoreOverlays;
- // Must go up out of overlays when those do not overlap with pos
- if (overlays)
- for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) {
- if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, mode)) === null || _a === void 0 ? void 0 : _a.from) != scan.from)
- node = parent;
- }
- for (;;) {
- let inner = node.enter(pos, side, mode);
- if (!inner)
- return node;
- node = inner;
- }
- }
- class TreeNode {
- constructor(_tree, from,
- // Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay)
- index, _parent) {
- this._tree = _tree;
- this.from = from;
- this.index = index;
- this._parent = _parent;
- }
- get type() { return this._tree.type; }
- get name() { return this._tree.type.name; }
- get to() { return this.from + this._tree.length; }
- nextChild(i, dir, pos, side, mode = 0) {
- for (let parent = this;;) {
- for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) {
- let next = children[i], start = positions[i] + parent.from;
- if (!checkSide(side, pos, start, start + next.length))
- continue;
- if (next instanceof TreeBuffer) {
- if (mode & IterMode.ExcludeBuffers)
- continue;
- let index = next.findChild(0, next.buffer.length, dir, pos - start, side);
- if (index > -1)
- return new BufferNode(new BufferContext(parent, next, i, start), null, index);
- }
- else if ((mode & IterMode.IncludeAnonymous) || (!next.type.isAnonymous || hasChild(next))) {
- let mounted;
- if (!(mode & IterMode.IgnoreMounts) &&
- next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay)
- return new TreeNode(mounted.tree, start, i, parent);
- let inner = new TreeNode(next, start, i, parent);
- return (mode & IterMode.IncludeAnonymous) || !inner.type.isAnonymous ? inner
- : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side);
- }
- }
- if ((mode & IterMode.IncludeAnonymous) || !parent.type.isAnonymous)
- return null;
- if (parent.index >= 0)
- i = parent.index + dir;
- else
- i = dir < 0 ? -1 : parent._parent._tree.children.length;
- parent = parent._parent;
- if (!parent)
- return null;
- }
- }
- get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); }
- get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* DontCare */); }
- childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); }
- childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Before */); }
- enter(pos, side, mode = 0) {
- let mounted;
- if (!(mode & IterMode.IgnoreOverlays) && (mounted = this._tree.prop(NodeProp.mounted)) && mounted.overlay) {
- let rPos = pos - this.from;
- for (let { from, to } of mounted.overlay) {
- if ((side > 0 ? from <= rPos : from < rPos) &&
- (side < 0 ? to >= rPos : to > rPos))
- return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this);
- }
- }
- return this.nextChild(0, 1, pos, side, mode);
- }
- nextSignificantParent() {
- let val = this;
- while (val.type.isAnonymous && val._parent)
- val = val._parent;
- return val;
- }
- get parent() {
- return this._parent ? this._parent.nextSignificantParent() : null;
- }
- get nextSibling() {
- return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* DontCare */) : null;
- }
- get prevSibling() {
- return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null;
- }
- cursor(mode = 0) { return new TreeCursor(this, mode); }
- get tree() { return this._tree; }
- toTree() { return this._tree; }
- resolve(pos, side = 0) {
- return resolveNode(this, pos, side, false);
- }
- resolveInner(pos, side = 0) {
- return resolveNode(this, pos, side, true);
- }
- enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); }
- getChild(type, before = null, after = null) {
- let r = getChildren(this, type, before, after);
- return r.length ? r[0] : null;
- }
- getChildren(type, before = null, after = null) {
- return getChildren(this, type, before, after);
- }
- /// @internal
- toString() { return this._tree.toString(); }
- get node() { return this; }
- matchContext(context) { return matchNodeContext(this, context); }
- }
- function getChildren(node, type, before, after) {
- let cur = node.cursor(), result = [];
- if (!cur.firstChild())
- return result;
- if (before != null)
- while (!cur.type.is(before))
- if (!cur.nextSibling())
- return result;
- for (;;) {
- if (after != null && cur.type.is(after))
- return result;
- if (cur.type.is(type))
- result.push(cur.node);
- if (!cur.nextSibling())
- return after == null ? result : [];
- }
- }
- function matchNodeContext(node, context, i = context.length - 1) {
- for (let p = node.parent; i >= 0; p = p.parent) {
- if (!p)
- return false;
- if (!p.type.isAnonymous) {
- if (context[i] && context[i] != p.name)
- return false;
- i--;
- }
- }
- return true;
- }
- class BufferContext {
- constructor(parent, buffer, index, start) {
- this.parent = parent;
- this.buffer = buffer;
- this.index = index;
- this.start = start;
- }
- }
- class BufferNode {
- constructor(context, _parent, index) {
- this.context = context;
- this._parent = _parent;
- this.index = index;
- this.type = context.buffer.set.types[context.buffer.buffer[index]];
- }
- get name() { return this.type.name; }
- get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; }
- get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; }
- child(dir, pos, side) {
- let { buffer } = this.context;
- let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side);
- return index < 0 ? null : new BufferNode(this.context, this, index);
- }
- get firstChild() { return this.child(1, 0, 4 /* DontCare */); }
- get lastChild() { return this.child(-1, 0, 4 /* DontCare */); }
- childAfter(pos) { return this.child(1, pos, 2 /* After */); }
- childBefore(pos) { return this.child(-1, pos, -2 /* Before */); }
- enter(pos, side, mode = 0) {
- if (mode & IterMode.ExcludeBuffers)
- return null;
- let { buffer } = this.context;
- let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side);
- return index < 0 ? null : new BufferNode(this.context, this, index);
- }
- get parent() {
- return this._parent || this.context.parent.nextSignificantParent();
- }
- externalSibling(dir) {
- return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* DontCare */);
- }
- get nextSibling() {
- let { buffer } = this.context;
- let after = buffer.buffer[this.index + 3];
- if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length))
- return new BufferNode(this.context, this._parent, after);
- return this.externalSibling(1);
- }
- get prevSibling() {
- let { buffer } = this.context;
- let parentStart = this._parent ? this._parent.index + 4 : 0;
- if (this.index == parentStart)
- return this.externalSibling(-1);
- return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
- }
- cursor(mode = 0) { return new TreeCursor(this, mode); }
- get tree() { return null; }
- toTree() {
- let children = [], positions = [];
- let { buffer } = this.context;
- let startI = this.index + 4, endI = buffer.buffer[this.index + 3];
- if (endI > startI) {
- let from = buffer.buffer[this.index + 1], to = buffer.buffer[this.index + 2];
- children.push(buffer.slice(startI, endI, from, to));
- positions.push(0);
- }
- return new Tree(this.type, children, positions, this.to - this.from);
- }
- resolve(pos, side = 0) {
- return resolveNode(this, pos, side, false);
- }
- resolveInner(pos, side = 0) {
- return resolveNode(this, pos, side, true);
- }
- enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); }
- /// @internal
- toString() { return this.context.buffer.childString(this.index); }
- getChild(type, before = null, after = null) {
- let r = getChildren(this, type, before, after);
- return r.length ? r[0] : null;
- }
- getChildren(type, before = null, after = null) {
- return getChildren(this, type, before, after);
- }
- get node() { return this; }
- matchContext(context) { return matchNodeContext(this, context); }
- }
- /// A tree cursor object focuses on a given node in a syntax tree, and
- /// allows you to move to adjacent nodes.
- class TreeCursor {
- /// @internal
- constructor(node,
- /// @internal
- mode = 0) {
- this.mode = mode;
- /// @internal
- this.buffer = null;
- this.stack = [];
- /// @internal
- this.index = 0;
- this.bufferNode = null;
- if (node instanceof TreeNode) {
- this.yieldNode(node);
- }
- else {
- this._tree = node.context.parent;
- this.buffer = node.context;
- for (let n = node._parent; n; n = n._parent)
- this.stack.unshift(n.index);
- this.bufferNode = node;
- this.yieldBuf(node.index);
- }
- }
- /// Shorthand for `.type.name`.
- get name() { return this.type.name; }
- yieldNode(node) {
- if (!node)
- return false;
- this._tree = node;
- this.type = node.type;
- this.from = node.from;
- this.to = node.to;
- return true;
- }
- yieldBuf(index, type) {
- this.index = index;
- let { start, buffer } = this.buffer;
- this.type = type || buffer.set.types[buffer.buffer[index]];
- this.from = start + buffer.buffer[index + 1];
- this.to = start + buffer.buffer[index + 2];
- return true;
- }
- yield(node) {
- if (!node)
- return false;
- if (node instanceof TreeNode) {
- this.buffer = null;
- return this.yieldNode(node);
- }
- this.buffer = node.context;
- return this.yieldBuf(node.index, node.type);
- }
- /// @internal
- toString() {
- return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString();
- }
- /// @internal
- enterChild(dir, pos, side) {
- if (!this.buffer)
- return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode));
- let { buffer } = this.buffer;
- let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side);
- if (index < 0)
- return false;
- this.stack.push(this.index);
- return this.yieldBuf(index);
- }
- /// Move the cursor to this node's first child. When this returns
- /// false, the node has no child, and the cursor has not been moved.
- firstChild() { return this.enterChild(1, 0, 4 /* DontCare */); }
- /// Move the cursor to this node's last child.
- lastChild() { return this.enterChild(-1, 0, 4 /* DontCare */); }
- /// Move the cursor to the first child that ends after `pos`.
- childAfter(pos) { return this.enterChild(1, pos, 2 /* After */); }
- /// Move to the last child that starts before `pos`.
- childBefore(pos) { return this.enterChild(-1, pos, -2 /* Before */); }
- /// Move the cursor to the child around `pos`. If side is -1 the
- /// child may end at that position, when 1 it may start there. This
- /// will also enter [overlaid](#common.MountedTree.overlay)
- /// [mounted](#common.NodeProp^mounted) trees unless `overlays` is
- /// set to false.
- enter(pos, side, mode = this.mode) {
- if (!this.buffer)
- return this.yield(this._tree.enter(pos, side, mode));
- return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side);
- }
- /// Move to the node's parent node, if this isn't the top node.
- parent() {
- if (!this.buffer)
- return this.yieldNode((this.mode & IterMode.IncludeAnonymous) ? this._tree._parent : this._tree.parent);
- if (this.stack.length)
- return this.yieldBuf(this.stack.pop());
- let parent = (this.mode & IterMode.IncludeAnonymous) ? this.buffer.parent : this.buffer.parent.nextSignificantParent();
- this.buffer = null;
- return this.yieldNode(parent);
- }
- /// @internal
- sibling(dir) {
- if (!this.buffer)
- return !this._tree._parent ? false
- : this.yield(this._tree.index < 0 ? null
- : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* DontCare */, this.mode));
- let { buffer } = this.buffer, d = this.stack.length - 1;
- if (dir < 0) {
- let parentStart = d < 0 ? 0 : this.stack[d] + 4;
- if (this.index != parentStart)
- return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
- }
- else {
- let after = buffer.buffer[this.index + 3];
- if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3]))
- return this.yieldBuf(after);
- }
- return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* DontCare */, this.mode)) : false;
- }
- /// Move to this node's next sibling, if any.
- nextSibling() { return this.sibling(1); }
- /// Move to this node's previous sibling, if any.
- prevSibling() { return this.sibling(-1); }
- atLastNode(dir) {
- let index, parent, { buffer } = this;
- if (buffer) {
- if (dir > 0) {
- if (this.index < buffer.buffer.buffer.length)
- return false;
- }
- else {
- for (let i = 0; i < this.index; i++)
- if (buffer.buffer.buffer[i + 3] < this.index)
- return false;
- }
- ({ index, parent } = buffer);
- }
- else {
- ({ index, _parent: parent } = this._tree);
- }
- for (; parent; { index, _parent: parent } = parent) {
- if (index > -1)
- for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) {
- let child = parent._tree.children[i];
- if ((this.mode & IterMode.IncludeAnonymous) ||
- child instanceof TreeBuffer ||
- !child.type.isAnonymous ||
- hasChild(child))
- return false;
- }
- }
- return true;
- }
- move(dir, enter) {
- if (enter && this.enterChild(dir, 0, 4 /* DontCare */))
- return true;
- for (;;) {
- if (this.sibling(dir))
- return true;
- if (this.atLastNode(dir) || !this.parent())
- return false;
- }
- }
- /// Move to the next node in a
- /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR))
- /// traversal, going from a node to its first child or, if the
- /// current node is empty or `enter` is false, its next sibling or
- /// the next sibling of the first parent node that has one.
- next(enter = true) { return this.move(1, enter); }
- /// Move to the next node in a last-to-first pre-order traveral. A
- /// node is followed by its last child or, if it has none, its
- /// previous sibling or the previous sibling of the first parent
- /// node that has one.
- prev(enter = true) { return this.move(-1, enter); }
- /// Move the cursor to the innermost node that covers `pos`. If
- /// `side` is -1, it will enter nodes that end at `pos`. If it is 1,
- /// it will enter nodes that start at `pos`.
- moveTo(pos, side = 0) {
- // Move up to a node that actually holds the position, if possible
- while (this.from == this.to ||
- (side < 1 ? this.from >= pos : this.from > pos) ||
- (side > -1 ? this.to <= pos : this.to < pos))
- if (!this.parent())
- break;
- // Then scan down into child nodes as far as possible
- while (this.enterChild(1, pos, side)) { }
- return this;
- }
- /// Get a [syntax node](#common.SyntaxNode) at the cursor's current
- /// position.
- get node() {
- if (!this.buffer)
- return this._tree;
- let cache = this.bufferNode, result = null, depth = 0;
- if (cache && cache.context == this.buffer) {
- scan: for (let index = this.index, d = this.stack.length; d >= 0;) {
- for (let c = cache; c; c = c._parent)
- if (c.index == index) {
- if (index == this.index)
- return c;
- result = c;
- depth = d + 1;
- break scan;
- }
- index = this.stack[--d];
- }
- }
- for (let i = depth; i < this.stack.length; i++)
- result = new BufferNode(this.buffer, result, this.stack[i]);
- return this.bufferNode = new BufferNode(this.buffer, result, this.index);
- }
- /// Get the [tree](#common.Tree) that represents the current node, if
- /// any. Will return null when the node is in a [tree
- /// buffer](#common.TreeBuffer).
- get tree() {
- return this.buffer ? null : this._tree._tree;
- }
- /// Iterate over the current node and all its descendants, calling
- /// `enter` when entering a node and `leave`, if given, when leaving
- /// one. When `enter` returns `false`, any children of that node are
- /// skipped, and `leave` isn't called for it.
- iterate(enter, leave) {
- for (let depth = 0;;) {
- let mustLeave = false;
- if (this.type.isAnonymous || enter(this) !== false) {
- if (this.firstChild()) {
- depth++;
- continue;
- }
- if (!this.type.isAnonymous)
- mustLeave = true;
- }
- for (;;) {
- if (mustLeave && leave)
- leave(this);
- mustLeave = this.type.isAnonymous;
- if (this.nextSibling())
- break;
- if (!depth)
- return;
- this.parent();
- depth--;
- mustLeave = true;
- }
- }
- }
- /// Test whether the current node matches a given context—a sequence
- /// of direct parent node names. Empty strings in the context array
- /// are treated as wildcards.
- matchContext(context) {
- if (!this.buffer)
- return matchNodeContext(this.node, context);
- let { buffer } = this.buffer, { types } = buffer.set;
- for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) {
- if (d < 0)
- return matchNodeContext(this.node, context, i);
- let type = types[buffer.buffer[this.stack[d]]];
- if (!type.isAnonymous) {
- if (context[i] && context[i] != type.name)
- return false;
- i--;
- }
- }
- return true;
- }
- }
- function hasChild(tree) {
- return tree.children.some(ch => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch));
- }
- function buildTree(data) {
- var _a;
- let { buffer, nodeSet, maxBufferLength = DefaultBufferLength, reused = [], minRepeatType = nodeSet.types.length } = data;
- let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer;
- let types = nodeSet.types;
- let contextHash = 0, lookAhead = 0;
- function takeNode(parentStart, minPos, children, positions, inRepeat) {
- let { id, start, end, size } = cursor;
- let lookAheadAtStart = lookAhead;
- while (size < 0) {
- cursor.next();
- if (size == -1 /* Reuse */) {
- let node = reused[id];
- children.push(node);
- positions.push(start - parentStart);
- return;
- }
- else if (size == -3 /* ContextChange */) { // Context change
- contextHash = id;
- return;
- }
- else if (size == -4 /* LookAhead */) {
- lookAhead = id;
- return;
- }
- else {
- throw new RangeError(`Unrecognized record size: ${size}`);
- }
- }
- let type = types[id], node, buffer;
- let startPos = start - parentStart;
- if (end - start <= maxBufferLength && (buffer = findBufferSize(cursor.pos - minPos, inRepeat))) {
- // Small enough for a buffer, and no reused nodes inside
- let data = new Uint16Array(buffer.size - buffer.skip);
- let endPos = cursor.pos - buffer.size, index = data.length;
- while (cursor.pos > endPos)
- index = copyToBuffer(buffer.start, data, index);
- node = new TreeBuffer(data, end - buffer.start, nodeSet);
- startPos = buffer.start - parentStart;
- }
- else { // Make it a node
- let endPos = cursor.pos - size;
- cursor.next();
- let localChildren = [], localPositions = [];
- let localInRepeat = id >= minRepeatType ? id : -1;
- let lastGroup = 0, lastEnd = end;
- while (cursor.pos > endPos) {
- if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) {
- if (cursor.end <= lastEnd - maxBufferLength) {
- makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart);
- lastGroup = localChildren.length;
- lastEnd = cursor.end;
- }
- cursor.next();
- }
- else {
- takeNode(start, endPos, localChildren, localPositions, localInRepeat);
- }
- }
- if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length)
- makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart);
- localChildren.reverse();
- localPositions.reverse();
- if (localInRepeat > -1 && lastGroup > 0) {
- let make = makeBalanced(type);
- node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make);
- }
- else {
- node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end);
- }
- }
- children.push(node);
- positions.push(startPos);
- }
- function makeBalanced(type) {
- return (children, positions, length) => {
- let lookAhead = 0, lastI = children.length - 1, last, lookAheadProp;
- if (lastI >= 0 && (last = children[lastI]) instanceof Tree) {
- if (!lastI && last.type == type && last.length == length)
- return last;
- if (lookAheadProp = last.prop(NodeProp.lookAhead))
- lookAhead = positions[lastI] + last.length + lookAheadProp;
- }
- return makeTree(type, children, positions, length, lookAhead);
- };
- }
- function makeRepeatLeaf(children, positions, base, i, from, to, type, lookAhead) {
- let localChildren = [], localPositions = [];
- while (children.length > i) {
- localChildren.push(children.pop());
- localPositions.push(positions.pop() + base - from);
- }
- children.push(makeTree(nodeSet.types[type], localChildren, localPositions, to - from, lookAhead - to));
- positions.push(from - base);
- }
- function makeTree(type, children, positions, length, lookAhead = 0, props) {
- if (contextHash) {
- let pair = [NodeProp.contextHash, contextHash];
- props = props ? [pair].concat(props) : [pair];
- }
- if (lookAhead > 25) {
- let pair = [NodeProp.lookAhead, lookAhead];
- props = props ? [pair].concat(props) : [pair];
- }
- return new Tree(type, children, positions, length, props);
- }
- function findBufferSize(maxSize, inRepeat) {
- // Scan through the buffer to find previous siblings that fit
- // together in a TreeBuffer, and don't contain any reused nodes
- // (which can't be stored in a buffer).
- // If `inRepeat` is > -1, ignore node boundaries of that type for
- // nesting, but make sure the end falls either at the start
- // (`maxSize`) or before such a node.
- let fork = cursor.fork();
- let size = 0, start = 0, skip = 0, minStart = fork.end - maxBufferLength;
- let result = { size: 0, start: 0, skip: 0 };
- scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos;) {
- let nodeSize = fork.size;
- // Pretend nested repeat nodes of the same type don't exist
- if (fork.id == inRepeat && nodeSize >= 0) {
- // Except that we store the current state as a valid return
- // value.
- result.size = size;
- result.start = start;
- result.skip = skip;
- skip += 4;
- size += 4;
- fork.next();
- continue;
- }
- let startPos = fork.pos - nodeSize;
- if (nodeSize < 0 || startPos < minPos || fork.start < minStart)
- break;
- let localSkipped = fork.id >= minRepeatType ? 4 : 0;
- let nodeStart = fork.start;
- fork.next();
- while (fork.pos > startPos) {
- if (fork.size < 0) {
- if (fork.size == -3 /* ContextChange */)
- localSkipped += 4;
- else
- break scan;
- }
- else if (fork.id >= minRepeatType) {
- localSkipped += 4;
- }
- fork.next();
- }
- start = nodeStart;
- size += nodeSize;
- skip += localSkipped;
- }
- if (inRepeat < 0 || size == maxSize) {
- result.size = size;
- result.start = start;
- result.skip = skip;
- }
- return result.size > 4 ? result : undefined;
- }
- function copyToBuffer(bufferStart, buffer, index) {
- let { id, start, end, size } = cursor;
- cursor.next();
- if (size >= 0 && id < minRepeatType) {
- let startIndex = index;
- if (size > 4) {
- let endPos = cursor.pos - (size - 4);
- while (cursor.pos > endPos)
- index = copyToBuffer(bufferStart, buffer, index);
- }
- buffer[--index] = startIndex;
- buffer[--index] = end - bufferStart;
- buffer[--index] = start - bufferStart;
- buffer[--index] = id;
- }
- else if (size == -3 /* ContextChange */) {
- contextHash = id;
- }
- else if (size == -4 /* LookAhead */) {
- lookAhead = id;
- }
- return index;
- }
- let children = [], positions = [];
- while (cursor.pos > 0)
- takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1);
- let length = (_a = data.length) !== null && _a !== void 0 ? _a : (children.length ? positions[0] + children[0].length : 0);
- return new Tree(types[data.topID], children.reverse(), positions.reverse(), length);
- }
- const nodeSizeCache = new WeakMap;
- function nodeSize(balanceType, node) {
- if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType)
- return 1;
- let size = nodeSizeCache.get(node);
- if (size == null) {
- size = 1;
- for (let child of node.children) {
- if (child.type != balanceType || !(child instanceof Tree)) {
- size = 1;
- break;
- }
- size += nodeSize(balanceType, child);
- }
- nodeSizeCache.set(node, size);
- }
- return size;
- }
- function balanceRange(
- // The type the balanced tree's inner nodes.
- balanceType,
- // The direct children and their positions
- children, positions,
- // The index range in children/positions to use
- from, to,
- // The start position of the nodes, relative to their parent.
- start,
- // Length of the outer node
- length,
- // Function to build the top node of the balanced tree
- mkTop,
- // Function to build internal nodes for the balanced tree
- mkTree) {
- let total = 0;
- for (let i = from; i < to; i++)
- total += nodeSize(balanceType, children[i]);
- let maxChild = Math.ceil((total * 1.5) / 8 /* BranchFactor */);
- let localChildren = [], localPositions = [];
- function divide(children, positions, from, to, offset) {
- for (let i = from; i < to;) {
- let groupFrom = i, groupStart = positions[i], groupSize = nodeSize(balanceType, children[i]);
- i++;
- for (; i < to; i++) {
- let nextSize = nodeSize(balanceType, children[i]);
- if (groupSize + nextSize >= maxChild)
- break;
- groupSize += nextSize;
- }
- if (i == groupFrom + 1) {
- if (groupSize > maxChild) {
- let only = children[groupFrom]; // Only trees can have a size > 1
- divide(only.children, only.positions, 0, only.children.length, positions[groupFrom] + offset);
- continue;
- }
- localChildren.push(children[groupFrom]);
- }
- else {
- let length = positions[i - 1] + children[i - 1].length - groupStart;
- localChildren.push(balanceRange(balanceType, children, positions, groupFrom, i, groupStart, length, null, mkTree));
- }
- localPositions.push(groupStart + offset - start);
- }
- }
- divide(children, positions, from, to, 0);
- return (mkTop || mkTree)(localChildren, localPositions, length);
- }
- /// Provides a way to associate values with pieces of trees. As long
- /// as that part of the tree is reused, the associated values can be
- /// retrieved from an updated tree.
- class NodeWeakMap {
- constructor() {
- this.map = new WeakMap();
- }
- setBuffer(buffer, index, value) {
- let inner = this.map.get(buffer);
- if (!inner)
- this.map.set(buffer, inner = new Map);
- inner.set(index, value);
- }
- getBuffer(buffer, index) {
- let inner = this.map.get(buffer);
- return inner && inner.get(index);
- }
- /// Set the value for this syntax node.
- set(node, value) {
- if (node instanceof BufferNode)
- this.setBuffer(node.context.buffer, node.index, value);
- else if (node instanceof TreeNode)
- this.map.set(node.tree, value);
- }
- /// Retrieve value for this syntax node, if it exists in the map.
- get(node) {
- return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index)
- : node instanceof TreeNode ? this.map.get(node.tree) : undefined;
- }
- /// Set the value for the node that a cursor currently points to.
- cursorSet(cursor, value) {
- if (cursor.buffer)
- this.setBuffer(cursor.buffer.buffer, cursor.index, value);
- else
- this.map.set(cursor.tree, value);
- }
- /// Retrieve the value for the node that a cursor currently points
- /// to.
- cursorGet(cursor) {
- return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree);
- }
- }
- /// Tree fragments are used during [incremental
- /// parsing](#common.Parser.startParse) to track parts of old trees
- /// that can be reused in a new parse. An array of fragments is used
- /// to track regions of an old tree whose nodes might be reused in new
- /// parses. Use the static
- /// [`applyChanges`](#common.TreeFragment^applyChanges) method to
- /// update fragments for document changes.
- class TreeFragment {
- /// Construct a tree fragment.
- constructor(
- /// The start of the unchanged range pointed to by this fragment.
- /// This refers to an offset in the _updated_ document (as opposed
- /// to the original tree).
- from,
- /// The end of the unchanged range.
- to,
- /// The tree that this fragment is based on.
- tree,
- /// The offset between the fragment's tree and the document that
- /// this fragment can be used against. Add this when going from
- /// document to tree positions, subtract it to go from tree to
- /// document positions.
- offset, openStart = false, openEnd = false) {
- this.from = from;
- this.to = to;
- this.tree = tree;
- this.offset = offset;
- this.open = (openStart ? 1 /* Start */ : 0) | (openEnd ? 2 /* End */ : 0);
- }
- /// Whether the start of the fragment represents the start of a
- /// parse, or the end of a change. (In the second case, it may not
- /// be safe to reuse some nodes at the start, depending on the
- /// parsing algorithm.)
- get openStart() { return (this.open & 1 /* Start */) > 0; }
- /// Whether the end of the fragment represents the end of a
- /// full-document parse, or the start of a change.
- get openEnd() { return (this.open & 2 /* End */) > 0; }
- /// Create a set of fragments from a freshly parsed tree, or update
- /// an existing set of fragments by replacing the ones that overlap
- /// with a tree with content from the new tree. When `partial` is
- /// true, the parse is treated as incomplete, and the resulting
- /// fragment has [`openEnd`](#common.TreeFragment.openEnd) set to
- /// true.
- static addTree(tree, fragments = [], partial = false) {
- let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)];
- for (let f of fragments)
- if (f.to > tree.length)
- result.push(f);
- return result;
- }
- /// Apply a set of edits to an array of fragments, removing or
- /// splitting fragments as necessary to remove edited ranges, and
- /// adjusting offsets for fragments that moved.
- static applyChanges(fragments, changes, minGap = 128) {
- if (!changes.length)
- return fragments;
- let result = [];
- let fI = 1, nextF = fragments.length ? fragments[0] : null;
- for (let cI = 0, pos = 0, off = 0;; cI++) {
- let nextC = cI < changes.length ? changes[cI] : null;
- let nextPos = nextC ? nextC.fromA : 1e9;
- if (nextPos - pos >= minGap)
- while (nextF && nextF.from < nextPos) {
- let cut = nextF;
- if (pos >= cut.from || nextPos <= cut.to || off) {
- let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off;
- cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC);
- }
- if (cut)
- result.push(cut);
- if (nextF.to > nextPos)
- break;
- nextF = fI < fragments.length ? fragments[fI++] : null;
- }
- if (!nextC)
- break;
- pos = nextC.toA;
- off = nextC.toA - nextC.toB;
- }
- return result;
- }
- }
- /// A superclass that parsers should extend.
- class Parser {
- /// Start a parse, returning a [partial parse](#common.PartialParse)
- /// object. [`fragments`](#common.TreeFragment) can be passed in to
- /// make the parse incremental.
- ///
- /// By default, the entire input is parsed. You can pass `ranges`,
- /// which should be a sorted array of non-empty, non-overlapping
- /// ranges, to parse only those ranges. The tree returned in that
- /// case will start at `ranges[0].from`.
- startParse(input, fragments, ranges) {
- if (typeof input == "string")
- input = new StringInput(input);
- ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)];
- return this.createParse(input, fragments || [], ranges);
- }
- /// Run a full parse, returning the resulting tree.
- parse(input, fragments, ranges) {
- let parse = this.startParse(input, fragments, ranges);
- for (;;) {
- let done = parse.advance();
- if (done)
- return done;
- }
- }
- }
- class StringInput {
- constructor(string) {
- this.string = string;
- }
- get length() { return this.string.length; }
- chunk(from) { return this.string.slice(from); }
- get lineChunks() { return false; }
- read(from, to) { return this.string.slice(from, to); }
- }
- /// Create a parse wrapper that, after the inner parse completes,
- /// scans its tree for mixed language regions with the `nest`
- /// function, runs the resulting [inner parses](#common.NestedParse),
- /// and then [mounts](#common.NodeProp^mounted) their results onto the
- /// tree.
- ///
- /// The nesting function is passed a cursor to provide context for a
- /// node, but _should not_ move that cursor, only inspect its
- /// properties and optionally access its
- /// [node object](#common.TreeCursor.node).
- function parseMixed(nest) {
- return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges);
- }
- class InnerParse {
- constructor(parser, parse, overlay, target, ranges) {
- this.parser = parser;
- this.parse = parse;
- this.overlay = overlay;
- this.target = target;
- this.ranges = ranges;
- }
- }
- class ActiveOverlay {
- constructor(parser, predicate, mounts, index, start, target, prev) {
- this.parser = parser;
- this.predicate = predicate;
- this.mounts = mounts;
- this.index = index;
- this.start = start;
- this.target = target;
- this.prev = prev;
- this.depth = 0;
- this.ranges = [];
- }
- }
- const stoppedInner = new NodeProp({ perNode: true });
- class MixedParse {
- constructor(base, nest, input, fragments, ranges) {
- this.nest = nest;
- this.input = input;
- this.fragments = fragments;
- this.ranges = ranges;
- this.inner = [];
- this.innerDone = 0;
- this.baseTree = null;
- this.stoppedAt = null;
- this.baseParse = base;
- }
- advance() {
- if (this.baseParse) {
- let done = this.baseParse.advance();
- if (!done)
- return null;
- this.baseParse = null;
- this.baseTree = done;
- this.startInner();
- if (this.stoppedAt != null)
- for (let inner of this.inner)
- inner.parse.stopAt(this.stoppedAt);
- }
- if (this.innerDone == this.inner.length) {
- let result = this.baseTree;
- if (this.stoppedAt != null)
- result = new Tree(result.type, result.children, result.positions, result.length, result.propValues.concat([[stoppedInner, this.stoppedAt]]));
- return result;
- }
- let inner = this.inner[this.innerDone], done = inner.parse.advance();
- if (done) {
- this.innerDone++;
- // This is a somewhat dodgy but super helpful hack where we
- // patch up nodes created by the inner parse (and thus
- // presumably not aliased anywhere else) to hold the information
- // about the inner parse.
- let props = Object.assign(Object.create(null), inner.target.props);
- props[NodeProp.mounted.id] = new MountedTree(done, inner.overlay, inner.parser);
- inner.target.props = props;
- }
- return null;
- }
- get parsedPos() {
- if (this.baseParse)
- return 0;
- let pos = this.input.length;
- for (let i = this.innerDone; i < this.inner.length; i++) {
- if (this.inner[i].ranges[0].from < pos)
- pos = Math.min(pos, this.inner[i].parse.parsedPos);
- }
- return pos;
- }
- stopAt(pos) {
- this.stoppedAt = pos;
- if (this.baseParse)
- this.baseParse.stopAt(pos);
- else
- for (let i = this.innerDone; i < this.inner.length; i++)
- this.inner[i].parse.stopAt(pos);
- }
- startInner() {
- let fragmentCursor = new FragmentCursor(this.fragments);
- let overlay = null;
- let covered = null;
- let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
- scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) {
- let enter = true, range;
- if (fragmentCursor.hasNode(cursor)) {
- if (overlay) {
- let match = overlay.mounts.find(m => m.frag.from <= cursor.from && m.frag.to >= cursor.to && m.mount.overlay);
- if (match)
- for (let r of match.mount.overlay) {
- let from = r.from + match.pos, to = r.to + match.pos;
- if (from >= cursor.from && to <= cursor.to && !overlay.ranges.some(r => r.from < to && r.to > from))
- overlay.ranges.push({ from, to });
- }
- }
- enter = false;
- }
- else if (covered && (isCovered = checkCover(covered.ranges, cursor.from, cursor.to))) {
- enter = isCovered != 2 /* Full */;
- }
- else if (!cursor.type.isAnonymous && cursor.from < cursor.to && (nest = this.nest(cursor, this.input))) {
- if (!cursor.tree)
- materialize(cursor);
- let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser);
- if (typeof nest.overlay == "function") {
- overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay);
- }
- else {
- let ranges = punchRanges(this.ranges, nest.overlay || [new Range(cursor.from, cursor.to)]);
- if (ranges.length)
- this.inner.push(new InnerParse(nest.parser, nest.parser.startParse(this.input, enterFragments(oldMounts, ranges), ranges), nest.overlay ? nest.overlay.map(r => new Range(r.from - cursor.from, r.to - cursor.from)) : null, cursor.tree, ranges));
- if (!nest.overlay)
- enter = false;
- else if (ranges.length)
- covered = { ranges, depth: 0, prev: covered };
- }
- }
- else if (overlay && (range = overlay.predicate(cursor))) {
- if (range === true)
- range = new Range(cursor.from, cursor.to);
- if (range.from < range.to)
- overlay.ranges.push(range);
- }
- if (enter && cursor.firstChild()) {
- if (overlay)
- overlay.depth++;
- if (covered)
- covered.depth++;
- }
- else {
- for (;;) {
- if (cursor.nextSibling())
- break;
- if (!cursor.parent())
- break scan;
- if (overlay && !--overlay.depth) {
- let ranges = punchRanges(this.ranges, overlay.ranges);
- if (ranges.length)
- this.inner.splice(overlay.index, 0, new InnerParse(overlay.parser, overlay.parser.startParse(this.input, enterFragments(overlay.mounts, ranges), ranges), overlay.ranges.map(r => new Range(r.from - overlay.start, r.to - overlay.start)), overlay.target, ranges));
- overlay = overlay.prev;
- }
- if (covered && !--covered.depth)
- covered = covered.prev;
- }
- }
- }
- }
- }
- function checkCover(covered, from, to) {
- for (let range of covered) {
- if (range.from >= to)
- break;
- if (range.to > from)
- return range.from <= from && range.to >= to ? 2 /* Full */ : 1 /* Partial */;
- }
- return 0 /* None */;
- }
- // Take a piece of buffer and convert it into a stand-alone
- // TreeBuffer.
- function sliceBuf(buf, startI, endI, nodes, positions, off) {
- if (startI < endI) {
- let from = buf.buffer[startI + 1], to = buf.buffer[endI - 2];
- nodes.push(buf.slice(startI, endI, from, to));
- positions.push(from - off);
- }
- }
- // This function takes a node that's in a buffer, and converts it, and
- // its parent buffer nodes, into a Tree. This is again acting on the
- // assumption that the trees and buffers have been constructed by the
- // parse that was ran via the mix parser, and thus aren't shared with
- // any other code, making violations of the immutability safe.
- function materialize(cursor) {
- let { node } = cursor, depth = 0;
- // Scan up to the nearest tree
- do {
- cursor.parent();
- depth++;
- } while (!cursor.tree);
- // Find the index of the buffer in that tree
- let i = 0, base = cursor.tree, off = 0;
- for (;; i++) {
- off = base.positions[i] + cursor.from;
- if (off <= node.from && off + base.children[i].length >= node.to)
- break;
- }
- let buf = base.children[i], b = buf.buffer;
- // Split a level in the buffer, putting the nodes before and after
- // the child that contains `node` into new buffers.
- function split(startI, endI, type, innerOffset, length) {
- let i = startI;
- while (b[i + 2] + off <= node.from)
- i = b[i + 3];
- let children = [], positions = [];
- sliceBuf(buf, startI, i, children, positions, innerOffset);
- let from = b[i + 1], to = b[i + 2];
- let isTarget = from + off == node.from && to + off == node.to && b[i] == node.type.id;
- children.push(isTarget ? node.toTree() : split(i + 4, b[i + 3], buf.set.types[b[i]], from, to - from));
- positions.push(from - innerOffset);
- sliceBuf(buf, b[i + 3], endI, children, positions, innerOffset);
- return new Tree(type, children, positions, length);
- }
- base.children[i] = split(0, b.length, NodeType.none, 0, buf.length);
- // Move the cursor back to the target node
- for (let d = 0; d <= depth; d++)
- cursor.childAfter(node.from);
- }
- class StructureCursor {
- constructor(root, offset) {
- this.offset = offset;
- this.done = false;
- this.cursor = root.cursor(IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
- }
- // Move to the first node (in pre-order) that starts at or after `pos`.
- moveTo(pos) {
- let { cursor } = this, p = pos - this.offset;
- while (!this.done && cursor.from < p) {
- if (cursor.to >= pos && cursor.enter(p, 1, IterMode.IgnoreOverlays | IterMode.ExcludeBuffers)) ;
- else if (!cursor.next(false))
- this.done = true;
- }
- }
- hasNode(cursor) {
- this.moveTo(cursor.from);
- if (!this.done && this.cursor.from + this.offset == cursor.from && this.cursor.tree) {
- for (let tree = this.cursor.tree;;) {
- if (tree == cursor.tree)
- return true;
- if (tree.children.length && tree.positions[0] == 0 && tree.children[0] instanceof Tree)
- tree = tree.children[0];
- else
- break;
- }
- }
- return false;
- }
- }
- class FragmentCursor {
- constructor(fragments) {
- var _a;
- this.fragments = fragments;
- this.curTo = 0;
- this.fragI = 0;
- if (fragments.length) {
- let first = this.curFrag = fragments[0];
- this.curTo = (_a = first.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : first.to;
- this.inner = new StructureCursor(first.tree, -first.offset);
- }
- else {
- this.curFrag = this.inner = null;
- }
- }
- hasNode(node) {
- while (this.curFrag && node.from >= this.curTo)
- this.nextFrag();
- return this.curFrag && this.curFrag.from <= node.from && this.curTo >= node.to && this.inner.hasNode(node);
- }
- nextFrag() {
- var _a;
- this.fragI++;
- if (this.fragI == this.fragments.length) {
- this.curFrag = this.inner = null;
- }
- else {
- let frag = this.curFrag = this.fragments[this.fragI];
- this.curTo = (_a = frag.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : frag.to;
- this.inner = new StructureCursor(frag.tree, -frag.offset);
- }
- }
- findMounts(pos, parser) {
- var _a;
- let result = [];
- if (this.inner) {
- this.inner.cursor.moveTo(pos, 1);
- for (let pos = this.inner.cursor.node; pos; pos = pos.parent) {
- let mount = (_a = pos.tree) === null || _a === void 0 ? void 0 : _a.prop(NodeProp.mounted);
- if (mount && mount.parser == parser) {
- for (let i = this.fragI; i < this.fragments.length; i++) {
- let frag = this.fragments[i];
- if (frag.from >= pos.to)
- break;
- if (frag.tree == this.curFrag.tree)
- result.push({
- frag,
- pos: pos.from - frag.offset,
- mount
- });
- }
- }
- }
- }
- return result;
- }
- }
- function punchRanges(outer, ranges) {
- let copy = null, current = ranges;
- for (let i = 1, j = 0; i < outer.length; i++) {
- let gapFrom = outer[i - 1].to, gapTo = outer[i].from;
- for (; j < current.length; j++) {
- let r = current[j];
- if (r.from >= gapTo)
- break;
- if (r.to <= gapFrom)
- continue;
- if (!copy)
- current = copy = ranges.slice();
- if (r.from < gapFrom) {
- copy[j] = new Range(r.from, gapFrom);
- if (r.to > gapTo)
- copy.splice(j + 1, 0, new Range(gapTo, r.to));
- }
- else if (r.to > gapTo) {
- copy[j--] = new Range(gapTo, r.to);
- }
- else {
- copy.splice(j--, 1);
- }
- }
- }
- return current;
- }
- function findCoverChanges(a, b, from, to) {
- let iA = 0, iB = 0, inA = false, inB = false, pos = -1e9;
- let result = [];
- for (;;) {
- let nextA = iA == a.length ? 1e9 : inA ? a[iA].to : a[iA].from;
- let nextB = iB == b.length ? 1e9 : inB ? b[iB].to : b[iB].from;
- if (inA != inB) {
- let start = Math.max(pos, from), end = Math.min(nextA, nextB, to);
- if (start < end)
- result.push(new Range(start, end));
- }
- pos = Math.min(nextA, nextB);
- if (pos == 1e9)
- break;
- if (nextA == pos) {
- if (!inA)
- inA = true;
- else {
- inA = false;
- iA++;
- }
- }
- if (nextB == pos) {
- if (!inB)
- inB = true;
- else {
- inB = false;
- iB++;
- }
- }
- }
- return result;
- }
- // Given a number of fragments for the outer tree, and a set of ranges
- // to parse, find fragments for inner trees mounted around those
- // ranges, if any.
- function enterFragments(mounts, ranges) {
- let result = [];
- for (let { pos, mount, frag } of mounts) {
- let startPos = pos + (mount.overlay ? mount.overlay[0].from : 0), endPos = startPos + mount.tree.length;
- let from = Math.max(frag.from, startPos), to = Math.min(frag.to, endPos);
- if (mount.overlay) {
- let overlay = mount.overlay.map(r => new Range(r.from + pos, r.to + pos));
- let changes = findCoverChanges(ranges, overlay, from, to);
- for (let i = 0, pos = from;; i++) {
- let last = i == changes.length, end = last ? to : changes[i].from;
- if (end > pos)
- result.push(new TreeFragment(pos, end, mount.tree, -startPos, frag.from >= pos, frag.to <= end));
- if (last)
- break;
- pos = changes[i].to;
- }
- }
- else {
- result.push(new TreeFragment(from, to, mount.tree, -startPos, frag.from >= startPos, frag.to <= endPos));
- }
- }
- return result;
- }
- export { DefaultBufferLength, IterMode, MountedTree, NodeProp, NodeSet, NodeType, NodeWeakMap, Parser, Tree, TreeBuffer, TreeCursor, TreeFragment, parseMixed };
|