Skip to content

Commit

Permalink
parser: implement NaN and Infinity parsing
Browse files Browse the repository at this point in the history
Also fix not throwing on some of the incorrect number
inputs.

Refs: #175
PR-URL: #201
Reviewed-By: Dmytro Nechai <nechaido@gmail.com>
Reviewed-By: Alexey Orlenko <eaglexrlnk@gmail.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
  • Loading branch information
belochub committed Jun 3, 2017
1 parent 8cc77d8 commit 8e87a28
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 24 deletions.
62 changes: 42 additions & 20 deletions src/jsrs_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "jsrs_parser.h"

#include <cctype>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <cstring>
Expand All @@ -18,6 +19,8 @@ using std::function;
using std::isalnum;
using std::isalpha;
using std::isdigit;
using std::isinf;
using std::isnan;
using std::isxdigit;
using std::memset;
using std::ptrdiff_t;
Expand Down Expand Up @@ -150,6 +153,11 @@ static bool GetType(const char* begin, const char* end, Type* type) {
}
break;
}
case 'N':
case 'I': {
*type = Type::kNumber;
break;
}
default: {
result = false;
if (isdigit(*begin) || *begin == '.' || *begin == '+' || *begin == '-') {
Expand Down Expand Up @@ -318,32 +326,46 @@ MaybeLocal<Value> ParseNumber(Isolate* isolate,
}
}

MaybeLocal<Value> result;

if (base == 10) {
return ParseDecimalNumber(isolate, begin, end, size);
result = ParseDecimalNumber(isolate, number_start, end, size,
negate_result);
} else {
auto value = ParseIntegerNumber(isolate, number_start, end, size,
base, negate_result);
auto offset = static_cast<size_t>(number_start - begin);
*size += offset;
return value;
result = ParseIntegerNumber(isolate, number_start, end, size,
base, negate_result);
}
*size += number_start - begin;
return result;
}

Local<Value> ParseDecimalNumber(Isolate* isolate,
const char* begin,
const char* end,
size_t* size) {
auto result = Number::New(isolate, atof(begin));
*size = end - begin;
size_t i = 0;
while (begin[i] != ',' &&
begin[i] != '}' &&
begin[i] != ']' &&
i < *size) {
i++;
MaybeLocal<Value> ParseDecimalNumber(Isolate* isolate,
const char* begin,
const char* end,
size_t* size,
bool negate_result) {
char* number_end;
double number = strtod(begin, &number_end);

if (negate_result) {
number = -number;
}
*size = i;
return result;

// strictly allow only "NaN" and "Infinity"
if (isnan(number)) {
if (strncmp(begin + 1, "aN", 2) != 0) {
THROW_EXCEPTION(SyntaxError, "Invalid format: expected NaN");
return MaybeLocal<Value>();
}
} else if (isinf(number)) {
if (strncmp(begin + 1, "nfinity", 7) != 0) {
THROW_EXCEPTION(SyntaxError, "Invalid format: expected Infinity");
return MaybeLocal<Value>();
}
}

*size = number_end - begin;
return Number::New(isolate, number);
}

Local<Value> ParseIntegerNumber(Isolate* isolate,
Expand Down
9 changes: 5 additions & 4 deletions src/jsrs_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,11 @@ v8::MaybeLocal<v8::Value> ParseObject(v8::Isolate* isolate,
std::size_t* size);

// Parses a decimal number, either integer or float.
v8::Local<v8::Value> ParseDecimalNumber(v8::Isolate* isolate,
const char* begin,
const char* end,
std::size_t* size);
v8::MaybeLocal<v8::Value> ParseDecimalNumber(v8::Isolate* isolate,
const char* begin,
const char* end,
std::size_t* size,
bool negate_result);

// Parses an integer number in arbitrary base without prefixes.
v8::Local<v8::Value> ParseIntegerNumber(v8::Isolate* isolate,
Expand Down

0 comments on commit 8e87a28

Please sign in to comment.