import { Parser, Input } from '../parser'; export class List[] = Parser[]> { constructor(nodes?: ArrayLike) { if (nodes === undefined) return; for (let i = 0; i < nodes.length; ++i) { this.push(nodes[i]); } } public length = 0; public isEmpty(): boolean { return this.head === undefined; } public head?: N = undefined; public last?: N = undefined; public get tail(): N | undefined { return this.head?.next; } public insert(node: N, before?: N): N { assert(!node.next && !node.prev); if (before === undefined) return this.push(node), node; if (before === this.head) return this.unshift(node), node; if (++this.length === 1) { return this.head = this.last = node; } assert(node !== before); const next = node.next = before; const prev = node.prev = next.prev!; return next.prev = prev.next = node; } public delete(node: N): N { assert(node.next || node.prev || this.head === this.last); assert(this.length > 0); if (--this.length === 0) { this.head = this.last = undefined; } else { const { next, prev } = node; prev === undefined ? this.head = next : prev.next = next; next === undefined ? this.last = prev : next.prev = prev; } node.next = node.prev = undefined; return node; } public unshift(node: N): this { assert(!node.next && !node.prev); if (++this.length === 1) { this.head = this.last = node; return this; } node.next = this.head; this.head = this.head!.prev = node; return this; } public push(node: N): this { assert(!node.next && !node.prev); if (++this.length === 1) { this.head = this.last = node; return this; } node.prev = this.last; this.last = this.last!.next = node; return this; } public shift(): N | undefined { if (this.length === 0) return; return this.delete(this.head!); } public pop(): N | undefined { if (this.length === 0) return; return this.delete(this.last!); } public import(list: List, before?: N): this { assert(list !== this); if (list.length === 0) return this; if (this.length === 0) { this.head = list.head; this.last = list.last; this.length = list.length; list.clear(); return this; } const head = list.head!; const last = list.last!; const next = last.next = before; const prev = head.prev = before?.prev ?? this.last!; next === undefined ? this.last = last : next.prev = last; prev.next = head; this.length += list.length; list.clear(); return this; } public clear(): void { this.length = 0; this.head = this.last = undefined; } public *[Symbol.iterator](): Iterator { for (let node = this.head; node && this.head;) { const next = node.next; yield node; node = next; } } public flatMap(f: (node: N) => List): List { const acc = new List(); for (let node = this.head; node && this.head;) { const next = node.next; acc.import(f(node)); node = next; } return acc; } public foldl(f: (acc: T, node: N) => T, acc: T): T { for (let node = this.head; node && this.head;) { const next = node.next; acc = f(acc, node); node = next; } return acc; } public foldr(f: (node: N, acc: T) => T, acc: T): T { for (let node = this.last; node && this.head;) { const prev = node.prev; acc = f(node, acc); node = prev; } return acc; } public find(f: (node: N) => unknown): N | undefined { for (let node = this.head; node && this.head;) { const next = node.next; if (f(node)) return node; node = next; } } } export namespace List { export interface Node { next?: this; prev?: this; } } export class Node implements List.Node { constructor( public value: T, public position: number = 0, public flags: Node.Flag = 0, ) { } public next?: this = undefined; public prev?: this = undefined; } export namespace Node { export const enum Flag { none, blank = 1 << 0, nested = 1 << 1, } }