summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2022-01-13 17:47:23 +0530
committerAkshay Nair <phenax5@gmail.com>2022-01-13 17:47:30 +0530
commitfc548093f151355842122912c582fc10a2d5acb2 (patch)
tree6140e512a596e501e8c08fabf5c37bb06d7ecac9 /src
parentb6e3ecb97b34d6cf623514b3ddbbf63e4f9b21ce (diff)
downloadelxr-fc548093f151355842122912c582fc10a2d5acb2.tar.gz
elxr-fc548093f151355842122912c582fc10a2d5acb2.zip
feat(parser): adds number and boolean literals
Diffstat (limited to 'src')
-rw-r--r--src/parser/index.ts38
-rw-r--r--src/parser/utils.ts29
-rw-r--r--src/types.ts9
3 files changed, 55 insertions, 21 deletions
diff --git a/src/parser/index.ts b/src/parser/index.ts
index c61364d..3943848 100644
--- a/src/parser/index.ts
+++ b/src/parser/index.ts
@@ -2,9 +2,11 @@ import { flow, pipe } from 'fp-ts/function'
import { chain, left, orElse, right } from 'fp-ts/lib/Either'
import {
delimited,
+ digits,
many0,
many1,
mapTo,
+ matchChar,
oneOf,
optional,
or,
@@ -18,7 +20,9 @@ import {
tuple3,
whitespaces0,
} from './utils'
-import { Expr, ListExpr } from '../types'
+import { Expr, ListExpr, Literal } from '../types'
+import {getOrElse, map} from 'fp-ts/lib/Option'
+import {snd} from 'fp-ts/lib/Tuple'
const start = mapTo(symbol('^'), _ => Expr.Start())
const end = mapTo(symbol('$'), _ => Expr.End())
@@ -76,6 +80,37 @@ const objectProperty = (input: string) =>
),
)
+const unsignedNum: Parser<number> = mapTo(pair(digits, optional(pair(matchChar('.'), digits))), ([int, decimal]) =>
+ pipe(
+ decimal,
+ map(snd),
+ getOrElse(() => '0'),
+ n => parseFloat(`${int}.${n}`),
+ )
+)
+
+const numberLiteral: Parser<Literal> = mapTo(
+ pair(optional(oneOf(['+', '-'])), unsignedNum),
+ ([signO, n]) =>
+ pipe(
+ signO,
+ getOrElse(() => '+'),
+ sign => (sign === '-' ? -1 : 1) * n,
+ Literal.Number,
+ )
+ ,
+)
+
+const booleanLiteral: Parser<Literal> = mapTo(oneOf(['true', 'false']), b =>
+ Literal.Boolean(b === 'true' ? true : false),
+)
+
+const literalP: Parser<Literal> = delimited(
+ whitespaces0,
+ or([booleanLiteral, numberLiteral]),
+ whitespaces0,
+)
+
const expressionP: Parser<Expr> = (input: string) =>
pipe(
input,
@@ -91,6 +126,7 @@ const expressionP: Parser<Expr> = (input: string) =>
anyBool,
truthy,
falsey,
+ mapTo(literalP, Expr.Literal),
]),
wrapQuantifiers,
wrapAlt,
diff --git a/src/parser/utils.ts b/src/parser/utils.ts
index 841d77c..908405e 100644
--- a/src/parser/utils.ts
+++ b/src/parser/utils.ts
@@ -10,7 +10,7 @@ import {
orElseW,
} from 'fp-ts/Either'
import { none, some, Option } from 'fp-ts/Option'
-import { mapFst, mapSnd, snd } from 'fp-ts/Tuple'
+import { fst, mapFst, mapSnd, snd } from 'fp-ts/Tuple'
import { eq } from '../utils'
export type char = string
@@ -46,7 +46,7 @@ export const many1 = <T>(parser: Parser<T>): Parser<Array<T>> =>
chain(([res, inp]) =>
res.length > 0
? right([res, inp])
- : left([`many1 failed to parse at ${inp}`, inp]),
+ : left([`many1 failed to parse at '${inp}'`, inp]),
),
),
)
@@ -66,21 +66,16 @@ const recoverInput =
)
export const prefixed = <T>(a: Parser<any>, b: Parser<T>): Parser<T> =>
- recoverInput(flow(a, chain(flow(snd, b))))
+ recoverInput(mapTo(pair(a, b), snd))
export const suffixed = <T>(a: Parser<T>, b: Parser<any>): Parser<T> =>
- recoverInput(
- flow(
- a,
- chain(([out, inp]) => pipe(inp, b, map(mapFst(_ => out)))),
- ),
- )
+ recoverInput(mapTo(pair(a, b), fst))
export const delimited = <T>(
p: Parser<any>,
a: Parser<T>,
s: Parser<any>,
-): Parser<T> => recoverInput(suffixed(prefixed(p, a), s))
+): Parser<T> => suffixed(prefixed(p, a), s)
export const satifyChar =
(f: (c: char) => boolean): Parser<char> =>
@@ -92,9 +87,9 @@ export const satifyChar =
export const digit = satifyChar(c => /^[0-9]$/g.test(c))
-export const integer: Parser<number> = flow(
+export const digits: Parser<string> = flow(
many1(digit),
- map(mapFst(ds => parseInt(ds.join(''), 10))),
+ map(mapFst(ds => ds.join(''))),
)
export const or = <T>(parsers: Parser<T>[]): Parser<T> => {
@@ -111,13 +106,6 @@ export const or = <T>(parsers: Parser<T>[]): Parser<T> => {
export const matchChar = (ch: char): Parser<char> => satifyChar(eq(ch))
-export const space = matchChar(' ')
-export const newline = matchChar('\n')
-export const tab = matchChar('\t')
-
-export const whitespace = or([space, newline, tab])
-export const whitespaces0 = many0(whitespace)
-
export const matchString =
(s: string): Parser<string> =>
(input: string) =>
@@ -127,6 +115,9 @@ export const matchString =
export const oneOf = (xs: string[]): Parser<string> => or(xs.map(matchString))
+export const whitespace = oneOf([' ', '\n', '\t'])
+export const whitespaces0 = many0(whitespace)
+
export const symbol = (s: string): Parser<string> =>
delimited(whitespaces0, matchString(s), whitespaces0)
diff --git a/src/types.ts b/src/types.ts
index d30413d..ac577a1 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -3,6 +3,13 @@ import { constructors, Union } from "./utils"
type _ = never
+export type Literal = Union<{
+ String: string,
+ Number: number,
+ Boolean: boolean,
+}>
+export const Literal = constructors<Literal>()
+
export type Expr = Union<{
Start: _,
End: _,
@@ -19,8 +26,8 @@ export type Expr = Union<{
Falsey: _,
Group: { exprs: Expr[] },
PropertyMatch: { name: string, exprs: Expr[] },
+ Literal: Literal,
}>
-
export const Expr = constructors<Expr>()
export type ListExpr = [