Pull out the number parsing logic

Pull out the number parsing logic from
AssemblyContext::binaryEncodeNumericLiteral() to utilities.

The new utility function: `ParseAndEncodeNumber()` now accepts:
  * number text to parse
  * number type
  * a emit function, which is a function which will be called with each
    parsed uint32 word.
  * a pointer to std::string to be overwritten with error messages.
    (pass nullptr if expect no error message)
and returns:
  * an enum result type to indicate the status

Type/Structs moved to utility:
  * template<typename T> class ClampToZeroIfUnsignedType

New type:
* enum EncodeNumberStatus: success or error code
* NumberType: hold the number type information for the number to be parsed.
 * several helper functions are also added for NumberType.

Functions moved to utility:
  * Helpers:
    * template<typename T> checkRangeAndIfHexThenSignExtend() -> CheckRangeAndIfHex....()
  * Interfaces:
    * template<typename T> parseNumber() -> ParseNumber()
    * binaryEncodeIntegerLiteral() -> ParseAndEncodeIntegerNumber()
    * binaryEncodeFloatingPointLiteral() -> ParseAndEncodeFloatingPointNumber()
    * binaryEncodeNumericLiteral() -> ParseAndEncodeNumber()

Tests added/moved to test/ParseNumber.cpp, including tests for:
* ParseNumber(): This is moved from TextToBinary.cpp to ParseNumber.cpp
* ParseAndEncodeIntegerNumber(): New added
* ParseAndEncodeFloatingPointNumber(): New added
* ParseAndEncodeNumber(): New added

