diff options
Diffstat (limited to '')
| -rw-r--r-- | src/eval/index.ts | 130 | ||||
| -rw-r--r-- | src/index.ts | 34 |
2 files changed, 152 insertions, 12 deletions
diff --git a/src/eval/index.ts b/src/eval/index.ts index 6656743..1050295 100644 --- a/src/eval/index.ts +++ b/src/eval/index.ts @@ -1,8 +1,136 @@ import { pipe } from 'fp-ts/function' import { takeLeftWhile } from 'fp-ts/lib/Array' +import { + chain, + getOrElseW, + isSome, + map, + none, + Option, + some, +} from 'fp-ts/lib/Option' import { Expr, ListExpr } from '../types' import { match } from '../utils' +export interface MatchGroupIndexed<T = any> { + value: T + index: number +} + +export interface MatchGroupResult { + groups: MatchGroupIndexed[] +} + +const group = <T>(value: T, index: number): MatchGroupIndexed<T> => ({ + value, + index, +}) + +// :: ListExpr -> [a] -> [{ groups: [T] }] +export const matchAll = <T>( + [startO, exprs, endO]: ListExpr, + list: T[], +): MatchGroupResult => { + const check = ( + index: number, + ls: T[], + expr: Expr, + ): Option<MatchGroupIndexed[]> => { + if (ls.length === 0) return some([]) + + const [item, ...rest] = ls + + const next = + (i: number = 1) => + (cur: Option<MatchGroupIndexed[]>) => + pipe( + check(index + i, ls.slice(i), expr), + getOrElseW(() => [] as MatchGroupIndexed[]), + nextMatch => + pipe( + cur, + map(curMatch => [...curMatch, ...nextMatch]), + ), + ) + + return pipe( + expr, + match<Option<MatchGroupIndexed<any>[]>, Expr>({ + AnyItem: _ => pipe(some([group(item, index)]), next()), + AnyNumber: _ => + pipe( + typeof item === 'number' ? some([group(item, index)]) : none, + next(), + ), + AnyString: _ => + pipe( + typeof item === 'string' ? some([group(item, index)]) : none, + next(), + ), + AnyBool: _ => + pipe( + typeof item === 'boolean' ? some([group(item, index)]) : none, + next(), + ), + Truthy: _ => pipe(!!item ? some([group(item, index)]) : none, next()), + Falsey: _ => pipe(!item ? some([group(item, index)]) : none, next()), + + Group: ({ exprs }) => { + const matches = exprs.reduce( + (acc, exp) => + pipe( + acc, + chain(m => + pipe( + check(index, ls, exp), + map(ac => [...ac, ...m]), + ), + ), + ), + some([] as MatchGroupIndexed<any>[]), + ) + // console.log(matches, exprs, '---', item) + + return next()(matches) + }, + + PropertyMatch: ({ name, exprs }) => + pipe( + Object.prototype.hasOwnProperty.call(item, name) + ? check(index, [item[name]], Expr.Group({ exprs })) + : none, + next(), + ), + + OneOrMore: ({ expr }) => { + //console.log(item) + // TODO: Nested quantified expression + const matches = pipe( + ls, + takeLeftWhile(a => isSome(check(index, [a], expr))), + ) + //console.log(matches) + return pipe( + matches.length > 0 ? some([group(matches, index)]) : none, + next(matches.length || 1), + ) + }, + + _: _ => none, + }), + ) + } + + const expr = Expr.Group({ exprs }) + + return { + groups: pipe( + check(0, list, expr), + getOrElseW(() => []), + ), + } +} + export const find = <T>([startO, exprs, endO]: ListExpr, list: T[]): any => { const check = (expr: Expr) => @@ -25,7 +153,7 @@ export const find = <T>([startO, exprs, endO]: ListExpr, list: T[]): any => { list.slice(i), takeLeftWhile(x => check(expr)(x, i, list)), ) - console.log(x) + //console.log(x) return true }, diff --git a/src/index.ts b/src/index.ts index 691d676..db6630c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,29 @@ -import { fold, map } from 'fp-ts/lib/Either' -import { identity, pipe } from 'fp-ts/lib/function' -import { find } from './eval' +import { getOrElseW, map } from 'fp-ts/lib/Either' +import { flow, pipe } from 'fp-ts/lib/function' +import {fst} from 'fp-ts/lib/Tuple' +import * as ev from './eval' import { parser } from './parser' +import {ListExpr} from './types' const toSourceString = (r: string | RegExp): string => typeof r === 'string' ? r : r.source -export const filter = <T>(listExp: string | RegExp, list: T[]): T[] => +export const liexp: (r: string | RegExp) => ListExpr = flow( + toSourceString, + parser, + map(fst), + getOrElseW(([e, _]) => { throw new Error(e) }) +) + +export const matchAll = <T>(exp: string | RegExp, list: T[]) => + pipe( + exp, + liexp, + lxp => ev.matchAll(lxp, list), + ) + +export const filter = <T>(exp: string | RegExp, list: T[]): T[] => pipe( - listExp, - toSourceString, - parser, - map(([lxp, _]) => find(lxp, list)), - fold(([err, _]) => { - throw new Error(err) - }, identity), + exp, + liexp, + lxp => ev.find(lxp, list), ) |
