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