Allow numeric literals to be checked for a decimal point.
The asm.js spec decides the type of numeric literals in several places based on if they contain a ".". http://asmjs.org/spec/latest/ Adding methods so that AST Literals can be checked for containg a dot. Adding a cctest that this information is available. LOG=N BUG= https://code.google.com/p/v8/issues/detail?id=4203 TEST=test-parsing R=rossberg@chromium.org,titzer@chromium.org Review URL: https://codereview.chromium.org/1201783003 Cr-Commit-Position: refs/heads/master@{#29395}
This commit is contained in:
parent
686e675734
commit
9adb5f0a59
@ -140,6 +140,7 @@ bool AstValue::BooleanValue() const {
|
|||||||
case SYMBOL:
|
case SYMBOL:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
case NUMBER_WITH_DOT:
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
return DoubleToBoolean(number_);
|
return DoubleToBoolean(number_);
|
||||||
case SMI:
|
case SMI:
|
||||||
@ -175,6 +176,7 @@ void AstValue::Internalize(Isolate* isolate) {
|
|||||||
value_ = isolate->factory()->home_object_symbol();
|
value_ = isolate->factory()->home_object_symbol();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NUMBER_WITH_DOT:
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
value_ = isolate->factory()->NewNumber(number_, TENURED);
|
value_ = isolate->factory()->NewNumber(number_, TENURED);
|
||||||
break;
|
break;
|
||||||
@ -290,8 +292,8 @@ const AstValue* AstValueFactory::NewSymbol(const char* name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const AstValue* AstValueFactory::NewNumber(double number) {
|
const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) {
|
||||||
AstValue* value = new (zone_) AstValue(number);
|
AstValue* value = new (zone_) AstValue(number, with_dot);
|
||||||
if (isolate_) {
|
if (isolate_) {
|
||||||
value->Internalize(isolate_);
|
value->Internalize(isolate_);
|
||||||
}
|
}
|
||||||
|
@ -142,9 +142,11 @@ class AstValue : public ZoneObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsNumber() const {
|
bool IsNumber() const {
|
||||||
return type_ == NUMBER || type_ == SMI;
|
return type_ == NUMBER || type_ == NUMBER_WITH_DOT || type_ == SMI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ContainsDot() const { return type_ == NUMBER_WITH_DOT; }
|
||||||
|
|
||||||
const AstRawString* AsString() const {
|
const AstRawString* AsString() const {
|
||||||
if (type_ == STRING)
|
if (type_ == STRING)
|
||||||
return string_;
|
return string_;
|
||||||
@ -153,7 +155,7 @@ class AstValue : public ZoneObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double AsNumber() const {
|
double AsNumber() const {
|
||||||
if (type_ == NUMBER)
|
if (type_ == NUMBER || type_ == NUMBER_WITH_DOT)
|
||||||
return number_;
|
return number_;
|
||||||
if (type_ == SMI)
|
if (type_ == SMI)
|
||||||
return smi_;
|
return smi_;
|
||||||
@ -189,6 +191,7 @@ class AstValue : public ZoneObject {
|
|||||||
STRING,
|
STRING,
|
||||||
SYMBOL,
|
SYMBOL,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
|
NUMBER_WITH_DOT,
|
||||||
SMI,
|
SMI,
|
||||||
BOOLEAN,
|
BOOLEAN,
|
||||||
NULL_TYPE,
|
NULL_TYPE,
|
||||||
@ -200,7 +203,14 @@ class AstValue : public ZoneObject {
|
|||||||
|
|
||||||
explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; }
|
explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; }
|
||||||
|
|
||||||
explicit AstValue(double n) : type_(NUMBER) { number_ = n; }
|
explicit AstValue(double n, bool with_dot) {
|
||||||
|
if (with_dot) {
|
||||||
|
type_ = NUMBER_WITH_DOT;
|
||||||
|
} else {
|
||||||
|
type_ = NUMBER;
|
||||||
|
}
|
||||||
|
number_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
AstValue(Type t, int i) : type_(t) {
|
AstValue(Type t, int i) : type_(t) {
|
||||||
DCHECK(type_ == SMI);
|
DCHECK(type_ == SMI);
|
||||||
@ -334,7 +344,7 @@ class AstValueFactory {
|
|||||||
const AstValue* NewString(const AstRawString* string);
|
const AstValue* NewString(const AstRawString* string);
|
||||||
// A JavaScript symbol (ECMA-262 edition 6).
|
// A JavaScript symbol (ECMA-262 edition 6).
|
||||||
const AstValue* NewSymbol(const char* name);
|
const AstValue* NewSymbol(const char* name);
|
||||||
const AstValue* NewNumber(double number);
|
const AstValue* NewNumber(double number, bool with_dot = false);
|
||||||
const AstValue* NewSmi(int number);
|
const AstValue* NewSmi(int number);
|
||||||
const AstValue* NewBoolean(bool b);
|
const AstValue* NewBoolean(bool b);
|
||||||
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
|
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
|
||||||
|
@ -3380,9 +3380,9 @@ class AstNodeFactory final BASE_EMBEDDED {
|
|||||||
return new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos);
|
return new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal* NewNumberLiteral(double number, int pos) {
|
Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
|
||||||
return new (zone_)
|
return new (zone_)
|
||||||
Literal(zone_, ast_value_factory_->NewNumber(number), pos);
|
Literal(zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal* NewSmiLiteral(int number, int pos) {
|
Literal* NewSmiLiteral(int number, int pos) {
|
||||||
|
@ -815,8 +815,9 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
|
|||||||
return factory->NewSmiLiteral(value, pos);
|
return factory->NewSmiLiteral(value, pos);
|
||||||
}
|
}
|
||||||
case Token::NUMBER: {
|
case Token::NUMBER: {
|
||||||
|
bool has_dot = scanner->ContainsDot();
|
||||||
double value = scanner->DoubleValue();
|
double value = scanner->DoubleValue();
|
||||||
return factory->NewNumberLiteral(value, pos);
|
return factory->NewNumberLiteral(value, pos, has_dot);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
DCHECK(false);
|
DCHECK(false);
|
||||||
|
@ -1425,6 +1425,13 @@ double Scanner::DoubleValue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Scanner::ContainsDot() {
|
||||||
|
DCHECK(is_literal_one_byte());
|
||||||
|
Vector<const uint8_t> str = literal_one_byte_string();
|
||||||
|
return std::find(str.begin(), str.end(), '.') != str.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Scanner::FindSymbol(DuplicateFinder* finder, int value) {
|
int Scanner::FindSymbol(DuplicateFinder* finder, int value) {
|
||||||
if (is_literal_one_byte()) {
|
if (is_literal_one_byte()) {
|
||||||
return finder->AddOneByteSymbol(literal_one_byte_string(), value);
|
return finder->AddOneByteSymbol(literal_one_byte_string(), value);
|
||||||
|
@ -435,6 +435,7 @@ class Scanner {
|
|||||||
const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
|
const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
|
||||||
|
|
||||||
double DoubleValue();
|
double DoubleValue();
|
||||||
|
bool ContainsDot();
|
||||||
bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
|
bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
|
||||||
if (is_literal_one_byte() &&
|
if (is_literal_one_byte() &&
|
||||||
literal_length() == length &&
|
literal_length() == length &&
|
||||||
|
@ -1100,6 +1100,58 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckParsesToNumber(const char* source, bool with_dot) {
|
||||||
|
v8::V8::Initialize();
|
||||||
|
HandleAndZoneScope handles;
|
||||||
|
|
||||||
|
i::Isolate* isolate = CcTest::i_isolate();
|
||||||
|
i::Factory* factory = isolate->factory();
|
||||||
|
|
||||||
|
std::string full_source = "function f() { return ";
|
||||||
|
full_source += source;
|
||||||
|
full_source += "; }";
|
||||||
|
|
||||||
|
i::Handle<i::String> source_code =
|
||||||
|
factory->NewStringFromUtf8(i::CStrVector(full_source.c_str()))
|
||||||
|
.ToHandleChecked();
|
||||||
|
|
||||||
|
i::Handle<i::Script> script = factory->NewScript(source_code);
|
||||||
|
|
||||||
|
i::ParseInfo info(handles.main_zone(), script);
|
||||||
|
i::Parser parser(&info);
|
||||||
|
parser.set_allow_harmony_arrow_functions(true);
|
||||||
|
parser.set_allow_harmony_sloppy(true);
|
||||||
|
info.set_global();
|
||||||
|
info.set_lazy(false);
|
||||||
|
info.set_allow_lazy_parsing(false);
|
||||||
|
info.set_toplevel(true);
|
||||||
|
|
||||||
|
i::CompilationInfo compilation_info(&info);
|
||||||
|
CHECK(i::Compiler::ParseAndAnalyze(&info));
|
||||||
|
|
||||||
|
CHECK(info.scope()->declarations()->length() == 1);
|
||||||
|
i::FunctionLiteral* fun =
|
||||||
|
info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun();
|
||||||
|
CHECK(fun->body()->length() == 1);
|
||||||
|
CHECK(fun->body()->at(0)->IsReturnStatement());
|
||||||
|
i::ReturnStatement* ret = fun->body()->at(0)->AsReturnStatement();
|
||||||
|
CHECK(ret->expression()->IsLiteral());
|
||||||
|
i::Literal* lit = ret->expression()->AsLiteral();
|
||||||
|
const i::AstValue* val = lit->raw_value();
|
||||||
|
CHECK(with_dot == val->ContainsDot());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ParseNumbers) {
|
||||||
|
CheckParsesToNumber("1.34", true);
|
||||||
|
CheckParsesToNumber("134", false);
|
||||||
|
CheckParsesToNumber("134e44", false);
|
||||||
|
CheckParsesToNumber("134.e44", true);
|
||||||
|
CheckParsesToNumber("134.44e44", true);
|
||||||
|
CheckParsesToNumber(".44", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(ScopePositions) {
|
TEST(ScopePositions) {
|
||||||
// Test the parser for correctly setting the start and end positions
|
// Test the parser for correctly setting the start and end positions
|
||||||
// of a scope. We check the scope positions of exactly one scope
|
// of a scope. We check the scope positions of exactly one scope
|
||||||
|
Loading…
Reference in New Issue
Block a user