kuebiko/src/byte.js

83 lines
1.9 KiB
JavaScript

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