summaryrefslogtreecommitdiff
path: root/Libraries/LibJS
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-03-29 17:15:00 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-29 19:37:16 +0200
commit0a94661c148a17f455875bd29f977eed2e080d25 (patch)
treeea5032a85a99ed9bfc8fb13bcf80a38e3fad233e /Libraries/LibJS
parent7971af474d65e6035e13fb69d486b3a97a0ea6ae (diff)
downloadserenity-0a94661c148a17f455875bd29f977eed2e080d25.zip
LibJS: Implement String.prototype.startsWith()
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r--Libraries/LibJS/Runtime/StringPrototype.cpp27
-rw-r--r--Libraries/LibJS/Runtime/StringPrototype.h1
-rw-r--r--Libraries/LibJS/Tests/String.prototype.startsWith.js40
3 files changed, 68 insertions, 0 deletions
diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp
index 5d05545d05..6e871db061 100644
--- a/Libraries/LibJS/Runtime/StringPrototype.cpp
+++ b/Libraries/LibJS/Runtime/StringPrototype.cpp
@@ -41,6 +41,7 @@ StringPrototype::StringPrototype()
put_native_property("length", length_getter, nullptr);
put_native_function("charAt", char_at);
put_native_function("repeat", repeat);
+ put_native_function("startsWith", starts_with);
}
StringPrototype::~StringPrototype()
@@ -83,6 +84,32 @@ Value StringPrototype::repeat(Interpreter& interpreter)
return js_string(interpreter.heap(), builder.to_string());
}
+Value StringPrototype::starts_with(Interpreter& interpreter)
+{
+ auto* this_object = interpreter.this_value().to_object(interpreter.heap());
+ if (!this_object)
+ return {};
+ if (interpreter.call_frame().arguments.is_empty())
+ return Value(false);
+ auto search_string = interpreter.call_frame().arguments[0].to_string();
+ auto search_string_length = static_cast<i32>(search_string.length());
+ i32 position = 0;
+ if (interpreter.call_frame().arguments.size() > 1) {
+ auto number = interpreter.call_frame().arguments[1].to_number();
+ if (!number.is_nan())
+ position = number.to_i32();
+ }
+ ASSERT(this_object->is_string_object());
+ auto underlying_string = static_cast<const StringObject*>(this_object)->primitive_string()->string();
+ auto underlying_string_length = static_cast<i32>(underlying_string.length());
+ auto start = min(max(position, 0), underlying_string_length);
+ if (start + search_string_length > underlying_string_length)
+ return Value(false);
+ if (search_string_length == 0)
+ return Value(true);
+ return Value(underlying_string.substring(start, search_string_length) == search_string);
+}
+
Value StringPrototype::length_getter(Interpreter& interpreter)
{
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
diff --git a/Libraries/LibJS/Runtime/StringPrototype.h b/Libraries/LibJS/Runtime/StringPrototype.h
index b12c674584..000f373fb6 100644
--- a/Libraries/LibJS/Runtime/StringPrototype.h
+++ b/Libraries/LibJS/Runtime/StringPrototype.h
@@ -40,6 +40,7 @@ private:
static Value char_at(Interpreter&);
static Value repeat(Interpreter&);
+ static Value starts_with(Interpreter&);
static Value length_getter(Interpreter&);
};
diff --git a/Libraries/LibJS/Tests/String.prototype.startsWith.js b/Libraries/LibJS/Tests/String.prototype.startsWith.js
new file mode 100644
index 0000000000..b194816e43
--- /dev/null
+++ b/Libraries/LibJS/Tests/String.prototype.startsWith.js
@@ -0,0 +1,40 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+ var s = "foobar";
+ assert(s.startsWith("f") === true);
+ assert(s.startsWith("fo") === true);
+ assert(s.startsWith("foo") === true);
+ assert(s.startsWith("foob") === true);
+ assert(s.startsWith("fooba") === true);
+ assert(s.startsWith("foobar") === true);
+ assert(s.startsWith("foobar1") === false);
+ assert(s.startsWith("f", 0) === true);
+ assert(s.startsWith("fo", 0) === true);
+ assert(s.startsWith("foo", 0) === true);
+ assert(s.startsWith("foob", 0) === true);
+ assert(s.startsWith("fooba", 0) === true);
+ assert(s.startsWith("foobar", 0) === true);
+ assert(s.startsWith("foobar1", 0) === false);
+ assert(s.startsWith("foo", []) === true);
+ assert(s.startsWith("foo", null) === true);
+ assert(s.startsWith("foo", undefined) === true);
+ assert(s.startsWith("foo", false) === true);
+ assert(s.startsWith("foo", true) === false);
+ assert(s.startsWith("foo", "foo") === true);
+ assert(s.startsWith("foo", 0 - 1) === true);
+ assert(s.startsWith("foo", 42) === false);
+ assert(s.startsWith("bar", 3) === true);
+ assert(s.startsWith("bar", "3") === true);
+ assert(s.startsWith("bar1", 3) === false);
+ assert(s.startsWith() === false);
+ assert(s.startsWith("") === true);
+ assert(s.startsWith("", 0) === true);
+ assert(s.startsWith("", 1) === true);
+ assert(s.startsWith("", 0 - 1) === true);
+ assert(s.startsWith("", 42) === true);
+
+ console.log("PASS");
+} catch (e) {
+ console.log("FAIL: " + e);
+}