Sfoglia il codice sorgente

LibJS: Start implementing Date :^)

This adds:

- A global Date object (with `length` property and `now` function)
- The Date constructor (no arguments yet)
- The Date prototype (with `get*` functions)
Linus Groh 5 anni fa
parent
commit
d4e3688f4f

+ 29 - 0
Base/home/anon/js/date.js

@@ -0,0 +1,29 @@
+var now = Date.now();
+console.log("Unix timestamp: " + now / 1000);
+
+// FIXME: We need String.prototype.padStart() :^)
+var d = new Date();
+var year = d.getFullYear();
+var month = d.getMonth() + 1;
+if (month < 10)
+    month = "0" + month;
+var day = d.getDate();
+if (day < 10)
+    day = "0" + day;
+var hours = d.getHours();
+if (hours < 10)
+    hours = "0" + hours;
+var minutes = d.getMinutes();
+if (minutes < 10)
+    minutes = "0" + minutes;
+var seconds = d.getSeconds();
+if (seconds < 10)
+    seconds = "0" + seconds;
+var milliseconds = d.getMilliseconds();
+if (milliseconds < 10) {
+    milliseconds = "00" + milliseconds;
+} else if (milliseconds < 100) {
+    milliseconds = "0" + milliseconds;
+}
+console.log("Date: " + year + "-" + month + "-" + day);
+console.log("Time: " + hours + ":" + minutes + ":" + seconds + "." + milliseconds);

+ 3 - 0
Libraries/LibJS/Interpreter.cpp

@@ -28,6 +28,7 @@
 #include <LibJS/AST.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Runtime/ArrayPrototype.h>
+#include <LibJS/Runtime/DatePrototype.h>
 #include <LibJS/Runtime/Error.h>
 #include <LibJS/Runtime/ErrorPrototype.h>
 #include <LibJS/Runtime/GlobalObject.h>
@@ -46,6 +47,7 @@ Interpreter::Interpreter()
     m_string_prototype = heap().allocate<StringPrototype>();
     m_array_prototype = heap().allocate<ArrayPrototype>();
     m_error_prototype = heap().allocate<ErrorPrototype>();
+    m_date_prototype = heap().allocate<DatePrototype>();
 
     m_global_object = heap().allocate<GlobalObject>();
 }
@@ -165,6 +167,7 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
     roots.set(m_object_prototype);
     roots.set(m_array_prototype);
     roots.set(m_error_prototype);
+    roots.set(m_date_prototype);
 
     roots.set(m_exception);
 

+ 2 - 0
Libraries/LibJS/Interpreter.h

@@ -111,6 +111,7 @@ public:
     Object* object_prototype() { return m_object_prototype; }
     Object* array_prototype() { return m_array_prototype; }
     Object* error_prototype() { return m_error_prototype; }
+    Object* date_prototype() { return m_date_prototype; }
 
     Exception* exception() { return m_exception; }
     void clear_exception() { m_exception = nullptr; }
@@ -138,6 +139,7 @@ private:
     Object* m_object_prototype { nullptr };
     Object* m_array_prototype { nullptr };
     Object* m_error_prototype { nullptr };
+    Object* m_date_prototype { nullptr };
 
     Exception* m_exception { nullptr };
 

+ 3 - 0
Libraries/LibJS/Makefile

@@ -10,6 +10,9 @@ OBJS = \
     Runtime/ArrayPrototype.o \
     Runtime/Cell.o \
     Runtime/ConsoleObject.o \
+    Runtime/Date.o \
+    Runtime/DateConstructor.o \
+    Runtime/DatePrototype.o \
     Runtime/Error.o \
     Runtime/ErrorPrototype.o \
     Runtime/Exception.o \

+ 44 - 0
Libraries/LibJS/Runtime/Date.cpp

@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibCore/DateTime.h>
+#include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/Date.h>
+
+namespace JS {
+
+Date::Date(Core::DateTime datetime, u16 milliseconds)
+    : m_datetime(datetime)
+    , m_milliseconds(milliseconds)
+{
+    set_prototype(interpreter().date_prototype());
+}
+
+Date::~Date()
+{
+}
+
+}

+ 52 - 0
Libraries/LibJS/Runtime/Date.h

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibCore/DateTime.h>
+#include <LibJS/Runtime/Object.h>
+
+namespace JS {
+
+class Date final : public Object {
+public:
+    Date(Core::DateTime datetime, u16 milliseconds);
+    virtual ~Date() override;
+
+    Core::DateTime& datetime() { return m_datetime; }
+    u16 milliseconds() { return m_milliseconds; }
+    virtual Value value_of() const override
+    {
+        return Value(static_cast<double>(m_datetime.timestamp() * 1000 + m_milliseconds));
+    }
+
+private:
+    virtual bool is_date() const final { return true; }
+    virtual const char* class_name() const override { return "Date"; }
+
+    Core::DateTime m_datetime;
+    u16 m_milliseconds;
+};
+
+}

