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