From 2ed6d2a3b4ddf37f66f0f7f529341e12a0d3dfa0 Mon Sep 17 00:00:00 2001 From: stagas Date: Sun, 28 Nov 2021 17:28:12 +0200 Subject: [PATCH] feature: make peek more useful by passing group and value --- src/index.spec.ts | 64 ++++++++++++++++++++++++++++++++++++++++++++--- src/index.ts | 18 +++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/index.spec.ts b/src/index.spec.ts index 79623aa..528e0ad 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -37,7 +37,7 @@ describe('createLexer', () => { expect(error?.message).toContain('Unexpected') } - expect(l.accept('foo')).toBeUndefined() + expect(l.accept('foo')).toBeNull() expect(l.peek()).toEqual({ group: 'ident', @@ -70,15 +70,15 @@ describe('createLexer', () => { const lexer = createLexer(tokenizer) const l = lexer('foo bar baz') - expect(l.accept('ident', 'hello')).toBeUndefined() - expect(l.accept('any', 'foo')).toBeUndefined() + expect(l.accept('ident', 'hello')).toBeNull() + expect(l.accept('any', 'foo')).toBeNull() expect(l.accept('ident', 'foo')).toEqual({ group: 'ident', value: 'foo', index: 0 }) - expect(l.accept('ident', 'foo')).toBeUndefined() + expect(l.accept('ident', 'foo')).toBeNull() expect(l.accept('ident', 'bar')).toEqual({ group: 'ident', value: 'bar', @@ -201,4 +201,60 @@ describe('createLexer', () => { expect(source).toEqual({ input }) expect(l.advance()!.source).toBe(source) }) + + it('peek(group?, value?)', () => { + const tokenizer = (input: string) => + input.matchAll(/(?[a-z]+)|(?[0-9]+)/g) + const lexer = createLexer(tokenizer) + + const l = lexer('foo 0123 bar 456 baz') + + expect(l.peek()).toEqual({ + group: 'ident', + value: 'foo', + index: 0 + }) + + expect(l.peek('ident')).toEqual({ + group: 'ident', + value: 'foo', + index: 0 + }) + + expect(l.peek('ident', 'foo')).toEqual({ + group: 'ident', + value: 'foo', + index: 0 + }) + + expect(l.peek('ident', 'yo')).toBeNull() + + expect(l.peek('number')).toBeNull() + + expect(l.peek('number', '0123')).toBeNull() + + l.advance() + + expect(l.peek()).toEqual({ + group: 'number', + value: '0123', + index: 4 + }) + + expect(l.peek('number')).toEqual({ + group: 'number', + value: '0123', + index: 4 + }) + + expect(l.peek('number', '0123')).toEqual({ + group: 'number', + value: '0123', + index: 4 + }) + + expect(l.peek('number', '012')).toBeNull() + + expect(l.peek('ident')).toBeNull() + }) }) diff --git a/src/index.ts b/src/index.ts index edfb65c..b0240b3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,8 +59,13 @@ export interface Lexer { advance: () => LexerToken /** * Returns token under current position. + * When passed a `group` and maybe a `value` it will only return + * the token if they match, otherwise will return `null`. + * + * @param group The group name to examine + * @param value The value to match */ - peek: () => LexerToken + peek: (group?: string, value?: string) => LexerToken | null /** * Advances position only when current `token.group` matches `group`, * and optionally when `token.value` matches `value`, @@ -165,7 +170,16 @@ export const createLexer = const advance = () => (([last, curr] = [curr, next()]), last) - const peek = () => curr + const peek = (group?: string, value?: string) => + group != null + ? curr.group === group + ? value != null + ? curr.value === value + ? curr + : null + : curr + : null + : curr const accept = (group: string, value?: string) => curr.group === group && (value == null ? true : curr.value === value)