diff options
author | Thomas Lively <tlively@google.com> | 2024-02-05 10:24:16 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-05 10:24:16 -0800 |
commit | ed15efeedd33bbdbadfafabc812d70a792a9a06c (patch) | |
tree | 187d8cdd828369022d406e517d92be1f85ab2443 /src | |
parent | 845e0700c99d603c920d82c2312ec9b39a555c68 (diff) | |
download | binaryen-ed15efeedd33bbdbadfafabc812d70a792a9a06c.tar.gz binaryen-ed15efeedd33bbdbadfafabc812d70a792a9a06c.tar.bz2 binaryen-ed15efeedd33bbdbadfafabc812d70a792a9a06c.zip |
[Parser] Templatize lexing of integers (#6272)
Have a single implementation for lexing each of unsigned, signed, and
uninterpreted integers, each generic over the bit width of the integer. This
reduces duplication in the existing code and it will make it much easier to
support lexing more 8- and 16-bit integers.
Diffstat (limited to 'src')
-rw-r--r-- | src/parser/input-impl.h | 66 | ||||
-rw-r--r-- | src/parser/input.h | 11 | ||||
-rw-r--r-- | src/parser/lexer.cpp | 71 | ||||
-rw-r--r-- | src/parser/lexer.h | 10 |
4 files changed, 50 insertions, 108 deletions
diff --git a/src/parser/input-impl.h b/src/parser/input-impl.h index 0f8fc2e86..3ffce07f8 100644 --- a/src/parser/input-impl.h +++ b/src/parser/input-impl.h @@ -100,7 +100,7 @@ inline std::optional<uint64_t> ParseInput::takeOffset() { if (subLexer == subLexer.end()) { return {}; } - if (auto o = subLexer->getU64()) { + if (auto o = subLexer->getU<uint64_t>()) { ++subLexer; if (subLexer == subLexer.end()) { ++lexer; @@ -122,7 +122,7 @@ inline std::optional<uint32_t> ParseInput::takeAlign() { if (subLexer == subLexer.end()) { return {}; } - if (auto a = subLexer->getU32()) { + if (auto a = subLexer->getU<uint32_t>()) { ++subLexer; if (subLexer == subLexer.end()) { ++lexer; @@ -134,9 +134,9 @@ inline std::optional<uint32_t> ParseInput::takeAlign() { return {}; } -inline std::optional<uint64_t> ParseInput::takeU64() { +template<typename T> inline std::optional<T> ParseInput::takeU() { if (auto t = peek()) { - if (auto n = t->getU64()) { + if (auto n = t->getU<T>()) { ++lexer; return n; } @@ -144,67 +144,33 @@ inline std::optional<uint64_t> ParseInput::takeU64() { return std::nullopt; } -inline std::optional<int64_t> ParseInput::takeS64() { +template<typename T> inline std::optional<T> ParseInput::takeI() { if (auto t = peek()) { - if (auto n = t->getS64()) { + if (auto n = t->getI<T>()) { ++lexer; return n; } } - return {}; + return std::nullopt; } -inline std::optional<int64_t> ParseInput::takeI64() { - if (auto t = peek()) { - if (auto n = t->getI64()) { - ++lexer; - return n; - } - } - return {}; +inline std::optional<uint64_t> ParseInput::takeU64() { + return takeU<uint64_t>(); } -inline std::optional<uint32_t> ParseInput::takeU32() { - if (auto t = peek()) { - if (auto n = t->getU32()) { - ++lexer; - return n; - } - } - return std::nullopt; +inline std::optional<uint64_t> ParseInput::takeI64() { + return takeI<uint64_t>(); } -inline std::optional<int32_t> ParseInput::takeS32() { - if (auto t = peek()) { - if (auto n = t->getS32()) { - ++lexer; - return n; - } - } - return {}; +inline std::optional<uint32_t> ParseInput::takeU32() { + return takeU<uint64_t>(); } -inline std::optional<int32_t> ParseInput::takeI32() { - if (auto t = peek()) { - if (auto n = t->getI32()) { - ++lexer; - return n; - } - } - return {}; +inline std::optional<uint32_t> ParseInput::takeI32() { + return takeI<uint32_t>(); } -inline std::optional<uint8_t> ParseInput::takeU8() { - if (auto t = peek()) { - if (auto n = t->getU32()) { - if (n <= std::numeric_limits<uint8_t>::max()) { - ++lexer; - return uint8_t(*n); - } - } - } - return {}; -} +inline std::optional<uint8_t> ParseInput::takeU8() { return takeU<uint8_t>(); } inline std::optional<double> ParseInput::takeF64() { if (auto t = peek()) { diff --git a/src/parser/input.h b/src/parser/input.h index dbf3e4868..d4fdde1bd 100644 --- a/src/parser/input.h +++ b/src/parser/input.h @@ -51,11 +51,9 @@ struct ParseInput { std::optional<uint64_t> takeOffset(); std::optional<uint32_t> takeAlign(); std::optional<uint64_t> takeU64(); - std::optional<int64_t> takeS64(); - std::optional<int64_t> takeI64(); + std::optional<uint64_t> takeI64(); std::optional<uint32_t> takeU32(); - std::optional<int32_t> takeS32(); - std::optional<int32_t> takeI32(); + std::optional<uint32_t> takeI32(); std::optional<uint8_t> takeU8(); std::optional<double> takeF64(); std::optional<float> takeF32(); @@ -67,6 +65,11 @@ struct ParseInput { Index getPos(); [[nodiscard]] Err err(Index pos, std::string reason); [[nodiscard]] Err err(std::string reason) { return err(getPos(), reason); } + +private: + template<typename T> std::optional<T> takeU(); + template<typename T> std::optional<T> takeS(); + template<typename T> std::optional<T> takeI(); }; #include "input-impl.h" diff --git a/src/parser/lexer.cpp b/src/parser/lexer.cpp index 0796013fe..288660c76 100644 --- a/src/parser/lexer.cpp +++ b/src/parser/lexer.cpp @@ -767,77 +767,52 @@ std::optional<LexResult> keyword(std::string_view in) { } // anonymous namespace -std::optional<uint64_t> Token::getU64() const { +template<typename T> std::optional<T> Token::getU() const { + static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>); if (auto* tok = std::get_if<IntTok>(&data)) { - if (tok->sign == NoSign) { - return tok->n; - } - } - return {}; -} - -std::optional<int64_t> Token::getS64() const { - if (auto* tok = std::get_if<IntTok>(&data)) { - if (tok->sign == Neg) { - if (uint64_t(INT64_MIN) <= tok->n || tok->n == 0) { - return int64_t(tok->n); - } - // TODO: Add error production for signed underflow. - } else { - if (tok->n <= uint64_t(INT64_MAX)) { - return int64_t(tok->n); - } - // TODO: Add error production for signed overflow. - } - } - return {}; -} - -std::optional<uint64_t> Token::getI64() const { - if (auto n = getU64()) { - return *n; - } - if (auto n = getS64()) { - return *n; - } - return {}; -} - -std::optional<uint32_t> Token::getU32() const { - if (auto* tok = std::get_if<IntTok>(&data)) { - if (tok->sign == NoSign && tok->n <= UINT32_MAX) { - return int32_t(tok->n); + if (tok->sign == NoSign && tok->n <= std::numeric_limits<T>::max()) { + return T(tok->n); } // TODO: Add error production for unsigned overflow. } return {}; } -std::optional<int32_t> Token::getS32() const { +template<typename T> std::optional<T> Token::getS() const { + static_assert(std::is_integral_v<T> && std::is_signed_v<T>); if (auto* tok = std::get_if<IntTok>(&data)) { if (tok->sign == Neg) { - if (uint64_t(INT32_MIN) <= tok->n || tok->n == 0) { - return int32_t(tok->n); + if (uint64_t(std::numeric_limits<T>::min()) <= tok->n || tok->n == 0) { + return T(tok->n); } } else { - if (tok->n <= uint64_t(INT32_MAX)) { - return int32_t(tok->n); + if (tok->n <= uint64_t(std::numeric_limits<T>::max())) { + return T(tok->n); } } } return {}; } -std::optional<uint32_t> Token::getI32() const { - if (auto n = getU32()) { +template<typename T> std::optional<T> Token::getI() const { + static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>); + if (auto n = getU<T>()) { return *n; } - if (auto n = getS32()) { - return uint32_t(*n); + if (auto n = getS<std::make_signed_t<T>>()) { + return T(*n); } return {}; } +template std::optional<uint64_t> Token::getU<uint64_t>() const; +template std::optional<int64_t> Token::getS<int64_t>() const; +template std::optional<uint64_t> Token::getI<uint64_t>() const; +template std::optional<uint32_t> Token::getU<uint32_t>() const; +template std::optional<int32_t> Token::getS<int32_t>() const; +template std::optional<uint32_t> Token::getI<uint32_t>() const; +template std::optional<uint8_t> Token::getU<uint8_t>() const; + std::optional<double> Token::getF64() const { constexpr int signif = 52; constexpr uint64_t payloadMask = (1ull << signif) - 1; diff --git a/src/parser/lexer.h b/src/parser/lexer.h index 67d29b002..42b18508e 100644 --- a/src/parser/lexer.h +++ b/src/parser/lexer.h @@ -125,12 +125,10 @@ struct Token { } return {}; } - std::optional<uint64_t> getU64() const; - std::optional<int64_t> getS64() const; - std::optional<uint64_t> getI64() const; - std::optional<uint32_t> getU32() const; - std::optional<int32_t> getS32() const; - std::optional<uint32_t> getI32() const; + + template<typename T> std::optional<T> getU() const; + template<typename T> std::optional<T> getS() const; + template<typename T> std::optional<T> getI() const; std::optional<double> getF64() const; std::optional<float> getF32() const; std::optional<std::string_view> getString() const; |