-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
parser: implement NaN and Infinity parsing #201
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
#include "jsrs_parser.h" | ||
|
||
#include <cctype> | ||
#include <cmath> | ||
#include <cstddef> | ||
#include <cstdlib> | ||
#include <cstring> | ||
|
@@ -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; | ||
|
@@ -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 == '-') { | ||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wow, such a pain =( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's so painful here? I just avoided testing for the same character twice here, that's it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The need to actually check this. But anyway I see no other way. |
||
THROW_EXCEPTION(SyntaxError, "Invalid format: expected NaN"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's better to say 'Invalid number format: ...'. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wrote it like that to be consistent with the other error messages, it still isn't perfect everywhere, but hopefully I will fix it someday (see #69). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I wanted to say is that it is an issue for another PR which will improve error reporting in the native parser. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @belochub Ok, let's hope it will be done eventually =) |
||
return MaybeLocal<Value>(); | ||
} | ||
} else if (isinf(number)) { | ||
if (strncmp(begin + 1, "nfinity", 7) != 0) { | ||
THROW_EXCEPTION(SyntaxError, "Invalid format: expected Infinity"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto. |
||
return MaybeLocal<Value>(); | ||
} | ||
} | ||
|
||
*size = number_end - begin; | ||
return Number::New(isolate, number); | ||
} | ||
|
||
Local<Value> ParseIntegerNumber(Isolate* isolate, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this for the reasons @lundibundi has mentioned...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aqrln, why'd you put an ellipsis in the end of your comment?
Also, the problem stated by @lundibundi has nothing to do with this line, it is just incorrect usage of the
strtol
function, and I will fix this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I am sorry, I was really talking about
atof
in the previous comment, notstrtol
.strtod
has to be used instead of it.