diff options
| -rw-r--r-- | src/index.ts | 49 | ||||
| -rw-r--r-- | src/parser.ts | 21 | ||||
| -rw-r--r-- | tests/basic.spec.ts | 16 |
3 files changed, 67 insertions, 19 deletions
diff --git a/src/index.ts b/src/index.ts index 95a5411..75bc1af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,19 +6,36 @@ import { integer, many1, mapTo, + matchChar, optional, or, pair, + Parser, symbol, + tuple3, } from './parser' export const start = mapTo(symbol('^'), constant({ tag: 'Start' } as Expr)) export const end = mapTo(symbol('$'), constant({ tag: 'End' } as Expr)) -export const anyItem = mapTo(symbol(','), constant({ tag: 'AnyItem' } as Expr)) +export const anyItem = mapTo(symbol('.'), constant({ tag: 'AnyItem' } as Expr)) export const nextItem = mapTo( symbol(','), constant({ tag: 'NextItem' } as Expr) ) +export const anyString = mapTo( + symbol('\\s'), + constant({ tag: 'AnyString' } as Expr) +) +export const anyNumber = mapTo( + symbol('\\n'), + constant({ tag: 'AnyNumber' } as Expr) +) +export const anyBool = mapTo( + symbol('\\b'), + constant({ tag: 'AnyBool' } as Expr) +) +export const truthy = mapTo(symbol('\\T'), constant({ tag: 'Truthy' } as Expr)) +export const falsey = mapTo(symbol('\\F'), constant({ tag: 'Falsey' } as Expr)) // export const optional = mapTo(symbol('?'), constant({ tag: 'Optional' } as Expr)) // export const zeroOrMore = mapTo(symbol('*'), constant({ tag: 'ZeroOrMore' } as Expr)) // export const oneOrMore = mapTo(symbol('+'), constant({ tag: 'OneOrMore' } as Expr)) @@ -32,18 +49,32 @@ type Expr = | { tag: 'NextItem' } | { tag: 'AnyItem' } | { tag: 'Or' } - | { tag: 'String' } - | { tag: 'Number' } - | { tag: 'Bool' } + | { tag: 'AnyString' } + | { tag: 'AnyNumber' } + | { tag: 'AnyBool' } | { tag: 'Truthy' } | { tag: 'Falsey' } + | { tag: 'Group'; exprs: Expr[] } -export const expressionP = or([ - symbol('fuck'), - mapTo(many1(digit), (j) => j.join('')), -]) +export const expressionP: Parser<Expr> = (input: string) => + pipe( + input, + or([ + mapTo( + delimited(symbol('('), many1(expressionP), symbol(')')), + (exprs) => ({ tag: 'Group', exprs }) + ), + nextItem, + anyItem, + anyString, + anyNumber, + anyBool, + truthy, + falsey, + ]) + ) -export const parser = pair(pair(optional(start), expressionP), optional(end)) +export const parser = tuple3(optional(start), many1(expressionP), optional(end)) /* diff --git a/src/parser.ts b/src/parser.ts index 9baab8e..baa3e76 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -90,15 +90,12 @@ export const tab = matchChar('\t') export const whitespace = or([space, newline, tab]) export const whitespaces0 = many0(whitespace) -export const matchString = (s: string): Parser<string> => - s === '' - ? constP('') - : flow( - matchChar(s.charAt(0)), - chain(([c, inp]) => - pipe(inp, matchString(s.slice(1)), map(mapFst((s) => c + s))) - ) - ) +export const matchString = + (s: string): Parser<string> => + (input: string) => + input.slice(0, s.length) === s + ? right([s, input.slice(s.length)]) + : left([`Expected ${s} but got ${input.slice(0, 1)}`, input]) export const symbol = (s: string): Parser<string> => delimited(whitespaces0, matchString(s), whitespaces0) @@ -131,3 +128,9 @@ export const pair = <A, B>(a: Parser<A>, b: Parser<B>): Parser<[A, B]> => 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]) diff --git a/tests/basic.spec.ts b/tests/basic.spec.ts index 962f076..b0a4d50 100644 --- a/tests/basic.spec.ts +++ b/tests/basic.spec.ts @@ -12,6 +12,7 @@ import { optional, } from '../src/parser' import { parser } from '../src' +import {some} from 'fp-ts/lib/Option' describe('Foobar', () => { it('should do shit', () => { @@ -30,6 +31,19 @@ describe('Foobar', () => { }) it('should maybeshut', () => { - console.log(JSON.stringify(parser('fuck'), null, 2)) + expect(parser(/^ .\s(\n)\b \T $/.source)).toEqual(right([ + [ + some({ tag: 'Start' }), + [ + { tag: 'AnyItem' }, + { tag: 'AnyString' }, + { tag: 'Group', exprs: [{ tag: 'AnyNumber' },] }, + { tag: 'AnyBool' }, + { tag: 'Truthy' }, + ], + some({ tag: 'End' }), + ], + '' + ])) }) }) |