+ 65 - 0
Libraries/LibJS/Runtime/DateConstructor.cpp

@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibCore/DateTime.h>
+#include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/Date.h>
+#include <LibJS/Runtime/DateConstructor.h>
+#include <sys/time.h>
+#include <time.h>
+
+namespace JS {
+
+DateConstructor::DateConstructor()
+{
+    put("prototype", interpreter().date_prototype());
+    put("length", Value(7));
+
+    put_native_function("now", now);
+}
+
+DateConstructor::~DateConstructor()
+{
+}
+
+Value DateConstructor::call(Interpreter& interpreter)
+{
+    // TODO: Support args
+    struct timeval tv;
+    gettimeofday(&tv, nullptr);
+    auto datetime = Core::DateTime::now();
+    auto milliseconds = static_cast<u16>(tv.tv_usec / 1000);
+    return interpreter.heap().allocate<Date>(datetime, milliseconds);
+}
+
+Value DateConstructor::now(Interpreter&)
+{
+    struct timeval tv;
+    gettimeofday(&tv, nullptr);
+    return Value(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0);
+}
+
+}

+ 46 - 0
Libraries/LibJS/Runtime/DateConstructor.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/NativeFunction.h>
+
+namespace JS {
+
+class DateConstructor final : public NativeFunction {
+public:
+    DateConstructor();
+    virtual ~DateConstructor() override;
+
+    virtual Value call(Interpreter&) override;
+
+private:
+    virtual const char* class_name() const override { return "DateConstructor"; }
+
+    static Value now(Interpreter&);
+};
+
+}

+ 149 - 0
Libraries/LibJS/Runtime/DatePrototype.cpp

@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <AK/Function.h>
+#include <AK/String.h>
+#include <LibCore/DateTime.h>
+#include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/Date.h>
+#include <LibJS/Runtime/DatePrototype.h>
+#include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/Value.h>
+
+namespace JS {
+
+static Date* this_date_from_interpreter(Interpreter& interpreter)
+{
+    auto* this_object = interpreter.this_value().to_object(interpreter.heap());
+    if (!this_object)
+        return nullptr;
+    if (!this_object->is_date()) {
+        interpreter.throw_exception<Error>("TypeError", "object must be of type Date");
+        return nullptr;
+    }
+    return static_cast<Date*>(this_object);
+}
+
+DatePrototype::DatePrototype()
+{
+    put_native_function("getDate", get_date);
+    put_native_function("getDay", get_day);
+    put_native_function("getFullYear", get_full_year);
+    put_native_function("getHours", get_hours);
+    put_native_function("getMilliseconds", get_milliseconds);
+    put_native_function("getMinutes", get_minutes);
+    put_native_function("getMonth", get_month);
+    put_native_function("getSeconds", get_seconds);
+    put_native_function("getTime", get_time);
+}
+
+DatePrototype::~DatePrototype()
+{
+}
+
+Value DatePrototype::get_date(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto date = this_object->datetime().day();
+    return Value(static_cast<double>(date));
+}
+
+Value DatePrototype::get_day(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto day = this_object->datetime().weekday();
+    return Value(static_cast<double>(day));
+}
+
+Value DatePrototype::get_full_year(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto full_year = this_object->datetime().year();
+    return Value(static_cast<double>(full_year));
+}
+
+Value DatePrototype::get_hours(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto hours = this_object->datetime().hour();
+    return Value(static_cast<double>(hours));
+}
+
+Value DatePrototype::get_milliseconds(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto milliseconds = this_object->milliseconds();
+    return Value(static_cast<double>(milliseconds));
+}
+
+Value DatePrototype::get_minutes(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto minutes = this_object->datetime().minute();
+    return Value(static_cast<double>(minutes));
+}
+
+Value DatePrototype::get_month(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto months = this_object->datetime().month() - 1;
+    return Value(static_cast<double>(months));
+}
+
+Value DatePrototype::get_seconds(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto seconds = this_object->datetime().second();
+    return Value(static_cast<double>(seconds));
+}
+
+Value DatePrototype::get_time(Interpreter& interpreter)
+{
+    auto* this_object = this_date_from_interpreter(interpreter);
+    if (!this_object)
+        return {};
+    auto seconds = this_object->datetime().timestamp();
+    auto milliseconds = this_object->milliseconds();
+    return Value(static_cast<double>(seconds * 1000 + milliseconds));
+}
+
+}

+ 52 - 0
Libraries/LibJS/Runtime/DatePrototype.h

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Object.h>
+
+namespace JS {
+
+class DatePrototype final : public Object {
+public:
+    DatePrototype();
+    virtual ~DatePrototype() override;
+
+private:
+    virtual const char* class_name() const override { return "DatePrototype"; }
+
+    static Value get_date(Interpreter&);
+    static Value get_day(Interpreter&);
+    static Value get_full_year(Interpreter&);
+    static Value get_hours(Interpreter&);
+    static Value get_milliseconds(Interpreter&);
+    static Value get_minutes(Interpreter&);
+    static Value get_month(Interpreter&);
+    static Value get_seconds(Interpreter&);
+    static Value get_time(Interpreter&);
+};
+
+}

