diff options
| author | Akshay Nair <phenax5@gmail.com> | 2022-01-13 17:47:23 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2022-01-13 17:47:30 +0530 |
| commit | fc548093f151355842122912c582fc10a2d5acb2 (patch) | |
| tree | 6140e512a596e501e8c08fabf5c37bb06d7ecac9 /src/parser | |
| parent | b6e3ecb97b34d6cf623514b3ddbbf63e4f9b21ce (diff) | |
| download | elxr-fc548093f151355842122912c582fc10a2d5acb2.tar.gz elxr-fc548093f151355842122912c582fc10a2d5acb2.zip | |
feat(parser): adds number and boolean literals
Diffstat (limited to 'src/parser')
| -rw-r--r-- | src/parser/index.ts | 38 | ||||
| -rw-r--r-- | src/parser/utils.ts | 29 |
2 files changed, 47 insertions, 20 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) |
