summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wat-lexer.cpp173
-rw-r--r--src/wat-lexer.h32
2 files changed, 183 insertions, 22 deletions
diff --git a/src/wasm/wat-lexer.cpp b/src/wasm/wat-lexer.cpp
index 4bea32b59..0d1dc2794 100644
--- a/src/wasm/wat-lexer.cpp
+++ b/src/wasm/wat-lexer.cpp
@@ -151,23 +151,10 @@ public:
if (overflow) {
return {};
}
- auto basic = LexCtx::lexed();
- if (!basic) {
- return {};
- }
- // Check most significant bit for overflow of signed numbers.
- if (sign == Neg) {
- if (n > (1ull << 63)) {
- // TODO: Add error production for signed underflow.
- return {};
- }
- } else if (sign == Pos) {
- if (n > (1ull << 63) - 1) {
- // TODO: Add error production for signed overflow.
- return {};
- }
+ if (auto basic = LexCtx::lexed()) {
+ return LexIntResult{*basic, sign == Neg ? -n : n, sign};
}
- return LexIntResult{*basic, sign == Neg ? -n : n, sign};
+ return {};
}
void takeSign() {
@@ -592,12 +579,7 @@ std::optional<LexFloatResult> float_(std::string_view in) {
if (ctx.takePrefix(":0x"sv)) {
if (auto lexed = hexnum(ctx.next())) {
ctx.take(*lexed);
- if (1 <= lexed->n && lexed->n < (1ull << 52)) {
- ctx.nanPayload = lexed->n;
- } else {
- // TODO: Add error production for invalid NaN payload.
- return {};
- }
+ ctx.nanPayload = lexed->n;
} else {
// TODO: Add error production for malformed NaN payload.
return {};
@@ -781,6 +763,153 @@ std::optional<LexResult> keyword(std::string_view in) {
} // anonymous namespace
+std::optional<uint64_t> Token::getU64() const {
+ 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);
+ }
+ // TODO: Add error production for unsigned overflow.
+ }
+ return {};
+}
+
+std::optional<int32_t> Token::getS32() const {
+ 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);
+ }
+ } else {
+ if (tok->n <= uint64_t(INT32_MAX)) {
+ return int32_t(tok->n);
+ }
+ }
+ }
+ return {};
+}
+
+std::optional<uint32_t> Token::getI32() const {
+ if (auto n = getU32()) {
+ return *n;
+ }
+ if (auto n = getS32()) {
+ return uint32_t(*n);
+ }
+ return {};
+}
+
+std::optional<double> Token::getF64() const {
+ constexpr int signif = 52;
+ constexpr uint64_t payloadMask = (1ull << signif) - 1;
+ constexpr uint64_t nanDefault = 1ull << (signif - 1);
+ if (auto* tok = std::get_if<FloatTok>(&data)) {
+ double d = tok->d;
+ if (std::isnan(d)) {
+ // Inject payload.
+ uint64_t payload = tok->nanPayload ? *tok->nanPayload : nanDefault;
+ if (payload == 0 || payload > payloadMask) {
+ // TODO: Add error production for out-of-bounds payload.
+ return {};
+ }
+ uint64_t bits;
+ static_assert(sizeof(bits) == sizeof(d));
+ memcpy(&bits, &d, sizeof(bits));
+ bits = (bits & ~payloadMask) | payload;
+ memcpy(&d, &bits, sizeof(bits));
+ }
+ return d;
+ }
+ if (auto* tok = std::get_if<IntTok>(&data)) {
+ if (tok->sign == Neg) {
+ if (tok->n == 0) {
+ return -0.0;
+ }
+ return double(int64_t(tok->n));
+ }
+ return double(tok->n);
+ }
+ return {};
+}
+
+std::optional<float> Token::getF32() const {
+ constexpr int signif = 23;
+ constexpr uint32_t payloadMask = (1u << signif) - 1;
+ constexpr uint64_t nanDefault = 1ull << (signif - 1);
+ if (auto* tok = std::get_if<FloatTok>(&data)) {
+ float f = tok->d;
+ if (std::isnan(f)) {
+ // Validate and inject payload.
+ uint64_t payload = tok->nanPayload ? *tok->nanPayload : nanDefault;
+ if (payload == 0 || payload > payloadMask) {
+ // TODO: Add error production for out-of-bounds payload.
+ return {};
+ }
+ uint32_t bits;
+ static_assert(sizeof(bits) == sizeof(f));
+ memcpy(&bits, &f, sizeof(bits));
+ bits = (bits & ~payloadMask) | payload;
+ memcpy(&f, &bits, sizeof(bits));
+ }
+ return f;
+ }
+ if (auto* tok = std::get_if<IntTok>(&data)) {
+ if (tok->sign == Neg) {
+ if (tok->n == 0) {
+ return -0.0f;
+ }
+ return float(int64_t(tok->n));
+ }
+ return float(tok->n);
+ }
+ return {};
+}
+
+std::optional<std::string_view> Token::getString() const {
+ if (auto* tok = std::get_if<StringTok>(&data)) {
+ if (tok->str) {
+ return std::string_view(*tok->str);
+ }
+ return span.substr(1, span.size() - 2);
+ }
+ return {};
+}
+
void Lexer::skipSpace() {
if (auto ctx = space(next())) {
index += ctx->span.size();
diff --git a/src/wat-lexer.h b/src/wat-lexer.h
index 5a955f5c0..e4ba2efa8 100644
--- a/src/wat-lexer.h
+++ b/src/wat-lexer.h
@@ -15,6 +15,7 @@
*/
#include <cstddef>
+#include <cstring>
#include <iterator>
#include <optional>
#include <ostream>
@@ -101,6 +102,37 @@ struct Token {
std::string_view span;
Data data;
+ // ====================
+ // Token classification
+ // ====================
+
+ bool isLParen() const { return std::get_if<LParenTok>(&data); }
+
+ bool isRParen() const { return std::get_if<RParenTok>(&data); }
+
+ std::optional<std::string_view> getID() const {
+ if (std::get_if<IdTok>(&data)) {
+ return span;
+ }
+ return {};
+ }
+
+ std::optional<std::string_view> getKeyword() const {
+ if (std::get_if<KeywordTok>(&data)) {
+ return span;
+ }
+ 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;
+ std::optional<double> getF64() const;
+ std::optional<float> getF32() const;
+ std::optional<std::string_view> getString() const;
+
bool operator==(const Token&) const;
friend std::ostream& operator<<(std::ostream& os, const Token&);
};