+ 2 - 0
Libraries/LibJS/Runtime/GlobalObject.cpp

@@ -3,6 +3,7 @@
 #include <LibJS/Heap/Heap.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Runtime/ConsoleObject.h>
+#include <LibJS/Runtime/DateConstructor.h>
 #include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/MathObject.h>
 #include <LibJS/Runtime/NativeFunction.h>
@@ -17,6 +18,7 @@ GlobalObject::GlobalObject()
     put_native_function("isNaN", is_nan);
 
     put("console", heap().allocate<ConsoleObject>());
+    put("Date", heap().allocate<DateConstructor>());
     put("Math", heap().allocate<MathObject>());
     put("Object", heap().allocate<ObjectConstructor>());
 }

+ 3 - 2
Libraries/LibJS/Runtime/Object.h

@@ -49,12 +49,13 @@ public:
     void put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)>);
     void put_native_property(const FlyString& property_name, AK::Function<Value(Interpreter&)> getter, AK::Function<void(Interpreter&, Value)> setter);
 
-    virtual bool is_error() const { return false; }
     virtual bool is_array() const { return false; }
+    virtual bool is_date() const { return false; }
+    virtual bool is_error() const { return false; }
     virtual bool is_function() const { return false; }
     virtual bool is_native_function() const { return false; }
-    virtual bool is_string_object() const { return false; }
     virtual bool is_native_property() const { return false; }
+    virtual bool is_string_object() const { return false; }
 
     virtual const char* class_name() const override { return "Object"; }
     virtual void visit_children(Cell::Visitor&) override;

+ 1 - 1
Libraries/LibJS/Runtime/Value.cpp

@@ -58,7 +58,7 @@ String Value::to_string() const
             return "NaN";
 
         // FIXME: This needs improvement.
-        return String::number((i32)as_double());
+        return String::format("%f", as_double());
     }
 
     if (is_object())

+ 1 - 1
Libraries/LibJS/Runtime/Value.h

@@ -53,7 +53,7 @@ public:
     bool is_cell() const { return is_string() || is_object(); }
     bool is_array() const;
 
-    bool is_nan() const { return is_number() && __builtin_isnan( as_double()); }
+    bool is_nan() const { return is_number() && __builtin_isnan(as_double()); }
 
     Value()
         : m_type(Type::Undefined)

+ 15 - 0
Libraries/LibJS/Tests/Date.now.js

@@ -0,0 +1,15 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var last = 0;
+    for (var i = 0; i < 100; ++i) {
+        var now = Date.now();
+        assert(!isNaN(now))
+        assert(now > 1580000000000);
+        assert(now >= last);
+        last = now;
+    }
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getDate.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getDate()));
+    assert(1 <= d.getDate() <= 31);
+    assert(d.getDate() === d.getDate());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getDay.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getDay()));
+    assert(0 <= d.getDay() <= 6);
+    assert(d.getDay() === d.getDay());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getFullYear.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getFullYear()));
+    assert(d.getFullYear() >= 2020);
+    assert(d.getFullYear() === d.getFullYear());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getHours.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getHours()));
+    assert(0 <= d.getHours() <= 23);
+    assert(d.getHours() === d.getHours());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getMilliseconds.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getMilliseconds()));
+    assert(0 <= d.getMilliseconds() <= 999);
+    assert(d.getMilliseconds() === d.getMilliseconds());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getMinutes.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getMinutes()));
+    assert(0 <= d.getMinutes() <= 59);
+    assert(d.getMinutes() === d.getMinutes());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getMonth.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getMonth()));
+    assert(0 <= d.getMonth() <= 11);
+    assert(d.getMonth() === d.getMonth());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getSeconds.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getSeconds()));
+    assert(0 <= d.getSeconds() <= 59);
+    assert(d.getSeconds() === d.getSeconds());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 11 - 0
Libraries/LibJS/Tests/Date.prototype.getTime.js

@@ -0,0 +1,11 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+    var d = new Date();
+    assert(!isNaN(d.getTime()));
+    assert(d.getTime() > 1580000000000);
+    assert(d.getTime() === d.getTime());
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}

+ 1 - 1
Userland/Makefile

@@ -4,7 +4,7 @@ APPS = ${SRCS:.cpp=}
 
 EXTRA_CLEAN = $(APPS)
 
-LIB_DEPS = Web GUI Gfx Audio Protocol IPC Thread Pthread Core PCIDB Markdown JS
+LIB_DEPS = Web GUI Gfx Audio Protocol IPC Thread Pthread PCIDB Markdown JS Core
 
 include ../Makefile.common