| // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
| // Licensed under the MIT License: |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| // Parser combinator framework! |
| // |
| // This file declares several functions which construct parsers, usually taking other parsers as |
| // input, thus making them parser combinators. |
| // |
| // A valid parser is any functor which takes a reference to an input cursor (defined below) as its |
| // input and returns a Maybe. The parser returns null on parse failure, or returns the parsed |
| // result on success. |
| // |
| // An "input cursor" is any type which implements the same interface as IteratorInput, below. Such |
| // a type acts as a pointer to the current input location. When a parser returns successfully, it |
| // will have updated the input cursor to point to the position just past the end of what was parsed. |
| // On failure, the cursor position is unspecified. |
| |
| #pragma once |
| |
| #include "../common.h" |
| #include "../memory.h" |
| #include "../array.h" |
| #include "../tuple.h" |
| #include "../vector.h" |
| |
| #if _MSC_VER && _MSC_VER < 1920 && !__clang__ |
| #define KJ_MSVC_BROKEN_DECLTYPE 1 |
| #endif |
| |
| #if KJ_MSVC_BROKEN_DECLTYPE |
| #include <type_traits> // result_of_t |
| #endif |
| |
| KJ_BEGIN_HEADER |
| |
| namespace kj { |
| namespace parse { |
| |
| template <typename Element, typename Iterator> |
| class IteratorInput { |
| // A parser input implementation based on an iterator range. |
| |
| public: |
| IteratorInput(Iterator begin, Iterator end) |
| : parent(nullptr), pos(begin), end(end), best(begin) {} |
| explicit IteratorInput(IteratorInput& parent) |
| : parent(&parent), pos(parent.pos), end(parent.end), best(parent.pos) {} |
| ~IteratorInput() { |
| if (parent != nullptr) { |
| parent->best = kj::max(kj::max(pos, best), parent->best); |
| } |
| } |
| KJ_DISALLOW_COPY(IteratorInput); |
| |
| void advanceParent() { |
| parent->pos = pos; |
| } |
| void forgetParent() { |
| parent = nullptr; |
| } |
| |
| bool atEnd() { return pos == end; } |
| auto current() -> decltype(*instance<Iterator>()) { |
| KJ_IREQUIRE(!atEnd()); |
| return *pos; |
| } |
| auto consume() -> decltype(*instance<Iterator>()) { |
| KJ_IREQUIRE(!atEnd()); |
| return *pos++; |
| } |
| void next() { |
| KJ_IREQUIRE(!atEnd()); |
| ++pos; |
| } |
| |
| Iterator getBest() { return kj::max(pos, best); } |
| |
| Iterator getPosition() { return pos; } |
| |
| private: |
| IteratorInput* parent; |
| Iterator pos; |
| Iterator end; |
| Iterator best; // furthest we got with any sub-input |
| }; |
| |
| template <typename T> struct OutputType_; |
| template <typename T> struct OutputType_<Maybe<T>> { typedef T Type; }; |
| template <typename Parser, typename Input> |
| using OutputType = typename OutputType_< |
| #if KJ_MSVC_BROKEN_DECLTYPE |
| std::result_of_t<Parser(Input)> |
| // The instance<T&>() based version below results in many compiler errors on MSVC2017. |
| #else |
| decltype(instance<Parser&>()(instance<Input&>())) |
| #endif |
| >::Type; |
| // Synonym for the output type of a parser, given the parser type and the input type. |
| |
| // ======================================================================================= |
| |
| template <typename Input, typename Output> |
| class ParserRef { |
| // Acts as a reference to some other parser, with simplified type. The referenced parser |
| // is polymorphic by virtual call rather than templates. For grammars of non-trivial size, |
| // it is important to inject refs into the grammar here and there to prevent the parser types |
| // from becoming ridiculous. Using too many of them can hurt performance, though. |
| |
| public: |
| ParserRef(): parser(nullptr), wrapper(nullptr) {} |
| ParserRef(const ParserRef&) = default; |
| ParserRef(ParserRef&&) = default; |
| ParserRef& operator=(const ParserRef& other) = default; |
| ParserRef& operator=(ParserRef&& other) = default; |
| |
| template <typename Other> |
| constexpr ParserRef(Other&& other) |
| : parser(&other), wrapper(&WrapperImplInstance<Decay<Other>>::instance) { |
| static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary."); |
| } |
| |
| template <typename Other> |
| inline ParserRef& operator=(Other&& other) { |
| static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary."); |
| parser = &other; |
| wrapper = &WrapperImplInstance<Decay<Other>>::instance; |
| return *this; |
| } |
| |
| KJ_ALWAYS_INLINE(Maybe<Output> operator()(Input& input) const) { |
| // Always inline in the hopes that this allows branch prediction to kick in so the virtual call |
| // doesn't hurt so much. |
| return wrapper->parse(parser, input); |
| } |
| |
| private: |
| struct Wrapper { |
| virtual Maybe<Output> parse(const void* parser, Input& input) const = 0; |
| }; |
| template <typename ParserImpl> |
| struct WrapperImpl: public Wrapper { |
| Maybe<Output> parse(const void* parser, Input& input) const override { |
| return (*reinterpret_cast<const ParserImpl*>(parser))(input); |
| } |
| }; |
| template <typename ParserImpl> |
| struct WrapperImplInstance { |
| #if _MSC_VER && !__clang__ |
| // TODO(msvc): MSVC currently fails to initialize vtable pointers for constexpr values so |
| // we have to make this just const instead. |
| static const WrapperImpl<ParserImpl> instance; |
| #else |
| static constexpr WrapperImpl<ParserImpl> instance = WrapperImpl<ParserImpl>(); |
| #endif |
| }; |
| |
| const void* parser; |
| const Wrapper* wrapper; |
| }; |
| |
| template <typename Input, typename Output> |
| template <typename ParserImpl> |
| #if _MSC_VER && !__clang__ |
| const typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl> |
| ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance = WrapperImpl<ParserImpl>(); |
| #else |
| constexpr typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl> |
| ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance; |
| #endif |
| |
| template <typename Input, typename ParserImpl> |
| constexpr ParserRef<Input, OutputType<ParserImpl, Input>> ref(ParserImpl& impl) { |
| // Constructs a ParserRef. You must specify the input type explicitly, e.g. |
| // `ref<MyInput>(myParser)`. |
| |
| return ParserRef<Input, OutputType<ParserImpl, Input>>(impl); |
| } |
| |
| // ------------------------------------------------------------------- |
| // any |
| // Output = one token |
| |
| class Any_ { |
| public: |
| template <typename Input> |
| Maybe<Decay<decltype(instance<Input>().consume())>> operator()(Input& input) const { |
| if (input.atEnd()) { |
| return nullptr; |
| } else { |
| return input.consume(); |
| } |
| } |
| }; |
| |
| constexpr Any_ any = Any_(); |
| // A parser which matches any token and simply returns it. |
| |
| // ------------------------------------------------------------------- |
| // exactly() |
| // Output = Tuple<> |
| |
| template <typename T> |
| class Exactly_ { |
| public: |
| explicit constexpr Exactly_(T&& expected): expected(expected) {} |
| |
| template <typename Input> |
| Maybe<Tuple<>> operator()(Input& input) const { |
| if (input.atEnd() || input.current() != expected) { |
| return nullptr; |
| } else { |
| input.next(); |
| return Tuple<>(); |
| } |
| } |
| |
| private: |
| T expected; |
| }; |
| |
| template <typename T> |
| constexpr Exactly_<T> exactly(T&& expected) { |
| // Constructs a parser which succeeds when the input is exactly the token specified. The |
| // result is always the empty tuple. |
| |
| return Exactly_<T>(kj::fwd<T>(expected)); |
| } |
| |
| // ------------------------------------------------------------------- |
| // exactlyConst() |
| // Output = Tuple<> |
| |
| template <typename T, T expected> |
| class ExactlyConst_ { |
| public: |
| explicit constexpr ExactlyConst_() {} |
| |
| template <typename Input> |
| Maybe<Tuple<>> operator()(Input& input) const { |
| if (input.atEnd() || input.current() != expected) { |
| return nullptr; |
| } else { |
| input.next(); |
| return Tuple<>(); |
| } |
| } |
| }; |
| |
| template <typename T, T expected> |
| constexpr ExactlyConst_<T, expected> exactlyConst() { |
| // Constructs a parser which succeeds when the input is exactly the token specified. The |
| // result is always the empty tuple. This parser is templated on the token value which may cause |
| // it to perform better -- or worse. Be sure to measure. |
| |
| return ExactlyConst_<T, expected>(); |
| } |
| |
| // ------------------------------------------------------------------- |
| // constResult() |
| |
| template <typename SubParser, typename Result> |
| class ConstResult_ { |
| public: |
| explicit constexpr ConstResult_(SubParser&& subParser, Result&& result) |
| : subParser(kj::fwd<SubParser>(subParser)), result(kj::fwd<Result>(result)) {} |
| |
| template <typename Input> |
| Maybe<Result> operator()(Input& input) const { |
| if (subParser(input) == nullptr) { |
| return nullptr; |
| } else { |
| return result; |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| Result result; |
| }; |
| |
| template <typename SubParser, typename Result> |
| constexpr ConstResult_<SubParser, Result> constResult(SubParser&& subParser, Result&& result) { |
| // Constructs a parser which returns exactly `result` if `subParser` is successful. |
| return ConstResult_<SubParser, Result>(kj::fwd<SubParser>(subParser), kj::fwd<Result>(result)); |
| } |
| |
| template <typename SubParser> |
| constexpr ConstResult_<SubParser, Tuple<>> discard(SubParser&& subParser) { |
| // Constructs a parser which wraps `subParser` but discards the result. |
| return constResult(kj::fwd<SubParser>(subParser), Tuple<>()); |
| } |
| |
| // ------------------------------------------------------------------- |
| // sequence() |
| // Output = Flattened Tuple of outputs of sub-parsers. |
| |
| template <typename... SubParsers> class Sequence_; |
| |
| template <typename FirstSubParser, typename... SubParsers> |
| class Sequence_<FirstSubParser, SubParsers...> { |
| public: |
| template <typename T, typename... U> |
| explicit constexpr Sequence_(T&& firstSubParser, U&&... rest) |
| : first(kj::fwd<T>(firstSubParser)), rest(kj::fwd<U>(rest)...) {} |
| |
| // TODO(msvc): The trailing return types on `operator()` and `parseNext()` expose at least two |
| // bugs in MSVC: |
| // |
| // 1. An ICE. |
| // 2. 'error C2672: 'operator __surrogate_func': no matching overloaded function found)', |
| // which crops up in numerous places when trying to build the capnp command line tools. |
| // |
| // The only workaround I found for both bugs is to omit the trailing return types and instead |
| // rely on C++14's return type deduction. |
| |
| template <typename Input> |
| auto operator()(Input& input) const |
| #if !_MSC_VER || __clang__ |
| -> Maybe<decltype(tuple( |
| instance<OutputType<FirstSubParser, Input>>(), |
| instance<OutputType<SubParsers, Input>>()...))> |
| #endif |
| { |
| return parseNext(input); |
| } |
| |
| template <typename Input, typename... InitialParams> |
| auto parseNext(Input& input, InitialParams&&... initialParams) const |
| #if !_MSC_VER || __clang__ |
| -> Maybe<decltype(tuple( |
| kj::fwd<InitialParams>(initialParams)..., |
| instance<OutputType<FirstSubParser, Input>>(), |
| instance<OutputType<SubParsers, Input>>()...))> |
| #endif |
| { |
| KJ_IF_MAYBE(firstResult, first(input)) { |
| return rest.parseNext(input, kj::fwd<InitialParams>(initialParams)..., |
| kj::mv(*firstResult)); |
| } else { |
| // TODO(msvc): MSVC depends on return type deduction to compile this function, so we need to |
| // help it deduce the right type on this code path. |
| return Maybe<decltype(tuple( |
| kj::fwd<InitialParams>(initialParams)..., |
| instance<OutputType<FirstSubParser, Input>>(), |
| instance<OutputType<SubParsers, Input>>()...))>{nullptr}; |
| } |
| } |
| |
| private: |
| FirstSubParser first; |
| Sequence_<SubParsers...> rest; |
| }; |
| |
| template <> |
| class Sequence_<> { |
| public: |
| template <typename Input> |
| Maybe<Tuple<>> operator()(Input& input) const { |
| return parseNext(input); |
| } |
| |
| template <typename Input, typename... Params> |
| auto parseNext(Input& input, Params&&... params) const -> |
| Maybe<decltype(tuple(kj::fwd<Params>(params)...))> { |
| return tuple(kj::fwd<Params>(params)...); |
| } |
| }; |
| |
| template <typename... SubParsers> |
| constexpr Sequence_<SubParsers...> sequence(SubParsers&&... subParsers) { |
| // Constructs a parser that executes each of the parameter parsers in sequence and returns a |
| // tuple of their results. |
| |
| return Sequence_<SubParsers...>(kj::fwd<SubParsers>(subParsers)...); |
| } |
| |
| // ------------------------------------------------------------------- |
| // many() |
| // Output = Array of output of sub-parser, or just a uint count if the sub-parser returns Tuple<>. |
| |
| template <typename SubParser, bool atLeastOne> |
| class Many_ { |
| template <typename Input, typename Output = OutputType<SubParser, Input>> |
| struct Impl; |
| public: |
| explicit constexpr Many_(SubParser&& subParser) |
| : subParser(kj::fwd<SubParser>(subParser)) {} |
| |
| template <typename Input> |
| auto operator()(Input& input) const |
| -> decltype(Impl<Input>::apply(instance<const SubParser&>(), input)); |
| |
| private: |
| SubParser subParser; |
| }; |
| |
| template <typename SubParser, bool atLeastOne> |
| template <typename Input, typename Output> |
| struct Many_<SubParser, atLeastOne>::Impl { |
| static Maybe<Array<Output>> apply(const SubParser& subParser, Input& input) { |
| typedef Vector<OutputType<SubParser, Input>> Results; |
| Results results; |
| |
| while (!input.atEnd()) { |
| Input subInput(input); |
| |
| KJ_IF_MAYBE(subResult, subParser(subInput)) { |
| subInput.advanceParent(); |
| results.add(kj::mv(*subResult)); |
| } else { |
| break; |
| } |
| } |
| |
| if (atLeastOne && results.empty()) { |
| return nullptr; |
| } |
| |
| return results.releaseAsArray(); |
| } |
| }; |
| |
| template <typename SubParser, bool atLeastOne> |
| template <typename Input> |
| struct Many_<SubParser, atLeastOne>::Impl<Input, Tuple<>> { |
| // If the sub-parser output is Tuple<>, just return a count. |
| |
| static Maybe<uint> apply(const SubParser& subParser, Input& input) { |
| uint count = 0; |
| |
| while (!input.atEnd()) { |
| Input subInput(input); |
| |
| KJ_IF_MAYBE(subResult, subParser(subInput)) { |
| subInput.advanceParent(); |
| ++count; |
| } else { |
| break; |
| } |
| } |
| |
| if (atLeastOne && count == 0) { |
| return nullptr; |
| } |
| |
| return count; |
| } |
| }; |
| |
| template <typename SubParser, bool atLeastOne> |
| template <typename Input> |
| auto Many_<SubParser, atLeastOne>::operator()(Input& input) const |
| -> decltype(Impl<Input>::apply(instance<const SubParser&>(), input)) { |
| return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, input); |
| } |
| |
| template <typename SubParser> |
| constexpr Many_<SubParser, false> many(SubParser&& subParser) { |
| // Constructs a parser that repeatedly executes the given parser until it fails, returning an |
| // Array of the results (or a uint count if `subParser` returns an empty tuple). |
| return Many_<SubParser, false>(kj::fwd<SubParser>(subParser)); |
| } |
| |
| template <typename SubParser> |
| constexpr Many_<SubParser, true> oneOrMore(SubParser&& subParser) { |
| // Like `many()` but the parser must parse at least one item to be successful. |
| return Many_<SubParser, true>(kj::fwd<SubParser>(subParser)); |
| } |
| |
| // ------------------------------------------------------------------- |
| // times() |
| // Output = Array of output of sub-parser, or Tuple<> if sub-parser returns Tuple<>. |
| |
| template <typename SubParser> |
| class Times_ { |
| template <typename Input, typename Output = OutputType<SubParser, Input>> |
| struct Impl; |
| public: |
| explicit constexpr Times_(SubParser&& subParser, uint count) |
| : subParser(kj::fwd<SubParser>(subParser)), count(count) {} |
| |
| template <typename Input> |
| auto operator()(Input& input) const |
| -> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input)); |
| |
| private: |
| SubParser subParser; |
| uint count; |
| }; |
| |
| template <typename SubParser> |
| template <typename Input, typename Output> |
| struct Times_<SubParser>::Impl { |
| static Maybe<Array<Output>> apply(const SubParser& subParser, uint count, Input& input) { |
| auto results = heapArrayBuilder<OutputType<SubParser, Input>>(count); |
| |
| while (results.size() < count) { |
| if (input.atEnd()) { |
| return nullptr; |
| } else KJ_IF_MAYBE(subResult, subParser(input)) { |
| results.add(kj::mv(*subResult)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| return results.finish(); |
| } |
| }; |
| |
| template <typename SubParser> |
| template <typename Input> |
| struct Times_<SubParser>::Impl<Input, Tuple<>> { |
| // If the sub-parser output is Tuple<>, just return a count. |
| |
| static Maybe<Tuple<>> apply(const SubParser& subParser, uint count, Input& input) { |
| uint actualCount = 0; |
| |
| while (actualCount < count) { |
| if (input.atEnd()) { |
| return nullptr; |
| } else KJ_IF_MAYBE(subResult, subParser(input)) { |
| ++actualCount; |
| } else { |
| return nullptr; |
| } |
| } |
| |
| return tuple(); |
| } |
| }; |
| |
| template <typename SubParser> |
| template <typename Input> |
| auto Times_<SubParser>::operator()(Input& input) const |
| -> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input)) { |
| return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, count, input); |
| } |
| |
| template <typename SubParser> |
| constexpr Times_<SubParser> times(SubParser&& subParser, uint count) { |
| // Constructs a parser that repeats the subParser exactly `count` times. |
| return Times_<SubParser>(kj::fwd<SubParser>(subParser), count); |
| } |
| |
| // ------------------------------------------------------------------- |
| // optional() |
| // Output = Maybe<output of sub-parser> |
| |
| template <typename SubParser> |
| class Optional_ { |
| public: |
| explicit constexpr Optional_(SubParser&& subParser) |
| : subParser(kj::fwd<SubParser>(subParser)) {} |
| |
| template <typename Input> |
| Maybe<Maybe<OutputType<SubParser, Input>>> operator()(Input& input) const { |
| typedef Maybe<OutputType<SubParser, Input>> Result; |
| |
| Input subInput(input); |
| KJ_IF_MAYBE(subResult, subParser(subInput)) { |
| subInput.advanceParent(); |
| return Result(kj::mv(*subResult)); |
| } else { |
| return Result(nullptr); |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| }; |
| |
| template <typename SubParser> |
| constexpr Optional_<SubParser> optional(SubParser&& subParser) { |
| // Constructs a parser that accepts zero or one of the given sub-parser, returning a Maybe |
| // of the sub-parser's result. |
| return Optional_<SubParser>(kj::fwd<SubParser>(subParser)); |
| } |
| |
| // ------------------------------------------------------------------- |
| // oneOf() |
| // All SubParsers must have same output type, which becomes the output type of the |
| // OneOfParser. |
| |
| template <typename... SubParsers> |
| class OneOf_; |
| |
| template <typename FirstSubParser, typename... SubParsers> |
| class OneOf_<FirstSubParser, SubParsers...> { |
| public: |
| explicit constexpr OneOf_(FirstSubParser&& firstSubParser, SubParsers&&... rest) |
| : first(kj::fwd<FirstSubParser>(firstSubParser)), rest(kj::fwd<SubParsers>(rest)...) {} |
| |
| template <typename Input> |
| Maybe<OutputType<FirstSubParser, Input>> operator()(Input& input) const { |
| { |
| Input subInput(input); |
| Maybe<OutputType<FirstSubParser, Input>> firstResult = first(subInput); |
| |
| if (firstResult != nullptr) { |
| subInput.advanceParent(); |
| return kj::mv(firstResult); |
| } |
| } |
| |
| // Hoping for some tail recursion here... |
| return rest(input); |
| } |
| |
| private: |
| FirstSubParser first; |
| OneOf_<SubParsers...> rest; |
| }; |
| |
| template <> |
| class OneOf_<> { |
| public: |
| template <typename Input> |
| decltype(nullptr) operator()(Input& input) const { |
| return nullptr; |
| } |
| }; |
| |
| template <typename... SubParsers> |
| constexpr OneOf_<SubParsers...> oneOf(SubParsers&&... parsers) { |
| // Constructs a parser that accepts one of a set of options. The parser behaves as the first |
| // sub-parser in the list which returns successfully. All of the sub-parsers must return the |
| // same type. |
| return OneOf_<SubParsers...>(kj::fwd<SubParsers>(parsers)...); |
| } |
| |
| // ------------------------------------------------------------------- |
| // transform() |
| // Output = Result of applying transform functor to input value. If input is a tuple, it is |
| // unpacked to form the transformation parameters. |
| |
| template <typename Position> |
| struct Span { |
| public: |
| inline const Position& begin() const { return begin_; } |
| inline const Position& end() const { return end_; } |
| |
| Span() = default; |
| inline constexpr Span(Position&& begin, Position&& end): begin_(mv(begin)), end_(mv(end)) {} |
| |
| private: |
| Position begin_; |
| Position end_; |
| }; |
| |
| template <typename Position> |
| constexpr Span<Decay<Position>> span(Position&& start, Position&& end) { |
| return Span<Decay<Position>>(kj::fwd<Position>(start), kj::fwd<Position>(end)); |
| } |
| |
| template <typename SubParser, typename TransformFunc> |
| class Transform_ { |
| public: |
| explicit constexpr Transform_(SubParser&& subParser, TransformFunc&& transform) |
| : subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {} |
| |
| template <typename Input> |
| Maybe<decltype(kj::apply(instance<TransformFunc&>(), |
| instance<OutputType<SubParser, Input>&&>()))> |
| operator()(Input& input) const { |
| KJ_IF_MAYBE(subResult, subParser(input)) { |
| return kj::apply(transform, kj::mv(*subResult)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| TransformFunc transform; |
| }; |
| |
| template <typename SubParser, typename TransformFunc> |
| class TransformOrReject_ { |
| public: |
| explicit constexpr TransformOrReject_(SubParser&& subParser, TransformFunc&& transform) |
| : subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {} |
| |
| template <typename Input> |
| decltype(kj::apply(instance<TransformFunc&>(), instance<OutputType<SubParser, Input>&&>())) |
| operator()(Input& input) const { |
| KJ_IF_MAYBE(subResult, subParser(input)) { |
| return kj::apply(transform, kj::mv(*subResult)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| TransformFunc transform; |
| }; |
| |
| template <typename SubParser, typename TransformFunc> |
| class TransformWithLocation_ { |
| public: |
| explicit constexpr TransformWithLocation_(SubParser&& subParser, TransformFunc&& transform) |
| : subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {} |
| |
| template <typename Input> |
| Maybe<decltype(kj::apply(instance<TransformFunc&>(), |
| instance<Span<Decay<decltype(instance<Input&>().getPosition())>>>(), |
| instance<OutputType<SubParser, Input>&&>()))> |
| operator()(Input& input) const { |
| auto start = input.getPosition(); |
| KJ_IF_MAYBE(subResult, subParser(input)) { |
| return kj::apply(transform, Span<decltype(start)>(kj::mv(start), input.getPosition()), |
| kj::mv(*subResult)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| TransformFunc transform; |
| }; |
| |
| template <typename SubParser, typename TransformFunc> |
| constexpr Transform_<SubParser, TransformFunc> transform( |
| SubParser&& subParser, TransformFunc&& functor) { |
| // Constructs a parser which executes some other parser and then transforms the result by invoking |
| // `functor` on it. Typically `functor` is a lambda. It is invoked using `kj::apply`, |
| // meaning tuples will be unpacked as arguments. |
| return Transform_<SubParser, TransformFunc>( |
| kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor)); |
| } |
| |
| template <typename SubParser, typename TransformFunc> |
| constexpr TransformOrReject_<SubParser, TransformFunc> transformOrReject( |
| SubParser&& subParser, TransformFunc&& functor) { |
| // Like `transform()` except that `functor` returns a `Maybe`. If it returns null, parsing fails, |
| // otherwise the parser's result is the content of the `Maybe`. |
| return TransformOrReject_<SubParser, TransformFunc>( |
| kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor)); |
| } |
| |
| template <typename SubParser, typename TransformFunc> |
| constexpr TransformWithLocation_<SubParser, TransformFunc> transformWithLocation( |
| SubParser&& subParser, TransformFunc&& functor) { |
| // Like `transform` except that `functor` also takes a `Span` as its first parameter specifying |
| // the location of the parsed content. The span's position type is whatever the parser input's |
| // getPosition() returns. |
| return TransformWithLocation_<SubParser, TransformFunc>( |
| kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor)); |
| } |
| |
| // ------------------------------------------------------------------- |
| // notLookingAt() |
| // Fails if the given parser succeeds at the current location. |
| |
| template <typename SubParser> |
| class NotLookingAt_ { |
| public: |
| explicit constexpr NotLookingAt_(SubParser&& subParser) |
| : subParser(kj::fwd<SubParser>(subParser)) {} |
| |
| template <typename Input> |
| Maybe<Tuple<>> operator()(Input& input) const { |
| Input subInput(input); |
| subInput.forgetParent(); |
| if (subParser(subInput) == nullptr) { |
| return Tuple<>(); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| private: |
| SubParser subParser; |
| }; |
| |
| template <typename SubParser> |
| constexpr NotLookingAt_<SubParser> notLookingAt(SubParser&& subParser) { |
| // Constructs a parser which fails at any position where the given parser succeeds. Otherwise, |
| // it succeeds without consuming any input and returns an empty tuple. |
| return NotLookingAt_<SubParser>(kj::fwd<SubParser>(subParser)); |
| } |
| |
| // ------------------------------------------------------------------- |
| // endOfInput() |
| // Output = Tuple<>, only succeeds if at end-of-input |
| |
| class EndOfInput_ { |
| public: |
| template <typename Input> |
| Maybe<Tuple<>> operator()(Input& input) const { |
| if (input.atEnd()) { |
| return Tuple<>(); |
| } else { |
| return nullptr; |
| } |
| } |
| }; |
| |
| constexpr EndOfInput_ endOfInput = EndOfInput_(); |
| // A parser that succeeds only if it is called with no input. |
| |
| } // namespace parse |
| } // namespace kj |
| |
| KJ_END_HEADER |