diff options
author | Tim Reichen <timreichen@users.noreply.github.com> | 2020-08-15 16:37:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-15 10:37:17 -0400 |
commit | 684eddcc6bf0c1446c9aba0cdf001c661c19ab24 (patch) | |
tree | 134f5f1609cf9f35295f841e27ba26d64c720795 /std/datetime/tokenizer.ts | |
parent | b684df784ef0ecbdf8bc3b6015177b6829420f86 (diff) |
feat(std/datetime): generalise parser, add formatter (#6619)
Diffstat (limited to 'std/datetime/tokenizer.ts')
-rw-r--r-- | std/datetime/tokenizer.ts | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/std/datetime/tokenizer.ts b/std/datetime/tokenizer.ts new file mode 100644 index 000000000..05314b770 --- /dev/null +++ b/std/datetime/tokenizer.ts @@ -0,0 +1,69 @@ +export type Token = { + type: string; + value: string | number; + index: number; +}; + +interface ReceiverResult { + [name: string]: string | number; +} +export type CallbackResult = { type: string; value: string | number }; +type CallbackFunction = (value: unknown) => CallbackResult; + +export type TestResult = { value: unknown; length: number } | undefined; +export type TestFunction = ( + string: string, +) => TestResult | undefined; + +export interface Rule { + test: TestFunction; + fn: CallbackFunction; +} + +export class Tokenizer { + rules: Rule[]; + + constructor(rules: Rule[] = []) { + this.rules = rules; + } + + addRule(test: TestFunction, fn: CallbackFunction): Tokenizer { + this.rules.push({ test, fn }); + return this; + } + + tokenize( + string: string, + receiver = (token: Token): ReceiverResult => token, + ): ReceiverResult[] { + function* generator(rules: Rule[]): IterableIterator<ReceiverResult> { + let index = 0; + for (const rule of rules) { + const result = rule.test(string); + if (result) { + const { value, length } = result; + index += length; + string = string.slice(length); + const token = { ...rule.fn(value), index }; + yield receiver(token); + yield* generator(rules); + } + } + } + const tokenGenerator = generator(this.rules); + + const tokens: ReceiverResult[] = []; + + for (const token of tokenGenerator) { + tokens.push(token); + } + + if (string.length) { + throw new Error( + `parser error: string not fully parsed! ${string.slice(0, 25)}`, + ); + } + + return tokens; + } +} |