Note that the error messages are kept almost the same as before, but
they may be inappropriate for an utility function. Those will be fixed
in another CL.
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index ec3c23e..a045ce1 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -115,6 +115,7 @@
 
   ${CMAKE_CURRENT_SOURCE_DIR}/util/bitutils.h
   ${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/util/parse_number.h
   ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.h
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h
@@ -135,6 +136,7 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
   ${CMAKE_CURRENT_SOURCE_DIR}/validate.h
 
+  ${CMAKE_CURRENT_SOURCE_DIR}/util/parse_number.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
diff --git a/source/text.cpp b/source/text.cpp
index dc3519e..d317264 100644
--- a/source/text.cpp
+++ b/source/text.cpp
@@ -38,6 +38,7 @@
 #include "table.h"
 #include "text_handler.h"
 #include "util/bitutils.h"
+#include "util/parse_number.h"
 
 bool spvIsValidIDCharacter(const char value) {
   return value == '_' || 0 != ::isalnum(value);
@@ -159,10 +160,10 @@
                              const char* text, spv_instruction_t* pInst) {
   assert(*text == '!');
   uint32_t parse_result;
-  if (auto error =
-          context->parseNumber(text + 1, SPV_ERROR_INVALID_TEXT, &parse_result,
-                               "Invalid immediate integer: !"))
-    return error;
+  if (!spvutils::ParseNumber(text + 1, &parse_result)) {
+    return context->diagnostic(SPV_ERROR_INVALID_TEXT)
+           << "Invalid immediate integer: !" << text + 1;
+  }
   context->binaryEncodeU32(parse_result, pInst);
   context->seekForward(static_cast<uint32_t>(strlen(text)));
   return SPV_SUCCESS;
diff --git a/source/text_handler.cpp b/source/text_handler.cpp
index 65c5e0d..8724b1c 100644
--- a/source/text_handler.cpp
+++ b/source/text_handler.cpp
@@ -27,13 +27,9 @@
 #include "text.h"
 #include "util/bitutils.h"
 #include "util/hex_float.h"
+#include "util/parse_number.h"
 
 namespace {
-
-using spvutils::BitwiseCast;
-using spvutils::FloatProxy;
-using spvutils::HexFloat;
-
 // Advances |text| to the start of the next line and writes the new position to
 // |position|.
 spv_result_t advanceLine(spv_text text, spv_position position) {
@@ -217,37 +213,61 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
-                                              spv_instruction_t* pInst) {
-  uint32_t low = uint32_t(0x00000000ffffffff & value);
-  uint32_t high = uint32_t((0xffffffff00000000 & value) >> 32);
-  binaryEncodeU32(low, pInst);
-  binaryEncodeU32(high, pInst);
-  return SPV_SUCCESS;
-}
-
 spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
     const char* val, spv_result_t error_code, const IdType& type,
     spv_instruction_t* pInst) {
-  const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
-  const bool is_floating = libspirv::isScalarFloating(type);
-  const bool is_integer = libspirv::isScalarIntegral(type);
-
-  if (!is_bottom && !is_floating && !is_integer) {
-    return diagnostic(SPV_ERROR_INTERNAL)
-           << "The expected type is not a scalar integer or float type";
+  using spvutils::EncodeNumberStatus;
+  // Populate the NumberType from the IdType for parsing.
+  spvutils::NumberType number_type;
+  switch (type.type_class) {
+    case IdTypeClass::kOtherType:
+      return diagnostic(SPV_ERROR_INTERNAL)
+             << "Unexpected numeric literal type";
+    case IdTypeClass::kScalarIntegerType:
+      if (type.isSigned) {
+        number_type = {type.bitwidth, SPV_NUMBER_SIGNED_INT};
+      } else {
+        number_type = {type.bitwidth, SPV_NUMBER_UNSIGNED_INT};
+      }
+      break;
+    case IdTypeClass::kScalarFloatType:
+      number_type = {type.bitwidth, SPV_NUMBER_FLOATING};
+      break;
+    case IdTypeClass::kBottom:
+      // kBottom means the type is unknown and we need to infer the type before
+      // parsing the number. The rule is: If there is a decimal point, treat
+      // the value as a floating point value, otherwise a integer value, then
+      // if the first char of the integer text is '-', treat the integer as a
+      // signed integer, otherwise an unsigned integer.
+      uint32_t bitwidth = static_cast<uint32_t>(assumedBitWidth(type));
+      if (strchr(val, '.')) {
+        number_type = {bitwidth, SPV_NUMBER_FLOATING};
+      } else if (type.isSigned || val[0] == '-') {
+        number_type = {bitwidth, SPV_NUMBER_SIGNED_INT};
+      } else {
+        number_type = {bitwidth, SPV_NUMBER_UNSIGNED_INT};
+      }
+      break;
   }
 
-  // If this is bottom, but looks like a float, we should treat it like a
-  // float.
-  const bool looks_like_float = is_bottom && strchr(val, '.');
-
-  // If we explicitly expect a floating-point number, we should handle that
-  // first.
-  if (is_floating || looks_like_float)
-    return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
-
-  return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
+  std::string error_msg;
+  EncodeNumberStatus parse_status = ParseAndEncodeNumber(
+      val, number_type,
+      [this, pInst](uint32_t d) { this->binaryEncodeU32(d, pInst); },
+      &error_msg);
+  switch (parse_status) {
+    case EncodeNumberStatus::kSuccess:
+      return SPV_SUCCESS;
+    case EncodeNumberStatus::kInvalidText:
+      return diagnostic(error_code) << error_msg;
+    case EncodeNumberStatus::kUnsupported:
+      return diagnostic(SPV_ERROR_INTERNAL) << error_msg;
+    case EncodeNumberStatus::kInvalidUsage:
+      return diagnostic(SPV_ERROR_INVALID_TEXT) << error_msg;
+  }
+  // This line is not reachable, only added to satisfy the compiler.
+  return diagnostic(SPV_ERROR_INTERNAL)
+         << "Unexpected result code from ParseAndEncodeNumber()";
 }
 
 spv_result_t AssemblyContext::binaryEncodeString(const char* value,
@@ -342,167 +362,4 @@
   return std::get<1>(*type);
 }
 
-spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
-    const char* val, spv_result_t error_code, const IdType& type,
-    spv_instruction_t* pInst) {
-  const auto bit_width = assumedBitWidth(type);
-  switch (bit_width) {
-    case 16: {
-      spvutils::HexFloat<FloatProxy<spvutils::Float16>> hVal(0);
-      if (auto error = parseNumber(val, error_code, &hVal,
-                                   "Invalid 16-bit float literal: "))
-        return error;
-      // getAsFloat will return the spvutils::Float16 value, and get_value
-      // will return a uint16_t representing the bits of the float.
-      // The encoding is therefore correct from the perspective of the SPIR-V
-      // spec since the top 16 bits will be 0.
-      return binaryEncodeU32(
-          static_cast<uint32_t>(hVal.value().getAsFloat().get_value()), pInst);
-    } break;
-    case 32: {
-      spvutils::HexFloat<FloatProxy<float>> fVal(0.0f);
-      if (auto error = parseNumber(val, error_code, &fVal,
-                                   "Invalid 32-bit float literal: "))
-        return error;
-      return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
-    } break;
-    case 64: {
-      spvutils::HexFloat<FloatProxy<double>> dVal(0.0);
-      if (auto error = parseNumber(val, error_code, &dVal,
-                                   "Invalid 64-bit float literal: "))
-        return error;
-      return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
-    } break;
-    default:
-      break;
-  }
-  return diagnostic() << "Unsupported " << bit_width << "-bit float literals";
-}
-
-// Returns SPV_SUCCESS if the given value fits within the target scalar
-// integral type.  The target type may have an unusual bit width.
-// If the value was originally specified as a hexadecimal number, then
-// the overflow bits should be zero.  If it was hex and the target type is
-// signed, then return the sign-extended value through the
-// updated_value_for_hex pointer argument.
-// On failure, return the given error code and emit a diagnostic if that error
-// code is not SPV_FAILED_MATCH.
-template <typename T>
-spv_result_t checkRangeAndIfHexThenSignExtend(T value, spv_result_t error_code,
-                                              const IdType& type, bool is_hex,
-                                              T* updated_value_for_hex) {
-  // The encoded result has three regions of bits that are of interest, from
-  // least to most significant:
-  //   - magnitude bits, where the magnitude of the number would be stored if
-  //     we were using a signed-magnitude representation.
-  //   - an optional sign bit
-  //   - overflow bits, up to bit 63 of a 64-bit number
-  // For example:
-  //   Type                Overflow      Sign       Magnitude
-  //   ---------------     --------      ----       ---------
-  //   unsigned 8 bit      8-63          n/a        0-7
-  //   signed 8 bit        8-63          7          0-6
-  //   unsigned 16 bit     16-63         n/a        0-15
-  //   signed 16 bit       16-63         15         0-14
-
-  // We'll use masks to define the three regions.
-  // At first we'll assume the number is unsigned.
-  const uint32_t bit_width = assumedBitWidth(type);
-  uint64_t magnitude_mask =
-      (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
-  uint64_t sign_mask = 0;
-  uint64_t overflow_mask = ~magnitude_mask;
-
-  if (value < 0 || type.isSigned) {
-    // Accommodate the sign bit.
-    magnitude_mask >>= 1;
-    sign_mask = magnitude_mask + 1;
-  }
-
-  bool failed = false;
-  if (value < 0) {
-    // The top bits must all be 1 for a negative signed value.
-    failed = ((value & overflow_mask) != overflow_mask) ||
-             ((value & sign_mask) != sign_mask);
-  } else {
-    if (is_hex) {
-      // Hex values are a bit special. They decode as unsigned values, but
-      // may represent a negative number.  In this case, the overflow bits
-      // should be zero.
-      failed = (value & overflow_mask) != 0;
-    } else {
-      const uint64_t value_as_u64 = static_cast<uint64_t>(value);
-      // Check overflow in the ordinary case.
-      failed = (value_as_u64 & magnitude_mask) != value_as_u64;
-    }
-  }
-
-  if (failed) {
-    return error_code;
-  }
-
-  // Sign extend hex the number.
-  if (is_hex && (value & sign_mask))
-    *updated_value_for_hex = (value | overflow_mask);
-
-  return SPV_SUCCESS;
-}
-
-spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
-    const char* val, spv_result_t error_code, const IdType& type,
-    spv_instruction_t* pInst) {
-  const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
-  const uint32_t bit_width = assumedBitWidth(type);
-
-  if (bit_width > 64)
-    return diagnostic(SPV_ERROR_INTERNAL) << "Unsupported " << bit_width
-                                          << "-bit integer literals";
-
-  // Either we are expecting anything or integer.
-  bool is_negative = val[0] == '-';
-  bool can_be_signed = is_bottom || type.isSigned;
-
-  if (is_negative && !can_be_signed) {
-    return diagnostic()
-           << "Cannot put a negative number in an unsigned literal";
-  }
-
-  const bool is_hex = val[0] == '0' && (val[1] == 'x' || val[1] == 'X');
-
-  uint64_t decoded_bits;
-  if (is_negative) {
-    int64_t decoded_signed = 0;
-
-    if (auto error = parseNumber(val, error_code, &decoded_signed,
-                                 "Invalid signed integer literal: "))
-      return error;
-    if (auto error = checkRangeAndIfHexThenSignExtend(
-            decoded_signed, error_code, type, is_hex, &decoded_signed)) {
-      diagnostic(error_code)
-          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
-          << decoded_signed << " does not fit in a " << std::dec << bit_width
-          << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
-      return error;
-    }
-    decoded_bits = decoded_signed;
-  } else {
-    // There's no leading minus sign, so parse it as an unsigned integer.
-    if (auto error = parseNumber(val, error_code, &decoded_bits,
-                                 "Invalid unsigned integer literal: "))
-      return error;
-    if (auto error = checkRangeAndIfHexThenSignExtend(
-            decoded_bits, error_code, type, is_hex, &decoded_bits)) {
-      diagnostic(error_code)
-          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
-          << decoded_bits << " does not fit in a " << std::dec << bit_width
-          << "-bit " << (type.isSigned ? "signed" : "unsigned") << " integer";
-      return error;
-    }
-  }
-  if (bit_width > 32) {
-    return binaryEncodeU64(decoded_bits, pInst);
-  } else {
-    return binaryEncodeU32(uint32_t(decoded_bits), pInst);
-  }
-}
 }  // namespace libspirv
diff --git a/source/text_handler.h b/source/text_handler.h
index 521d514..9951643 100644
--- a/source/text_handler.h
+++ b/source/text_handler.h
@@ -226,68 +226,8 @@
   // id is not the id for an extended instruction type.
   spv_ext_inst_type_t getExtInstTypeForId(uint32_t id) const;
 
-  // Parses a numeric value of a given type from the given text.  The number
-  // should take up the entire string, and should be within bounds for the
-  // target type.  On success, returns SPV_SUCCESS and populates the object
-  // referenced by value_pointer. On failure, returns the given error code,
-  // and emits a diagnostic if that error code is not SPV_FAILED_MATCH.
-  template <typename T>
-  spv_result_t parseNumber(const char* text, spv_result_t error_code,
-                           T* value_pointer,
-                           const char* error_message_fragment) {
-    // C++11 doesn't define std::istringstream(int8_t&), so calling this method
-    // with a single-byte type leads to implementation-defined behaviour.
-    // Similarly for uint8_t.
-    static_assert(sizeof(T) > 1,
-                  "Don't use a single-byte type this parse method");
-
-    std::istringstream text_stream(text);
-    // Allow both decimal and hex input for integers.
-    // It also allows octal input, but we don't care about that case.
-    text_stream >> std::setbase(0);
-    text_stream >> *value_pointer;
-
-    // We should have read something.
-    bool ok = (text[0] != 0) && !text_stream.bad();
-    // It should have been all the text.
-    ok = ok && text_stream.eof();
-    // It should have been in range.
-    ok = ok && !text_stream.fail();
-
-    // Work around a bug in the GNU C++11 library. It will happily parse
-    // "-1" for uint16_t as 65535.
-    if (ok && text[0] == '-')
-      ok = !ClampToZeroIfUnsignedType<T>::Clamp(value_pointer);
-
-    if (ok) return SPV_SUCCESS;
-    return diagnostic(error_code) << error_message_fragment << text;
-  }
-
  private:
 
-  // Appends the given floating point literal to the given instruction.
-  // Returns SPV_SUCCESS if the value was correctly parsed.  Otherwise
-  // returns the given error code, and emits a diagnostic if that error
-  // code is not SPV_FAILED_MATCH.
-  // Only 32 and 64 bit floating point numbers are supported.
-  spv_result_t binaryEncodeFloatingPointLiteral(const char* numeric_literal,
-                                                spv_result_t error_code,
-                                                const IdType& type,
-                                                spv_instruction_t* pInst);
-
-  // Appends the given integer literal to the given instruction.
-  // Returns SPV_SUCCESS if the value was correctly parsed.  Otherwise
-  // returns the given error code, and emits a diagnostic if that error
-  // code is not SPV_FAILED_MATCH.
-  // Integers up to 64 bits are supported.
-  spv_result_t binaryEncodeIntegerLiteral(const char* numeric_literal,
-                                          spv_result_t error_code,
-                                          const IdType& type,
-                                          spv_instruction_t* pInst);
-
-  // Writes the given 64-bit literal value into the instruction.
-  // return SPV_SUCCESS if the value could be written in the instruction.
-  spv_result_t binaryEncodeU64(const uint64_t value, spv_instruction_t* pInst);
   // Maps ID names to their corresponding numerical ids.
   using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
   // Maps type-defining IDs to their IdType.
diff --git a/source/util/hex_float.h b/source/util/hex_float.h
index d94d900..ac7e002 100644
--- a/source/util/hex_float.h
+++ b/source/util/hex_float.h
@@ -21,6 +21,7 @@
 #include <cstdint>
 #include <iomanip>
 #include <limits>
+#include <sstream>
 
 #include "bitutils.h"
 
diff --git a/source/util/parse_number.cpp b/source/util/parse_number.cpp
new file mode 100644
index 0000000..bba7545
--- /dev/null
+++ b/source/util/parse_number.cpp
@@ -0,0 +1,199 @@
+// Copyright (c) 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/parse_number.h"
+
+#include <functional>
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <tuple>
+
+#include "util/hex_float.h"
+
+namespace spvutils {
+
+namespace {
+// A helper class that temporarily stores error messages and dump the messages
+// to a string which given as as pointer when it is destructed. If the given
+// pointer is a nullptr, this class does not store error message.
+class ErrorMsgStream {
+ public:
+  explicit ErrorMsgStream(std::string* error_msg_sink)
+      : error_msg_sink_(error_msg_sink) {
+    if (error_msg_sink_) stream_.reset(new std::ostringstream());
+  }
+  ~ErrorMsgStream() {
+    if (error_msg_sink_ && stream_) *error_msg_sink_ = stream_->str();
+  }
+  template <typename T>
+  ErrorMsgStream& operator<<(T val) {
+    if (stream_) *stream_ << val;
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<std::ostringstream> stream_;
+  // The destination string to which this class dump the error message when
+  // destructor is called.
+  std::string* error_msg_sink_;
+};
+}
+
+EncodeNumberStatus ParseAndEncodeIntegerNumber(
+    const char* text, const NumberType& type,
+    std::function<void(uint32_t)> emit, std::string* error_msg) {
+  if (!IsIntegral(type)) {
+    ErrorMsgStream(error_msg) << "The expected type is not a integer type";
+    return EncodeNumberStatus::kInvalidUsage;
+  }
+
+  const uint32_t bit_width = AssumedBitWidth(type);
+
+  if (bit_width > 64) {
+    ErrorMsgStream(error_msg) << "Unsupported " << bit_width
+                              << "-bit integer literals";
+    return EncodeNumberStatus::kUnsupported;
+  }
+
+  // Either we are expecting anything or integer.
+  bool is_negative = text[0] == '-';
+  bool can_be_signed = IsSigned(type);
+
+  if (is_negative && !can_be_signed) {
+    ErrorMsgStream(error_msg)
+        << "Cannot put a negative number in an unsigned literal";
+    return EncodeNumberStatus::kInvalidUsage;
+  }
+
+  const bool is_hex = text[0] == '0' && (text[1] == 'x' || text[1] == 'X');
+
+  uint64_t decoded_bits;
+  if (is_negative) {
+    int64_t decoded_signed = 0;
+
+    if (!ParseNumber(text, &decoded_signed)) {
+      ErrorMsgStream(error_msg) << "Invalid signed integer literal: " << text;
+      return EncodeNumberStatus::kInvalidText;
+    }
+
+    if (!CheckRangeAndIfHexThenSignExtend(decoded_signed, type, is_hex,
+                                          &decoded_signed)) {
+      ErrorMsgStream(error_msg)
+          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
+          << decoded_signed << " does not fit in a " << std::dec << bit_width
+          << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
+      return EncodeNumberStatus::kInvalidText;
+    }
+    decoded_bits = decoded_signed;
+  } else {
+    // There's no leading minus sign, so parse it as an unsigned integer.
+    if (!ParseNumber(text, &decoded_bits)) {
+      ErrorMsgStream(error_msg) << "Invalid unsigned integer literal: " << text;
+      return EncodeNumberStatus::kInvalidText;
+    }
+    if (!CheckRangeAndIfHexThenSignExtend(decoded_bits, type, is_hex,
+                                          &decoded_bits)) {
+      ErrorMsgStream(error_msg)
+          << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
+          << decoded_bits << " does not fit in a " << std::dec << bit_width
+          << "-bit " << (IsSigned(type) ? "signed" : "unsigned") << " integer";
+      return EncodeNumberStatus::kInvalidText;
+    }
+  }
+  if (bit_width > 32) {
+    uint32_t low = uint32_t(0x00000000ffffffff & decoded_bits);
+    uint32_t high = uint32_t((0xffffffff00000000 & decoded_bits) >> 32);
+    emit(low);
+    emit(high);
+  } else {
+    emit(uint32_t(decoded_bits));
+  }
+  return EncodeNumberStatus::kSuccess;
+}
+
+EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
+    const char* text, const NumberType& type,
+    std::function<void(uint32_t)> emit, std::string* error_msg) {
+  if (!IsFloating(type)) {
+    ErrorMsgStream(error_msg) << "The expected type is not a float type";
+    return EncodeNumberStatus::kInvalidUsage;
+  }
+
+  const auto bit_width = AssumedBitWidth(type);
+  switch (bit_width) {
+    case 16: {
+      HexFloat<FloatProxy<spvutils::Float16>> hVal(0);
+      if (!ParseNumber(text, &hVal)) {
+        ErrorMsgStream(error_msg) << "Invalid 16-bit float literal: " << text;
+        return EncodeNumberStatus::kInvalidText;
+      }
+      // getAsFloat will return the spvutils::Float16 value, and get_value
+      // will return a uint16_t representing the bits of the float.
+      // The encoding is therefore correct from the perspective of the SPIR-V
+      // spec since the top 16 bits will be 0.
+      emit(static_cast<uint32_t>(hVal.value().getAsFloat().get_value()));
+      return EncodeNumberStatus::kSuccess;
+    } break;
+    case 32: {
+      HexFloat<FloatProxy<float>> fVal(0.0f);
+      if (!ParseNumber(text, &fVal)) {
+        ErrorMsgStream(error_msg) << "Invalid 32-bit float literal: " << text;
+        return EncodeNumberStatus::kInvalidText;
+      }
+      emit(BitwiseCast<uint32_t>(fVal));
+      return EncodeNumberStatus::kSuccess;
+    } break;
+    case 64: {
+      HexFloat<FloatProxy<double>> dVal(0.0);
+      if (!ParseNumber(text, &dVal)) {
+        ErrorMsgStream(error_msg) << "Invalid 64-bit float literal: " << text;
+        return EncodeNumberStatus::kInvalidText;
+      }
+      uint64_t decoded_val = BitwiseCast<uint64_t>(dVal);
+      uint32_t low = uint32_t(0x00000000ffffffff & decoded_val);
+      uint32_t high = uint32_t((0xffffffff00000000 & decoded_val) >> 32);
+      emit(low);
+      emit(high);
+      return EncodeNumberStatus::kSuccess;
+    } break;
+    default:
+      break;
+  }
+  ErrorMsgStream(error_msg) << "Unsupported " << bit_width
+                            << "-bit float literals";
+  return EncodeNumberStatus::kUnsupported;
+}
+
+EncodeNumberStatus ParseAndEncodeNumber(const char* text,
+                                        const NumberType& type,
+                                        std::function<void(uint32_t)> emit,
+                                        std::string* error_msg) {
+  if (IsUnknown(type)) {
+    ErrorMsgStream(error_msg)
+        << "The expected type is not a integer or float type";
+    return EncodeNumberStatus::kInvalidUsage;
+  }
+
+  // If we explicitly expect a floating-point number, we should handle that
+  // first.
+  if (IsFloating(type)) {
+    return ParseAndEncodeFloatingPointNumber(text, type, emit, error_msg);
+  }
+
+  return ParseAndEncodeIntegerNumber(text, type, emit, error_msg);
+}
+
+}  // namespace spvutils
diff --git a/source/util/parse_number.h b/source/util/parse_number.h
new file mode 100644
index 0000000..6b9903a
--- /dev/null
+++ b/source/util/parse_number.h
@@ -0,0 +1,249 @@
+// Copyright (c) 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef LIBSPIRV_UTIL_PARSE_NUMBER_H_
+#define LIBSPIRV_UTIL_PARSE_NUMBER_H_
+
+#include <functional>
+#include <string>
+#include <tuple>
+
+#include "spirv-tools/libspirv.h"
+#include "util/hex_float.h"
+
+namespace spvutils {
+
+// A struct to hold the expected type information for the number in text to be
+// parsed.
+struct NumberType {
+  uint32_t bitwidth;
+  // SPV_NUMBER_NONE means the type is unknown and is invalid to be used with
+  // ParseAndEncode{|Integer|Floating}Number().
+  spv_number_kind_t kind;
+};
+
+// Returns true if the type is a scalar integer type.
+inline bool IsIntegral(const NumberType& type) {
+  return type.kind == SPV_NUMBER_UNSIGNED_INT ||
+         type.kind == SPV_NUMBER_SIGNED_INT;
+}
+
+// Returns true if the type is a scalar floating point type.
+inline bool IsFloating(const NumberType& type) {
+  return type.kind == SPV_NUMBER_FLOATING;
+}
+
+// Returns true if the type is a signed value.
+inline bool IsSigned(const NumberType& type) {
+  return type.kind == SPV_NUMBER_FLOATING || type.kind == SPV_NUMBER_SIGNED_INT;
+}
+
+// Returns true if the type is unknown.
+inline bool IsUnknown(const NumberType& type) {
+  return type.kind == SPV_NUMBER_NONE;
+}
+
+// Returns the number of bits in the type. This is only valid for integer and
+// floating types.
+inline int AssumedBitWidth(const NumberType& type) {
+  switch (type.kind) {
+    case SPV_NUMBER_SIGNED_INT:
+    case SPV_NUMBER_UNSIGNED_INT:
+    case SPV_NUMBER_FLOATING:
+      return type.bitwidth;
+    default:
+      break;
+  }
+  // We don't care about this case.
+  return 0;
+}
+
+// A templated class with a static member function Clamp, where Clamp sets a
+// referenced value of type T to 0 if T is an unsigned integer type, and
+// returns true if it modified the referenced value.
+template <typename T, typename = void>
+class ClampToZeroIfUnsignedType {
+ public:
+  // The default specialization does not clamp the value.
+  static bool Clamp(T*) { return false; }
+};
+
+// The specialization of ClampToZeroIfUnsignedType for unsigned integer types.
+template <typename T>
+class ClampToZeroIfUnsignedType<
+    T, typename std::enable_if<std::is_unsigned<T>::value>::type> {
+ public:
+  static bool Clamp(T* value_pointer) {
+    if (*value_pointer) {
+      *value_pointer = 0;
+      return true;
+    }
+    return false;
+  }
+};
+
+// Returns true if the given value fits within the target scalar integral type.
+// The target type may have an unusual bit width. If the value was originally
+// specified as a hexadecimal number, then the overflow bits should be zero.
+// If it was hex and the target type is signed, then return the sign-extended
+// value through the updated_value_for_hex pointer argument. On failure,
+// returns false.
+template <typename T>
+bool CheckRangeAndIfHexThenSignExtend(T value, const NumberType& type,
+                                      bool is_hex, T* updated_value_for_hex) {
+  // The encoded result has three regions of bits that are of interest, from
+  // least to most significant:
+  //   - magnitude bits, where the magnitude of the number would be stored if
+  //     we were using a signed-magnitude representation.
+  //   - an optional sign bit
+  //   - overflow bits, up to bit 63 of a 64-bit number
+  // For example:
+  //   Type                Overflow      Sign       Magnitude
+  //   ---------------     --------      ----       ---------
+  //   unsigned 8 bit      8-63          n/a        0-7
+  //   signed 8 bit        8-63          7          0-6
+  //   unsigned 16 bit     16-63         n/a        0-15
+  //   signed 16 bit       16-63         15         0-14
+
+  // We'll use masks to define the three regions.
+  // At first we'll assume the number is unsigned.
+  const uint32_t bit_width = AssumedBitWidth(type);
+  uint64_t magnitude_mask =
+      (bit_width == 64) ? -1 : ((uint64_t(1) << bit_width) - 1);
+  uint64_t sign_mask = 0;
+  uint64_t overflow_mask = ~magnitude_mask;
+
+  if (value < 0 || IsSigned(type)) {
+    // Accommodate the sign bit.
+    magnitude_mask >>= 1;
+    sign_mask = magnitude_mask + 1;
+  }
+
+  bool failed = false;
+  if (value < 0) {
+    // The top bits must all be 1 for a negative signed value.
+    failed = ((value & overflow_mask) != overflow_mask) ||
+             ((value & sign_mask) != sign_mask);
+  } else {
+    if (is_hex) {
+      // Hex values are a bit special. They decode as unsigned values, but may
+      // represent a negative number. In this case, the overflow bits should
+      // be zero.
+      failed = (value & overflow_mask) != 0;
+    } else {
+      const uint64_t value_as_u64 = static_cast<uint64_t>(value);
+      // Check overflow in the ordinary case.
+      failed = (value_as_u64 & magnitude_mask) != value_as_u64;
+    }
+  }
+
+  if (failed) {
+    return false;
+  }
+
+  // Sign extend hex the number.
+  if (is_hex && (value & sign_mask))
+    *updated_value_for_hex = (value | overflow_mask);
+
+  return true;
+}
+
+// Parses a numeric value of a given type from the given text.  The number
+// should take up the entire string, and should be within bounds for the target
+// type. On success, returns true and populates the object referenced by
+// value_pointer. On failure, returns false.
+template <typename T>
+bool ParseNumber(const char* text, T* value_pointer) {
+  // C++11 doesn't define std::istringstream(int8_t&), so calling this method
+  // with a single-byte type leads to implementation-defined behaviour.
+  // Similarly for uint8_t.
+  static_assert(sizeof(T) > 1,
+                "Don't use a single-byte type this parse method");
+
+  std::istringstream text_stream(text);
+  // Allow both decimal and hex input for integers.
+  // It also allows octal input, but we don't care about that case.
+  text_stream >> std::setbase(0);
+  text_stream >> *value_pointer;
+
+  // We should have read something.
+  bool ok = (text[0] != 0) && !text_stream.bad();
+  // It should have been all the text.
+  ok = ok && text_stream.eof();
+  // It should have been in range.
+  ok = ok && !text_stream.fail();
+
+  // Work around a bug in the GNU C++11 library. It will happily parse
+  // "-1" for uint16_t as 65535.
+  if (ok && text[0] == '-')
+    ok = !ClampToZeroIfUnsignedType<T>::Clamp(value_pointer);
+
+  return ok;
+}
+
+// Enum to indicate the parsing and encoding status.
+enum class EncodeNumberStatus {
+  kSuccess = 0,
+  // Unsupported bit width etc.
+  kUnsupported,
+  // Expected type (NumberType) is not a scalar int or float, or putting a
+  // negative number in an unsigned literal.
+  kInvalidUsage,
+  // Number value does not fit the bit width of the expected type etc.
+  kInvalidText,
+};
+
+// Parses an integer value of a given |type| from the given |text| and encodes
+// the number by the given |emit| function. On success, returns
+// EncodeNumberStatus::kSuccess and the parsed number will be consumed by the
+// given |emit| function word by word (least significant word first). On
+// failure, this function returns the error code of the encoding status and
+// |emit| function will not be called. If the string pointer |error_msg| is not
+// a nullptr, it will be overwritten with error messages in case of failure. In
+// case of success, |error_msg| will not be touched. Integers up to 64 bits are
+// supported.
+EncodeNumberStatus ParseAndEncodeIntegerNumber(
+    const char* text, const NumberType& type,
+    std::function<void(uint32_t)> emit, std::string* error_msg);
+
+// Parses a floating point value of a given |type| from the given |text| and
+// encodes the number by the given |emit| funciton. On success, returns
+// EncodeNumberStatus::kSuccess and the parsed number will be consumed by the
+// given |emit| function word by word (least significant word first). On
+// failure, this function returns the error code of the encoding status and
+// |emit| function will not be called. If the string pointer |error_msg| is not
+// a nullptr, it will be overwritten with error messages in case of failure. In
+// case of success, |error_msg| will not be touched. Only 16, 32 and 64 bit
+// floating point numbers are supported.
+EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
+    const char* text, const NumberType& type,
+    std::function<void(uint32_t)> emit, std::string* error_msg);
+
+// Parses an integer or floating point number of a given |type| from the given
+// |text| and encodes the number by the given |emit| function. On success,
+// returns EncodeNumberStatus::kSuccess and the parsed number will be consumed
+// by the given |emit| function word by word (least significant word first). On
+// failure, this function returns the error code of the encoding status and
+// |emit| function will not be called. If the string pointer |error_msg| is not
+// a nullptr, it will be overwritten with error messages in case of failure. In
+// case of success, |error_msg| will not be touched. Integers up to 64 bits
+// and 16/32/64 bit floating point values are supported.
+EncodeNumberStatus ParseAndEncodeNumber(const char* text,
+                                        const NumberType& type,
+                                        std::function<void(uint32_t)> emit,
+                                        std::string* error_msg);
+
+}  // namespace spvutils
+
+#endif  // LIBSPIRV_UTIL_PARSE_NUMBER_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 10012b4..b585a26 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -134,5 +134,10 @@
   SRCS cpp_interface.cpp
   LIBS SPIRV-Tools-opt ${SPIRV_TOOLS})
 
