diff --git a/packages/core/src/systems/en-UK/long-count/parse.ts b/packages/core/src/systems/en-UK/long-count/parse.ts index 585751d..f55152e 100644 --- a/packages/core/src/systems/en-UK/long-count/parse.ts +++ b/packages/core/src/systems/en-UK/long-count/parse.ts @@ -30,6 +30,12 @@ import { TENS_ONES_SEPARATOR, TensName, THOUSAND, + DoParseState, + ParseGroupsMode, + ParserState, + parseOnes, + parseTenPlusOnes, + parseTens, } from '../../en/common'; const FINAL_TOKEN = '' as const; @@ -61,13 +67,6 @@ export const tokenize = (value: string) => ( .filter((maybeToken) => maybeToken.length > 0) ); -interface DoParseState { - groupNameCurrent: string; - millias: number[]; - milliaIndex: number; - done: boolean; -} - /** * Deconstructs a group name token (e.g. "million", "duodecillion", etc.) to its affixes and * parses them. @@ -219,50 +218,6 @@ const getGroupPlaceFromGroupName = (groupName: string) => { return bigGroupPlace * BigInt(2) + (groupName.startsWith(THOUSAND) ? BigInt(1) : BigInt(0)); }; -/** - * Mode of the group parser. - */ -enum ParseGroupsMode { - /** - * Initial mode. - */ - INITIAL = 'initial', - /** - * Has parsed a ones name. - */ - ONES_MODE = 'ones', - /** - * Has parsed a tens name. - */ - TENS_MODE = 'tens', - /** - * Has parsed a ten-plus-ones name. - */ - TEN_PLUS_ONES_MODE = 'tenPlusOnes', - /** - * Has parsed a "hundred" token. - */ - HUNDRED_MODE = 'hundred', - /** - * Has parsed a "thousand" or any "-illion" token. - */ - THOUSAND_MODE = 'thousand', - /** - * Done parsing. - */ - DONE = 'done', -} - -/** - * State of the group parser. - */ -interface ParserState { - lastToken?: string; - groups: Group[]; - mode: ParseGroupsMode; - negative: boolean; -} - const parseThousand = (acc: ParserState, token: string): ParserState => { const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; @@ -337,68 +292,6 @@ const parseFinal = (acc: ParserState): ParserState => { return acc; }; -const parseOnes = (acc: ParserState, token: string): ParserState => { - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - // Create next empty place - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.ONES_MODE, - groups: [...acc.groups, [...EMPTY_PLACE]], - }; - } - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.ONES_MODE, - }; -}; - -const parseTenPlusOnes = (acc: ParserState, token: string): ParserState => { - const tenPlusOnes = TEN_PLUS_ONES.findIndex((t) => t === token); - const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, - groups: [...acc.groups, [`01${tenPlusOnes}` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], - }; - } - - lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}` as GroupDigits; - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, - groups: [...acc.groups.slice(0, -1), lastGroup], - }; -}; - -const parseTens = (acc: ParserState, token: string): ParserState => { - const tens = TENS.findIndex((t) => t === token); - const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TENS_MODE, - groups: [...acc.groups, [`0${tens}0` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], - }; - } - - lastGroup[GROUP_DIGITS_INDEX] = ( - `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` - ) as GroupDigits; - - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TENS_MODE, - groups: [...acc.groups.slice(0, -1), lastGroup], - }; -}; - /** * Parses groups from a string. * @param tokens - The string to parse groups from. diff --git a/packages/core/src/systems/en-US/short-count/parse.ts b/packages/core/src/systems/en-US/short-count/parse.ts index e76c04f..53e3269 100644 --- a/packages/core/src/systems/en-US/short-count/parse.ts +++ b/packages/core/src/systems/en-US/short-count/parse.ts @@ -30,6 +30,12 @@ import { TENS_ONES_SEPARATOR, TensName, THOUSAND, + DoParseState, + ParseGroupsMode, + ParserState, + parseOnes, + parseTens, + parseTenPlusOnes, } from '../../en/common'; const FINAL_TOKEN = '' as const; @@ -55,13 +61,6 @@ export const tokenize = (value: string) => ( .filter((maybeToken) => maybeToken.length > 0) ); -interface DoParseState { - groupNameCurrent: string; - millias: number[]; - milliaIndex: number; - done: boolean; -} - /** * Deconstructs a group name token (e.g. "million", "duodecillion", etc.) to its affixes and * parses them. @@ -217,50 +216,6 @@ const getGroupPlaceFromGroupName = (groupName: string) => { return bigGroupPlace + BigInt(1); }; -/** - * Mode of the group parser. - */ -enum ParseGroupsMode { - /** - * Initial mode. - */ - INITIAL = 'initial', - /** - * Has parsed a ones name. - */ - ONES_MODE = 'ones', - /** - * Has parsed a tens name. - */ - TENS_MODE = 'tens', - /** - * Has parsed a ten-plus-ones name. - */ - TEN_PLUS_ONES_MODE = 'tenPlusOnes', - /** - * Has parsed a "hundred" token. - */ - HUNDRED_MODE = 'hundred', - /** - * Has parsed a "thousand" or any "-illion" token. - */ - THOUSAND_MODE = 'thousand', - /** - * Done parsing. - */ - DONE = 'done', -} - -/** - * State of the group parser. - */ -interface ParserState { - lastToken?: string; - groups: Group[]; - mode: ParseGroupsMode; - negative: boolean; -} - const parseThousand = (acc: ParserState, token: string): ParserState => { const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; @@ -335,68 +290,6 @@ const parseFinal = (acc: ParserState): ParserState => { return acc; }; -const parseOnes = (acc: ParserState, token: string): ParserState => { - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - // Create next empty place - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.ONES_MODE, - groups: [...acc.groups, [...EMPTY_PLACE]], - }; - } - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.ONES_MODE, - }; -}; - -const parseTenPlusOnes = (acc: ParserState, token: string): ParserState => { - const tenPlusOnes = TEN_PLUS_ONES.findIndex((t) => t === token); - const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, - groups: [...acc.groups, [`01${tenPlusOnes}` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], - }; - } - - lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}` as GroupDigits; - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, - groups: [...acc.groups.slice(0, -1), lastGroup], - }; -}; - -const parseTens = (acc: ParserState, token: string): ParserState => { - const tens = TENS.findIndex((t) => t === token); - const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; - if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TENS_MODE, - groups: [...acc.groups, [`0${tens}0` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], - }; - } - - lastGroup[GROUP_DIGITS_INDEX] = ( - `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` - ) as GroupDigits; - - return { - ...acc, - lastToken: token, - mode: ParseGroupsMode.TENS_MODE, - groups: [...acc.groups.slice(0, -1), lastGroup], - }; -}; - /** * Parses groups from a string. * @param tokens - The string to parse groups from. diff --git a/packages/core/src/systems/en/common.ts b/packages/core/src/systems/en/common.ts index 30fa4ab..0126fbf 100644 --- a/packages/core/src/systems/en/common.ts +++ b/packages/core/src/systems/en/common.ts @@ -1,4 +1,10 @@ -import { Group, GroupPlace } from '../../common'; +import { + Group, + GROUP_DIGITS_INDEX, + GROUP_PLACE_INDEX, + GroupDigits, + GroupPlace, +} from '../../common'; export const GROUP_SEPARATOR = ' ' as const; @@ -341,3 +347,116 @@ export const makeNegative = (s: string) => { const negativePrefix = `${NEGATIVE} `; return s.startsWith(negativePrefix) ? s.slice(negativePrefix.length) : `${negativePrefix}${s}`; }; + +export interface DoParseState { + groupNameCurrent: string; + millias: number[]; + milliaIndex: number; + done: boolean; +} + +/** + * Mode of the group parser. + */ +export enum ParseGroupsMode { + /** + * Initial mode. + */ + INITIAL = 'initial', + /** + * Has parsed a ones name. + */ + ONES_MODE = 'ones', + /** + * Has parsed a tens name. + */ + TENS_MODE = 'tens', + /** + * Has parsed a ten-plus-ones name. + */ + TEN_PLUS_ONES_MODE = 'tenPlusOnes', + /** + * Has parsed a "hundred" token. + */ + HUNDRED_MODE = 'hundred', + /** + * Has parsed a "thousand" or any "-illion" token. + */ + THOUSAND_MODE = 'thousand', + /** + * Done parsing. + */ + DONE = 'done', +} + +/** + * State of the group parser. + */ +export interface ParserState { + lastToken?: string; + groups: Group[]; + mode: ParseGroupsMode; + negative: boolean; +} + +export const parseOnes = (acc: ParserState, token: string): ParserState => { + if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { + // Create next empty place + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.ONES_MODE, + groups: [...acc.groups, [...EMPTY_PLACE]], + }; + } + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.ONES_MODE, + }; +}; + +export const parseTenPlusOnes = (acc: ParserState, token: string): ParserState => { + const tenPlusOnes = TEN_PLUS_ONES.findIndex((t) => t === token); + const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; + if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, + groups: [...acc.groups, [`01${tenPlusOnes}` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], + }; + } + + lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}` as GroupDigits; + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, + groups: [...acc.groups.slice(0, -1), lastGroup], + }; +}; + +export const parseTens = (acc: ParserState, token: string): ParserState => { + const tens = TENS.findIndex((t) => t === token); + const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; + if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.TENS_MODE, + groups: [...acc.groups, [`0${tens}0` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]], + }; + } + + lastGroup[GROUP_DIGITS_INDEX] = ( + `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` + ) as GroupDigits; + + return { + ...acc, + lastToken: token, + mode: ParseGroupsMode.TENS_MODE, + groups: [...acc.groups.slice(0, -1), lastGroup], + }; +};