#ifndef frontend_EitherParser_h
#define frontend_EitherParser_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/Tuple.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Utf8.h"
#include "mozilla/Variant.h"
#include <utility>
#include "frontend/BCEParserHandle.h"
#include "frontend/Parser.h"
#include "frontend/TokenStream.h"
namespace js {
namespace detail {
template <template <class Parser> class GetThis,
template <class This> class MemberFunction, typename... Args>
struct InvokeMemberFunction {
mozilla::Tuple<typename mozilla::Decay<Args>::Type...> args;
template <class This, size_t... Indices>
auto matchInternal(This* obj, std::index_sequence<Indices...>) -> decltype(
((*obj).*(MemberFunction<This>::get()))(mozilla::Get<Indices>(args)...)) {
return ((*obj).*
(MemberFunction<This>::get()))(mozilla::Get<Indices>(args)...);
}
public:
template <typename... ActualArgs>
explicit InvokeMemberFunction(ActualArgs&&... actualArgs)
: args{std::forward<ActualArgs>(actualArgs)...} {}
template <class Parser>
auto match(Parser* parser)
-> decltype(this->matchInternal(GetThis<Parser>::get(parser),
std::index_sequence_for<Args...>{})) {
return this->matchInternal(GetThis<Parser>::get(parser),
std::index_sequence_for<Args...>{});
}
};
template <class Parser>
struct GetParser {
static Parser* get(Parser* parser) { return parser; }
};
template <class Parser>
struct GetTokenStream {
static auto get(Parser* parser) { return &parser->tokenStream; }
};
template <class Parser>
struct ParserOptions {
static constexpr auto get() { return &Parser::options; }
};
template <class Parser>
struct ParserNewObjectBox {
static constexpr auto get() { return &Parser::newObjectBox; }
};
template <class TokenStream>
struct TokenStreamComputeLineAndColumn {
static constexpr auto get() { return &TokenStream::computeLineAndColumn; }
};
struct ParseHandlerMatcher {
template <class Parser>
frontend::FullParseHandler& match(Parser* parser) {
return parser->handler_;
}
};
struct ParserSharedBaseMatcher {
template <class Parser>
frontend::ParserSharedBase& match(Parser* parser) {
return *static_cast<frontend::ParserSharedBase*>(parser);
}
};
struct ErrorReporterMatcher {
template <class Parser>
frontend::ErrorReporter& match(Parser* parser) {
return parser->tokenStream;
}
};
}
namespace frontend {
class EitherParser : public BCEParserHandle {
mozilla::Variant<Parser<FullParseHandler, char16_t>* const,
Parser<FullParseHandler, mozilla::Utf8Unit>* const>
parser;
using Node = typename FullParseHandler::Node;
template <template <class Parser> class GetThis,
template <class This> class GetMemberFunction,
typename... StoredArgs>
using InvokeMemberFunction =
detail::InvokeMemberFunction<GetThis, GetMemberFunction, StoredArgs...>;
public:
template <class Parser>
explicit EitherParser(Parser* parser) : parser(parser) {}
FullParseHandler& astGenerator() final {
return parser.match(detail::ParseHandlerMatcher());
}
ErrorReporter& errorReporter() final {
return parser.match(detail::ErrorReporterMatcher());
}
const ErrorReporter& errorReporter() const final {
return parser.match(detail::ErrorReporterMatcher());
}
const JS::ReadOnlyCompileOptions& options() const final {
InvokeMemberFunction<detail::GetParser, detail::ParserOptions>
optionsMatcher;
return parser.match(std::move(optionsMatcher));
}
ObjectBox* newObjectBox(JSObject* obj) final {
InvokeMemberFunction<detail::GetParser, detail::ParserNewObjectBox,
JSObject*>
matcher{obj};
return parser.match(std::move(matcher));
}
void computeLineAndColumn(uint32_t offset, uint32_t* line,
uint32_t* column) const {
InvokeMemberFunction<detail::GetTokenStream,
detail::TokenStreamComputeLineAndColumn, uint32_t,
uint32_t*, uint32_t*>
matcher{offset, line, column};
return parser.match(std::move(matcher));
}
};
}
}
#endif