Allow numeric literals to be checked for a decimal point.
authorbradnelson <bradnelson@google.com>
Tue, 30 Jun 2015 21:12:12 +0000 (14:12 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 30 Jun 2015 21:12:20 +0000 (21:12 +0000)
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}

src/ast-value-factory.cc
src/ast-value-factory.h
src/ast.h
src/parser.cc
src/scanner.cc
src/scanner.h
test/cctest/test-parsing.cc

index a819483eccbc417ea76e5e687dc59a3f304461d9..68cf015200365c988adfcfd55bc73cbcaff49c7e 100644 (file)
@@ -140,6 +140,7 @@ bool AstValue::BooleanValue() const {
     case SYMBOL:
       UNREACHABLE();
       break;
+    case NUMBER_WITH_DOT:
     case NUMBER:
       return DoubleToBoolean(number_);
     case SMI:
@@ -175,6 +176,7 @@ void AstValue::Internalize(Isolate* isolate) {
         value_ = isolate->factory()->home_object_symbol();
       }
       break;
+    case NUMBER_WITH_DOT:
     case NUMBER:
       value_ = isolate->factory()->NewNumber(number_, TENURED);
       break;
@@ -290,8 +292,8 @@ const AstValue* AstValueFactory::NewSymbol(const char* name) {
 }
 
 
-const AstValue* AstValueFactory::NewNumber(double number) {
-  AstValue* value = new (zone_) AstValue(number);
+const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) {
+  AstValue* value = new (zone_) AstValue(number, with_dot);
   if (isolate_) {
     value->Internalize(isolate_);
   }
index dd575e26abe337585351d96cbfddced2961cb23b..2fee0396fd487b02ac8d4020de783abcb989c810 100644 (file)
@@ -142,9 +142,11 @@ class AstValue : public ZoneObject {
   }
 
   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 {
     if (type_ == STRING)
       return string_;
@@ -153,7 +155,7 @@ class AstValue : public ZoneObject {
   }
 
   double AsNumber() const {
-    if (type_ == NUMBER)
+    if (type_ == NUMBER || type_ == NUMBER_WITH_DOT)
       return number_;
     if (type_ == SMI)
       return smi_;
@@ -189,6 +191,7 @@ class AstValue : public ZoneObject {
     STRING,
     SYMBOL,
     NUMBER,
+    NUMBER_WITH_DOT,
     SMI,
     BOOLEAN,
     NULL_TYPE,
@@ -200,7 +203,14 @@ class AstValue : public ZoneObject {
 
   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) {
     DCHECK(type_ == SMI);
@@ -334,7 +344,7 @@ class AstValueFactory {
   const AstValue* NewString(const AstRawString* string);
   // A JavaScript symbol (ECMA-262 edition 6).
   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* NewBoolean(bool b);
   const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
index e8a8e0e012067e56f5df9dd82fa4893729670425..c281408c82fcd56c04a7695e0d19203856534aed 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -3380,9 +3380,9 @@ class AstNodeFactory final BASE_EMBEDDED {
     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_)
-        Literal(zone_, ast_value_factory_->NewNumber(number), pos);
+        Literal(zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
   }
 
   Literal* NewSmiLiteral(int number, int pos) {
index faf36c4c7455d541f2bf38f6761f52fe1b359bd1..b9dcbfd84d11baf66e5b9f51e3f822510e0ed1d1 100644 (file)
@@ -815,8 +815,9 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
       return factory->NewSmiLiteral(value, pos);
     }
     case Token::NUMBER: {
+      bool has_dot = scanner->ContainsDot();
       double value = scanner->DoubleValue();
-      return factory->NewNumberLiteral(value, pos);
+      return factory->NewNumberLiteral(value, pos, has_dot);
     }
     default:
       DCHECK(false);
index cf5a69c142de44b9d4e9d36db1aa911337872899..ad7c7d983c5e375afa7ddea2b1e89d6ac2ea89fd 100644 (file)
@@ -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) {
   if (is_literal_one_byte()) {
     return finder->AddOneByteSymbol(literal_one_byte_string(), value);
index 5559b8424c389d763a4860656499ee0fb8ca4963..c842f987b62718b9651e56d7cd900471e788e594 100644 (file)
@@ -435,6 +435,7 @@ class Scanner {
   const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
 
   double DoubleValue();
+  bool ContainsDot();
   bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
     if (is_literal_one_byte() &&
         literal_length() == length &&
index a4293d662af36426f38b7c4863a3dea33892b7a5..88dadcb1bf8ba35db6d0d986065e2f52ca370350 100644 (file)
@@ -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 the parser for correctly setting the start and end positions
   // of a scope. We check the scope positions of exactly one scope