UNPKG

@masala/parser

Version:
142 lines (120 loc) 5.36 kB
import { describe, it, expect } from 'vitest' import Streams from '../../lib/stream/index' import { F, C } from '../../lib/parsec/index' describe('Chars Bundle Tests', () => { it('accepts a single character', () => { const stream = Streams.ofString('a') const parsing = F.regex(/[a-z]/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('a') expect(parsing.offset).toBe(1) }) it('consumes when accepting a single character', () => { const stream = Streams.ofString('aa') const parsing = F.regex(/[a-z]/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('a') expect(parsing.offset).toBe(1) }) it('do not consumes when rejecting a single character', () => { const stream = Streams.ofString('0a') const parsing = F.regex(/[a-z]/).parse(stream) expect(parsing.isAccepted()).toBe(false) expect(parsing.value).toBeUndefined() expect(parsing.offset).toBe(0) }) it('accepts multiple characters', () => { const stream = Streams.ofString('abc') const parsing = F.regex(/[a-z]+/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('abc') expect(parsing.offset).toBe(3) }) it('moves as long as possible eating multiple characters', () => { const stream = Streams.ofString('abc0') const parsing = F.regex(/[a-z]+/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('abc') expect(parsing.offset).toBe(3) }) it('star is accepted even rejects when no characters match', () => { const stream = Streams.ofString('0') const parsing = F.regex(/[a-z]*/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).not.toBeUndefined() // empty but accepted! expect(parsing.value).toBe('') expect(parsing.offset).toBe(0) }) it('accept a identifier building', () => { const stream = Streams.ofString('myUser = "John";') const parsing = F.regex(/[a-zA-Z_][a-zA-Z0-9_]*/).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('myUser') expect(parsing.offset).toBe(6) }) it('rejects a identifier building', () => { const stream = Streams.ofString('0myUser = "John";') const parsing = F.regex(/[a-zA-Z_][a-zA-Z0-9_]*/).parse(stream) expect(parsing.isAccepted()).toBe(false) expect(parsing.value).toBeUndefined() expect(parsing.offset).toBe(0) }) it('goes in a then flow', () => { const expression = 'myUser :=otherUser' const stream = Streams.ofString(expression) const parsing = assignParser().parse(stream) expect(parsing.isAccepted()).toBeTruthy() expect(parsing.offset).toBe(expression.length) }) it('stops in a then flow', () => { const expression = 'myUser := 0otherUser' const stream = Streams.ofString(expression) const parsing = assignParser().parse(stream) expect(parsing.isAccepted()).toBeFalsy() expect(parsing.value).toBeUndefined() expect(parsing.offset).toBe(expression.indexOf('0')) }) it('consumes the number but not the unit using look-ahead', () => { const pixelRe = /\d+(?=px)/ // look-ahead keeps "px" in input const stream = Streams.ofString('20px') const parsing = F.regex(pixelRe).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('20') expect(parsing.offset).toBe(2) // only “20” eaten }) it('accepts a 3- or 6-digit CSS hex colour', () => { // #RGB | #RRGGBB const colourRe = /#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?/ const stream = Streams.ofString('#abcDEF;') const parsing = F.regex(colourRe).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('#abcDEF') expect(parsing.offset).toBe(7) // consumed exactly the colour }) it('accepts a quoted string whose end quote matches the start', () => { const quotedRe = /(['"])(.*?)\1/ // "Hello", 'Hello', etc. const stream = Streams.ofString('"Hello World" rest') const parsing = F.regex(quotedRe).parse(stream) expect(parsing.isAccepted()).toBe(true) expect(parsing.value).toBe('"Hello World"') expect(parsing.offset).toBe(13) // length of `"Hello World"` }) it('rejects a quoted string with wrong back reference', () => { const quotedRe = /(['"])(.*?)\1/ // "Hello" ok, but not "Hello' const stream = Streams.ofString(`"Hello World' rest`) const parsing = F.regex(quotedRe).parse(stream) expect(parsing.isAccepted()).toBe(false) expect(parsing.value).toBeUndefined() expect(parsing.offset).toBe(0) // length of `"Hello World"` }) }) function assignParser() { const identifier = F.regex(/[a-zA-Z_][a-zA-Z0-9_]*/) const space = F.regex(/\s+/) const assign = C.string(':=') return identifier .then(space.optrep().drop()) .then(assign) .then(space.optrep().drop()) .then(identifier) }