diff options
| -rw-r--r-- | src/parser/index.ts | 14 | ||||
| -rw-r--r-- | src/parser/utils.ts | 13 | ||||
| -rw-r--r-- | src/types.ts | 20 | ||||
| -rw-r--r-- | tests/basic.spec.ts | 34 |
4 files changed, 60 insertions, 21 deletions
diff --git a/src/parser/index.ts b/src/parser/index.ts index ec29099..b8e6764 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -8,6 +8,7 @@ import { or, Parser, ParserResult, + prefixed, symbol, tuple3, } from './utils' @@ -36,6 +37,17 @@ export const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> = ), ) +export const wrapAlt: (e: ParserResult<Expr>) => ParserResult<Expr> = chain( + ([expr, input]) => + pipe( + input, + mapTo(prefixed(symbol('|'), many1(expressionP)), rest => + Expr.Or({ left: expr, right: rest }), + ), + orElse(_ => right([expr, input])), + ), +) + export const expressionP: Parser<Expr> = (input: string) => pipe( input, @@ -52,6 +64,7 @@ export const expressionP: Parser<Expr> = (input: string) => falsey, ]), wrapQuantifiers, + wrapAlt, ) export const parser = tuple3(optional(start), many1(expressionP), optional(end)) @@ -62,7 +75,6 @@ export const parser = tuple3(optional(start), many1(expressionP), optional(end)) (> 5) => number greater than (< 5) => number less than [name x] => apply x on property `name` -| => or /x/ => match regular expression (string values in list) */ diff --git a/src/parser/utils.ts b/src/parser/utils.ts index a06b6c9..debff22 100644 --- a/src/parser/utils.ts +++ b/src/parser/utils.ts @@ -78,7 +78,7 @@ export const delimited = <T>( p: Parser<any>, a: Parser<T>, s: Parser<any>, -): Parser<T> => suffixed(prefixed(p, a), s) +): Parser<T> => recoverInput(suffixed(prefixed(p, a), s)) export const satifyChar = (f: (c: char) => boolean): Parser<char> => @@ -150,13 +150,16 @@ export const optional = <T>(p: Parser<T>): Parser<Option<T>> => ) export const pair = <A, B>(a: Parser<A>, b: Parser<B>): Parser<[A, B]> => - pipe( - a, - andThen(ra => mapTo(b, rb => [ra, rb])), + recoverInput( + pipe( + a, + andThen(ra => mapTo(b, rb => [ra, rb])), + ), ) export const tuple3 = <A, B, C>( a: Parser<A>, b: Parser<B>, c: Parser<C>, -): Parser<[A, B, C]> => mapTo(pair(pair(a, b), c), ([[a, b], c]) => [a, b, c]) +): Parser<[A, B, C]> => + recoverInput(mapTo(pair(pair(a, b), c), ([[a, b], c]) => [a, b, c])) diff --git a/src/types.ts b/src/types.ts index 7863981..7f6546f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,19 +1,19 @@ import { constructors, Union } from "./utils" type ExprT = { - Start: any, - End: any, + Start: null, + End: null, Optional: { expr: Expr }, OneOrMore: { expr: Expr }, ZeroOrMore: { expr: Expr }, - NextItem: any, - AnyItem: any, - Or: any, - AnyString: any, - AnyNumber: any, - AnyBool: any, - Truthy: any, - Falsey: any, + NextItem: null, + AnyItem: null, + Or: { left: Expr, right: Expr[] }, + AnyString: null, + AnyNumber: null, + AnyBool: null, + Truthy: null, + Falsey: null, Group: { exprs: Expr[] }, } diff --git a/tests/basic.spec.ts b/tests/basic.spec.ts index d443ce1..150966b 100644 --- a/tests/basic.spec.ts +++ b/tests/basic.spec.ts @@ -6,9 +6,11 @@ import { delimited, } from '../src/parser/utils' import { parser } from '../src/parser' -import { some } from 'fp-ts/Option' +import { none, some } from 'fp-ts/Option' import { Expr } from '../src/types' +const plog = (x: any) => console.log(JSON.stringify(x, null, 2)) + describe('Foobar', () => { it('should do shit', () => { expect(integer('12901')).toEqual(right([12901, ''])) @@ -18,10 +20,10 @@ describe('Foobar', () => { expect(whitespace('a')).toEqual(left(['unable to match', 'a'])) expect(delimited(whitespaces0, integer, whitespaces0)(' 20 ')).toEqual( - right([20, '']) + right([20, '']), ) expect(delimited(whitespaces0, integer, whitespaces0)(' 2 0 ')).toEqual( - right([2, '0 ']) + right([2, '0 ']), ) }) @@ -40,7 +42,7 @@ describe('Foobar', () => { some(Expr.End(null)), ], '', - ]) + ]), ) expect(parser(/^ \s* \T? \n+ $/.source)).toEqual( @@ -55,7 +57,29 @@ describe('Foobar', () => { some(Expr.End(null)), ], '', - ]) + ]), + ) + + expect(parser(/ \s|\b\T|\n /.source)).toEqual( + right([ + [ + none, + [ + Expr.Or({ + left: Expr.AnyString(null), + right: [ + Expr.AnyBool(null), + Expr.Or({ + left: Expr.Truthy(null), + right: [Expr.AnyNumber(null)], + }), + ], + }), + ], + none, + ], + '', + ]), ) }) }) |
