68 lines
1.5 KiB
JavaScript
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)
|
|
)
|
|
}
|
|
|