aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2022-01-24 19:19:15 +0530
committerAkshay Nair <phenax5@gmail.com>2022-01-24 19:19:15 +0530
commitdb497bb9950648c056c079c591b239ad4932b5c9 (patch)
treea554e54f9a3b0d7d7373874c508831e52ee33416
parenta4e2b5b44823571a693ad47250e40efca5f7fe10 (diff)
downloadelxr-db497bb9950648c056c079c591b239ad4932b5c9.tar.gz
elxr-db497bb9950648c056c079c591b239ad4932b5c9.zip
feat(parser): implements min-max quantifier parser
-rw-r--r--src/eval/index.ts4
-rw-r--r--src/parser/index.ts21
-rw-r--r--src/types.ts3
-rw-r--r--tests/parser.spec.ts39
4 files changed, 61 insertions, 6 deletions
diff --git a/src/eval/index.ts b/src/eval/index.ts
index 8e162b4..ed757e7 100644
--- a/src/eval/index.ts
+++ b/src/eval/index.ts
@@ -1,7 +1,7 @@
import { identity, pipe } from 'fp-ts/function'
import { filter, takeLeftWhile, zip, zipWith } from 'fp-ts/Array'
import * as Option from 'fp-ts/Option'
-import { Expr, ListExpr } from '../types'
+import { index, Expr, ListExpr } from '../types'
import { match } from '../utils'
export interface MatchGroupIndexed<T = any> {
@@ -18,8 +18,6 @@ const group = <T>(value: T, index: number): MatchGroupIndexed<T> => ({
index,
})
-type index = number
-
const indexed = <T>(ls: T[]): Array<[number, T]> => ls.map((x, i) => [i, x])
const accumulateSkip = () => {
diff --git a/src/parser/index.ts b/src/parser/index.ts
index 2db91a4..a336b83 100644
--- a/src/parser/index.ts
+++ b/src/parser/index.ts
@@ -23,7 +23,7 @@ import {
tuple3,
whitespaces0,
} from './utils'
-import { Expr, ListExpr, Literal } from '../types'
+import { Expr, index, ListExpr, Literal } from '../types'
import * as Option from 'fp-ts/Option'
import { snd } from 'fp-ts/Tuple'
@@ -36,6 +36,13 @@ const anyBool = mapTo(symbol('\\b'), _ => Expr.AnyBool())
const truthy = mapTo(symbol('\\T'), _ => Expr.Truthy())
const falsey = mapTo(symbol('\\F'), _ => Expr.Falsey())
+const parseQuantifier = (s: Option.Option<string>, def: index): index =>
+ pipe(
+ s,
+ Option.map(s => parseInt(s, 10)),
+ Option.getOrElse(() => def),
+ )
+
const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> =
Either.chain(([expr, input]) =>
pipe(
@@ -44,6 +51,18 @@ const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> =
mapTo(symbol('*'), _ => Expr.ZeroOrMore({ expr })),
mapTo(symbol('+'), _ => Expr.OneOrMore({ expr })),
mapTo(symbol('?'), _ => Expr.Optional({ expr })),
+ mapTo(
+ pair(
+ prefixed(symbol('{'), optional(digits)),
+ delimited(symbol(','), optional(digits), symbol('}')),
+ ),
+ ([min, max]) =>
+ Expr.MinMax({
+ expr,
+ min: parseQuantifier(min, 0),
+ max: parseQuantifier(max, Infinity),
+ }),
+ ),
]),
Either.orElse(_ => Either.right([expr, input])),
),
diff --git a/src/types.ts b/src/types.ts
index 473f5e1..dd40ce9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -3,6 +3,8 @@ import { constructors, Union } from './utils'
type _ = never
+export type index = number
+
export type Literal = Union<{
String: string
Number: number
@@ -15,6 +17,7 @@ export type Expr = Union<{
End: _
Optional: { expr: Expr }
OneOrMore: { expr: Expr }
+ MinMax: { expr: Expr, min: index, max: index }
ZeroOrMore: { expr: Expr }
AnyItem: _
Or: { exprs: Expr[] }
diff --git a/tests/parser.spec.ts b/tests/parser.spec.ts
index 6033040..13a8838 100644
--- a/tests/parser.spec.ts
+++ b/tests/parser.spec.ts
@@ -14,7 +14,7 @@ import {
import { parser } from '../src/parser'
import { none, some } from 'fp-ts/Option'
import { Expr, Literal } from '../src/types'
-import {jlog} from '../src/utils'
+import { jlog } from '../src/utils'
const wrap = (e: Expr) => right([[none, e, none], ''])
const grouped = (l: Expr[]) => wrap(Expr.Group({ exprs: l }))
@@ -77,6 +77,37 @@ describe('Parser', () => {
'',
]),
)
+
+ expect(parser(/ \s([age \n]{ 2, 5 }) /.source)).toEqual(
+ grouped([
+ Expr.AnyString(),
+ Expr.MinMax({
+ expr: Expr.PropertyMatch({ name: 'age', expr: Expr.AnyNumber() }),
+ min: 2,
+ max: 5,
+ }),
+ ]),
+ )
+ expect(parser(/ \s([age \n]{ 2, }) /.source)).toEqual(
+ grouped([
+ Expr.AnyString(),
+ Expr.MinMax({
+ expr: Expr.PropertyMatch({ name: 'age', expr: Expr.AnyNumber() }),
+ min: 2,
+ max: Infinity,
+ }),
+ ]),
+ )
+ expect(parser(/ \s([age \n]{ , 20 }) /.source)).toEqual(
+ grouped([
+ Expr.AnyString(),
+ Expr.MinMax({
+ expr: Expr.PropertyMatch({ name: 'age', expr: Expr.AnyNumber() }),
+ min: 0,
+ max: 20,
+ }),
+ ]),
+ )
})
it('should or expressions', () => {
@@ -152,7 +183,11 @@ describe('Parser', () => {
wrap(Expr.Literal(Literal.String('foobar'))),
)
expect(parser(/ "\nwowksadj\n\t wjksdlsd'' !@#%^(&^%$) " /.source)).toEqual(
- wrap(Expr.Literal(Literal.String('\\nwowksadj\\n\\t wjksdlsd\'\' !@#%^(&^%$) '))),
+ wrap(
+ Expr.Literal(
+ Literal.String("\\nwowksadj\\n\\t wjksdlsd'' !@#%^(&^%$) "),
+ ),
+ ),
)
})