diff options
| -rw-r--r-- | src/parser/index.ts | 22 | ||||
| -rw-r--r-- | src/parser/utils.ts | 17 | ||||
| -rw-r--r-- | tests/parser.spec.ts | 10 |
3 files changed, 38 insertions, 11 deletions
diff --git a/src/parser/index.ts b/src/parser/index.ts index a2276bb..2db91a4 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -5,15 +5,18 @@ import { digits, many0, many1, + manyTill, mapTo, matchChar, + matchString, oneOf, optional, or, pair, Parser, ParserResult, - satifyChar, + prefixed, + satisfyChar, sepBy1, suffixed, symbol, @@ -49,7 +52,7 @@ const wrapQuantifiers: (e: ParserResult<Expr>) => ParserResult<Expr> = const propRegex = /^[A-Za-z0-9_-]$/ export const propertyName: Parser<string> = pipe( - satifyChar(c => propRegex.test(c)), + satisfyChar(c => propRegex.test(c)), many1, p => mapTo(p, xs => xs.join('')), p => suffixed(p, whitespaces0), @@ -94,9 +97,22 @@ const booleanLiteral: Parser<Literal> = mapTo(oneOf(['true', 'false']), b => Literal.Boolean(b === 'true' ? true : false), ) +const stringDelimiter = matchChar('"') + +const stringLiteral: Parser<Literal> = mapTo( + prefixed( + stringDelimiter, + manyTill( + satisfyChar(_ => true), + stringDelimiter, + ), + ), + s => Literal.String(s.join('')), +) + const literalP: Parser<Literal> = delimited( whitespaces0, - or([booleanLiteral, numberLiteral]), + or([booleanLiteral, numberLiteral, stringLiteral]), whitespaces0, ) diff --git a/src/parser/utils.ts b/src/parser/utils.ts index 4e2c9d6..564d97c 100644 --- a/src/parser/utils.ts +++ b/src/parser/utils.ts @@ -29,18 +29,20 @@ export const sepBy1 = <T>(sep: Parser<any>, parser: Parser<T>): Parser<T[]> => ), ) -export const not = (parser: Parser<any>): Parser<null> => (input: string) => +export const not = (parser: Parser<any>): Parser<never> => (input: string) => pipe( input, parser, Either.fold( - ([_left, inp]) => Either.right([null, inp]), + ([_left, inp]) => Either.right([null as never, inp]), ([_right, inp]) => Either.left(['`not` parser failed. Match found', inp]) ), ) -export const manyTill = <T>(parser: Parser<T>, end: Parser<any>): Parser<T[]> => - mapTo(pair(many0(suffixed(parser, not(end))), parser), ([xs, l]) => xs.concat([l])) +export const manyTill = <T>(parser: Parser<T>, end: Parser<any>): Parser<T[]> => { + const p = pair(many0(suffixed(parser, not(end))), suffixed(parser, end)) + return mapTo(p, ([xs, l]) => xs.concat([l])) +} export const many0 = <T>(parser: Parser<T>): Parser<Array<T>> => flow( @@ -94,15 +96,16 @@ export const delimited = <T>( s: Parser<any>, ): Parser<T> => suffixed(prefixed(p, a), s) -export const satifyChar = +export const satisfyChar = (f: (c: char) => boolean): Parser<char> => (input: string) => { + if (input.length === 0) return Either.left(['Unexpected end of input', input]) const c = input.charAt(0) if (f(c)) return Either.right([c, input.slice(1)]) return Either.left([`Expected to satisfy ${f}, got "${c}"`, input]) } -export const digit = satifyChar(c => /^[0-9]$/g.test(c)) +export const digit = satisfyChar(c => /^[0-9]$/g.test(c)) export const digits: Parser<string> = flow( many1(digit), @@ -121,7 +124,7 @@ export const or = <T>(parsers: Parser<T>[]): Parser<T> => { : (inp: string) => Either.left(['unable to match', inp]) } -export const matchChar = (ch: char): Parser<char> => satifyChar(eq(ch)) +export const matchChar = (ch: char): Parser<char> => satisfyChar(eq(ch)) export const matchString = (s: string): Parser<string> => diff --git a/tests/parser.spec.ts b/tests/parser.spec.ts index 0506be0..6033040 100644 --- a/tests/parser.spec.ts +++ b/tests/parser.spec.ts @@ -6,7 +6,7 @@ import { delimited, not, symbol, - satifyChar, + satisfyChar, matchChar, manyTill, pair, @@ -146,6 +146,14 @@ describe('Parser', () => { expect(parser(/ false /.source)).toEqual( wrap(Expr.Literal(Literal.Boolean(false))), ) + + // String literal + expect(parser(/ "foobar" /.source)).toEqual( + wrap(Expr.Literal(Literal.String('foobar'))), + ) + expect(parser(/ "\nwowksadj\n\t wjksdlsd'' !@#%^(&^%$) " /.source)).toEqual( + wrap(Expr.Literal(Literal.String('\\nwowksadj\\n\\t wjksdlsd\'\' !@#%^(&^%$) '))), + ) }) it('sequence of values', () => { |
