82 lines
2 KiB
JavaScript
82 lines
2 KiB
JavaScript
import { pure, fail, anyItem, satisfy, literal, parse, parseSome, ParseError, EofError } from '../src/parser.js'
|
|
import { Err, Result } from '../src/result.js'
|
|
import { describe, it } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
const eq = (a, b) => assert.deepStrictEqual(a, b)
|
|
const parseErr = (i, desc) => new Err(new ParseError(i, desc))
|
|
const eof = (i = 0) => new Err(new EofError(i))
|
|
|
|
const streamState = stream => {
|
|
return [stream.index, Array.from(stream.clone())]
|
|
}
|
|
|
|
describe('Primitive parsers', () => {
|
|
it('pure', () => {
|
|
const result = parseSome(pure(123), 'abc')
|
|
const [value, stream] = result.unwrap()
|
|
|
|
eq(value, 123)
|
|
eq(streamState(stream), [0, ['a', 'b', 'c']])
|
|
|
|
const empty = parse(pure(123), [])
|
|
eq(empty, Result.ok(123))
|
|
})
|
|
|
|
it('fail', () => {
|
|
const msg = 'Expected failure'
|
|
const parser = fail(msg)
|
|
const expected = parseErr(0, msg)
|
|
|
|
eq(parse(parser, 'abc'), expected)
|
|
eq(parse(parser, ''), expected)
|
|
})
|
|
|
|
it('anyItem', () => {
|
|
const parser = anyItem()
|
|
eq(parse(parser, 'a'), Result.ok('a'))
|
|
|
|
const many = parseSome(parser, 'abc')
|
|
assert(many.isOk())
|
|
const [value, rest] = many.unwrap()
|
|
|
|
eq(value, 'a')
|
|
eq(streamState(rest), [1, ['b', 'c']])
|
|
|
|
eq(parse(parser, ''), eof())
|
|
})
|
|
|
|
it('satisfy', () => {
|
|
const pa = satisfy(x => x === 'a')
|
|
|
|
const result = parseSome(pa, 'abc')
|
|
assert(result.isOk())
|
|
|
|
const [value, rest] = result.unwrap()
|
|
|
|
eq(value, 'a')
|
|
eq(streamState(rest), [1, ['b', 'c']])
|
|
|
|
const err = parse(pa, 'cba')
|
|
eq(err, parseErr(0, 'Value did not match predicate: c'))
|
|
|
|
const eofErr = parse(pa, '')
|
|
eq(eofErr, eof())
|
|
})
|
|
|
|
it('literal', () => {
|
|
const px = literal('x')
|
|
const result = parseSome(px, 'xyz')
|
|
assert(result.isOk())
|
|
|
|
const [value, rest] = result.unwrap()
|
|
eq(value, 'x')
|
|
eq(streamState(rest), [1, ['y', 'z']])
|
|
|
|
const err = parse(px, 'yz')
|
|
eq(err, parseErr(0, 'Value did not match predicate: y'))
|
|
|
|
const eofErr = parse(px, '')
|
|
eq(eofErr, eof())
|
|
})
|
|
})
|