Experimental implementation of monadic parsers similar to Haskell's Parsec but in C++ using Free monads as engine.
The design of the library is not finished for now. Combinators are currently divided into two layers: ParserL and ParserT. These layers should be unified to eliminate the difference in usage.
Additional materials
- Monadic Parsers in C++ (Talk, Rus) | Slides (Eng) | My talk about this implementation at C++ Russia 2019 Moscow.
- cpp_stm_free | Software Transactional Memory with the same Free Monads approach
Requirements
- GCC 7.2 (C++17)
Samples
Monadic sequencing
struct R { Char dg0; Char ch1; Char ch2; }; auto p = bind<Char, R>(digit, [=](Char dg0) { return bind<Char, R>(lower, [=](Char ch1) { return bind<Char, R>(symbol('2'), [=](Char ch2) { return pure<R>(R{dg0, ch1, ch2}); }); }); }); ParserResult<R> result = parse(p, "1b2"); QVERIFY(isRight(result)); R r = getParsed<R>(result); QVERIFY(r.dg0 == '1'); QVERIFY(r.ch1 == 'b'); QVERIFY(r.ch2 == '2');
alt combinator
ParserResult<Char> result1 = parse(alt(upperPL, lowerPL), "A"); ParserResult<Char> result2 = parse(alt(upperPL, lowerPL), "a"); QVERIFY(isRight(result1)); QVERIFY(isRight(result2)); QVERIFY(getParsed(result1) == 'A'); QVERIFY(getParsed(result2) == 'a');
try and safe combinators
auto f = [](ParserResult<Unit>) { throw std::runtime_error("err2"); return pure(unit); }; ParserL<Unit> internalP = bind<Char, Unit>(digitThrowPL, [](Char) { return bind<Char, Unit>(digitThrowPL, [](Char) { throw std::runtime_error("err1"); return purePL(unit); }); }); ParserT<Unit> triedP = bind<ParserResult<Unit>, Unit>(tryP(internalP), f); ParserT<Unit> safedP = bind<ParserResult<Unit>, Unit>(safeP(internalP), f); auto result1 = parse(triedP, "123"); auto result2 = parse(safedP, "123"); QVERIFY(isLeft(result1)); QVERIFY(getError(result1).message == "err1"); QVERIFY(isLeft(result2)); QVERIFY(getError(result2).message == "err2");
many combinator
ParserT<Many<Char>> p = manyPL<Char>(digitThrowPL); ParserResult<Many<Char>> result = parse(p, "4321"); QVERIFY(isRight(result)); Many<Char> parsed = getParsed(result); QVERIFY(parsed.size() == 4); QVERIFY(parsed.front() == '4'); parsed.pop_front(); QVERIFY(parsed.front() == '3'); parsed.pop_front(); QVERIFY(parsed.front() == '2'); parsed.pop_front(); QVERIFY(parsed.front() == '1');