aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2022-01-08 21:12:20 +0530
committerAkshay Nair <phenax5@gmail.com>2022-01-08 21:12:20 +0530
commite246f2341ee13926f4273c6d634cef4fe07f040e (patch)
tree2dfcbdb24004b85c1a6ab2ed11c211621489c9a3
parent61bb1f0c8b109c66d48e678a4d2cf7cb29cf7efb (diff)
downloadelxr-e246f2341ee13926f4273c6d634cef4fe07f040e.tar.gz
elxr-e246f2341ee13926f4273c6d634cef4fe07f040e.zip
feat(parse): implements object property matching parser
-rw-r--r--src/parser/index.ts51
-rw-r--r--src/parser/utils.ts6
-rw-r--r--src/types.ts1
-rw-r--r--tests/parser.spec.ts20
4 files changed, 61 insertions, 17 deletions
diff --git a/src/parser/index.ts b/src/parser/index.ts
index 4ad3e7b..2f5781e 100644
--- a/src/parser/index.ts
+++ b/src/parser/index.ts
@@ -1,30 +1,36 @@
-import { pipe } from 'fp-ts/function'
-import { chain, orElse, right } from 'fp-ts/lib/Either'
+import { flow, pipe } from 'fp-ts/function'
+import { chain, left, orElse, right } from 'fp-ts/lib/Either'
import {
delimited,
+ many0,
many1,
mapTo,
+ oneOf,
optional,
or,
+ pair,
Parser,
ParserResult,
prefixed,
+ satifyChar,
+ suffixed,
symbol,
tuple3,
+ whitespaces0,
} from './utils'
import { Expr, ListExpr } from '../types'
-export const start = mapTo(symbol('^'), _ => Expr.Start(null))
-export const end = mapTo(symbol('$'), _ => Expr.End(null))
-export const anyItem = mapTo(symbol('.'), _ => Expr.AnyItem(null))
-export const nextItem = mapTo(symbol(','), _ => Expr.NextItem(null))
-export const anyString = mapTo(symbol('\\s'), _ => Expr.AnyString(null))
-export const anyNumber = mapTo(symbol('\\n'), _ => Expr.AnyNumber(null))
-export const anyBool = mapTo(symbol('\\b'), _ => Expr.AnyBool(null))
-export const truthy = mapTo(symbol('\\T'), _ => Expr.Truthy(null))
-export const falsey = mapTo(symbol('\\F'), _ => Expr.Falsey(null))
+const start = mapTo(symbol('^'), _ => Expr.Start(null))
+const end = mapTo(symbol('$'), _ => Expr.End(null))
+const anyItem = mapTo(symbol('.'), _ => Expr.AnyItem(null))
+const nextItem = mapTo(symbol(','), _ => Expr.NextItem(null))
+const anyString = mapTo(symbol('\\s'), _ => Expr.AnyString(null))
+const anyNumber = mapTo(symbol('\\n'), _ => Expr.AnyNumber(null))
+const anyBool = mapTo(symbol('\\b'), _ => Expr.AnyBool(null))
+const truthy = mapTo(symbol('\\T'), _ => Expr.Truthy(null))
+const falsey = mapTo(symbol('\\F'), _ => Expr.Falsey(null))
-export const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> =
+const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> =
chain(([expr, input]) =>
pipe(
input,
@@ -37,7 +43,7 @@ export const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> =
),
)
-export const wrapAlt: (e: ParserResult<Expr>) => ParserResult<Expr> = chain(
+const wrapAlt: (e: ParserResult<Expr>) => ParserResult<Expr> = chain(
([expr, input]) =>
pipe(
input,
@@ -48,13 +54,30 @@ export const wrapAlt: (e: ParserResult<Expr>) => ParserResult<Expr> = chain(
),
)
-export const expressionP: Parser<Expr> = (input: string) =>
+const propRegex = /^[A-Za-z0-9_-]$/
+
+export const propertyName: Parser<string> = pipe(
+ satifyChar(c => propRegex.test(c)),
+ many1,
+ p => mapTo(p, xs => xs.join('')),
+ p => suffixed(p, whitespaces0),
+)
+
+const objectProperty = (input: string) => pipe(
+ input,
+ mapTo(delimited(symbol('['), pair(propertyName, many0(expressionP)), symbol(']')), ([name, exprs]) =>
+ Expr.PropertyMatch({ name, exprs }),
+ ),
+)
+
+const expressionP: Parser<Expr> = (input: string) =>
pipe(
input,
or([
mapTo(delimited(symbol('('), many1(expressionP), symbol(')')), exprs =>
Expr.Group({ exprs }),
),
+ objectProperty,
nextItem,
anyItem,
anyString,
diff --git a/src/parser/utils.ts b/src/parser/utils.ts
index debff22..9e05286 100644
--- a/src/parser/utils.ts
+++ b/src/parser/utils.ts
@@ -40,14 +40,14 @@ export const many0 = <T>(parser: Parser<T>): Parser<Array<T>> =>
)
export const many1 = <T>(parser: Parser<T>): Parser<Array<T>> =>
- flow(
+ recoverInput(flow(
many0(parser),
chain(([res, inp]) =>
res.length > 0
? right([res, inp])
: left([`many1 failed to parse at ${inp}`, inp]),
),
- )
+ ))
const recoverInput =
<T>(p: Parser<T>): Parser<T> =>
@@ -123,6 +123,8 @@ export const matchString =
? right([s, input.slice(s.length)])
: left([`Expected ${s} but got ${input.slice(0, 1)}`, input])
+export const oneOf = (xs: string[]): Parser<string> => or(xs.map(matchString))
+
export const symbol = (s: string): Parser<string> =>
delimited(whitespaces0, matchString(s), whitespaces0)
diff --git a/src/types.ts b/src/types.ts
index 979745f..07e6e8a 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -16,6 +16,7 @@ type ExprT = {
Truthy: null,
Falsey: null,
Group: { exprs: Expr[] },
+ PropertyMatch: { name: string, exprs: Expr[] },
}
export type Expr = Union<ExprT>
diff --git a/tests/parser.spec.ts b/tests/parser.spec.ts
index 150966b..1ebd290 100644
--- a/tests/parser.spec.ts
+++ b/tests/parser.spec.ts
@@ -4,8 +4,10 @@ import {
whitespace,
whitespaces0,
delimited,
+ many1,
+ satifyChar,
} from '../src/parser/utils'
-import { parser } from '../src/parser'
+import { parser, propertyName } from '../src/parser'
import { none, some } from 'fp-ts/Option'
import { Expr } from '../src/types'
@@ -82,4 +84,20 @@ describe('Foobar', () => {
]),
)
})
+
+ it('object proprtyu', () => {
+ expect(parser(/ [name \s\T] [age \n] /.source)).toEqual(
+ right([
+ [
+ none,
+ [
+ Expr.PropertyMatch({ name: 'name', exprs: [Expr.AnyString(null), Expr.Truthy(null)] }),
+ Expr.PropertyMatch({ name: 'age', exprs: [Expr.AnyNumber(null)] }),
+ ],
+ none,
+ ],
+ '',
+ ]),
+ )
+ })
})