diff options
| -rw-r--r-- | default.nix | 12 | ||||
| -rw-r--r-- | src/index.ts | 26 | ||||
| -rw-r--r-- | src/parser.ts | 78 | ||||
| -rw-r--r-- | src/utils.ts | 4 |
4 files changed, 68 insertions, 52 deletions
diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..7b1a6c7 --- /dev/null +++ b/default.nix @@ -0,0 +1,12 @@ +{ pkgs ? import <nixpkgs> { } }: +with pkgs; +mkShell rec { + buildInputs = [ + nodejs-16_x + yarn + efm-langserver + nodePackages.vls + nodePackages.prettier + nodePackages.typescript-language-server + ]; +} diff --git a/src/index.ts b/src/index.ts index 582f9be..95a5411 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,16 @@ import { constant, flow, identity, pipe } from 'fp-ts/function' -import { andThen, delimited, mapTo, optional, pair, symbol } from './parser' +import { + andThen, + delimited, + digit, + integer, + many1, + mapTo, + optional, + or, + pair, + symbol, +} from './parser' export const start = mapTo(symbol('^'), constant({ tag: 'Start' } as Expr)) export const end = mapTo(symbol('$'), constant({ tag: 'End' } as Expr)) @@ -27,15 +38,12 @@ type Expr = | { tag: 'Truthy' } | { tag: 'Falsey' } -export const expressionP = symbol('fuck') +export const expressionP = or([ + symbol('fuck'), + mapTo(many1(digit), (j) => j.join('')), +]) -export const parser = pair( - pair( - optional(start), - expressionP, - ), - optional(end), -) +export const parser = pair(pair(optional(start), expressionP), optional(end)) /* diff --git a/src/parser.ts b/src/parser.ts index 5ccba43..9baab8e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,6 +1,8 @@ import { flow, pipe } from 'fp-ts/function' import { Either, left, right, map, chain, orElse, fold } from 'fp-ts/Either' -import { none, some, Option } from 'fp-ts/lib/Option' +import { none, some, Option } from 'fp-ts/Option' +import { mapFst, snd } from 'fp-ts/Tuple' +import { eq } from './utils' export type char = string @@ -17,13 +19,14 @@ export const many0 = <T>(parser: Parser<T>): Parser<Array<T>> => flow( parser, chain(([a, nextInput]) => - pipe( - nextInput, - many0(parser), - map(([ls, inp]): ParserResult<T[]> => [[a, ...ls], inp]) - ) + pipe(nextInput, many0(parser), map(mapFst((ls) => [a, ...ls]))) ), - orElse(([_, inp]) => right([[] as T[], inp])) + orElse( + flow( + mapFst((_) => [] as T[]), + right + ) + ) ) export const many1 = <T>(parser: Parser<T>): Parser<Array<T>> => @@ -37,21 +40,12 @@ export const many1 = <T>(parser: Parser<T>): Parser<Array<T>> => ) export const prefixed = <T>(a: Parser<any>, b: Parser<T>): Parser<T> => - flow( - a, - chain(([_, inp]) => b(inp)) - ) + flow(a, chain(flow(snd, b))) export const suffixed = <T>(a: Parser<T>, b: Parser<any>): Parser<T> => flow( a, - chain(([out, inp]) => - pipe( - inp, - b, - chain(([_, inp2]) => right([out, inp2])) - ) - ) + chain(([out, inp]) => pipe(inp, b, map(mapFst((_) => out)))) ) export const delimited = <T>( @@ -72,22 +66,22 @@ export const digit = satifyChar((c) => /^[0-9]$/g.test(c)) export const integer: Parser<number> = flow( many1(digit), - map(([ds, input]) => [parseInt(ds.join(''), 10), input]) + map(mapFst((ds) => parseInt(ds.join(''), 10))) ) export const or = <T>(parsers: Parser<T>[]): Parser<T> => { - const ppp = ([p, ...ps]: Parser<T>[]) => + const run = ([p, ...ps]: Parser<T>[]) => flow( p, orElse(([_, inp]) => or(ps)(inp)) ) return parsers.length > 0 - ? ppp(parsers) + ? run(parsers) : (inp: string) => left(['unable to match', inp]) } -export const matchChar = (ch: char): Parser<char> => satifyChar((c) => c === ch) +export const matchChar = (ch: char): Parser<char> => satifyChar(eq(ch)) export const space = matchChar(' ') export const newline = matchChar('\n') @@ -102,11 +96,7 @@ export const matchString = (s: string): Parser<string> => : flow( matchChar(s.charAt(0)), chain(([c, inp]) => - pipe( - inp, - matchString(s.slice(1)), - map(([s, inp]) => [c + s, inp]) - ) + pipe(inp, matchString(s.slice(1)), map(mapFst((s) => c + s))) ) ) @@ -114,28 +104,30 @@ export const symbol = (s: string): Parser<string> => delimited(whitespaces0, matchString(s), whitespaces0) export const mapTo = <I, R>(p: Parser<I>, f: (p: I) => R): Parser<R> => - flow( - p, - map(([v, inp]) => [f(v), inp]) - ) + flow(p, map(mapFst(f))) -export const andThen = <I, R>(f: (p: I) => Parser<R>) => (p: Parser<I>): Parser<R> => - flow( - p, - chain(([v, inp]) => f(v)(inp)), - ) +export const andThen = + <I, R>(f: (p: I) => Parser<R>) => + (p: Parser<I>): Parser<R> => + flow( + p, + chain(([v, inp]) => f(v)(inp)) + ) export const optional = <T>(p: Parser<T>): Parser<Option<T>> => flow( p, fold( - ([_, inp]) => right([none, inp]), - ([v, inp]) => right([some(v), inp]) + flow( + mapFst((_) => none), + right + ), + flow(mapFst(some), right) ) ) -export const pair = <A, B>(a: Parser<A>, b: Parser<B>): Parser<[A, B]> => pipe( - a, - andThen(ra => mapTo(b, rb => [ra, rb])) -) - +export const pair = <A, B>(a: Parser<A>, b: Parser<B>): Parser<[A, B]> => + pipe( + a, + andThen((ra) => mapTo(b, (rb) => [ra, rb])) + ) diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..e7392bf --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,4 @@ +export const eq = + <T>(a: T) => + (b: T): boolean => + a === b |
