1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
import { Enum, constructors, match } from './adt';
export type Result<V, E> = Enum<{ Ok: V, Err: E }>
export const Result = constructors<Result<any, any>>()
export const mapResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => B): Result<B, E> =>
chainResult(res, a => Result.Ok(fn(a)))
export const chainResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => Result<B, E>): Result<B, E> =>
match(res, {
Ok: a => fn(a),
Err: e => Result.Err(e),
});
export type ParseResult<T> = Result<{ value: T, input: string }, { error: string, input: string }>;
export type Parser<T> = (input: string) => ParseResult<T>;
export const regex = (re: RegExp): Parser<string> => input => {
const res = input.match(re)
if (!res) return Result.Err({ error: 'fucked', input });
return Result.Ok({ value: res[0], input: input.replace(re, '') });
}
export const string = (str: string): Parser<string> => input => {
if (!input.startsWith(str)) return Result.Err({ error: 'fuckedstring', input })
return Result.Ok({ value: str, input: input.slice(str.length) });
}
export const or = <T>([parser, ...rest]: Array<Parser<T>>): Parser<T> => input => {
if (rest.length === 0) return parser(input);
const result = parser(input)
return match(result, {
Ok: () => result,
Err: (_) => or(rest)(input),
});
}
export const mapParseResult = <T, R>(parser: Parser<T>, fn: (_: { value: T, input: string }) => { value: R, input: string }): Parser<R> => input =>
mapResult(parser(input), fn)
export const map = <T, R>(parser: Parser<T>, fn: (_: T) => R): Parser<R> =>
mapParseResult(parser, ({ value, ...rest }) => ({ ...rest, value: fn(value) }));
export const zip2 = <A, B>(parserA: Parser<A>, parserB: Parser<B>): Parser<readonly [A, B]> => input => {
// TODO: refactor please. shit code
const resa: Result<{ value: A, input: string }, { error: string, input: string }> = parserA(input);
return chainResult(resa, ({ value: a, input: inputB }) => {
const res: Result<{ value: readonly [A, B], input: string }, { error: string, input: string }> =
map(parserB, (b) => [a, b] as const)(inputB)
return res
})
}
export const prefixed = <A>(parserPrefix: Parser<any>, parser: Parser<A>): Parser<A> =>
map(zip2(parserPrefix, parser), ([_, a]) => a);
export const suffixed = <A>(parser: Parser<A>, parserSuffix: Parser<any>): Parser<A> =>
map(zip2(parser, parserSuffix), ([a, _]) => a);
export const between = <A>(prefix: Parser<any>, parser: Parser<A>, suffix: Parser<any>): Parser<A> =>
suffixed(prefixed(prefix, parser), suffix)
|