diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index 6fe439fe0b32d4..8637f9afade673 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -81,6 +81,7 @@ StringPrototype::StringPrototype() put_native_function("substring", substring, 2, attr); put_native_function("includes", includes, 1, attr); put_native_function("slice", slice, 2, attr); + put_native_function("lastIndexOf", last_index_of, 1, attr); } StringPrototype::~StringPrototype() @@ -425,4 +426,37 @@ Value StringPrototype::slice(Interpreter& interpreter) return js_string(interpreter, string_part); } +Value StringPrototype::last_index_of(Interpreter& interpreter) +{ + auto string = string_from(interpreter); + if (string.is_null()) + return {}; + + if (interpreter.argument_count() == 0) + return Value(-1); + + auto search_string = interpreter.argument(0).to_string(); + if (search_string.length() > string.length()) + return Value(-1); + + ssize_t max_index = string.length() - search_string.length(); + ssize_t from_index = max_index; + if (interpreter.argument_count() >= 2) { + from_index = static_cast(interpreter.argument(1).to_i32()); + + if (from_index < 0) + from_index = 0; + if (from_index > max_index) + from_index = max_index; + } + + for (ssize_t i = from_index; i >= 0; --i) { + auto part_view = string.substring_view(i, search_string.length()); + if (part_view == search_string) + return Value((i32)i); + } + + return Value(-1); +} + } diff --git a/Libraries/LibJS/Runtime/StringPrototype.h b/Libraries/LibJS/Runtime/StringPrototype.h index df5221df7531f6..e25e6b648cb7b3 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.h +++ b/Libraries/LibJS/Runtime/StringPrototype.h @@ -57,6 +57,7 @@ class StringPrototype final : public StringObject { static Value concat(Interpreter&); static Value includes(Interpreter&); static Value slice(Interpreter&); + static Value last_index_of(Interpreter&); }; } diff --git a/Libraries/LibJS/Tests/String.prototype.lastIndexOf.js b/Libraries/LibJS/Tests/String.prototype.lastIndexOf.js new file mode 100644 index 00000000000000..dbd72147d7df1d --- /dev/null +++ b/Libraries/LibJS/Tests/String.prototype.lastIndexOf.js @@ -0,0 +1,27 @@ +load("test-common.js"); + +try { + assert(String.prototype.lastIndexOf.length === 1); + assert("hello friends".lastIndexOf() === -1); + assert("hello friends".lastIndexOf("e") === 9); + assert("hello friends".lastIndexOf("e", -7) === -1); + assert("hello friends".lastIndexOf("e", 100) === 9); + assert("hello friends".lastIndexOf("") === 13); + assert("hello friends".lastIndexOf("Z") === -1); + assert("hello friends".lastIndexOf("serenity") === -1); + assert("hello friends".lastIndexOf("", 4) === 4); + assert("hello serenity friends".lastIndexOf("serenity") === 6); + assert("hello serenity friends serenity".lastIndexOf("serenity") === 23); + assert("hello serenity friends serenity".lastIndexOf("serenity", 14) === 6); + assert("".lastIndexOf("") === 0); + assert("".lastIndexOf("", 1) === 0); + assert("".lastIndexOf("", -1) === 0); + assert("hello friends serenity".lastIndexOf("h", 10) === 0); + assert("hello friends serenity".lastIndexOf("l", 4) === 3); + assert("hello friends serenity".lastIndexOf("s", 13) === 12); + assert("hello".lastIndexOf("serenity") === -1); + + console.log("PASS"); +} catch (err) { + console.log("FAIL: " + err); +}