From 2102e7608b1b3634a651cb40508d2f560f3eeb05 Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Thu, 10 Aug 2023 22:04:02 +0530 Subject: feat: adds string literal and css variable identifier parsers --- src/parse-expr.ts | 50 ++++++++++++++++++++++++++++++++---------------- tests/parse-expr.spec.ts | 31 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/parse-expr.ts b/src/parse-expr.ts index ec387d6..1c5c08f 100644 --- a/src/parse-expr.ts +++ b/src/parse-expr.ts @@ -1,42 +1,61 @@ -import { Enum, constructors, match } from './utils/adt'; +import { Enum, constructors, match } from './utils/adt' import * as P from './utils/parser-comb' export type Expr = Enum<{ - Call: { name: string, args: Expr[] } - Var: { name: string, defaultValue: Expr } + Call: { name: string; args: Expr[] } Identifier: string - Chain: { exprs: Expr[] } + VarIdentifier: string LiteralString: string }> export const Expr = constructors() -const whitespace = P.regex(/\s*/) -const consumeWhitespace = (p: P.Parser): P.Parser => P.between(whitespace, p, whitespace) +const whitespace = P.regex(/^\s*/) +const consumeWhitespace = (p: P.Parser): P.Parser => + P.between(whitespace, p, whitespace) const comma = consumeWhitespace(P.string(',')) -const parens = (p: P.Parser): P.Parser => P.between(P.string('('), p, P.string(')')) +const parens = (p: P.Parser): P.Parser => + P.between(P.string('('), p, P.string(')')) const identifierParser = P.regex(/^[a-z][a-z0-9_-]*/i) +const varIdentifierParser = P.regex(/^--[a-z][a-z0-9-]*/i) +const singleQuote = P.string("'") +const doubleQuote = P.string('"') -const identifierExprParser = P.map(identifierParser, ident => Expr.Identifier(ident)) +const identifierExprParser = P.map(identifierParser, Expr.Identifier) +const varIdentifierExprParser = P.map(varIdentifierParser, Expr.VarIdentifier) -const callExprParser = (input: string) => P.map(P.zip2( - consumeWhitespace(identifierParser), - parens(consumeWhitespace(P.sepBy(exprParser, comma))), -), ([name, args]) => Expr.Call({ name, args }))(input) +const callExprParser = (input: string) => + P.map( + P.zip2( + consumeWhitespace(identifierParser), + parens(consumeWhitespace(P.sepBy(exprParser, comma))) + ), + ([name, args]) => Expr.Call({ name, args }) + )(input) + +const stringLiteralParser: P.Parser = P.map( + P.or([ + P.between(singleQuote, P.regex(/^[^']*/), singleQuote), + P.between(doubleQuote, P.regex(/^[^"]*/), doubleQuote), + ]), + Expr.LiteralString +) const exprParser: P.Parser = P.or([ + stringLiteralParser, + varIdentifierExprParser, callExprParser, identifierExprParser, ]) -const multiExpr = P.many1(exprParser) +const multiExprParser = P.many1(exprParser) export const parse = (input: string): Array => { - const res = multiExpr(input.trim()); + const res = multiExprParser(input.trim()) return match(res, { Ok: ({ value, input }) => { if (input) { - throw new Error(`Input not consumed completely here brosky: "${input}"`) + throw new Error(`Input not consumed completely here brosky: "${input}"`) } return value }, @@ -45,4 +64,3 @@ export const parse = (input: string): Array => { }, }) } - diff --git a/tests/parse-expr.spec.ts b/tests/parse-expr.spec.ts index 875af63..f873464 100644 --- a/tests/parse-expr.spec.ts +++ b/tests/parse-expr.spec.ts @@ -42,4 +42,35 @@ describe('parser', () => { }), ]) }) + + it('should parse string literal', () => { + expect(parse(`"hello world toodles \' nice single quote there"`)).toEqual([ + Expr.LiteralString(`hello world toodles \' nice single quote there`), + ]) + + expect(parse(` 'hello world toodles \" nice double quote there' `)).toEqual( + [Expr.LiteralString(`hello world toodles \" nice double quote there`)] + ) + }) + + it('should parse var identifiers', () => { + expect(parse(`var(--hello, 'default')`)).toEqual([ + Expr.Call({ + name: 'var', + args: [Expr.VarIdentifier('--hello'), Expr.LiteralString(`default`)], + }), + ]) + + expect(parse(`calc(var(--hello))`)).toEqual([ + Expr.Call({ + name: 'calc', + args: [ + Expr.Call({ + name: 'var', + args: [Expr.VarIdentifier('--hello')], + }), + ], + }), + ]) + }) }) -- cgit v1.3.1