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) ) }