diff --git a/packages/parse/src/presets/alpha.ts b/packages/parse/src/presets/alpha.ts index 71f1bb6902..5c51edd11d 100644 --- a/packages/parse/src/presets/alpha.ts +++ b/packages/parse/src/presets/alpha.ts @@ -1,23 +1,23 @@ +import { ALPHA as _ALPHA, ALPHA_NUM as _ALPHA_NUM } from "@thi.ng/strings"; +import { oneOf } from "../prims/one-of"; import { range } from "../prims/range"; -import { alt } from "../combinators/alt"; -import { DIGIT } from "./digits"; /** * Matches single char in `a` - `z` range. */ -export const LOWER_CASE = range("a", "z"); +export const LOWER_CASE = range("a", "z"); /** * Matches single char in `A` - `Z` range. */ -export const UPPER_CASE = range("A", "Z"); +export const UPPER_CASE = range("A", "Z"); /** * Matches single in {@link LOWER_CASE} or {@link UPPER_CASE}. */ -export const ALPHA = alt([LOWER_CASE, UPPER_CASE]); +export const ALPHA = oneOf(_ALPHA); /** * Matches single in {@link ALPHA} or {@link DIGIT}. */ -export const ALPHA_NUM = alt([ALPHA, DIGIT]); +export const ALPHA_NUM = oneOf(_ALPHA_NUM); diff --git a/packages/parse/src/presets/bits.ts b/packages/parse/src/presets/bits.ts new file mode 100644 index 0000000000..2e5acb942b --- /dev/null +++ b/packages/parse/src/presets/bits.ts @@ -0,0 +1,8 @@ +import { oneOf } from "../prims/one-of"; +import { xfInt } from "../xform/number"; +import { repeat } from "../combinators/repeat"; +import { xform } from "../combinators/xform"; + +export const BIT = oneOf("01"); + +export const BINARY_UINT = xform(repeat(BIT, 1, 32, "uint"), xfInt(2)); diff --git a/packages/parse/src/presets/digits.ts b/packages/parse/src/presets/digits.ts index 658f237043..c54c9b796c 100644 --- a/packages/parse/src/presets/digits.ts +++ b/packages/parse/src/presets/digits.ts @@ -1,32 +1,12 @@ -import { alt } from "../combinators/alt"; -import { oneOrMore, zeroOrMore } from "../combinators/repeat"; +import { oneOrMore } from "../combinators/repeat"; import { range } from "../prims/range"; /** * Matches single decimal digit. */ -export const DIGIT = range("0", "9", "digit"); - -/** - * Matches single hex digit (case insensitive). - */ -export const HEX_DIGIT = alt([ - DIGIT, - range("a", "f"), - range("A", "F"), -]); - -/** - * Matches zero or more {@link DIGIT}s. - */ -export const DIGITS_0 = zeroOrMore(DIGIT); +export const DIGIT = range("0", "9", "digit"); /** * Matches one or more {@link DIGIT}s. */ -export const DIGITS_1 = oneOrMore(DIGIT); - -/** - * Matches one or more {@link HEX_DIGIT}s. - */ -export const HEX_DIGITS_1 = oneOrMore(HEX_DIGIT); +export const DIGITS = oneOrMore(DIGIT); diff --git a/packages/parse/src/presets/escape.ts b/packages/parse/src/presets/escape.ts new file mode 100644 index 0000000000..263616a177 --- /dev/null +++ b/packages/parse/src/presets/escape.ts @@ -0,0 +1,22 @@ +import { always } from "../prims/always"; +import { litD } from "../prims/lit"; +import { seq } from "../combinators/seq"; +import { hoist } from "../xform/hoist"; +import { xform } from "../combinators/xform"; +import { repeat } from "../combinators/repeat"; +import { HEX_DIGIT } from "./hex"; +import { stringD } from "../prims/string"; +import { xfInt } from "../xform/number"; + +export const ESC = hoist(seq([litD("\\"), always()], "esc")); + +/** + * Matches a single `\uNNNN` escaped unicode hex literal and transforms + * it into it actual character via `String.fromCharCode()`. + */ +export const UNICODE = xform( + seq([stringD("\\u"), repeat(HEX_DIGIT, 4, 4)], "unicode"), + ($, ctx) => ( + ($!.result = String.fromCharCode(xfInt(16)($, ctx)!.result)), $ + ) +); diff --git a/packages/parse/src/presets/hex.ts b/packages/parse/src/presets/hex.ts new file mode 100644 index 0000000000..a728a77cf2 --- /dev/null +++ b/packages/parse/src/presets/hex.ts @@ -0,0 +1,21 @@ +import { HEX } from "@thi.ng/strings"; +import { oneOrMore, repeat } from "../combinators/repeat"; +import { xform } from "../combinators/xform"; +import { oneOf } from "../prims/one-of"; +import { xfInt } from "../xform/number"; + +/** + * Matches single hex digit (case insensitive). + */ +export const HEX_DIGIT = oneOf(HEX); + +/** + * Matches one or more {@link HEX_DIGIT}s. + */ +export const HEX_DIGITS = oneOrMore(HEX_DIGIT); + +/** + * Matches 1-8 successive {@link HEX_DIGIT} and transforms with + * {@link xfInt} to JS number. + */ +export const HEX_UINT = xform(repeat(HEX_DIGIT, 1, 8, "uint"), xfInt(16)); diff --git a/packages/parse/src/presets/numbers.ts b/packages/parse/src/presets/numbers.ts index fe5d491d7a..c66f663ccf 100644 --- a/packages/parse/src/presets/numbers.ts +++ b/packages/parse/src/presets/numbers.ts @@ -1,11 +1,15 @@ import { alt } from "../combinators/alt"; import { maybe } from "../combinators/maybe"; +import { zeroOrMore } from "../combinators/repeat"; import { seq } from "../combinators/seq"; import { xform } from "../combinators/xform"; import { lit } from "../prims/lit"; import { oneOf } from "../prims/one-of"; +import { comp } from "../xform/comp"; +import { join } from "../xform/join"; import { xfFloat, xfInt } from "../xform/number"; -import { DIGITS_0, DIGITS_1, HEX_DIGITS_1 } from "./digits"; +import { xfID } from "../xform/with-id"; +import { DIGIT, DIGITS } from "./digits"; /** * Matches single `+` or `-` char. @@ -13,35 +17,33 @@ import { DIGITS_0, DIGITS_1, HEX_DIGITS_1 } from "./digits"; export const SIGN = maybe(oneOf("-+")); /** - * Matches optionally signed {@link DIGITS_1} and result transformed w/ + * Matches optionally signed {@link DIGITS} and result transformed w/ * {@link xfInt} to JS number. */ -export const INT = xform(seq([SIGN, DIGITS_1], "int"), xfInt()); +export const INT = xform(seq([SIGN, DIGITS], "int"), xfInt()); /** - * Matches same as {@link DIGITS_1}, but result transformed w/ + * Matches same as {@link DIGITS} but result transformed w/ * {@link xfInt} to JS number. */ -export const UINT = xform(DIGITS_1, xfInt()); +export const UINT = xform(DIGITS, comp(xfID("uint"), xfInt())); -/** - * Matches same as {@link HEX_DIGITS_1}, but result transformed w/ - * {@link xfInt} to JS number. - */ -export const HEX_UINT = xform(HEX_DIGITS_1, xfInt(16)); - -const EXP = maybe(seq([maybe(oneOf("eE")), SIGN, DIGITS_1])); +const EXP = maybe(seq([maybe(oneOf("eE")), SIGN, DIGITS])); const DOT = lit("."); -const FRACT0 = maybe(seq([DOT, DIGITS_0])); -const FRACT1 = seq([DOT, DIGITS_1]); +const FRACT0 = maybe(seq([DOT, zeroOrMore(DIGIT)])); +const FRACT1 = seq([DOT, DIGITS]); + +const _REAL = seq([SIGN, alt([FRACT1, seq([DIGITS, FRACT0])]), EXP], "real"); + +/** + * Matches IEEE754 floating point number. + */ +export const REAL = join(_REAL); /** - * Matches IEEE754 floating point number and transforms result w/ - * {@link xfFloat}. + * Like {@link REAL} but transforms result w/ {@link xfFloat} to JS + * number. */ -export const FLOAT = xform( - seq([SIGN, alt([FRACT1, seq([DIGITS_1, FRACT0])]), EXP], "float"), - xfFloat -); +export const FLOAT = xform(_REAL, xfFloat); diff --git a/packages/parse/src/presets/whitespace.ts b/packages/parse/src/presets/whitespace.ts index 5f12bf7b02..a14f078d7c 100644 --- a/packages/parse/src/presets/whitespace.ts +++ b/packages/parse/src/presets/whitespace.ts @@ -1,16 +1,16 @@ import { discard } from "../combinators/discard"; import { oneOrMore, zeroOrMore } from "../combinators/repeat"; -import { oneOf } from "../prims/one-of"; +import { oneOf, oneOfD } from "../prims/one-of"; /** - * Matches single whitespace char. + * Matches & discards single whitespace char: ` \t\n\r`. */ -export const WS = oneOf(" \t\n\r", "ws"); +export const WS = oneOfD(" \t\n\r"); /** - * Matches single space or tab char. + * Matches & discards single space or tab char. */ -export const SPACE = oneOf(" \t", "space"); +export const SPACE = oneOfD(" \t"); /** * Matches single `\n` or `\r` char. @@ -20,24 +20,24 @@ export const NL = oneOf("\n\r"); /** * Matches & discards single `\n` or `\r` char. */ -export const DNL = discard(NL); +export const DNL = oneOfD("\n\r"); /** * Zero or more {@link WS}. Result will be discarded. */ -export const WS_0 = discard(zeroOrMore(WS)); +export const WS0 = discard(zeroOrMore(WS)); /** * One or more {@link WS}. Result will be discarded. */ -export const WS_1 = discard(oneOrMore(WS)); +export const WS1 = discard(oneOrMore(WS)); /** * Zero or more {@link SPACE}. Result will be discarded. */ -export const SPACE_0 = discard(zeroOrMore(SPACE)); +export const SPACES0 = discard(zeroOrMore(SPACE)); /** * One or more {@link SPACE}. Result will be discarded. */ -export const SPACE_1 = discard(oneOrMore(SPACE)); +export const SPACES = discard(oneOrMore(SPACE));