From b880de0b08454a8af34ae3aeb05937788af17a69 Mon Sep 17 00:00:00 2001 From: rowan Date: Wed, 2 Jul 2025 11:13:04 -0400 Subject: [PATCH] v2 --- dist/index.d.ts | 0 dist/index.js | 1712 ------------------------------------- jsconfig.json | 14 - package-lock.json | 496 ----------- package.json | 25 +- src/byte.js | 83 -- src/clone.js | 11 - src/combinator.js | 71 -- src/cond.js | 55 -- src/const.js | 6 - src/fn.js | 69 -- src/index.js | 6 - src/iter.js | 418 --------- src/iterator.js | 63 ++ src/multi.js | 68 -- src/option.js | 106 +++ src/parser.js | 194 +++++ src/result.js | 163 ++++ src/state.js | 60 -- src/string.js | 10 + src/tuple.js | 61 -- src/utils.js | 41 + tests/combinators.test.js | 205 +++++ tests/index.d.ts | 2 - tests/index.js | 7 - tests/iterator.test.js | 127 +++ tests/primitives.test.js | 82 ++ tests/units/bytes.d.ts | 1 - tests/units/bytes.js | 70 -- tests/units/common.d.ts | 3 - tests/units/common.js | 15 - tests/units/cond.d.ts | 1 - tests/units/cond.js | 11 - tests/units/index.d.ts | 3 - tests/units/index.js | 4 - tests/units/iter.d.ts | 1 - tests/units/iter.js | 21 - tsconfig.json | 116 --- typings/byte.d.ts | 16 - typings/clone.d.ts | 2 - typings/combinator.d.ts | 14 - typings/cond.d.ts | 7 - typings/const.d.ts | 5 - typings/fn.d.ts | 11 - typings/index.d.ts | 5 - typings/iter.d.ts | 14 - typings/multi.d.ts | 8 - typings/state.d.ts | 24 - typings/tuple.d.ts | 18 - 49 files changed, 998 insertions(+), 3527 deletions(-) delete mode 100644 dist/index.d.ts delete mode 100644 dist/index.js delete mode 100644 jsconfig.json delete mode 100644 package-lock.json delete mode 100644 src/byte.js delete mode 100644 src/clone.js delete mode 100644 src/combinator.js delete mode 100644 src/cond.js delete mode 100644 src/const.js delete mode 100644 src/fn.js delete mode 100644 src/index.js delete mode 100644 src/iter.js create mode 100644 src/iterator.js delete mode 100644 src/multi.js create mode 100644 src/option.js create mode 100644 src/parser.js create mode 100644 src/result.js delete mode 100644 src/state.js create mode 100644 src/string.js delete mode 100644 src/tuple.js create mode 100644 src/utils.js create mode 100644 tests/combinators.test.js delete mode 100644 tests/index.d.ts delete mode 100755 tests/index.js create mode 100644 tests/iterator.test.js create mode 100644 tests/primitives.test.js delete mode 100644 tests/units/bytes.d.ts delete mode 100644 tests/units/bytes.js delete mode 100644 tests/units/common.d.ts delete mode 100644 tests/units/common.js delete mode 100644 tests/units/cond.d.ts delete mode 100644 tests/units/cond.js delete mode 100644 tests/units/index.d.ts delete mode 100644 tests/units/index.js delete mode 100644 tests/units/iter.d.ts delete mode 100644 tests/units/iter.js delete mode 100644 tsconfig.json delete mode 100644 typings/byte.d.ts delete mode 100644 typings/clone.d.ts delete mode 100644 typings/combinator.d.ts delete mode 100644 typings/cond.d.ts delete mode 100644 typings/const.d.ts delete mode 100644 typings/fn.d.ts delete mode 100644 typings/index.d.ts delete mode 100644 typings/iter.d.ts delete mode 100644 typings/multi.d.ts delete mode 100644 typings/state.d.ts delete mode 100644 typings/tuple.d.ts diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index 0a9b921..0000000 --- a/dist/index.js +++ /dev/null @@ -1,1712 +0,0 @@ -"use strict"; -(() => { - // src/iter.js - var Iter = class _Iter { - _iterator; - _source; - /** - * @param {Iterator} iterator - * @param {Iterabl} [source] - */ - constructor(iterator, source) { - this._iterator = iterator; - this._source = source; - } - /** - * @template T - * @param {any} value - * @returns {value is Iterable} - */ - static _isIterable(value) { - return typeof value[Symbol.iterator] === "function"; - } - /** - * @template T - * @param {T} value - */ - static from(value) { - if (value instanceof _Iter) { - return value; - } - if (_Iter._isIterable(value)) { - const iterator = value[Symbol.iterator](); - if (iterator instanceof _Iter) { - return iterator; - } - return new _Iter(iterator, value); - } - throw new TypeError("object is not an iterator"); - } - clone() { - if (this._source) { - return _Iter.from(this._source); - } - throw new Error("Cannot clone Iterator: not created from an iterable"); - } - /** - * @param {any} [value] - */ - next(value) { - const n = this._iterator.next(value); - return n; - } - /** - * @param {any} [value] - */ - return(value) { - return this._iterator.return(value); - } - /** - * @param {any} err - */ - throw(err2) { - return this._iterator.throw(err2); - } - /** - * @param {number} limit - */ - drop(limit) { - return new DropIter(this, limit); - } - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - every(callbackFn) { - let next2 = this.next(); - let index = 0; - let result = true; - while (!next2.done) { - if (!callbackFn(next2.value, index)) { - result = false; - break; - } - next2 = this.next(); - index += 1; - } - this.return(); - return result; - } - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - filter(callbackFn) { - return new FilterIter(this, callbackFn); - } - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - find(callbackFn) { - let next2 = this.next(); - let index = 0; - while (!next2.done) { - if (callbackFn(next2.value, index)) { - this.return(); - return next2.value; - } - next2 = this.next(); - index += 1; - } - } - /** - * @param {(value: T, index: number) => U} callbackFn - */ - flatMap(callbackFn) { - return new FlatMapIter(this, callbackFn); - } - /** - * @param {(value: T, index: number) => void} callbackFn - */ - forEach(callbackFn) { - let next2 = this.next(); - let index = 0; - while (!next2.done) { - callbackFn(next2.value, index); - next2 = this.next(); - index += 1; - } - } - /** - * @param {(value: T, index: number) => U} callbackFn - */ - map(callbackFn) { - return new MapIter(this, callbackFn); - } - /** - * @template U - * @param {(accumulator: U, value: T, index: number) => U} callbackFn - * @param {U} init - */ - reduce(callbackFn, init) { - let next2 = this.next(); - let index = 0; - let acc = init; - while (!next2.done) { - acc = callbackFn(acc, next2.value, index); - next2 = this.next(); - index += 1; - } - this.return(); - return acc; - } - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - some(callbackFn) { - let next2 = this.next(); - let index = 0; - let result = false; - while (!next2.done) { - if (callbackFn(next2.value, index)) { - result = true; - break; - } - next2 = this.next(); - index += 1; - } - this.return(); - return result; - } - /** - * @param {number} limit - */ - take(limit) { - return new TakeIter(this, limit); - } - /* - * @returns {T[]} - */ - toArray() { - const result = []; - for (const item of this) { - result.push(item); - } - return result; - } - *[Symbol.iterator]() { - return this; - } - }; - var DropIter = class extends Iter { - _limit; - /** - * @param {Iterator} iterator - * @param {number} limit - */ - constructor(iterator, limit) { - super(iterator); - this._limit = limit; - } - /** - * @param {any} value - */ - next(value) { - for (let i = this._limit; i > 0; i--) { - const next2 = super.next(value); - if (next2.done) { - return next2; - } - } - return super.next(value); - } - }; - var FilterIter = class extends Iter { - _filter; - _index = 0; - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => boolean} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator); - this._filter = callbackFn; - } - /** - * @param {any} [value] - * @returns {IteratorResult} - */ - next(value) { - let next2 = super.next(value); - while (!next2.done && !this._filter(next2.value, this._index)) { - next2 = super.next(value); - this._index += 1; - } - return next2; - } - }; - var FlatMapIter = class extends Iter { - _flatMap; - _index = 0; - /** @type {Iterator | undefined} */ - _inner = void 0; - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => Iterator | Iterable} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator); - this._flatMap = callbackFn; - } - /** - * @param {any} value - * @returns {IteratorResult} - */ - next(value) { - if (this._inner) { - const innerResult = this._inner.next(value); - if (!innerResult.done) { - this._index += 1; - return { value: innerResult.value, done: false }; - } - this._inner = void 0; - } - const outerResult = super.next(value); - if (outerResult.done) { - return { value: void 0, done: true }; - } - const nextIterable = this._flatMap(outerResult.value, this._index || 0); - if (Iter._isIterable(nextIterable)) { - this._inner = Iter.from(nextIterable); - return this.next(value); - } else { - throw new TypeError("value is not an iterator"); - } - } - }; - var MapIter = class extends Iter { - _map; - _index = 0; - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => U} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator); - this._map = callbackFn; - } - /** @param {any} value */ - next(value) { - let next2 = super.next(value); - if (next2.done) { - return next2; - } - const result = { - done: false, - value: this._map(next2.value, this._index) - }; - this._index += 1; - return result; - } - }; - var TakeIter = class extends Iter { - _limit; - /** - * @param {Iterator} iterator - * @param {number} limit - */ - constructor(iterator, limit) { - super(iterator); - this._limit = limit; - } - /** - * @param {any} value - * @returns {IteratorResult} - */ - next(value) { - if (this._limit > 0) { - const next2 = super.next(value); - if (!next2.done) { - this._limit -= 1; - } - return next2; - } - return { value: void 0, done: true }; - } - }; - - // node_modules/kojima/src/mixin.js - var _appliedMixin = "__mixwith_appliedMixin"; - var apply = (superclass, mixin) => { - let application = mixin(superclass); - application.prototype[_appliedMixin] = unwrap(mixin); - return application; - }; - var isApplicationOf = (proto, mixin) => proto.hasOwnProperty(_appliedMixin) && proto[_appliedMixin] === unwrap(mixin); - var hasMixin = (o, mixin) => { - while (o != null) { - if (isApplicationOf(o, mixin)) return true; - o = Object.getPrototypeOf(o); - } - return false; - }; - var _wrappedMixin = "__mixwith_wrappedMixin"; - var wrap = (mixin, wrapper) => { - Object.setPrototypeOf(wrapper, mixin); - if (!mixin[_wrappedMixin]) { - mixin[_wrappedMixin] = mixin; - } - return wrapper; - }; - var unwrap = (wrapper) => wrapper[_wrappedMixin] || wrapper; - var _cachedApplications = "__mixwith_cachedApplications"; - var Cached = (mixin) => wrap(mixin, (superclass) => { - let cachedApplications = superclass[_cachedApplications]; - if (!cachedApplications) { - cachedApplications = superclass[_cachedApplications] = /* @__PURE__ */ new Map(); - } - let application = cachedApplications.get(mixin); - if (!application) { - application = mixin(superclass); - cachedApplications.set(mixin, application); - } - return application; - }); - var DeDupe = (mixin) => wrap(mixin, (superclass) => hasMixin(superclass.prototype, mixin) ? superclass : mixin(superclass)); - var BareMixin = (mixin) => wrap(mixin, (s) => apply(s, mixin)); - var Mixin = (mixin) => DeDupe(Cached(BareMixin(mixin))); - var mix = (superclass) => new MixinBuilder(superclass); - var MixinBuilder = class { - constructor(superclass) { - this.superclass = superclass || class { - }; - } - /** - * Applies `mixins` in order to the superclass given to `mix()`. - * - * @param {Array.} mixins - * @return {FunctionConstructor} a subclass of `superclass` with `mixins` applied - */ - with(...mixins) { - return mixins.reduce((c, m) => m(c), this.superclass); - } - }; - - // node_modules/kojima/src/algebra/interfaces.js - var ProtectedConstructor = Symbol("ProtectedConstructor"); - var NotImplementedError = class extends Error { - /** @param {string} name */ - constructor(name) { - super(`${name} is not implemented`); - } - }; - var MethodType = Object.freeze({ - Instance: 0, - Static: 1 - }); - var Method = class _Method { - #name; - /** @type {MethodType} */ - #type = MethodType.Instance; - /** @type {Fn} */ - #implementation; - /** - * @param {string | Method} name - */ - constructor(name) { - if (name instanceof _Method) { - return name; - } - this.#name = name; - } - /** - * @param {string | Method} value - */ - static from(value) { - return new _Method(value); - } - isInstance() { - this.#type = MethodType.Instance; - return this; - } - isStatic() { - this.#type = MethodType.Static; - return this; - } - /** @param {Fn} f */ - implementation(f) { - this.#implementation = f; - return this; - } - /** - * @param {string} interfaceName - */ - _defaultImplementation(interfaceName) { - const err2 = new NotImplementedError( - `${interfaceName}::${this.#name}` - ); - return function() { - throw err2; - }; - } - /** - * @param {Function} target - */ - _getInstallationPoint(target) { - switch (this.#type) { - case 0: - return Object.getPrototypeOf(target); - case 1: - return target; - default: - return target; - } - } - /** - * @param {Interface} builder - * @param {Function} target - */ - implement(builder, target) { - const impl = this.#implementation || this._defaultImplementation(builder.name); - this._getInstallationPoint(target)[this.#name] = impl; - } - }; - var Implementations = Symbol(); - var Interface = class { - #name; - /** @type {MixinFunction} */ - #mixin; - /** @type {Set} */ - #methods = /* @__PURE__ */ new Set(); - /** @type {Set} */ - #interfaces = /* @__PURE__ */ new Set(); - /** @param {string} name */ - constructor(name) { - this.#name = name; - this.#mixin = Mixin(this.build.bind(this)); - } - get name() { - return this.#name; - } - findInterfaces(type) { - let interfaces = /* @__PURE__ */ new Set(); - let current = type; - while (current != null) { - interfaces = new Set(current[Implementations]).union(interfaces); - current = Object.getPrototypeOf(current); - } - return interfaces; - } - /** - * @param {{ name: string }} type - * @returns {boolean} - */ - implementedBy(type) { - return this.findInterfaces(type).has(this); - } - /** - * @param {...(PropertyKey | Method)} methods - * @returns {this} - */ - specifies(...methods) { - this.#methods = new Set( - methods.map(Method.from).concat(...this.#methods) - ); - return this; - } - /** - * @param {...Interface} interfaces - * @returns {this} - */ - extends(...interfaces) { - this.#interfaces = new Set(interfaces.concat(...this.#interfaces)); - return this; - } - /** - * @returns {MixinFunction} - */ - asMixin() { - return this.#mixin; - } - /** - * @param {FunctionConstructor} base - */ - build(base) { - const interfaces = [...this.#interfaces.values()]; - const mixins = interfaces.map((x) => x.asMixin()); - const Interfaces5 = mix(base).with(...mixins); - const Algebra2 = class extends Interfaces5 { - }; - for (const method of this.#methods) { - method.implement(this, Algebra2); - } - const prototype = Object.getPrototypeOf(Algebra2); - prototype[Implementations] = new Set(interfaces); - return Algebra2; - } - }; - var BaseSet = class { - }; - var AlgebraWithBase = (base) => (...algebras) => { - return mix(base).with(...algebras.map((x) => x.asMixin())); - }; - var Algebra = AlgebraWithBase(BaseSet); - var Setoid = new Interface("Setoid").specifies("equals"); - var Ord = new Interface("Ord").specifies("lte"); - var Semigroupoid = new Interface("Semigroupoid").specifies("compose"); - var Category = new Interface("Category").extends(Semigroupoid).specifies( - Method.from("id").isStatic() - ); - var Semigroup = new Interface("Semigroup").specifies("concat"); - var Monoid = new Interface("Monoid").extends(Semigroup).specifies( - Method.from("empty").isStatic() - ); - var Group = new Interface("Group").extends(Monoid).specifies("invert"); - var Filterable = new Interface("Filterable").specifies("filter"); - var Functor = new Interface("Functor").specifies("map"); - var Contravariant = new Interface("Contravariant").specifies("contramap"); - var Apply = new Interface("Apply").extends(Functor).specifies("ap"); - var Applicative = new Interface("Applicative").extends(Apply).specifies( - Method.from("of").isStatic() - ); - var Alt = new Interface("Alt").extends(Functor).specifies("alt"); - var Plus = new Interface("Plus").extends(Alt).specifies( - Method.from("zero").isStatic() - ); - var Alternative = new Interface("Alternative").extends(Applicative, Plus); - var Foldable = new Interface("Foldable").specifies("fold"); - var Traversable = new Interface("Traversable").extends(Functor, Foldable).specifies("traverse"); - var Chain = new Interface("Chain").extends(Apply).specifies( - Method.from("chain").implementation(function(f) { - return f(this._value); - }) - ); - var ChainRef = new Interface("ChainRec").extends(Chain).specifies( - Method.from("chainRec").isStatic() - ); - var Monad = new Interface("Monad").extends(Applicative, Chain); - var Extend = new Interface("Extend").extends(Functor).specifies("extend"); - var Comonad = new Interface("Comonad").extends(Extend).specifies("extract"); - var Bifunctor = new Interface("Bifunctor").extends(Functor).specifies("bimap"); - var Profunctor = new Interface("Profunctor").extends(Functor).specifies("promap"); - - // node_modules/kojima/src/algebra/identity.js - var Identity = class extends Algebra(Monad, Comonad) { - #value; - /** - * @param {T} value - */ - constructor(value) { - super(); - this.#value = value; - } - /** - * @template T - * @param {T} value - */ - static of(value) { - return id(value); - } - /** - * @template U - * @type {Functor['map']} - * @param {Morphism} f - * @returns {Identity} - */ - map(f) { - return id(f(this.#value)); - } - /** - * @template U - * @type {Apply['ap']} - * @param {Apply>} b - * @returns {Apply} - */ - ap(b) { - return ( - /** @type {Apply} */ - b.map((f) => f(this.#value)) - ); - } - /** - * @template U - * @param {Morphism>} f - */ - chain(f) { - return f(this.#value); - } - /** - * @param {(value: Identity) => T} f - */ - extend(f) { - return id(f(this)); - } - extract() { - return this.#value; - } - toString() { - return `Identity(${this.#value})`; - } - }; - var id = (value) => new Identity(value); - - // node_modules/kojima/src/algebra/option.js - var Interfaces = Algebra(Setoid, Alternative, Monad, Foldable); - var Some = class _Some extends Interfaces { - /** @type {T} */ - #value; - /** @param {T} value */ - constructor(value) { - super(); - this.#value = value; - } - /** - * @type {SetoidT['equals']} - * @param {Some} other - */ - equals(other) { - if (other instanceof _Some) { - return false; - } - const eq = ( - /** @type {Some} */ - other.chain((v) => id(v === this.#value)) - ); - return ( - /** @type {Identity} */ - eq.extract() - ); - } - /** - * @template U - * @type {Apply['ap']} - * @param {Some>} b - * @returns {Some} - */ - ap(b) { - return ( - /** @type {Some} */ - b.chain( - (f) => ( - /** @type {Some} */ - this.map(f) - ) - ) - ); - } - /** - * @type {Alt['alt']} - */ - alt(b) { - return this; - } - /** - * @type {Chain['chain']} - */ - chain(f) { - return f(this.#value); - } - /** - * @template U - * @type {Functor['map']} - * @param {Morphism} f - * @returns {Some} - */ - map(f) { - return ( - /** @type {Some} */ - this.chain((v) => some(f(v))) - ); - } - /** - * @type {Functor['map']} - */ - then(f) { - return this.map(f); - } - /** - * @template U - * @type {FoldableT['reduce']} - * @param {(acc: U, value: T) => U} f - * @param {U} init - * @returns {U} - */ - reduce(f, init) { - return f(init, this.#value); - } - toString() { - return `Some(${this.#value})`; - } - }; - var None = class extends Interfaces { - /** - * @type {SetoidT['equals']} - */ - equals(other) { - return other === none; - } - /** - * @type {Apply['ap']} - * @returns {this} - */ - ap(_b) { - return this; - } - /** - * @type {Alt['alt']} - */ - alt(b) { - return b; - } - /** - * @template U - * @type {Chain['chain']} - * @param {Morphism} _f - * @returns {this} - */ - chain(_f) { - return this; - } - /** - * @template U - * @type {Functor['map']} - * @param {Morphism} _f - * @returns {this} - */ - map(_f) { - return this; - } - /** - * @template R - * @type {Functor['map']} - * @param {Morphism} _f - * @returns {None} - */ - then(_f) { - return this; - } - /** - * @template U - * @type {FoldableT['reduce']} - * @param {(acc: U, value: T) => U} _f - * @param {U} init - * @returns {U} - */ - reduce(_f, init) { - return init; - } - toString() { - return "None"; - } - }; - var some = (value) => new Some(value); - var none = new None(); - var TypeRef = some; - TypeRef.constructor["of"] = some; - TypeRef.constructor["zero"] = none; - - // node_modules/kojima/src/algebra/result.js - var Interfaces2 = Algebra(Setoid, Alternative, Monad, Foldable, Bifunctor); - var Ok = class _Ok extends Interfaces2 { - /** @type {T} */ - #value; - /** - * @param {T} value - * @constructs {Ok} - */ - constructor(value) { - super(); - this.#value = value; - } - /** - * @type {SetoidT['equals']} - * @param {Result} other - * @returns {boolean} - */ - equals(other) { - if (!(other instanceof _Ok)) { - return false; - } - const eq = other.chain((v) => id(v === this.#value)); - return ( - /** @type {Identity} */ - eq.extract() - ); - } - /** @returns {this is Ok} */ - isOk() { - return true; - } - /** @returns {this is Err} */ - isErr() { - return false; - } - /** - * @type {Chain['chain']} - */ - chain(f) { - return f(this.#value); - } - /** - * @template E2 - * @type {Chain['chain']} - * @param {Morphism} _f - * @returns {this} - */ - chainErr(_f) { - return this; - } - /** - * @template U - * @type {Functor['map']} - * @param {Morphism} f - * @returns {Functor} - */ - map(f) { - return this.chain((v) => ok(f(v))); - } - /** - * @template E2 - * @type {Functor['map']} - * @this {Result} - * @param {Morphism} _f - * @returns {Result} - */ - mapErr(_f) { - return ( - /** @type {never} */ - this - ); - } - /** - * @template U - * @type {Apply['ap']} - * @param {Apply>} b - * @returns {Result} - */ - ap(b) { - return ( - /** @type {Result} */ - this.chain( - (v) => ( - /** @type {Chain} */ - b.map((f) => f(v)) - ) - ) - ); - } - /** - * @type Alt['alt'] - */ - alt(_b) { - return this; - } - /** - * @template U - * @borrows {Result~map} - * @param {Morphism} f - */ - then(f) { - return this.map(f); - } - /** - * @template R - * @param {Morphism} _f - * @returns {this} - */ - catch(_f) { - return this; - } - /** - * @template U - * @type {FoldableT['reduce']} - * @param {(acc: U, value: T) => U} f - * @param {U} init - * @returns {U} - */ - reduce(f, init) { - return f(init, this.#value); - } - /** - * @template T2, E2 - * @type {BifunctorT['bimap']} - * @param {Morphism} f - * @param {Morphism} _g - * @returns {Result} - */ - bimap(f, _g) { - return ( - /** @type {Result} */ - this.map(f) - ); - } - toString() { - return `Ok(${this.#value})`; - } - }; - var Err = class _Err extends Interfaces2 { - /** @type {E} */ - #value; - /** - * @param {E} value - * @constructs {Err} - */ - constructor(value) { - super(); - this.#value = value; - } - /** - * @type {SetoidT['equals']} - * @param {Err} other - * @returns {boolean} - */ - equals(other) { - if (!(other instanceof _Err)) { - return false; - } - const eq = other.chainErr((v) => id(v === this.#value)); - return ( - /** @type {Identity} */ - eq.extract() - ); - } - /** @returns {this is Ok} */ - isOk() { - return false; - } - /** @returns {this is Err} */ - isErr() { - return true; - } - /** - * @type {Chain['chain']} - * @returns {this} - */ - chain(_f) { - return this; - } - /** - * @template E2 - * @type {Chain['chain']} - * @param {Morphism>} f - * @returns {Result} - */ - chainErr(f) { - return f(this.#value); - } - /** - * @type {Functor['map']} - * @returns {this} - */ - map(_f) { - return this; - } - /** - * @template E2 - * @type {Functor['map']} - * @param {Morphism} f - * @returns {Result} - */ - mapErr(f) { - return ( - /** @type {Result} */ - this.bimap(id, f) - ); - } - /** - * @type {Functor['map']} - * @returns {this} - */ - then(_f) { - return this; - } - /** - * @template R - * @type {Functor['map']} - * @param {Morphism} f - * @returns {Err} - */ - catch(f) { - return new _Err(f(this.#value)); - } - /** - * @type Alt['alt'] - */ - alt(b) { - return b; - } - /** - * @template U - * @type {FoldableT['reduce']} - * @param {(acc: U, value: T) => U} _f - * @param {U} init - * @returns {U} - */ - reduce(_f, init) { - return init; - } - /** - * @template T2, E2 - * @type {BifunctorT['bimap']} - * @param {Morphism} _f - * @param {Morphism} g - * @returns {Result} - */ - bimap(_f, g) { - return ( - /** @type {Result} */ - err(g(this.#value)) - ); - } - toString() { - return `Err(${this.#value})`; - } - }; - var ok = (v) => new Ok(v); - var err = (e) => new Err(e); - var TypeRef2 = ok; - TypeRef2.constructor["of"] = ok; - TypeRef2.constructor["zero"] = err; - - // node_modules/kojima/src/algebra/list.js - var Interfaces3 = Algebra(Semigroup, Foldable, Monoid, Comonad); - var Empty = class extends Interfaces3 { - constructor() { - super(); - } - /** - * @template U - * @type {Chain['chain']} - * @this {Empty} - * @param {Morphism>} _f - * @returns {List} - */ - chain(_f) { - return ( - /** @type {List} */ - this - ); - } - /** - * @template U - * @type {Functor['map']} - * @this {Empty} - * @param {Morphism} _f - * @returns {List} - */ - map(_f) { - return this; - } - /** - * @template U - * @type {Apply['ap']} - * @this {Empty} - * @param {List>} _b - * @returns {List} - */ - ap(_b) { - return ( - /** @type {List} */ - this - ); - } - /** - * @type {SemigroupT['concat']} - */ - concat(b) { - return b; - } - /** - * @type {FoldableT['reduce']} - */ - reduce(_f, acc) { - return acc; - } - count() { - return 0; - } - /** @returns {this is Empty} */ - isEmpty() { - return true; - } - toString() { - return `List(Empty)`; - } - }; - var empty = new Empty(); - - // node_modules/kojima/src/algebra/free.js - var Interfaces4 = Algebra(Monad); - - // node_modules/kojima/src/algebra/io.js - var IO = class _IO extends Algebra(Monad) { - _effect; - /** - * @param {T} effect - */ - constructor(effect) { - super(); - this._effect = effect; - } - /** - * @template {Fn} T - * @param {T} a - */ - static of(a) { - return new _IO(() => a); - } - /** - * @template {Fn} U - * @type {Chain['chain']} - * @param {Morphism>} f - * @returns {IO} - */ - chain(f) { - return ( - /** @type {IO} */ - _IO.of(() => f(this.run()).run()) - ); - } - /** - * @template {Fn} U - * @type {Functor['map']} - * @param {Morphism} f - * @returns {IO} - */ - map(f) { - return ( - /** @type {IO} */ - _IO.of(() => f(this.run())) - ); - } - /** - * @template {Fn} U - * @type {Apply['ap']} - * @param {IO>} other - * @returns {IO} - */ - ap(other) { - return ( - /** @type {IO} */ - _IO.of(() => other.run()(this.run())) - ); - } - run() { - return this._effect(); - } - toString() { - return `IO(${this._effect})`; - } - }; - - // node_modules/kojima/vendor/izuna/src/curry.js - function curryN(arity, func) { - return function curried(...args) { - if (args.length >= arity) { - return func.apply(this, args); - } else { - return function(...args2) { - return curried.apply(this, args.concat(args2)); - }; - } - }; - } - function curry(func) { - return curryN(func.length, func); - } - - // node_modules/kojima/vendor/izuna/src/list.js - function isIterable(value) { - return value[Symbol.iterator] != null; - } - function* iter(value) { - if (isIterable(value)) { - yield* Iterator.from(value); - } else { - yield value; - } - } - var concat = function* (...iterators) { - for (const iter3 of iterators) { - for (const item of Iterator.from(iter3)) { - yield item; - } - } - }; - var prepend = curry( - /** - * @template T - * @param {T} x - * @param {Iterable} xs - */ - (x, xs) => concat([x], xs) - ); - - // node_modules/kojima/vendor/izuna/src/function.js - var id2 = (x) => x; - var compose = curry( - /** - * @template T, U, V - * @param {Morphism} f - * @param {Morphism} g - * @param {T} x - * @returns V - */ - (f, g, x) => chain(g, chain(f, x)) - ); - var liftA = (a) => Array.isArray(a) ? a : [a]; - var liftF = curry((binary, x, y) => binary(x, y)); - var ifElse = curry( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} pass - * @param {InferredMorphism} fail - * @param {T} x - */ - (pred, pass, fail2, x) => pred(x) ? pass(x) : fail2(x) - ); - var when = curry( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} pass - * @param {T} x - */ - (pred, pass, x) => ifElse(pred, pass, id2, x) - ); - var unless = curry( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} fail - * @param {T} x - */ - (pred, fail2, x) => ifElse(pred, id2, fail2, x) - ); - var ap = curry( - /** - * @template A, B - * @template {Morphism} Ap - * @param {Morphism} f - * @param {{ ap: Ap } | Ap} a - */ - (f, a) => { - const fs = liftA(dispatchF("ap", f)); - const args = liftA(a); - const xs = fs.reduce((acc, f2) => concat(acc, iter(map(f2, args))), []); - return [...xs]; - } - ); - var chain = curry( - function chain2(f, a) { - } - ); - var map = curry((f, a) => { - }); - var reduce = curry((f, acc, xs) => { - }); - - // node_modules/kojima/vendor/izuna/src/type.js - var is = curry( - /** - * @template T - * @param {FunctionConstructor} ctr - * @param {T} x - */ - (ctr, x) => x.constructor === ctr - ); - var isArray = Array.isArray; - - // node_modules/kojima/src/algebra/reader.js - var Reader = class _Reader extends Algebra(Monad) { - #run; - /** @param {InferredMorphism} run */ - constructor(run) { - super(); - this.#run = run; - } - /** - * @template T - * @type {ApplicativeTypeRef>['of']} - * @param {T} a - * @returns {Reader} - */ - static of(a) { - return new _Reader( - /** @type {InferredMorphism} */ - (_env) => a - ); - } - /** @template T */ - static ask() { - return new _Reader( - /** @type {InferredMorphism} */ - id2 - ); - } - /** - * @type {Functor['map']} - * @param {InferredMorphism} f - * @returns {Reader} - */ - map(f) { - return ( - /** @type {Reader} */ - this.chain((value) => _Reader.of(f(value))) - ); - } - /** - * @type {Chain['chain']} - * @param {InferredMorphism} f - * @returns {Reader} - */ - chain(f) { - return new _Reader((env) => { - const result = this.#run(env); - const next2 = f(result); - return next2.run(env); - }); - } - /** - * @template U - * @type {Apply['ap']} - * @param {Reader>} b - * @returns {Reader} - */ - ap(b) { - return ( - /** @type {Reader} */ - b.chain( - (f) => ( - /** @type {Reader} */ - this.map(f) - ) - ) - ); - } - /** - * @param {InferredMorphism} f - * @returns {Reader} - */ - local(f) { - return new _Reader( - /** @type {InferredMorphism} */ - (env) => this.#run(f(env)) - ); - } - /** - * @template U - * @param {T} env - * @returns {U} - */ - run(env) { - return this.#run(env); - } - }; - - // node_modules/izuna/src/curry.js - function curryN2(arity, func) { - return function curried(...args) { - if (args.length >= arity) { - return func.apply(this, args); - } else { - return function(...args2) { - return curried.apply(this, args.concat(args2)); - }; - } - }; - } - function curry2(func) { - return curryN2(func.length, func); - } - - // node_modules/izuna/src/list.js - function isIterable2(value) { - return value[Symbol.iterator] != null; - } - function* iter2(value) { - if (isIterable2(value)) { - yield* Iterator.from(value); - } else { - yield value; - } - } - var concat2 = function* (...iterators) { - for (const iter3 of iterators) { - for (const item of Iterator.from(iter3)) { - yield item; - } - } - }; - var prepend2 = curry2( - /** - * @template T - * @param {T} x - * @param {Iterable} xs - */ - (x, xs) => concat2([x], xs) - ); - - // node_modules/izuna/src/function.js - var id3 = (x) => x; - var pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); - var compose2 = curry2( - /** - * @template T, U, V - * @param {Morphism} f - * @param {Morphism} g - * @param {T} x - * @returns V - */ - (f, g, x) => chain3(g, chain3(f, x)) - ); - var liftA2 = (a) => Array.isArray(a) ? a : [a]; - var liftF2 = curry2((binary, x, y) => binary(x, y)); - var ifElse2 = curry2( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} pass - * @param {InferredMorphism} fail - * @param {T} x - */ - (pred, pass, fail2, x) => pred(x) ? pass(x) : fail2(x) - ); - var when2 = curry2( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} pass - * @param {T} x - */ - (pred, pass, x) => ifElse2(pred, pass, id3, x) - ); - var unless2 = curry2( - /** - * @template T - * @param {Predicate} pred - * @param {InferredMorphism} fail - * @param {T} x - */ - (pred, fail2, x) => ifElse2(pred, id3, fail2, x) - ); - var ap2 = curry2( - /** - * @template A, B - * @template {Morphism} Ap - * @param {Morphism} f - * @param {{ ap: Ap } | Ap} a - */ - (f, a) => { - const fs = liftA2(dispatchF("ap", f)); - const args = liftA2(a); - const xs = fs.reduce((acc, f2) => concat2(acc, iter2(map2(f2, args))), []); - return [...xs]; - } - ); - var chain3 = curry2( - function chain4(f, a) { - } - ); - var map2 = curry2((f, a) => { - }); - var reduce2 = curry2((f, acc, xs) => { - }); - - // node_modules/izuna/src/type.js - var is2 = curry2( - /** - * @template T - * @param {FunctionConstructor} ctr - * @param {T} x - */ - (ctr, x) => x.constructor === ctr - ); - var isArray2 = Array.isArray; - - // src/fn.js - var Tuple = (...values) => Object.freeze(values); - var clone = ([h, iter3]) => [h, iter3.clone()]; - var succeed = (v, [x, y]) => ok(Tuple(x.concat(v), y)); - var fail = (msg, state, e = void 0) => err(new ParseError(msg, state, e)); - var next = (state) => state[1].next().value; - var diff = (a, b) => b.slice(-Math.max(0, b.length - a.length)); - var join = curry2( - /** - * @param {string} delim - * @param {string[]} val - */ - (delim, val) => val.join(delim) - ); - var mapStr = curry2( - /** - * @param {(...args: any[]) => any} fn - * @param {string} str - */ - (fn, str2) => Array.from(str2).map((v) => fn(v)) - ); - - // src/seq.js - var take = (n) => (state) => { - let result = anyChar(state); - for (let i = n; i > 0; i--) { - if (result.isErr()) { - return result.chain((e) => fail(`"take(${n})" failed`, state, e)); - } - result = result.chain(anyChar); - } - return result; - }; - var seq = (...parsers) => ( - /** @param {ParserState} state */ - (state) => { - let acc = ok(state); - for (const parser of parsers) { - if (acc.isOk()) { - acc = acc.chain(parser); - } else { - break; - } - } - return acc; - } - ); - var many = curry2((parser, state) => { - let result = ok(state); - while (true) { - const res = parser(clone(state)); - if (res.isOk()) { - result = res; - } else { - break; - } - } - return result; - }); - var many1 = (parser) => seq(parser, many(parser)); - - // src/cond.js - var maybe = curry2( - /** - * @param {(...args: any[]) => Result} parser - * @param {ParserState} state - */ - (parser, state) => { - const result = parser(clone(state)); - return result.isOk() ? result : succeed([], state); - } - ); - var not = curry2((parser, state) => { - const result = parser(clone(state)); - if (result.isOk()) { - return fail(`'not' parser failed for ${parser.name}`, state); - } else { - return succeed([], state); - } - }); - var until = curry2((parser, state) => { - let result = ok(state); - while (result.isOk()) { - console.log(parser.name, state); - result = result.chain(pipe(clone, parser)); - if (result.isOk()) { - break; - } else { - result = anyChar(state); - } - } - return result; - }); - var skip = curry2((parser, state) => { - }); - - // src/combinator.js - var any = (...parsers) => ( - /** - * @param {ParserState} state - */ - (state) => { - for (const parser of parsers) { - const result = parser(clone(state)); - if (result.isOk()) { - return result; - } - } - return fail("no matching parsers", state); - } - ); - var anyOf = curry2( - /** - * @param {string} str - * @param {ParserState} state - */ - (str2, state) => any(...mapStr(char, str2))(state) - ); - var map3 = curry2( - /** - * @param {(...args: any[]) => any} fn - * @param {Parser} parser - * @param {ParserState} state - */ - (fn, parser, state) => { - return parser(state).chain((result) => { - try { - const parsed = fn(diff(state[0], result[0])); - const backtrack = Tuple(state[0], result[1]); - return succeed(parsed, backtrack); - } catch (e) { - return fail("failed to map", state, e); - } - }); - } - ); - var eof = (state) => { - return clone(state).next().done ? succeed([], state) : fail("not end of stream", state); - }; - - // src/state.js - var ParseError = class extends Error { - /** - * @param {string} message - * @param {ParserState} state - * @param {Error} [cause] - */ - constructor(message, state, cause) { - super(message, { cause }); - this.state = state; - } - }; - var State = (value) => Object.freeze([[], Iter.from(value)]); - var parse = curry2((parser, input) => parser(State(input))); - var parseAll = curry2((parser, input) => pipe( - State, - seq( - parser, - until(eof) - ) - )(input)); - - // src/const.js - var LowerAlpha = "abcdefghijklmnopqrstuvwxyz"; - var UpperAlpha = LowerAlpha.toUpperCase(); - var Alpha = LowerAlpha + UpperAlpha; - var Digits = "1234567890"; - var Alphanumeric = Alpha + Digits; - - // src/char.js - var char = curry2( - /** - * @param {string} ch - * @param {ParserState} state - */ - (ch, state) => next(state) === ch ? succeed(ch, state) : fail(`could not parse ${ch} `, state) - ); - var str = curry2( - /** - * @param {string} str - * @param {ParserState} state - */ - (str2, state) => map3( - join(""), - seq(...mapStr(char, str2)) - )(state) - ); - var anyChar = (state) => { - const ch = next(state); - return !!ch ? succeed(ch, state) : fail("end of input", state); - }; - var digit = anyOf(Digits); - var lowerAlpha = anyOf(LowerAlpha); - var upperAlpha = anyOf(UpperAlpha); - var alpha = any(lowerAlpha, upperAlpha); - var alphanumeric = any(alpha, digit); -})(); diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index ab41553..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "moduleResolution": "node", - "module": "es2020", - "target": "es6", - "lib": ["es2022", "dom"], - "checkJs": false, - }, - "exclude": [ - "node_modules" - ] -} - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 88eac79..0000000 --- a/package-lock.json +++ /dev/null @@ -1,496 +0,0 @@ -{ - "name": "kuebiko", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "kuebiko", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "izuna": "git+https://git.kitsu.cafe/rowan/izuna.git", - "kojima": "git+https://git.kitsu.cafe/rowan/kojima.git" - }, - "devDependencies": { - "esbuild": "^0.25.2", - "folktest": "git+https://git.kitsu.cafe/rowan/folktest.git", - "typescript": "^5.8.3" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" - } - }, - "node_modules/folktest": { - "version": "1.0.0", - "resolved": "git+https://git.kitsu.cafe/rowan/folktest.git#cbf48ff3b1334eb883f202a77a5bc89d24534520", - "dev": true, - "license": "GPL-3.0-or-later" - }, - "node_modules/izuna": { - "version": "1.0.0", - "resolved": "git+https://git.kitsu.cafe/rowan/izuna.git#4ab7c265d83856f2dc527780a3ac87b3d54676f1", - "license": "GPL-3.0-or-later" - }, - "node_modules/kojima": { - "version": "1.0.0", - "resolved": "git+https://git.kitsu.cafe/rowan/kojima.git#b997bca5e31323bb81b38fafe5f823cae6e574de", - "license": "GPL-3.0-or-later", - "dependencies": { - "esbuild": "^0.25.2", - "izuna": "git+https://git.kitsu.cafe/rowan/izuna.git", - "typescript": "^5.8.2" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/package.json b/package.json index f324348..b591fdb 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,13 @@ { "name": "kuebiko", - "version": "1.0.0", - "type": "module", - "main": "./src/index.js", - "types": "./typings/index.d.ts", + "version": "2.0.0", "author": "Rowan (https://kitsu.cafe)", + "type": "module", + "main": "index.js", "scripts": { - "test": "./tests/index.js", - "build": "esbuild ./src/index.js --bundle --outfile=dist/index.js" + "test": "node --test" }, - "keywords": [], - "license": "ISC", - "description": "", - "devDependencies": { - "esbuild": "^0.25.2", - "folktest": "git+https://git.kitsu.cafe/rowan/folktest.git", - "typescript": "^5.8.3" - }, - "dependencies": { - "izuna": "git+https://git.kitsu.cafe/rowan/izuna.git", - "kojima": "git+https://git.kitsu.cafe/rowan/kojima.git" - } + "keywords": ["parser", "functional", "combinator"], + "license": "MIT", + "description": "" } diff --git a/src/byte.js b/src/byte.js deleted file mode 100644 index 679544f..0000000 --- a/src/byte.js +++ /dev/null @@ -1,83 +0,0 @@ -import { chain, curry } from 'izuna' -import { any, map, seq } from './combinator.js' -import { not } from './cond.js' -import { Digits, LowerAlpha, UpperAlpha } from './const.js' -import { clone, fail, join, mapStr, next, succeed } from './fn.js' -import { ok } from 'kojima' - -/** @import { ParserState } from './state.js' */ - -export const char = curry( - /** - * @param {string} ch - * @param {ParserState} state - */ - (ch, state) => { - return next(state) === ch ? succeed(ch, state) : fail(`could not parse ${ch} `, state) - }) - -export const tag = curry( - /** - * @param {string} str - * @param {ParserState} state - */ - (str, state) => ( - map( - join(''), - seq(...mapStr(char, str)) - )(state) - )) - -export const charNoCase = curry((ch, state) => { - return any( - char(ch.toLowerCase()), - char(ch.toUpperCase()) - )(state) -}) - -export const tagNoCase = curry( - (str, state) => ( - map( - join(''), - seq(...mapStr(charNoCase, str)) - )(state) - )) - -export const anyChar = state => { - const ch = next(state) - return !!ch ? succeed(ch, state) : fail('end of input', state) -} - -export const take = curry( - (limit, state) => { - let res = ok(state) - - while (res.isOk() && limit > 0) { - res = chain(anyChar, res) - limit -= 1 - } - return res - } -) - -export const oneOf = curry( - /** - * @param {string} str - * @param {ParserState} state - */ - (str, state) => ( - any(...mapStr(char, str))(state) - )) - -export const noneOf = curry((str, state) => seq(not(any(oneOf(str), eof)), anyChar)(state)) - -export const digit = oneOf(Digits) -export const lowerAlpha = oneOf(LowerAlpha) -export const upperAlpha = oneOf(UpperAlpha) -export const alpha = any(lowerAlpha, upperAlpha) -export const alphanumeric = any(alpha, digit) - -export const eof = state => { - return clone(state).next().done ? succeed([], state) : fail('not end of stream', state) -} - diff --git a/src/clone.js b/src/clone.js deleted file mode 100644 index 453e17c..0000000 --- a/src/clone.js +++ /dev/null @@ -1,11 +0,0 @@ -export const Clone = Symbol('clone') - -export const clone = target => { - if (target[Clone]) { - return target[Clone]() - } else { - return structuredClone(target) - } -} - - diff --git a/src/combinator.js b/src/combinator.js deleted file mode 100644 index 706d5bd..0000000 --- a/src/combinator.js +++ /dev/null @@ -1,71 +0,0 @@ -import { chain, curry } from 'izuna' -import { ok } from 'kojima' -import { clone, diff, fail, succeed } from './fn.js' -import { state as State } from './state.js' -import { skip } from './cond.js' - -/** @import { ParserState } from './state.js' */ - -/** - * @param {...Parser} parsers - */ -export const seq = (...parsers) => - /** @param {ParserState} state */ - state => { - let acc = ok(state) - for (const parser of parsers) { - if (acc.isOk()) { - acc = chain(parser, acc) - } else { - break - } - } - - return acc - } - -/** - * @param {...any} parsers - */ -export const any = (...parsers) => - /** - * @param {ParserState} state - */ - state => { - for (const parser of parsers) { - //console.log('combinator.js::35/any:', state) - const result = parser(clone(state)) - if (result.isOk()) { - return result - } - } - - return fail('no matching parsers', state) - } - -export const map = curry( - /** - * @param {(...args: any[]) => any} fn - * @param {Parser} parser - * @param {ParserState} state - */ - (fn, parser, state) => { - return parser(state).chain(result => { - try { - /** @type {Result} */ - const parsed = fn(diff(state[0], result[0])) - const backtrack = State(result[1], state[0]) - - return succeed(parsed, backtrack) - } catch (e) { - return fail('failed to map', state, e) - } - }) - }) - -export const delimited = curry((first, second, third, state) => seq(skip(first), second, skip(third))(state)) -export const preceded = curry((first, second, state) => seq(skip(first), second)(state)) -export const terminated = curry((first, second, state) => seq(first, skip(second))(state)) - -export const separatedPair = curry((first, delimiter, second, state) => seq(first, skip(delimiter), second)(state)) - diff --git a/src/cond.js b/src/cond.js deleted file mode 100644 index 58a6658..0000000 --- a/src/cond.js +++ /dev/null @@ -1,55 +0,0 @@ -import { ParseError } from './state.js' -import { clone, fail, succeed } from './fn.js' -import { anyChar } from './byte.js' -import { ok } from 'kojima' -import { chain, curry, pipe } from 'izuna' - -/** @import { Result } from '../vendor/kojima/src/index.js' */ -/** @import { ParserState } from './state.js' */ - -export const maybe = curry( - /** - * @param {(...args: any[]) => Result} parser - * @param {ParserState} state - */ - (parser, state) => { - const result = parser(clone(state)) - return result.isOk() ? result : succeed([], state) - }) - -export const not = curry((parser, state) => { - const result = parser(clone(state)) - - if (result.isOk()) { - return fail(`'not' parser failed`, state) - } else { - return succeed([], state) - } -}) - -export const until = curry((parser, state) => { - let result = ok(state) - - while (result.isOk()) { - result = result.chain(pipe(clone, parser)) - if (result.isOk()) { - break - } else { - result = anyChar(state) - } - } - - return result -}) - -export const verify = curry((parser, predicate, state) => { - const result = chain(parser, clone(state)) - return chain(x => ( - predicate(x) ? result : fail('verification failed', state) - ), result) -}) - -export const skip = curry((parser, state) => { - return chain(_ => succeed([], state), parser(state)) -}) - diff --git a/src/const.js b/src/const.js deleted file mode 100644 index f51d393..0000000 --- a/src/const.js +++ /dev/null @@ -1,6 +0,0 @@ -export const LowerAlpha = 'abcdefghijklmnopqrstuvwxyz' -export const UpperAlpha = LowerAlpha.toUpperCase() -export const Alpha = LowerAlpha + UpperAlpha -export const Digits = '1234567890' -export const Alphanumeric = Alpha + Digits - diff --git a/src/fn.js b/src/fn.js deleted file mode 100644 index 620211f..0000000 --- a/src/fn.js +++ /dev/null @@ -1,69 +0,0 @@ -import { err, ok } from 'kojima' -import { concat, curry } from 'izuna' -import { ParseError, state } from './state.js' -import { IndexableIterator } from './iter.js' - -/** @import { ParserState } from './state.js' */ - - -export const iter = value => new IndexableIterator(value) - -/** - * @param {ParserState} state - */ -export const clone = (state) => state.clone() - -/** - * @template T - * @param {T | T[]} v - * @param {ParserState} state - */ -export const succeed = (v, [x, y]) => { - return ok(state(y, concat(v, x))) -} - -/** - * @param {string} msg - * @param {ParserState} state - * @param {Error} [e] - */ -export const fail = (msg, state, e = undefined) => err(new ParseError(msg, state, e)) - -/** - * @template T - * @param {number & keyof T} n - * @param {T[]} iter - */ -export const nth = (n, iter) => iter[n] - -/** - * @param {ParserState} state - */ -export const next = state => state.next().value - -/** - * @template T - * @param {T[]} a - * @param {T[]} b - */ -export const diff = (a, b) => b.slice(-Math.max(0, b.length - a.length)) - -export const join = curry( - /** - * @param {string} delim - * @param {string[]} val - */ - (delim, val) => val.join(delim) -) - -export const mapStr = curry( - /** - * @param {(...args: any[]) => any} fn - * @param {string} str - */ - (fn, str) => Array.from(str).flatMap(x => { - return fn(x) - }) -) - - diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 604d8f2..0000000 --- a/src/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export * from './byte.js' -export * from './combinator.js' -export * from './cond.js' -export * from './multi.js' -export * from './state.js' - diff --git a/src/iter.js b/src/iter.js deleted file mode 100644 index fd88dda..0000000 --- a/src/iter.js +++ /dev/null @@ -1,418 +0,0 @@ -import { Clone } from './clone.js' - -export class IndexableIterator extends Iterator { - _value - _index - - constructor(value, index = 0) { - super() - - this._value = value - this._index = index - } - - clone() { - return this[Clone]() - } - - done() { - return this._index >= this._value.length - } - - next() { - if (this.done()) { - return { value: undefined, done: true } - } else { - return { value: this._value[this._index++], done: false } - } - } - - [Clone]() { - return new IndexableIterator( - this._value, - this._index - ) - } - - [Symbol.iterator]() { - return this.clone() - } -} - -/** - * @template T - * @implements Iterator - * @implements Iterable - */ -class Iter { - /** - * @template T - * @param {any} value - * @returns {value is Iterable} - */ - static _isIterable(value) { - return typeof value[Symbol.iterator] === 'function' - } - - /** - * @template T - * @param {T} value - */ - static from(value) { - if (value instanceof Iter) { - return value - } - - if (Array.isArray(value) || typeof value === 'string') { - return new IndexableIterator(value) - } - - if (Iter._isIterable(value)) { - const iterator = value[Symbol.iterator]() - - if (iterator instanceof Iter) { - return iterator - } - - return new this(iterator, value) - } - - throw new TypeError('object is not an iterator') - } - - /** - * @param {number} limit - */ - drop(limit) { - return new DropIter(this, limit) - } - - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - every(callbackFn) { - let next = this.next() - let index = 0 - let result = true - - while (!next.done) { - if (!callbackFn(next.value, index)) { - result = false - break - } - - next = this.next() - index += 1 - } - - this.return() - return result - } - - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - filter(callbackFn) { - return new FilterIter(this, callbackFn) - } - - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - find(callbackFn) { - let next = this.next() - let index = 0 - - while (!next.done) { - if (callbackFn(next.value, index)) { - this.return() - return next.value - } - - next = this.next() - index += 1 - } - } - - /** - * @param {(value: T, index: number) => U} callbackFn - */ - flatMap(callbackFn) { - return new FlatMapIter(this, callbackFn) - } - - /** - * @param {(value: T, index: number) => void} callbackFn - */ - forEach(callbackFn) { - let next = this.next() - let index = 0 - - while (!next.done) { - callbackFn(next.value, index) - next = this.next() - index += 1 - } - } - - /** - * @param {(value: T, index: number) => U} callbackFn - */ - map(callbackFn) { - return new MapIter(this, callbackFn) - } - - /** - * @template U - * @param {(accumulator: U, value: T, index: number) => U} callbackFn - * @param {U} init - */ - reduce(callbackFn, init) { - let next = this.next() - let index = 0 - let acc = init - - while (!next.done) { - acc = callbackFn(acc, next.value, index) - - next = this.next() - index += 1 - } - - this.return() - return acc - } - - /** - * @param {(value: T, index: number) => boolean} callbackFn - */ - some(callbackFn) { - let next = this.next() - let index = 0 - let result = false - - while (!next.done) { - if (callbackFn(next.value, index)) { - result = true - break - } - - next = this.next() - index += 1 - } - - this.return() - return result - } - - /** - * @param {number} limit - */ - take(limit) { - return new TakeIter(this, limit) - } - - /* - * @returns {T[]} - */ - toArray() { - /** @type {T[]} */ - const result = [] - - for (const item of this) { - result.push(item) - } - - return result - } - - *[Symbol.iterator]() { - return this - } -} - -/** - * @template T - * @extends Iter - */ -class DropIter extends Iter { - _limit - - /** - * @param {Iterator} iterator - * @param {number} limit - */ - constructor(iterator, limit) { - super(iterator) - this._limit = limit - } - - /** - * @param {any} value - */ - next(value) { - for (let i = this._limit; i > 0; i--) { - const next = super.next(value) - - if (next.done) { - return next - } - } - - return super.next(value) - } -} - -/** - * @template T - * @extends Iter - */ -class FilterIter extends Iter { - _filter - _index = 0 - - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => boolean} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator) - this._filter = callbackFn - } - - /** - * @param {any} [value] - * @returns {IteratorResult} - */ - next(value) { - let next = super.next(value) - - while (!next.done && !this._filter(next.value, this._index)) { - next = super.next(value) - this._index += 1 - } - - return next - } -} - -/** - * @template T - * @extends Iter - */ -class FlatMapIter extends Iter { - _flatMap - _index = 0 - - /** @type {Iterator | undefined} */ - _inner = undefined - - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => Iterator | Iterable} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator) - this._flatMap = callbackFn - } - - /** - * @param {any} value - * @returns {IteratorResult} - */ - next(value) { - if (this._inner) { - const innerResult = this._inner.next(value) - - if (!innerResult.done) { - this._index += 1 - return { value: innerResult.value, done: false } - } - - this._inner = undefined - } - - const outerResult = super.next(value) - if (outerResult.done) { - return { value: undefined, done: true } - } - - const nextIterable = this._flatMap(outerResult.value, this._index || 0) - if (Iter._isIterable(nextIterable)) { - this._inner = Iter.from(nextIterable) - return this.next(value) - } else { - throw new TypeError('value is not an iterator') - } - } -} - -/** - * @template T - * @extends Iter - */ -class MapIter extends Iter { - _map - _index = 0 - - /** - * @param {Iterator} iterator - * @param {(value: T, index: number) => U} callbackFn - */ - constructor(iterator, callbackFn) { - super(iterator) - this._map = callbackFn - } - - /** @param {any} value */ - next(value) { - let next = super.next(value) - - if (next.done) { - return next - } - - const result = { - done: false, - value: this._map(next.value, this._index) - } - - this._index += 1 - return result - } -} - - -/** - * @template T - * @extends Iter - */ -class TakeIter extends Iter { - _limit - - /** - * @param {Iterator} iterator - * @param {number} limit - */ - constructor(iterator, limit) { - super(iterator) - this._limit = limit - } - - /** - * @param {any} value - * @returns {IteratorResult} - */ - next(value) { - if (this._limit > 0) { - const next = super.next(value) - if (!next.done) { - this._limit -= 1 - } - return next - } - - return { value: undefined, done: true } - } -} - diff --git a/src/iterator.js b/src/iterator.js new file mode 100644 index 0000000..8367f6b --- /dev/null +++ b/src/iterator.js @@ -0,0 +1,63 @@ +import { Option } from './option.js' +import { range, tee } from './utils.js' + +export class Stream { + _iterator + _index + + constructor(iterator, index = 0) { + this._iterator = Iterator.from(iterator) + this._index = index + } + + get index() { + return this._index + } + + clone() { + const [a, b] = tee(this._iterator) + this._iterator = a + return new Stream(b, this.index) + } + + consume() { + return Option.from(this.next().value) + } + + *take(limit = 1) { + for (const _index of range(limit)) { + const next = this.next() + if (next.done) { return } + yield next.value + } + } + + drop(limit = 1) { + while (limit > 0 && this.consume().isSome()) { + limit -= 1 + } + + return this + } + + peek() { + const [a, b] = tee(this._iterator) + this._iterator = a + return Option.from(b.next().value) + } + + next() { + const result = this._iterator.next() + + if (!result.done) { + this._index += 1 + } + + return result + } + + [Symbol.iterator]() { + return this + } +} + diff --git a/src/multi.js b/src/multi.js deleted file mode 100644 index b84bca6..0000000 --- a/src/multi.js +++ /dev/null @@ -1,68 +0,0 @@ -import { ok } from 'kojima' -import { curry, } from 'izuna' -import { clone } from './fn.js' -import { verify } from './cond.js' -import { anyChar } from './byte.js' - -/** @import { ParseError, ParserState } from './state.js' */ -/** @import { Result } from '../vendor/kojima/src/index.js' */ - -export const takeWhile = curry((predicate, state) => { - let result = ok(state) - - while (result.isOk()) { - result = verify(anyChar, predicate, state) - } - - return result -}) - -export const takeUntil = curry((parser, state) => not(takeWhile(parser, state))) - -export const skip = curry((parser, state) => { - const tokens = state[0] - const result = parser(state) - if (result.isOk()) { - return result.map(other => [tokens, other[1]]) - } else { - return result - } -}) - -export const many = curry((parser, state) => { - let result = ok(state) - - while (true) { - const res = parser(clone(state)) - if (res.isOk()) { - result = res - } else { - break - } - } - - return result -}) - -export const many1 = parser => seq(parser, many(parser)) - -const _range = (start, end, step = 1, deny = []) => { - const len = end - start - deny.length + 1 - const result = new Array(len) - - for (let i = 0, n = start; i <= len; i += i, n += step) { - if (deny.includes(n)) { continue } - result[i] = n - } - - return result -} - -const code = s => s.codePointAt(0) - -export const range = (start, end, deny = []) => { - return anyChar( - _range(code(start), code(end), deny.map(code)).map(String.fromCodePoint) - ) -} - diff --git a/src/option.js b/src/option.js new file mode 100644 index 0000000..4e6cfed --- /dev/null +++ b/src/option.js @@ -0,0 +1,106 @@ +import { Result } from './result.js' + +export class Option { + static some(value) { + return new Some(value) + } + + static none() { + return None + } + + static from(value) { + if (value == null) { + return None + } else { + return new Some(value) + } + } + + isSome() { + return this instanceof Some + } + + isNone() { + return this === None + } +} + +export class Some extends Option { + #value + + constructor(value) { + super() + this.#value = value + Object.freeze(this) + } + + ap(value) { + return this.#value(value) + } + + filter(predicate) { + if (predicate(this.#value)) { + return this + } else { + return None + } + } + + andThen(fn) { + return fn(this.#value) + } + + map(fn) { + return new Some(fn(this.#value)) + } + + okOr(_error) { + return Result.ok(this.#value) + } + + okOrElse(_fn) { + return Result.ok(this.#value) + } + + unwrap() { + return this.#value + } +} + +class _None extends Option { + constructor() { + super() + Object.freeze(this) + } + + ap(_value) { + return this + } + + filter(_predicate) { + return this + } + + map(_fn) { + return this + } + + andThen(_fn) { + return this + } + + okOr(error) { + return Result.err(error) + } + + okOrElse(fn) { + return Result.err(fn()) + } + + unwrap() { + throw new UnwrapError('attempted to unwrap a None value') + } +} + +export const None = new _None() diff --git a/src/parser.js b/src/parser.js new file mode 100644 index 0000000..d3fe77c --- /dev/null +++ b/src/parser.js @@ -0,0 +1,194 @@ +import { Stream } from './iterator.js' +import { Result } from './result.js' +import { curry, range } from './utils.js' +import * as string from './string.js' + +export class ParseError extends Error { + name + index + description + + constructor(index, description) { + super() + this.name = 'ParseError' + this.index = index + this.description = description + } +} + +export class EofError extends ParseError { + name = 'EofError' + description = 'End of stream reached' +} + +// convenience factory functions and cached callbacks +const eofErr = index => () => new EofError(index) +const parseErr = (index, desc) => () => new ParseError(index, desc) +const eq = a => b => a === b +const toString = value => value.toString() + +export const pure = curry((value, input) => Result.ok([value, input])) +export const fail = curry((error, input) => Result.err(new ParseError(input.index, error))) + +export const anyItem = () => input => { + return input.peek().okOrElse(eofErr(input.index)) + .map(value => [value, input.drop()]) +} + +export const satisfy = curry((predicate, input) => { + return input.peek() + .okOrElse(eofErr(input.index)) + .filterOrElse( + predicate, + value => parseErr(input.index, `Value did not match predicate: ${value}`) + ) + .map(value => [value, input.drop()]) +}) + +export const literal = curry((value, input) => ( + satisfy(eq(value), input) +)) + +export const bind = curry((parser, transform, input) => + parser(input).andThen(([value, rest]) => transform(value)(rest)) +) + +export const map = curry((parser, morphism, input) => ( + parser(input).map(([value, rest]) => [morphism(value), rest]) +)) + +export const seq = curry((a, b, input) => ( + bind(a, x => map(b, y => [x, y]), input) +)) + +export const alt = (...parsers) => input => { + for (const p of parsers) { + const result = p(input.clone()) + + if (result.isOk()) { + return result + } + } + + return Result.err(new ParseError(input.index, "No parsers matched alt")) +} + +export const many = curry((parser, input) => { + const results = [] + let stream = input + + while (true) { + const result = parser(stream.clone()) + if (result.isOk()) { + const [value, rest] = result.unwrap() + results.push(value) + stream = rest + } else { + break + } + } + + return Result.ok([results, stream]) +}) + +export const many1 = curry((parser, input) => ( + parser(input).andThen(([first, rest]) => ( + many(parser, rest).map(([others, rest]) => ( + [[first, ...others], rest] + )) + )) +)) + +export const optional = curry((parser, input) => + parser(input.clone()).orElse(() => Result.ok([undefined, input])) +) + +export const eof = () => input => ( + anyItem()(input) + .andThen(([value, rest]) => + Result.err( + new ParseError(rest.index, `Expected EOF, found ${value}`) + ) + ) + .orElse(err => { + if (err instanceof EofError) { + return Result.ok([null, input]) + } else { + return Result.err(err) + } + }) +) + +export const take = curry((limit, input) => { + const result = [] + const next = anyItem() + let stream = input + + for (const _index of range(limit)) { + const nextResult = next(stream) + if (nextResult.isOk()) { + const [value, rest] = nextResult.unwrap() + result.push(value) + stream = rest + } else { + return nextResult + } + } + + return Result.ok([result, stream]) +}) + +export const drop = curry((limit, input) => + skip(take(limit), input) +) + +export const skip = curry((parser, input) => + parser(input).map(([_, rest]) => [undefined, rest]) +) + +const streamInfo = (stream, n = 3) => { + const clone = stream.clone() + const values = clone.take(n).map(toString).join(', ') + const hasMore = clone.peek().isSome() + const ellip = hasMore ? '...' : '' + + return `Stream { index = ${stream.index}, values = [${values}${ellip}]` +} + +export const trace = curry((parser, label, input) => { + const name = label || parser.name || 'anonymous parser' + console.log(`trace(parser = ${name}, input = ${streamInfo(input)})`) + const result = parser(input) + if (result.isOk()) { + const [value, rest] = result.unwrap() + console.log(` success: value = ${toString(value)}, remaining = ${streamInfo(rest)}`) + } else { + const err = result.unwrapErr() + console.log(` fail: error = ${err}`) + } +}) + +// cached parsers +const LetterParser = alt(...Array.from(string.AsciiLetters).map(x => literal(x))) +const DigitParser = alt(...Array.from(string.Digits).map(x => literal(x))) +const WhitespaceParser = alt(...Array.from(string.Whitespace).map(x => literal(x))) + +export const letter = () => LetterParser +export const digit = () => DigitParser +export const whitespace = () => WhitespaceParser + +export const parseSome = curry((parser, value) => + parser(new Stream(value)) +) + +export const parse = curry((parser, value) => { + const result = parseSome(seq(parser, eof()), value) + + if (result.isOk()) { + const [[value, _rest], _stream] = result.unwrap() + return Result.ok(value) + } else { + return result + } +}) + diff --git a/src/result.js b/src/result.js new file mode 100644 index 0000000..0a075b1 --- /dev/null +++ b/src/result.js @@ -0,0 +1,163 @@ +import { None } from './option.js' + +class UnwrapError extends Error { + constructor(message) { + super(message) + this.name = 'UnwrapError' + if (Error.captureStackTrace) { + Error.captureStackTrace(this, UnwrapError) + } + } +} + +export class Result { + static ok(value) { + return new Ok(value) + } + + static err(error) { + return new Err(error) + } + + isOk() { + return this instanceof Ok + } + + isErr() { + return this instanceof Err + } +} + +export class Ok extends Result { + #value + + constructor(value) { + super() + this.#value = value + Object.freeze(this) + } + + ap(value) { + return this.#value(value) + } + + andThen(fn) { + return fn(this.#value) + } + + map(fn) { + return new Ok(fn(this.#value)) + } + + filterOr(predicate, err) { + if (predicate(this.#value)) { + return this + } else { + return Result.err(err) + } + } + + filterOrElse(predicate, fn) { + if (predicate(this.#value)) { + return this + } else { + return Result.err(fn(this.#value)) + } + } + + inspect(fn) { + fn(this.#value) + return this + } + + ok() { + return Option.some(this.#value) + } + + err() { + return None + } + + orOther(_value) { + return this + } + + orElse(_fn) { + return this + } + + unwrap() { + return this.#value + } + + unwrapErr() { + throw new UnwrapError('attempted to unwrapErr an Ok value') + } + + toString() { + return `Ok(${this.#value})` + } +} + +export class Err extends Result { + #error + + constructor(error) { + super() + this.#error = error + Object.freeze(this) + } + + ap(_value) { + return this + } + + andThen(_fn) { + return this + } + + map(_fn) { + return this + } + + filterOr(_predicate, _err) { + return this + } + + filterOrElse(_predicate, _fn) { + return this + } + + inspect(_fn) { + return this + } + + ok() { + return None + } + + err() { + return Option.some(this.#error) + } + + orOther(value) { + return value + } + + orElse(fn) { + return fn(this.#error) + } + + unwrap() { + throw new UnwrapError('attempted to unwrap an Err value') + } + + unwrapErr() { + return this.#error + } + + toString() { + return `Err(${this.#error})` + } +} + diff --git a/src/state.js b/src/state.js deleted file mode 100644 index 28e48ae..0000000 --- a/src/state.js +++ /dev/null @@ -1,60 +0,0 @@ -import { ok } from 'kojima' -import { chain, compose, curry, pipe } from 'izuna' -import { eof } from './byte.js' -import { Tuple } from './tuple.js' -import { iter } from './fn.js' -import { Clone } from './clone.js' - -/** - * @typedef {Readonly<[any[], Iterator]>} ParserState - */ - -export class ParseError extends Error { - /** - * @param {string} message - * @param {ParserState} state - * @param {Error} [cause] - */ - constructor(message, state, cause) { - super(message, { cause }) - this.state = state - } -} - -export class State extends Tuple { - constructor(remaining, read = []) { - super([['read', read], ['remaining', remaining]]) - } - - static from(values) { - return new State(iter(values)) - } - - next() { - return this.remaining.next() - } - - toString() { - return `State(${this.read}, ${[...this.clone().remaining]})` - } - - [Clone]() { - return Object.freeze(new State(this.remaining.clone(), this.read)) - } - - [Symbol.iterator]() { - return super[Symbol.iterator]() - } -} - -export const state = (remaining, read) => new State(remaining, read) - -export const parse = curry((parser, input) => pipe( - iter, - state, - ok, - chain(parser), -)(input)) - -export const parseAll = curry((parser, input) => compose(eof, parse(parser), input)) - diff --git a/src/string.js b/src/string.js new file mode 100644 index 0000000..1c1d48f --- /dev/null +++ b/src/string.js @@ -0,0 +1,10 @@ +export const LowerAscii = 'abcdefghijklmnopqrstuvwxyz' +export const UpperAscii = LowerAscii.toLocaleLowerCase() +export const AsciiLetters = LowerAscii + UpperAscii +export const HexDigits = '0123456789abcdefABCDEF' +export const OctDigits = '01234567' +export const Punctuation = '!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~.' +export const Whitespace = ' \t\r\n\x0c\x0b' +export const Digits = '0123456789' +export const Printable = Digits + AsciiLetters + Punctuation + Whitespace + diff --git a/src/tuple.js b/src/tuple.js deleted file mode 100644 index cbfb911..0000000 --- a/src/tuple.js +++ /dev/null @@ -1,61 +0,0 @@ -import { entries } from 'izuna' -import { Clone } from './clone.js' -import { IndexableIterator } from './iter.js' - -/** - * @param {...any} values - */ -export class Tuple { - _values - _length - - get length() { - return this._length - } - - constructor(values) { - if (values.length > 0) { - this._length = values.length - values.forEach(this._setEntry.bind(this)) - } - - this._values = values - } - - _setEntry([key, value], index) { - if (typeof key !== 'number') { - Object.defineProperty(this, key, { - get() { - return this[index] - } - }) - } - - this[index] = value - } - - static from(values) { - return Object.freeze(new this(entries(values))) - } - - - toString() { - return `(${this._values.map(([_, v]) => v.toString())})` - } - - clone() { - return this[Clone]() - } - - [Clone]() { - return Object.freeze(new this.constructor(this._values)) - } - - [Symbol.iterator]() { - return new IndexableIterator(this._values.map(([_, v]) => v)) - } -} - -export const tuple = Tuple.from - - diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..108fc5c --- /dev/null +++ b/src/utils.js @@ -0,0 +1,41 @@ +export const curry = (fn, arity = fn.length) => { + return function curried(...args) { + if (args.length >= arity) { + return fn.apply(this, args) + } else { + return function(...nextArgs) { + return curried.apply(this, args.concat(nextArgs)) + } + } + } +} + +export function* range(start, stop, step = 1) { + if (stop == null) { + stop = start + start = 0 + } + + for (let i = start; i < stop; i += step) { + yield i + } +} + +export function tee(iterator, n = 2) { + iterator = Iterator.from(iterator) + + function* gen(current) { + while (true) { + if (!current.next) { + const { done, value } = iterator.next() + if (done) return + current.next = { value } + } + current = current.next + yield current.value + } + } + + return Array(n).fill({}).map(gen) +} + diff --git a/tests/combinators.test.js b/tests/combinators.test.js new file mode 100644 index 0000000..0fdf40f --- /dev/null +++ b/tests/combinators.test.js @@ -0,0 +1,205 @@ +import { drop, skip, literal, bind, seq, many, parse, parseSome, ParseError, EofError, map, alt, many1, optional } from '../src/parser.js' +import { Err } from '../src/result.js' +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' + +const eq = (a, b) => assert.deepStrictEqual(a, b) +const parseErr = (i, desc) => new Err(new ParseError(i, desc)) +const eof = (i = 0) => new Err(new EofError(i)) + +const streamState = stream => { + return [stream.index, Array.from(stream.clone())] +} + +describe('Combinators', () => { + it('bind', () => { + const a = literal('a') + const b = literal('b') + + // simple parser + const p = bind(a, () => b) + + let res = parseSome(p, 'ab') + + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, 'b') + eq(streamState(r1), [2, []]) + + + // complex parser + const pab = bind(a, x => map(b, y => `${x}${y}`)) + res = parseSome(pab, 'abc') + const [v2, r2] = res.unwrap() + assert(res.isOk()) + eq(v2, 'ab') + eq(streamState(r2), [2, ['c']]) + + // fail on first parser + res = parseSome(p, 'xb') + eq(res, parseErr(0, 'Value did not match predicate: x')) + + // fail on second parser + res = parseSome(p, 'ax') + eq(res, parseErr(1, 'Value did not match predicate: x')) + + // eof on first parser + res = parseSome(p, '') + eq(res, eof()) + + // eof on second parser + res = parseSome(p, 'a') + eq(res, eof()) + }) + + it('map', () => { + const p = map(literal('a'), char => char.toUpperCase()) + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [value, rest] = res.unwrap() + eq(value, 'A') + eq(streamState(rest), [1, ['b', 'c']]) + + res = parseSome(p, 'xyz') + eq(res, parseErr(0, 'Value did not match predicate: x')) + }) + + it('seq', () => { + const p = seq(literal('a'), literal('b')) + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [value, rest] = res.unwrap() + eq(value, ['a', 'b']) + eq(streamState(rest), [2, ['c']]) + + res = parseSome(p, 'xbc') + eq(res, parseErr(0, 'Value did not match predicate: x')) + + res = parseSome(p, 'axc') + eq(res, parseErr(1, 'Value did not match predicate: x')) + }) + + it('alt', () => { + const p = alt(literal('a'), literal('b')) + let res = parseSome(p, 'abc') + assert(res.isOk()) + + const [v1, r1] = res.unwrap() + eq(v1, 'a') + eq(streamState(r1), [1, ['b', 'c']]) + + res = parseSome(p, 'bac') + assert(res.isOk()) + const [v2, r2] = res.unwrap() + eq(v2, 'b') + eq(streamState(r2), [1, ['a', 'c']]) + + res = parseSome(p, 'xyz') + eq(res, parseErr(1, 'No parsers matched alt')) + + res = parseSome(alt(), 'abc') + eq(res, parseErr(0, 'No parsers matched alt')) + }) + + it('many', () => { + const p = many(literal('a')) + let res = parseSome(p, 'xyz') + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, []) + eq(streamState(r1), [0, ['x', 'y', 'z']]) + + res = parseSome(p, 'abc') + assert(res.isOk()) + const [v2, r2] = res.unwrap() + eq(v2, ['a']) + eq(streamState(r2), [1, ['b', 'c']]) + + res = parseSome(p, 'aaabc') + assert(res.isOk()) + const [v3, r3] = res.unwrap() + eq(v3, ['a', 'a', 'a']) + eq(streamState(r3), [3, ['b', 'c']]) + + res = parse(p, 'aaa') + assert(res.isOk()) + eq(res.unwrap(), ['a', 'a', 'a']) + + res = parseSome(p, '') + assert(res.isOk()) + const [v4, r4] = res.unwrap() + eq(v4, []) + eq(streamState(r4), [0, []]) + }) + + it('many1', () => { + const p = many1(literal('a')) + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, ['a']) + eq(streamState(r1), [1, ['b', 'c']]) + + res = parseSome(p, 'aaab') + assert(res.isOk()) + const [v2, r2] = res.unwrap() + eq(v2, ['a', 'a', 'a']) + eq(streamState(r2), [3, ['b']]) + + res = parseSome(p, 'xyz') + eq(res, parseErr(0, 'Value did not match predicate: x')) + + res = parseSome(p, '') + eq(res, eof()) + }) + + it('optional', () => { + const p = optional(literal('a')) + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, 'a') + eq(streamState(r1), [1, ['b', 'c']]) + + res = parseSome(p, 'xyz') + assert(res.isOk()) + const [v2, r2] = res.unwrap() + eq(v2, undefined) + eq(streamState(r2), [0, ['x', 'y', 'z']]) + + res = parseSome(p, '') + assert(res.isOk()) + const [v3, r3] = res.unwrap() + eq(v3, undefined) + eq(streamState(r3), [0, []]) + }) + + it('drop', () => { + const p = drop(1) + + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, undefined) + eq(streamState(r1), [1, ['b', 'c']]) + + res = parseSome(p, '') + eq(res, eof()) + }) + + it('skip', () => { + const p = skip(literal('a')) + let res = parseSome(p, 'abc') + assert(res.isOk()) + const [v1, r1] = res.unwrap() + eq(v1, undefined) + eq(streamState(r1), [1, ['b', 'c']]) + + res = parseSome(p, 'xyz') + eq(res, parseErr(0, 'Value did not match predicate: x')) + + res = parseSome(p, '') + eq(res, eof()) + }) +}) + diff --git a/tests/index.d.ts b/tests/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/tests/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/tests/index.js b/tests/index.js deleted file mode 100755 index d9b03db..0000000 --- a/tests/index.js +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -import { TerminalRunner } from 'folktest' -import * as Tests from './units/index.js' - -console.log(TerminalRunner(Tests).toString()) - diff --git a/tests/iterator.test.js b/tests/iterator.test.js new file mode 100644 index 0000000..c301091 --- /dev/null +++ b/tests/iterator.test.js @@ -0,0 +1,127 @@ +import { Stream } from '../src/iterator.js' +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' + +describe('Stream class', () => { + it('should iterate a range', () => { + const stream = new Stream([1, 2, 3]) + + assert.equal(stream.index, 0) + + assert.deepStrictEqual(stream.next(), { value: 1, done: false }) + assert.equal(stream.index, 1) + + assert.deepStrictEqual(stream.next(), { value: 2, done: false }) + assert.equal(stream.index, 2) + + assert.deepStrictEqual(stream.next(), { value: 3, done: false }) + assert.equal(stream.index, 3) + + assert.deepStrictEqual(stream.next(), { value: undefined, done: true }) + assert.equal(stream.index, 3) + }) + + it('should handle an empty stream', () => { + const stream = new Stream([]) + + assert.deepStrictEqual(stream.next(), { value: undefined, done: true }) + assert.equal(stream.index, 0) + }) + + it('should handle a single item', () => { + const stream = new Stream([1]) + + assert.equal(stream.index, 0) + + assert.deepStrictEqual(stream.next(), { value: 1, done: false }) + assert.equal(stream.index, 1) + + assert.deepStrictEqual(stream.next(), { value: undefined, done: true }) + assert.equal(stream.index, 1) + }) + + it('should should an independent stream', () => { + const stream = new Stream([1, 2, 3]) + + assert.deepStrictEqual(stream.next(), { value: 1, done: false }) + assert.equal(stream.index, 1) + + const clone = stream.clone() + assert.equal(clone.index, 1) + + assert.deepStrictEqual(clone.next(), { value: 2, done: false }) + assert.equal(clone.index, 2) + + assert.deepStrictEqual(clone.next(), { value: 3, done: false }) + assert.equal(clone.index, 3) + + assert.deepStrictEqual(stream.next(), { value: 2, done: false }) + assert.equal(stream.index, 2) + }) + + it('should support multiple clones', () => { + const stream = new Stream('abcdefg') + stream.next() + stream.next() + + assert.deepStrictEqual(stream.index, 2) + + const clone1 = stream.clone() + assert.deepStrictEqual(clone1.index, 2) + + stream.next() + stream.next() + assert.deepStrictEqual(stream.index, 4) + + const clone2 = stream.clone() + assert.deepStrictEqual(clone2.index, 4) + + assert.deepStrictEqual(clone1.next(), { value: 'c', done: false }) + assert.deepStrictEqual(clone1.next(), { value: 'd', done: false }) + assert.deepStrictEqual(clone1.next(), { value: 'e', done: false }) + assert.deepStrictEqual(clone1.index, 5) + + assert.deepStrictEqual(clone2.next(), { value: 'e', done: false }) + assert.deepStrictEqual(clone2.next(), { value: 'f', done: false }) + assert.deepStrictEqual(clone2.index, 6) + + assert.deepStrictEqual(stream.next(), { value: 'e', done: false }) + assert.deepStrictEqual(stream.index, 5) + }) + + it('should yield a value on consume', () => { + const stream = new Stream('abc') + assert.deepStrictEqual(stream.consume().unwrap(), 'a') + assert.deepStrictEqual(stream.consume().unwrap(), 'b') + assert.deepStrictEqual(stream.consume().unwrap(), 'c') + assert(stream.consume().isNone()) + }) + + it('should take from a stream', () => { + const stream5 = new Stream([1, 2, 3, 4, 5]) + const take3 = stream5.take(3) + assert.deepStrictEqual(Array.from(take3), [1, 2, 3]) + + assert.deepStrictEqual(stream5.index, 3) + assert.deepStrictEqual(Array.from(stream5), [4, 5]) + + const emptyStream = new Stream([]) + const take0 = emptyStream.take(3) + assert.deepStrictEqual(Array.from(take0), []) + assert.deepStrictEqual(emptyStream.index, 0) + assert.deepStrictEqual(Array.from(emptyStream), []) + + const streamDefault = new Stream('abc') + const genDefault = streamDefault.take() + assert.deepStrictEqual(Array.from(genDefault), ['a']) + assert.deepStrictEqual(streamDefault.index, 1) + assert.deepStrictEqual(Array.from(streamDefault), ['b', 'c']) + + const stream3 = new Stream([10, 20, 30]) + const genZero = streamDefault.take(0) + assert.deepStrictEqual(Array.from(genZero), []) + assert.deepStrictEqual(stream3.index, 0) + assert.deepStrictEqual(Array.from(stream3), [10, 20, 30]) + }) +}) + diff --git a/tests/primitives.test.js b/tests/primitives.test.js new file mode 100644 index 0000000..db382ed --- /dev/null +++ b/tests/primitives.test.js @@ -0,0 +1,82 @@ +import { pure, fail, anyItem, satisfy, literal, parse, parseSome, ParseError, EofError } from '../src/parser.js' +import { Err, Result } from '../src/result.js' +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' + +const eq = (a, b) => assert.deepStrictEqual(a, b) +const parseErr = (i, desc) => new Err(new ParseError(i, desc)) +const eof = (i = 0) => new Err(new EofError(i)) + +const streamState = stream => { + return [stream.index, Array.from(stream.clone())] +} + +describe('Primitive parsers', () => { + it('pure', () => { + const result = parseSome(pure(123), 'abc') + const [value, stream] = result.unwrap() + + eq(value, 123) + eq(streamState(stream), [0, ['a', 'b', 'c']]) + + const empty = parse(pure(123), []) + eq(empty, Result.ok(123)) + }) + + it('fail', () => { + const msg = 'Expected failure' + const parser = fail(msg) + const expected = parseErr(0, msg) + + eq(parse(parser, 'abc'), expected) + eq(parse(parser, ''), expected) + }) + + it('anyItem', () => { + const parser = anyItem() + eq(parse(parser, 'a'), Result.ok('a')) + + const many = parseSome(parser, 'abc') + assert(many.isOk()) + const [value, rest] = many.unwrap() + + eq(value, 'a') + eq(streamState(rest), [1, ['b', 'c']]) + + eq(parse(parser, ''), eof()) + }) + + it('satisfy', () => { + const pa = satisfy(x => x === 'a') + + const result = parseSome(pa, 'abc') + assert(result.isOk()) + + const [value, rest] = result.unwrap() + + eq(value, 'a') + eq(streamState(rest), [1, ['b', 'c']]) + + const err = parse(pa, 'cba') + eq(err, parseErr(0, 'Value did not match predicate: c')) + + const eofErr = parse(pa, '') + eq(eofErr, eof()) + }) + + it('literal', () => { + const px = literal('x') + const result = parseSome(px, 'xyz') + assert(result.isOk()) + + const [value, rest] = result.unwrap() + eq(value, 'x') + eq(streamState(rest), [1, ['y', 'z']]) + + const err = parse(px, 'yz') + eq(err, parseErr(0, 'Value did not match predicate: y')) + + const eofErr = parse(px, '') + eq(eofErr, eof()) + }) +}) diff --git a/tests/units/bytes.d.ts b/tests/units/bytes.d.ts deleted file mode 100644 index feba6d8..0000000 --- a/tests/units/bytes.d.ts +++ /dev/null @@ -1 +0,0 @@ -export const Byte: any[]; diff --git a/tests/units/bytes.js b/tests/units/bytes.js deleted file mode 100644 index 9dff35c..0000000 --- a/tests/units/bytes.js +++ /dev/null @@ -1,70 +0,0 @@ -import { it, assert, assertEq } from 'folktest' -import { char, charNoCase, noneOf, oneOf, parse, tag, tagNoCase, take, takeWhile } from '../../src/index.js' -import { Alphanumeric } from '../../src/const.js' -import { chain, curry, map } from 'izuna' -import { assertState, parseEq } from './common.js' - -export const Byte = [ - it('char', () => { - const parser = char('a') - - parseEq(parser, 'abc', ['a']) - assert(parse(parser, ' abc').isErr()) - assert(parse(parser, 'bc').isErr()) - assert(parse(parser, '').isErr()) - }), - - it('oneOf', () => { - parse(oneOf('abc'), 'b').chain(assertState('b')) - assert(parse(oneOf('a'), 'bc').isErr()) - assert(parse(oneOf('a'), '').isErr()) - }), - - it('noneOf', () => { - parse(noneOf('abc'), 'z').chain(assertState(['z'])) - assert(parse(noneOf('ab'), 'a').isErr()) - assert(parse(noneOf('ab'), '').isErr()) - }), - - it('tag', () => { - const parser = tag('Hello') - parse(parser, 'Hello, World!').chain(assertState(['Hello'])) - assert(parse(parser, 'Something').isErr()) - assert(parse(parser, '').isErr()) - }), - - it('charNoCase', () => { - const parser = charNoCase('a') - parse(parser, 'abc').chain(assertState(['a'])) - parse(parser, 'Abc').chain(assertState(['A'])) - assert(parse(parser, ' abc').isErr()) - assert(parse(parser, 'bc').isErr()) - assert(parse(parser, '').isErr()) - }), - - it('tagNoCase', () => { - const parser = tagNoCase('hello') - parse(parser, 'Hello, World!').chain(assertState(['Hello'])) - parse(parser, 'hello, World!').chain(assertState(['hello'])) - parse(parser, 'HeLlO, World!').chain(assertState(['HeLlO'])) - assert(parse(parser, 'Something').isErr()) - assert(parse(parser, '').isErr()) - }), - - it('take', () => { - const parser = take(6) - parse(parser, '1234567').chain(assertState('123456'.split(''))) - parse(parser, 'things').chain(assertState('things'.split(''))) - assert(parse(parser, 'short').isErr()) - assert(parse(parser, '').isErr()) - }), - - it('takeWhile', () => { - const parser = takeWhile(x => Alphanumeric.includes(x)) - parse(parser, 'latin123').chain(assertState(['latin'])) - parse(parser, '123').chain(assertState([])) - parse(parser, 'latin').chain(assertState(['latin'])) - parse(parser, '').chain(assertState([])) - }) -] - diff --git a/tests/units/common.d.ts b/tests/units/common.d.ts deleted file mode 100644 index f614221..0000000 --- a/tests/units/common.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const assertState: any; -export const parseEq: any; -export const parseErr: any; diff --git a/tests/units/common.js b/tests/units/common.js deleted file mode 100644 index ca3eea6..0000000 --- a/tests/units/common.js +++ /dev/null @@ -1,15 +0,0 @@ -import { chain, curry } from 'izuna' -import { parse } from '../../src/index.js' - -export const assertState = curry((expected, state) => { - assertEq(expected, state[0]) -}) - -export const parseEq = curry((parser, input, expected) => - chain(assertState(expected), parse(parser, input)) -) - -export const parseErr = curry((parser, input) => - assert(parse(parser, input).isErr(), `expected an error but '${input}' parsed successfully`) -) - diff --git a/tests/units/cond.d.ts b/tests/units/cond.d.ts deleted file mode 100644 index b6db36d..0000000 --- a/tests/units/cond.d.ts +++ /dev/null @@ -1 +0,0 @@ -export const Conditionals: any[]; diff --git a/tests/units/cond.js b/tests/units/cond.js deleted file mode 100644 index 726d979..0000000 --- a/tests/units/cond.js +++ /dev/null @@ -1,11 +0,0 @@ -import { it, assertEq } from 'folktest' -import { anyChar, parse } from '../../src/index.js' -import { skip } from '../../src/cond.js' -import { parseEq } from './common.js' - -export const Conditionals = [ - it('skip', () => { - parseEq(skip(anyChar), 'test', []) - }) -] - diff --git a/tests/units/index.d.ts b/tests/units/index.d.ts deleted file mode 100644 index 7e6d287..0000000 --- a/tests/units/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./bytes.js"; -export * from "./iter.js"; -export * from "./cond.js"; diff --git a/tests/units/index.js b/tests/units/index.js deleted file mode 100644 index aad520c..0000000 --- a/tests/units/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export * from './bytes.js' -export * from './iter.js' -export * from './cond.js' - diff --git a/tests/units/iter.d.ts b/tests/units/iter.d.ts deleted file mode 100644 index c5e3d0c..0000000 --- a/tests/units/iter.d.ts +++ /dev/null @@ -1 +0,0 @@ -export const Iterator: any[]; diff --git a/tests/units/iter.js b/tests/units/iter.js deleted file mode 100644 index 61d9ca0..0000000 --- a/tests/units/iter.js +++ /dev/null @@ -1,21 +0,0 @@ -import { it, assert, assertEq } from 'folktest' -import { IndexableIterator } from '../../src/iter.js' -import { state } from '../../src/state.js' - -export const Iterator = [ - it('should be cloneable', () => { - const hi = new IndexableIterator('hi :3') - const hihi = hi.clone() - - assertEq(hi.next().value, 'h') - - assertEq(hi.next().value, 'i') - assertEq(hihi.next().value, 'h') - }), - - it('should have iterator helpers', () => { - const aaaaa = new IndexableIterator('awawawawa').filter(x => x !== 'w') - assertEq([...aaaaa].join(''), 'aaaaa') - }) -] - diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 3b520cf..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "libReplacement": true, /* Enable lib replacement. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./typings", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - "declarationDir": "./typings", /* Specify the output directory for generated declaration files. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ - // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "include": [ - "src" - ] -} diff --git a/typings/byte.d.ts b/typings/byte.d.ts deleted file mode 100644 index 1f45c6d..0000000 --- a/typings/byte.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** @import { ParserState } from './state.js' */ -export const char: any; -export const tag: any; -export const charNoCase: any; -export const tagNoCase: any; -export function anyChar(state: any): any; -export const take: any; -export const oneOf: any; -export const noneOf: any; -export const digit: any; -export const lowerAlpha: any; -export const upperAlpha: any; -export const alpha: (state: ParserState) => any; -export const alphanumeric: (state: ParserState) => any; -export function eof(state: any): any; -import type { ParserState } from './state.js'; diff --git a/typings/clone.d.ts b/typings/clone.d.ts deleted file mode 100644 index 6e59b1e..0000000 --- a/typings/clone.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const Clone: unique symbol; -export function clone(target: any): any; diff --git a/typings/combinator.d.ts b/typings/combinator.d.ts deleted file mode 100644 index bd8ae38..0000000 --- a/typings/combinator.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function seq(...parsers: Parser[]): ( -/** @param {ParserState} state */ -state: ParserState) => any; -export function any(...parsers: any[]): ( -/** - * @param {ParserState} state - */ -state: ParserState) => any; -export const map: any; -export const delimited: any; -export const preceded: any; -export const terminated: any; -export const separatedPair: any; -import type { ParserState } from './state.js'; diff --git a/typings/cond.d.ts b/typings/cond.d.ts deleted file mode 100644 index 270171b..0000000 --- a/typings/cond.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** @import { Result } from '../vendor/kojima/src/index.js' */ -/** @import { ParserState } from './state.js' */ -export const maybe: any; -export const not: any; -export const until: any; -export const verify: any; -export const skip: any; diff --git a/typings/const.d.ts b/typings/const.d.ts deleted file mode 100644 index 5ef1105..0000000 --- a/typings/const.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const LowerAlpha: "abcdefghijklmnopqrstuvwxyz"; -export const UpperAlpha: string; -export const Alpha: string; -export const Digits: "1234567890"; -export const Alphanumeric: string; diff --git a/typings/fn.d.ts b/typings/fn.d.ts deleted file mode 100644 index 24ea332..0000000 --- a/typings/fn.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function iter(value: any): IndexableIterator; -export function clone(state: ParserState): any; -export function succeed(v: T | T[], [x, y]: ParserState): any; -export function fail(msg: string, state: ParserState, e?: Error): any; -export function nth(n: number & keyof T, iter: T[]): T[][number & keyof T]; -export function next(state: ParserState): any; -export function diff(a: T[], b: T[]): T[]; -export const join: any; -export const mapStr: any; -import { IndexableIterator } from './iter.js'; -import type { ParserState } from './state.js'; diff --git a/typings/index.d.ts b/typings/index.d.ts deleted file mode 100644 index a7ae774..0000000 --- a/typings/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./byte.js"; -export * from "./combinator.js"; -export * from "./cond.js"; -export * from "./multi.js"; -export * from "./state.js"; diff --git a/typings/iter.d.ts b/typings/iter.d.ts deleted file mode 100644 index 20bf425..0000000 --- a/typings/iter.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class IndexableIterator { - constructor(value: any, index?: number); - _value: any; - _index: number; - clone(): IndexableIterator; - done(): boolean; - next(): { - value: any; - done: boolean; - }; - [Clone](): IndexableIterator; - [Symbol.iterator](): IndexableIterator; -} -import { Clone } from './clone.js'; diff --git a/typings/multi.d.ts b/typings/multi.d.ts deleted file mode 100644 index b95ce8f..0000000 --- a/typings/multi.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** @import { ParseError, ParserState } from './state.js' */ -/** @import { Result } from '../vendor/kojima/src/index.js' */ -export const takeWhile: any; -export const takeUntil: any; -export const skip: any; -export const many: any; -export function many1(parser: any): any; -export function range(start: any, end: any, deny?: any[]): any; diff --git a/typings/state.d.ts b/typings/state.d.ts deleted file mode 100644 index e2b4c88..0000000 --- a/typings/state.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @typedef {Readonly<[any[], Iterator]>} ParserState - */ -export class ParseError extends Error { - /** - * @param {string} message - * @param {ParserState} state - * @param {Error} [cause] - */ - constructor(message: string, state: ParserState, cause?: Error); - state: readonly [any[], Iterator]; -} -export class State extends Tuple { - static from(values: any): State; - constructor(remaining: any, read?: any[]); - next(): any; - [Clone](): Readonly; -} -export function state(remaining: any, read: any): State; -export const parse: any; -export const parseAll: any; -export type ParserState = Readonly<[any[], Iterator]>; -import { Tuple } from './tuple.js'; -import { Clone } from './clone.js'; diff --git a/typings/tuple.d.ts b/typings/tuple.d.ts deleted file mode 100644 index 2adeacd..0000000 --- a/typings/tuple.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @param {...any} values - */ -export class Tuple { - static from(values: any): Readonly; - constructor(values: any); - _values: any; - _length: any; - get length(): any; - _setEntry([key, value]: [any, any], index: any): void; - toString(): string; - clone(): any; - [Clone](): any; - [Symbol.iterator](): IndexableIterator; -} -export function tuple(values: any): Readonly; -import { Clone } from './clone.js'; -import { IndexableIterator } from './iter.js';