diff --git a/doc/site/modules/core/string.markdown b/doc/site/modules/core/string.markdown index e1a58515d..114f583df 100644 --- a/doc/site/modules/core/string.markdown +++ b/doc/site/modules/core/string.markdown @@ -117,6 +117,20 @@ var string = "(ᵔᴥᵔ)" System.print(string.codePoints[2]) //> -1 (in the middle of "ᵔ") +### **compareTo**(other) + +Compares this string with `other` lexicographically by codepoint. + +Returns a negative value if `this` appears before `other`, zero if `this` compares equal to `other` or a positive value if `this` appears after `other` in lexicographical order. + +
+System.print("abc".compareTo("def")) //> -3
+System.print("def".compareTo("abc")) //> 3
+System.print("abc".compareTo("abc")) //> 0
+
+
+It is a runtime error if `other` is not a string.
+
### **contains**(other)
Checks if `other` is a substring of the string.
@@ -268,7 +282,23 @@ Checks if the string is equal to `other`.
### **!=**(other) operator
-Check if the string is not equal to `other`.
+Checks if the string is not equal to `other`.
+
+### **<**(other) operator
+
+Checks if the string appears before `other` in lexicographical order.
+
+### **<=**(other) operator
+
+Checks if the string appears before or compares equal to `other` in lexicographical order.
+
+### **>**(other) operator
+
+Checks if the string appears after `other` in lexicographical order
+
+### **>=**(other) operator
+
+Checks if the string appears after or compares equal to `other` in lexicographical order.
### **[**index**]** operator
diff --git a/src/vm/wren_core.c b/src/vm/wren_core.c
index d0a121f8c..83a19f3aa 100644
--- a/src/vm/wren_core.c
+++ b/src/vm/wren_core.c
@@ -1042,6 +1042,31 @@ DEF_PRIMITIVE(string_codePointAt)
string->length - index));
}
+DEF_PRIMITIVE(string_compareTo)
+{
+ if (!validateString(vm, args[1], "Argument")) return false;
+
+ ObjString* str1 = AS_STRING(args[0]);
+ ObjString* str2 = AS_STRING(args[1]);
+
+ size_t len1 = str1->length;
+ size_t len2 = str2->length;
+
+ // Get minimum length for comparison.
+ size_t minLen = (len1 <= len2) ? len1 : len2;
+ int res = memcmp(str1->value, str2->value, minLen);
+
+ // If result is non-zero, just return that.
+ if (res) RETURN_NUM(res);
+
+ // If the lengths are the same, the strings must be equal
+ if (len1 == len2) RETURN_NUM(0);
+
+ // Otherwise the shorter string will come first.
+ res = (len1 < len2) ? -1 : 1;
+ RETURN_NUM(res);
+}
+
DEF_PRIMITIVE(string_contains)
{
if (!validateString(vm, args[1], "Argument")) return false;
@@ -1417,6 +1442,7 @@ void wrenInitializeCore(WrenVM* vm)
PRIMITIVE(vm->stringClass, "byteAt_(_)", string_byteAt);
PRIMITIVE(vm->stringClass, "byteCount_", string_byteCount);
PRIMITIVE(vm->stringClass, "codePointAt_(_)", string_codePointAt);
+ PRIMITIVE(vm->stringClass, "compareTo(_)", string_compareTo);
PRIMITIVE(vm->stringClass, "contains(_)", string_contains);
PRIMITIVE(vm->stringClass, "endsWith(_)", string_endsWith);
PRIMITIVE(vm->stringClass, "indexOf(_)", string_indexOf1);
diff --git a/src/vm/wren_core.wren b/src/vm/wren_core.wren
index f073062c2..ca5e52120 100644
--- a/src/vm/wren_core.wren
+++ b/src/vm/wren_core.wren
@@ -289,6 +289,11 @@ class String is Sequence {
}
return result
}
+
+ < (other) { compareTo(other) < 0 }
+ <= (other) { compareTo(other) <= 0 }
+ > (other) { compareTo(other) > 0 }
+ >= (other) { compareTo(other) >= 0 }
}
class StringByteSequence is Sequence {
diff --git a/src/vm/wren_core.wren.inc b/src/vm/wren_core.wren.inc
index be296cdf7..7aeb0d619 100644
--- a/src/vm/wren_core.wren.inc
+++ b/src/vm/wren_core.wren.inc
@@ -291,6 +291,11 @@ static const char* coreModuleSource =
" }\n"
" return result\n"
" }\n"
+"\n"
+" < (other) { compareTo(other) < 0 }\n"
+" <= (other) { compareTo(other) <= 0 }\n"
+" > (other) { compareTo(other) > 0 }\n"
+" >= (other) { compareTo(other) >= 0 }\n"
"}\n"
"\n"
"class StringByteSequence is Sequence {\n"
diff --git a/test/core/string/comparisons.wren b/test/core/string/comparisons.wren
new file mode 100644
index 000000000..395ba7bf8
--- /dev/null
+++ b/test/core/string/comparisons.wren
@@ -0,0 +1,16 @@
+System.print("" < "abc") // expect: true
+System.print("abc" < "def") // expect: true
+System.print("abc" < "abc") // expect: false
+System.print("abc" <= "abc") // expect: true
+System.print("ghi" > "") // expect: true
+System.print("ghi" > "abc") // expect: true
+System.print("ghi" > "ghi") // expect: false
+System.print("ghi" >= "ghi") // expect: true
+
+// Non-ascii
+System.print("ÀÁA" < "àáa") // expect: true
+System.print("ÀÁA" < "ÀÁA") // expect: false
+System.print("ÀÁA" <= "ÀÁA") // expect: true
+System.print("a€E" > "a€e") // expect: false
+System.print("a€E" > "a€E") // expect: false
+System.print("a€E" >= "a€E") // expect: true