+add_spvtools_unittest(
+  TARGET parse_number
+  SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ParseNumber.cpp
+  LIBS ${SPIRV_TOOLS})
+
 add_subdirectory(opt)
 add_subdirectory(val)
diff --git a/test/ParseNumber.cpp b/test/ParseNumber.cpp
new file mode 100644
index 0000000..42f3b2a
--- /dev/null
+++ b/test/ParseNumber.cpp
@@ -0,0 +1,943 @@
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "source/util/parse_number.h"
+#include "spirv-tools/libspirv.h"
+
+namespace {
+using spvutils::NumberType;
+using spvutils::EncodeNumberStatus;
+using spvutils::ParseNumber;
+using spvutils::ParseAndEncodeIntegerNumber;
+using spvutils::ParseAndEncodeFloatingPointNumber;
+using spvutils::ParseAndEncodeNumber;
+using testing::Eq;
+using testing::IsNull;
+using testing::NotNull;
+
+TEST(ParseNarrowSignedIntegers, Sample) {
+  int16_t i16;
+
+  EXPECT_FALSE(ParseNumber("", &i16));
+  EXPECT_FALSE(ParseNumber("0=", &i16));
+
+  EXPECT_TRUE(ParseNumber("0", &i16));
+  EXPECT_EQ(0, i16);
+  EXPECT_TRUE(ParseNumber("32767", &i16));
+  EXPECT_EQ(32767, i16);
+  EXPECT_TRUE(ParseNumber("-32768", &i16));
+  EXPECT_EQ(-32768, i16);
+  EXPECT_TRUE(ParseNumber("-0", &i16));
+  EXPECT_EQ(0, i16);
+
+  // These are out of range, so they should return an error.
+  // The error code depends on whether this is an optional value.
+  EXPECT_FALSE(ParseNumber("32768", &i16));
+  EXPECT_FALSE(ParseNumber("65535", &i16));
+
+  // Check hex parsing.
+  EXPECT_TRUE(ParseNumber("0x7fff", &i16));
+  EXPECT_EQ(32767, i16);
+  // This is out of range.
+  EXPECT_FALSE(ParseNumber("0xffff", &i16));
+}
+
+TEST(ParseNarrowUnsignedIntegers, Sample) {
+  uint16_t u16;
+
+  EXPECT_FALSE(ParseNumber("", &u16));
+  EXPECT_FALSE(ParseNumber("0=", &u16));
+
+  EXPECT_TRUE(ParseNumber("0", &u16));
+  EXPECT_EQ(0, u16);
+  EXPECT_TRUE(ParseNumber("65535", &u16));
+  EXPECT_EQ(65535, u16);
+  EXPECT_FALSE(ParseNumber("65536", &u16));
+
+  // We don't care about -0 since it's rejected at a higher level.
+  EXPECT_FALSE(ParseNumber("-1", &u16));
+  EXPECT_TRUE(ParseNumber("0xffff", &u16));
+  EXPECT_EQ(0xffff, u16);
+  EXPECT_FALSE(ParseNumber("0x10000", &u16));
+}
+
+TEST(ParseSignedIntegers, Sample) {
+  int32_t i32;
+
+  // Invalid parse.
+  EXPECT_FALSE(ParseNumber("", &i32));
+  EXPECT_FALSE(ParseNumber("0=", &i32));
+
+  // Decimal values.
+  EXPECT_TRUE(ParseNumber("0", &i32));
+  EXPECT_EQ(0, i32);
+  EXPECT_TRUE(ParseNumber("2147483647", &i32));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), i32);
+  EXPECT_FALSE(ParseNumber("2147483648", &i32));
+  EXPECT_TRUE(ParseNumber("-0", &i32));
+  EXPECT_EQ(0, i32);
+  EXPECT_TRUE(ParseNumber("-1", &i32));
+  EXPECT_EQ(-1, i32);
+  EXPECT_TRUE(ParseNumber("-2147483648", &i32));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), i32);
+
+  // Hex values.
+  EXPECT_TRUE(ParseNumber("0x7fffffff", &i32));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), i32);
+  EXPECT_FALSE(ParseNumber("0x80000000", &i32));
+  EXPECT_TRUE(ParseNumber("-0x000", &i32));
+  EXPECT_EQ(0, i32);
+  EXPECT_TRUE(ParseNumber("-0x001", &i32));
+  EXPECT_EQ(-1, i32);
+  EXPECT_TRUE(ParseNumber("-0x80000000", &i32));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), i32);
+}
+
+TEST(ParseUnsignedIntegers, Sample) {
+  uint32_t u32;
+
+  // Invalid parse.
+  EXPECT_FALSE(ParseNumber("", &u32));
+  EXPECT_FALSE(ParseNumber("0=", &u32));
+
+  // Valid values.
+  EXPECT_TRUE(ParseNumber("0", &u32));
+  EXPECT_EQ(0u, u32);
+  EXPECT_TRUE(ParseNumber("4294967295", &u32));
+  EXPECT_EQ(std::numeric_limits<uint32_t>::max(), u32);
+  EXPECT_FALSE(ParseNumber("4294967296", &u32));
+
+  // Hex values.
+  EXPECT_TRUE(ParseNumber("0xffffffff", &u32));
+  EXPECT_EQ(std::numeric_limits<uint32_t>::max(), u32);
+
+  // We don't care about -0 since it's rejected at a higher level.
+  EXPECT_FALSE(ParseNumber("-1", &u32));
+}
+
+TEST(ParseWideSignedIntegers, Sample) {
+  int64_t i64;
+  EXPECT_FALSE(ParseNumber("", &i64));
+  EXPECT_FALSE(ParseNumber("0=", &i64));
+  EXPECT_TRUE(ParseNumber("0", &i64));
+  EXPECT_EQ(0, i64);
+  EXPECT_TRUE(ParseNumber("0x7fffffffffffffff", &i64));
+  EXPECT_EQ(0x7fffffffffffffff, i64);
+  EXPECT_TRUE(ParseNumber("-0", &i64));
+  EXPECT_EQ(0, i64);
+  EXPECT_TRUE(ParseNumber("-1", &i64));
+  EXPECT_EQ(-1, i64);
+}
+
+TEST(ParseWideUnsignedIntegers, Sample) {
+  uint64_t u64;
+  EXPECT_FALSE(ParseNumber("", &u64));
+  EXPECT_FALSE(ParseNumber("0=", &u64));
+  EXPECT_TRUE(ParseNumber("0", &u64));
+  EXPECT_EQ(0u, u64);
+  EXPECT_TRUE(ParseNumber("0xffffffffffffffff", &u64));
+  EXPECT_EQ(0xffffffffffffffffULL, u64);
+
+  // We don't care about -0 since it's rejected at a higher level.
+  EXPECT_FALSE(ParseNumber("-1", &u64));
+}
+
+TEST(ParseFloat, Sample) {
+  float f;
+
+  EXPECT_FALSE(ParseNumber("", &f));
+  EXPECT_FALSE(ParseNumber("0=", &f));
+
+  // These values are exactly representatble.
+  EXPECT_TRUE(ParseNumber("0", &f));
+  EXPECT_EQ(0.0f, f);
+  EXPECT_TRUE(ParseNumber("42", &f));
+  EXPECT_EQ(42.0f, f);
+  EXPECT_TRUE(ParseNumber("2.5", &f));
+  EXPECT_EQ(2.5f, f);
+  EXPECT_TRUE(ParseNumber("-32.5", &f));
+  EXPECT_EQ(-32.5f, f);
+  EXPECT_TRUE(ParseNumber("1e38", &f));
+  EXPECT_EQ(1e38f, f);
+  EXPECT_TRUE(ParseNumber("-1e38", &f));
+  EXPECT_EQ(-1e38f, f);
+}
+
+TEST(ParseFloat, Overflow) {
+  // The assembler parses using HexFloat<FloatProxy<float>>.  Make
+  // sure that succeeds for in-range values, and fails for out of
+  // range values.  When it does overflow, the value is set to the
+  // nearest finite value, matching C++11 behavior for operator>>
+  // on floating point.
+  spvutils::HexFloat<spvutils::FloatProxy<float>> f(0.0f);
+
+  EXPECT_TRUE(ParseNumber("1e38", &f));
+  EXPECT_EQ(1e38f, f.value().getAsFloat());
+  EXPECT_TRUE(ParseNumber("-1e38", &f));
+  EXPECT_EQ(-1e38f, f.value().getAsFloat());
+  EXPECT_FALSE(ParseNumber("1e40", &f));
+  EXPECT_FALSE(ParseNumber("-1e40", &f));
+  EXPECT_FALSE(ParseNumber("1e400", &f));
+  EXPECT_FALSE(ParseNumber("-1e400", &f));
+}
+
+TEST(ParseDouble, Sample) {
+  double f;
+
+  EXPECT_FALSE(ParseNumber("", &f));
+  EXPECT_FALSE(ParseNumber("0=", &f));
+
+  // These values are exactly representatble.
+  EXPECT_TRUE(ParseNumber("0", &f));
+  EXPECT_EQ(0.0, f);
+  EXPECT_TRUE(ParseNumber("42", &f));
+  EXPECT_EQ(42.0, f);
+  EXPECT_TRUE(ParseNumber("2.5", &f));
+  EXPECT_EQ(2.5, f);
+  EXPECT_TRUE(ParseNumber("-32.5", &f));
+  EXPECT_EQ(-32.5, f);
+  EXPECT_TRUE(ParseNumber("1e38", &f));
+  EXPECT_EQ(1e38, f);
+  EXPECT_TRUE(ParseNumber("-1e38", &f));
+  EXPECT_EQ(-1e38, f);
+  // These are out of range for 32-bit float, but in range for 64-bit float.
+  EXPECT_TRUE(ParseNumber("1e40", &f));
+  EXPECT_EQ(1e40, f);
+  EXPECT_TRUE(ParseNumber("-1e40", &f));
+  EXPECT_EQ(-1e40, f);
+}
+
+TEST(ParseDouble, Overflow) {
+  // The assembler parses using HexFloat<FloatProxy<double>>.  Make
+  // sure that succeeds for in-range values, and fails for out of
+  // range values.  When it does overflow, the value is set to the
+  // nearest finite value, matching C++11 behavior for operator>>
+  // on floating point.
+  spvutils::HexFloat<spvutils::FloatProxy<double>> f(0.0);
+
+  EXPECT_TRUE(ParseNumber("1e38", &f));
+  EXPECT_EQ(1e38, f.value().getAsFloat());
+  EXPECT_TRUE(ParseNumber("-1e38", &f));
+  EXPECT_EQ(-1e38, f.value().getAsFloat());
+  EXPECT_TRUE(ParseNumber("1e40", &f));
+  EXPECT_EQ(1e40, f.value().getAsFloat());
+  EXPECT_TRUE(ParseNumber("-1e40", &f));
+  EXPECT_EQ(-1e40, f.value().getAsFloat());
+  EXPECT_FALSE(ParseNumber("1e400", &f));
+  EXPECT_FALSE(ParseNumber("-1e400", &f));
+}
+
+TEST(ParseFloat16, Overflow) {
+  // The assembler parses using HexFloat<FloatProxy<Float16>>.  Make
+  // sure that succeeds for in-range values, and fails for out of
+  // range values.  When it does overflow, the value is set to the
+  // nearest finite value, matching C++11 behavior for operator>>
+  // on floating point.
+  spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f(0);
+
+  EXPECT_TRUE(ParseNumber("-0.0", &f));
+  EXPECT_EQ(uint16_t{0x8000}, f.value().getAsFloat().get_value());
+  EXPECT_TRUE(ParseNumber("1.0", &f));
+  EXPECT_EQ(uint16_t{0x3c00}, f.value().getAsFloat().get_value());
+
+  // Overflows 16-bit but not 32-bit
+  EXPECT_FALSE(ParseNumber("1e38", &f));
+  EXPECT_FALSE(ParseNumber("-1e38", &f));
+
+  // Overflows 32-bit but not 64-bit
+  EXPECT_FALSE(ParseNumber("1e40", &f));
+  EXPECT_FALSE(ParseNumber("-1e40", &f));
+
+  // Overflows 64-bit
+  EXPECT_FALSE(ParseNumber("1e400", &f));
+  EXPECT_FALSE(ParseNumber("-1e400", &f));
+}
+
+void AssertEmitFunc(uint32_t) {
+  ASSERT_FALSE(true)
+      << "Should not call emit() function when the number can not be parsed.";
+  return;
+}
+
+TEST(ParseAndEncodeNarrowSignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {16, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid signed integer literal: -", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+}
+
+TEST(ParseAndEncodeNarrowSignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {16, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("32768", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer 32768 does not fit in a 16-bit signed integer", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-32769", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer -32769 does not fit in a 16-bit signed integer", err_msg);
+}
+
+TEST(ParseAndEncodeNarrowSignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {16, SPV_NUMBER_SIGNED_INT};
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber(
+      "0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "-0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "32767", type, [](uint32_t word) { EXPECT_EQ(0x00007fffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "-32768", type, [](uint32_t word) { EXPECT_EQ(0xffff8000u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber(
+      "0x7fff", type, [](uint32_t word) { EXPECT_EQ(0x00007fffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "0xffff", type, [](uint32_t word) { EXPECT_EQ(0xffffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+}
+
+TEST(ParseAndEncodeNarrowUnsignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {16, SPV_NUMBER_UNSIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-0", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-1", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+}
+
+TEST(ParseAndEncodeNarrowUnsignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg("random content");
+  NumberType type = {16, SPV_NUMBER_UNSIGNED_INT};
+
+  // Overflow
+  rc = ParseAndEncodeIntegerNumber("65536", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer 65536 does not fit in a 16-bit unsigned integer", err_msg);
+}
+
+TEST(ParseAndEncodeNarrowUnsignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {16, SPV_NUMBER_UNSIGNED_INT};
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber(
+      "0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "65535", type, [](uint32_t word) { EXPECT_EQ(0x0000ffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber(
+      "0xffff", type, [](uint32_t word) { EXPECT_EQ(0x0000ffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+}
+
+TEST(ParseAndEncodeSignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid signed integer literal: -", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+}
+
+TEST(ParseAndEncodeSignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  rc =
+      ParseAndEncodeIntegerNumber("2147483648", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer 2147483648 does not fit in a 32-bit signed integer",
+            err_msg);
+  rc = ParseAndEncodeIntegerNumber("-2147483649", type, AssertEmitFunc,
+                                   &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer -2147483649 does not fit in a 32-bit signed integer",
+            err_msg);
+}
+
+TEST(ParseAndEncodeSignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber(
+      "0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "-0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "2147483647", type, [](uint32_t word) { EXPECT_EQ(0x7fffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "-2147483648", type, [](uint32_t word) { EXPECT_EQ(0x80000000u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber(
+      "0x7fffffff", type, [](uint32_t word) { EXPECT_EQ(0x7fffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "0xffffffff", type, [](uint32_t word) { EXPECT_EQ(0xffffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+}
+
+TEST(ParseAndEncodeUnsignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_UNSIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-0", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-1", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+}
+
+TEST(ParseAndEncodeUnsignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg("random content");
+  NumberType type = {32, SPV_NUMBER_UNSIGNED_INT};
+
+  // Overflow
+  rc =
+      ParseAndEncodeIntegerNumber("4294967296", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Integer 4294967296 does not fit in a 32-bit unsigned integer",
+            err_msg);
+}
+
+TEST(ParseAndEncodeUnsignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {32, SPV_NUMBER_UNSIGNED_INT};
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber(
+      "0", type, [](uint32_t word) { EXPECT_EQ(0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeIntegerNumber(
+      "4294967295", type, [](uint32_t word) { EXPECT_EQ(0xffffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber(
+      "0xffffffff", type, [](uint32_t word) { EXPECT_EQ(0xffffffffu, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+}
+
+TEST(ParseAndEncodeWideSignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {64, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid signed integer literal: -", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+}
+
+TEST(ParseAndEncodeWideSignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {64, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("9223372036854775808", type, AssertEmitFunc,
+                                   &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ(
+      "Integer 9223372036854775808 does not fit in a 64-bit signed integer",
+      err_msg);
+  rc = ParseAndEncodeIntegerNumber("-9223372036854775809", type, AssertEmitFunc,
+                                   &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid signed integer literal: -9223372036854775809", err_msg);
+}
+
+TEST(ParseAndEncodeWideSignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {64, SPV_NUMBER_SIGNED_INT};
+  std::vector<uint32_t> word_buffer;
+  auto emit = [&word_buffer](uint32_t word) {
+    if (word_buffer.size() == 2) word_buffer.clear();
+    word_buffer.push_back(word);
+  };
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber("0", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0u}));
+  rc = ParseAndEncodeIntegerNumber("-0", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0u}));
+  rc = ParseAndEncodeIntegerNumber("9223372036854775807", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0x7fffffffu}));
+  rc = ParseAndEncodeIntegerNumber("-9223372036854775808", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0x80000000u}));
+  rc = ParseAndEncodeIntegerNumber("-1", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0xffffffffu}));
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber("0x7fffffffffffffff", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0x7fffffffu}));
+  rc = ParseAndEncodeIntegerNumber("0xffffffffffffffff", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0xffffffffu}));
+}
+
+TEST(ParseAndEncodeWideUnsignedIntegers, Invalid) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {64, SPV_NUMBER_UNSIGNED_INT};
+
+  // Invalid
+  rc = ParseAndEncodeIntegerNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: ", err_msg);
+  rc = ParseAndEncodeIntegerNumber("=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: =", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 0=", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-0", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+  rc = ParseAndEncodeIntegerNumber("-1", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("Cannot put a negative number in an unsigned literal", err_msg);
+}
+
+TEST(ParseAndEncodeWideUnsignedIntegers, Overflow) {
+  // The error message should be overwritten after each parsing call.
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {64, SPV_NUMBER_UNSIGNED_INT};
+
+  // Overflow
+  rc = ParseAndEncodeIntegerNumber("18446744073709551616", type, AssertEmitFunc,
+                                   &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: 18446744073709551616", err_msg);
+}
+
+TEST(ParseAndEncodeWideUnsignedIntegers, Success) {
+  // Don't care the error message in this case.
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  NumberType type = {64, SPV_NUMBER_UNSIGNED_INT};
+  std::vector<uint32_t> word_buffer;
+  auto emit = [&word_buffer](uint32_t word) {
+    if (word_buffer.size() == 2) word_buffer.clear();
+    word_buffer.push_back(word);
+  };
+
+  // Zero, maximum, and minimum value
+  rc = ParseAndEncodeIntegerNumber("0", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0u}));
+  rc = ParseAndEncodeIntegerNumber("18446744073709551615", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0xffffffffu}));
+
+  // Hex parsing
+  rc = ParseAndEncodeIntegerNumber("0xffffffffffffffff", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xffffffffu, 0xffffffffu}));
+}
+
+TEST(ParseAndEncodeIntegerNumber, TypeNone) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_NONE};
+
+  rc = ParseAndEncodeIntegerNumber(
+      "0.0", type, [](uint32_t word) { EXPECT_EQ(0x0u, word); }, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("The expected type is not a integer type", err_msg);
+}
+
+TEST(ParseAndEncodeIntegerNumber, InvalidCaseWithoutErrorMessageString) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber("invalid", type, AssertEmitFunc, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+}
+
+TEST(ParseAndEncodeIntegerNumber, DoNotTouchErrorMessageStringOnSuccess) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  std::string err_msg("random content");
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  rc = ParseAndEncodeIntegerNumber(
+      "100", type, [](uint32_t word) { EXPECT_EQ(100u, word); }, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_EQ("random content", err_msg);
+}
+
+TEST(ParseAndEncodeFloat, Sample) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_FLOATING};
+
+  // Invalid
+  rc = ParseAndEncodeFloatingPointNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: ", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: 0=", err_msg);
+
+  // Representative samples
+  rc = ParseAndEncodeFloatingPointNumber(
+      "0.0", type, [](uint32_t word) { EXPECT_EQ(0x0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "-0.0", type, [](uint32_t word) { EXPECT_EQ(0x80000000u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "42", type, [](uint32_t word) { EXPECT_EQ(0x42280000u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "2.5", type, [](uint32_t word) { EXPECT_EQ(0x40200000u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "-32.5", type, [](uint32_t word) { EXPECT_EQ(0xc2020000u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "1e38", type, [](uint32_t word) { EXPECT_EQ(0x7e967699u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "-1e38", type, [](uint32_t word) { EXPECT_EQ(0xfe967699u, word); },
+      nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Overflow
+  rc =
+      ParseAndEncodeFloatingPointNumber("1e40", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: 1e40", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e40", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: -1e40", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: 1e400", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 32-bit float literal: -1e400", err_msg);
+}
+
+TEST(ParseAndEncodeDouble, Sample) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {64, SPV_NUMBER_FLOATING};
+  std::vector<uint32_t> word_buffer;
+  auto emit = [&word_buffer](uint32_t word) {
+    if (word_buffer.size() == 2) word_buffer.clear();
+    word_buffer.push_back(word);
+  };
+
+  // Invalid
+  rc = ParseAndEncodeFloatingPointNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 64-bit float literal: ", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 64-bit float literal: 0=", err_msg);
+
+  // Representative samples
+  rc = ParseAndEncodeFloatingPointNumber("0.0", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0u}));
+  rc = ParseAndEncodeFloatingPointNumber("-0.0", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0x80000000u}));
+  rc = ParseAndEncodeFloatingPointNumber("42", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0x40450000u}));
+  rc = ParseAndEncodeFloatingPointNumber("2.5", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0x40040000u}));
+  rc = ParseAndEncodeFloatingPointNumber("32.5", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0u, 0x40404000u}));
+  rc = ParseAndEncodeFloatingPointNumber("1e38", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0x2a16a1b1u, 0x47d2ced3u}));
+  rc = ParseAndEncodeFloatingPointNumber("-1e38", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0x2a16a1b1u, 0xc7d2ced3u}));
+  rc = ParseAndEncodeFloatingPointNumber("1e40", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xf1c35ca5u, 0x483d6329u}));
+  rc = ParseAndEncodeFloatingPointNumber("-1e40", type, emit, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_THAT(word_buffer, Eq(std::vector<uint32_t>{0xf1c35ca5u, 0xc83d6329u}));
+
+  // Overflow
+  rc = ParseAndEncodeFloatingPointNumber("1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 64-bit float literal: 1e400", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 64-bit float literal: -1e400", err_msg);
+}
+
+TEST(ParseAndEncodeFloat16, Sample) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {16, SPV_NUMBER_FLOATING};
+
+  // Invalid
+  rc = ParseAndEncodeFloatingPointNumber("", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: ", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("0=", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: 0=", err_msg);
+
+  // Representative samples
+  rc = ParseAndEncodeFloatingPointNumber(
+      "0.0", type, [](uint32_t word) { EXPECT_EQ(0x0u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "-0.0", type, [](uint32_t word) { EXPECT_EQ(0x8000u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "1.0", type, [](uint32_t word) { EXPECT_EQ(0x3c00u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "2.5", type, [](uint32_t word) { EXPECT_EQ(0x4100u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  rc = ParseAndEncodeFloatingPointNumber(
+      "32.5", type, [](uint32_t word) { EXPECT_EQ(0x5010u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Overflow
+  rc =
+      ParseAndEncodeFloatingPointNumber("1e38", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: 1e38", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e38", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: -1e38", err_msg);
+  rc =
+      ParseAndEncodeFloatingPointNumber("1e40", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: 1e40", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e40", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: -1e40", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: 1e400", err_msg);
+  rc = ParseAndEncodeFloatingPointNumber("-1e400", type, AssertEmitFunc,
+                                         &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid 16-bit float literal: -1e400", err_msg);
+}
+
+TEST(ParseAndEncodeFloatingPointNumber, TypeNone) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_NONE};
+
+  rc = ParseAndEncodeFloatingPointNumber(
+      "0.0", type, [](uint32_t word) { EXPECT_EQ(0x0u, word); }, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidUsage, rc);
+  EXPECT_EQ("The expected type is not a float type", err_msg);
+}
+
+TEST(ParseAndEncodeFloatingPointNumber, InvalidCaseWithoutErrorMessageString) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  NumberType type = {32, SPV_NUMBER_FLOATING};
+
+  rc = ParseAndEncodeFloatingPointNumber("invalid", type, AssertEmitFunc,
+                                         nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+}
+
+TEST(ParseAndEncodeFloatingPointNumber, DoNotTouchErrorMessageStringOnSuccess) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kInvalidText;
+  std::string err_msg("random content");
+  NumberType type = {32, SPV_NUMBER_FLOATING};
+
+  rc = ParseAndEncodeFloatingPointNumber(
+      "0.0", type, [](uint32_t word) { EXPECT_EQ(0x0u, word); }, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_EQ("random content", err_msg);
+}
+
+TEST(ParseAndEncodeNumber, Sample) {
+  EncodeNumberStatus rc = EncodeNumberStatus::kSuccess;
+  std::string err_msg;
+  NumberType type = {32, SPV_NUMBER_SIGNED_INT};
+
+  // Invalid with error message string
+  rc = ParseAndEncodeNumber("something wrong", type, AssertEmitFunc, &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+  EXPECT_EQ("Invalid unsigned integer literal: something wrong", err_msg);
+
+  // Invalid without error message string
+  rc = ParseAndEncodeNumber("something wrong", type, AssertEmitFunc, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kInvalidText, rc);
+
+  // Signed integer, should not touch the error message string.
+  err_msg = "random content";
+  rc = ParseAndEncodeNumber("-1", type,
+                            [](uint32_t word) { EXPECT_EQ(0xffffffffu, word); },
+                            &err_msg);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+  EXPECT_EQ("random content", err_msg);
+
+  // Unsigned integer
+  type = {32, SPV_NUMBER_UNSIGNED_INT};
+  rc = ParseAndEncodeNumber(
+      "1", type, [](uint32_t word) { EXPECT_EQ(1u, word); }, nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+
+  // Float
+  type = {32, SPV_NUMBER_FLOATING};
+  rc = ParseAndEncodeNumber("-1.0", type,
+                            [](uint32_t word) { EXPECT_EQ(0xbf800000, word); },
+                            nullptr);
+  EXPECT_EQ(EncodeNumberStatus::kSuccess, rc);
+}
+
+}  // anonymous namespace
diff --git a/test/TextToBinary.cpp b/test/TextToBinary.cpp
index 0e1cae3..0a1439a 100644
--- a/test/TextToBinary.cpp
+++ b/test/TextToBinary.cpp
@@ -256,290 +256,6 @@
         {"0x1.804p4", 0x00004e01},
     }), );
 
-TEST(AssemblyContextParseNarrowSignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  int16_t i16;
-
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &i16, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &i16, ""));
-
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &i16, ""));
-  EXPECT_EQ(0, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("32767", ec, &i16, ""));
-  EXPECT_EQ(32767, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32768", ec, &i16, ""));
-  EXPECT_EQ(-32768, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &i16, ""));
-  EXPECT_EQ(0, i16);
-
-  // These are out of range, so they should return an error.
-  // The error code depends on whether this is an optional value.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("32768", ec, &i16, ""));
-  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
-            context.parseNumber("65535", SPV_ERROR_INVALID_TEXT, &i16, ""));
-
-  // Check hex parsing.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0x7fff", ec, &i16, ""));
-  EXPECT_EQ(32767, i16);
-  // This is out of range.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0xffff", ec, &i16, ""));
-}
-
-TEST(AssemblyContextParseNarrowUnsignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  uint16_t u16;
-
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &u16, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &u16, ""));
-
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &u16, ""));
-  EXPECT_EQ(0, u16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("65535", ec, &u16, ""));
-  EXPECT_EQ(65535, u16);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("65536", ec, &u16, ""));
-
-  // We don't care about -0 since it's rejected at a higher level.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", ec, &u16, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0xffff", ec, &u16, ""));
-  EXPECT_EQ(0xffff, u16);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0x10000", ec, &u16, ""));
-}
-
-TEST(AssemblyContextParseSignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  int32_t i32;
-
-  // Invalid parse.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &i32, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &i32, ""));
-
-  // Decimal values.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &i32, ""));
-  EXPECT_EQ(0, i32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2147483647", ec, &i32, ""));
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), i32);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("2147483648", ec, &i32, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &i32, ""));
-  EXPECT_EQ(0, i32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1", ec, &i32, ""));
-  EXPECT_EQ(-1, i32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-2147483648", ec, &i32, ""));
-  EXPECT_EQ(std::numeric_limits<int32_t>::min(), i32);
-
-  // Hex values.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0x7fffffff", ec, &i32, ""));
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), i32);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0x80000000", ec, &i32, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0x000", ec, &i32, ""));
-  EXPECT_EQ(0, i32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0x001", ec, &i32, ""));
-  EXPECT_EQ(-1, i32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0x80000000", ec, &i32, ""));
-  EXPECT_EQ(std::numeric_limits<int32_t>::min(), i32);
-}
-
-TEST(AssemblyContextParseUnsignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  uint32_t u32;
-
-  // Invalid parse.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &u32, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &u32, ""));
-
-  // Valid values.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &u32, ""));
-  EXPECT_EQ(0u, u32);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("4294967295", ec, &u32, ""));
-  EXPECT_EQ(std::numeric_limits<uint32_t>::max(), u32);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("4294967296", ec, &u32, ""));
-
-  // Hex values.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0xffffffff", ec, &u32, ""));
-  EXPECT_EQ(std::numeric_limits<uint32_t>::max(), u32);
-
-  // We don't care about -0 since it's rejected at a higher level.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", ec, &u32, ""));
-}
-
-TEST(AssemblyContextParseWideSignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  int64_t i64;
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &i64, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &i64, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &i64, ""));
-  EXPECT_EQ(0, i64);
-  EXPECT_EQ(SPV_SUCCESS,
-            context.parseNumber("0x7fffffffffffffff", ec, &i64, ""));
-  EXPECT_EQ(0x7fffffffffffffff, i64);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &i64, ""));
-  EXPECT_EQ(0, i64);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1", ec, &i64, ""));
-  EXPECT_EQ(-1, i64);
-}
-
-TEST(AssemblyContextParseWideUnsignedIntegers, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  uint64_t u64;
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &u64, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &u64, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &u64, ""));
-  EXPECT_EQ(0u, u64);
-  EXPECT_EQ(SPV_SUCCESS,
-            context.parseNumber("0xffffffffffffffff", ec, &u64, ""));
-  EXPECT_EQ(0xffffffffffffffffULL, u64);
-
-  // We don't care about -0 since it's rejected at a higher level.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", ec, &u64, ""));
-}
-
-TEST(AssemblyContextParseFloat, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  float f;
-
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &f, ""));
-
-  // These values are exactly representatble.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &f, ""));
-  EXPECT_EQ(0.0f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", ec, &f, ""));
-  EXPECT_EQ(42.0f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", ec, &f, ""));
-  EXPECT_EQ(2.5f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", ec, &f, ""));
-  EXPECT_EQ(-32.5f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
-  EXPECT_EQ(1e38f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
-  EXPECT_EQ(-1e38f, f);
-}
-
-TEST(AssemblyContextParseFloat, Overflow) {
-  // The assembler parses using HexFloat<FloatProxy<float>>.  Make
-  // sure that succeeds for in-range values, and fails for out of
-  // range values.  When it does overflow, the value is set to the
-  // nearest finite value, matching C++11 behavior for operator>>
-  // on floating point.
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  spvutils::HexFloat<spvutils::FloatProxy<float>> f(0.0f);
-
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
-  EXPECT_EQ(1e38f, f.value().getAsFloat());
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
-  EXPECT_EQ(-1e38f, f.value().getAsFloat());
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e40", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1e40", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e400", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1e400", ec, &f, ""));
-}
-
-TEST(AssemblyContextParseDouble, Sample) {
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  double f;
-
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &f, ""));
-
-  // These values are exactly representatble.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &f, ""));
-  EXPECT_EQ(0.0, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", ec, &f, ""));
-  EXPECT_EQ(42.0, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", ec, &f, ""));
-  EXPECT_EQ(2.5, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", ec, &f, ""));
-  EXPECT_EQ(-32.5, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
-  EXPECT_EQ(1e38, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
-  EXPECT_EQ(-1e38, f);
-  // These are out of range for 32-bit float, but in range for 64-bit float.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e40", ec, &f, ""));
-  EXPECT_EQ(1e40, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e40", ec, &f, ""));
-  EXPECT_EQ(-1e40, f);
-}
-
-TEST(AssemblyContextParseDouble, Overflow) {
-  // The assembler parses using HexFloat<FloatProxy<double>>.  Make
-  // sure that succeeds for in-range values, and fails for out of
-  // range values.  When it does overflow, the value is set to the
-  // nearest finite value, matching C++11 behavior for operator>>
-  // on floating point.
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  spvutils::HexFloat<spvutils::FloatProxy<double>> f(0.0);
-
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
-  EXPECT_EQ(1e38, f.value().getAsFloat());
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
-  EXPECT_EQ(-1e38, f.value().getAsFloat());
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e40", ec, &f, ""));
-  EXPECT_EQ(1e40, f.value().getAsFloat());
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e40", ec, &f, ""));
-  EXPECT_EQ(-1e40, f.value().getAsFloat());
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e400", ec, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1e400", ec, &f, ""));
-}
-
-TEST(AssemblyContextParseFloat16, Overflow) {
-  // The assembler parses using HexFloat<FloatProxy<Float16>>.  Make
-  // sure that succeeds for in-range values, and fails for out of
-  // range values.  When it does overflow, the value is set to the
-  // nearest finite value, matching C++11 behavior for operator>>
-  // on floating point.
-  AssemblyContext context(AutoText(""), nullptr);
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f(0);
-
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0.0", ec, &f, ""));
-  EXPECT_EQ(uint16_t{0x8000}, f.value().getAsFloat().get_value());
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1.0", ec, &f, ""));
-  EXPECT_EQ(uint16_t{0x3c00}, f.value().getAsFloat().get_value());
-
-  // Overflows 16-bit but not 32-bit
-  EXPECT_EQ(ec, context.parseNumber("1e38", ec, &f, ""));
-  EXPECT_EQ(ec, context.parseNumber("-1e38", ec, &f, ""));
-
-  // Overflows 32-bit but not 64-bit
-  EXPECT_EQ(ec, context.parseNumber("1e40", ec, &f, ""));
-  EXPECT_EQ(ec, context.parseNumber("-1e40", ec, &f, ""));
-
-  // Overflows 64-bit
-  EXPECT_EQ(ec, context.parseNumber("1e400", ec, &f, ""));
-  EXPECT_EQ(ec, context.parseNumber("-1e400", ec, &f, ""));
-}
-
-TEST(AssemblyContextParseMessages, Errors) {
-  spv_diagnostic diag = nullptr;
-  const spv_result_t ec = SPV_FAILED_MATCH;
-  AssemblyContext context(AutoText(""), &diag);
-  int16_t i16;
-
-  // No message is generated for a failure to parse an optional value.
-  EXPECT_EQ(SPV_FAILED_MATCH,
-            context.parseNumber("abc", ec, &i16, "bad narrow int: "));
-  EXPECT_EQ(nullptr, diag);
-
-  // For a required value, use the message fragment.
-  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
-            context.parseNumber("abc", SPV_ERROR_INVALID_TEXT, &i16,
-                                "bad narrow int: "));
-  ASSERT_NE(nullptr, diag);
-  EXPECT_EQ("bad narrow int: abc", std::string(diag->error));
-  // Don't leak.
-  spvDiagnosticDestroy(diag);
-}
-
 TEST(CreateContext, InvalidEnvironment) {
   spv_target_env env;
   std::memset(&env, 99, sizeof(env));