Home Manual Reference Source

src/withMethods.js

import {TypeError} from '@failure-abstraction/error';
import {_reduce} from '@iterable-iterator/reduce';

export default function PersistentStack() {}
PersistentStack.prototype.push = function (value) {
	return new Pushed(value, this);
};

PersistentStack.prototype[Symbol.iterator] = function* () {
	// eslint-disable-next-line unicorn/no-this-assignment
	let current = this;
	while (!current.isEmpty()) {
		yield current.peek();
		current = current.pop();
	}
};

function Empty() {}
Empty.prototype = new PersistentStack();

Empty.prototype.isEmpty = function () {
	return true;
};

Empty.prototype.pop = function () {
	throw new TypeError('Cannot call pop on empty stack.');
};

Empty.prototype.peek = function () {
	throw new TypeError('Cannot call peek on empty stack.');
};

function Pushed(value, next) {
	this.value = value;
	this.next = next;
}

Pushed.prototype = new PersistentStack();
Pushed.prototype.isEmpty = function () {
	return false;
};

Pushed.prototype.pop = function () {
	return this.next;
};

Pushed.prototype.peek = function () {
	return this.value;
};

const EMPTY = new Empty();
PersistentStack.empty = () => EMPTY;
PersistentStack.push = (stack, value) => new Pushed(value, stack);
PersistentStack.isEmpty = (stack) => stack.isEmpty();
PersistentStack.pop = (stack) => stack.pop();
PersistentStack.peek = (stack) => stack.peek();
PersistentStack.iter = (stack) => stack[Symbol.iterator]();
PersistentStack.from = (iterable) =>
	_reduce(PersistentStack.push, iterable, EMPTY);