kuebiko/src/multi.js
2025-05-25 08:33:35 -05:00

68 lines
1.5 KiB
JavaScript

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