Bläddra i källkod

Merge pull request #116 from hallzy/substr

Added a String.substr() method
Marco Bambini 8 år sedan
förälder
incheckning
12ad08bfcb
4 ändrade filer med 62 tillägg och 17 borttagningar
  1. 4 0
      docs/types.html
  2. 49 12
      src/runtime/gravity_core.c
  3. 7 4
      test/string/loadat.gravity
  4. 2 1
      test/string/loadat_error.gravity

+ 4 - 0
docs/types.html

@@ -138,6 +138,10 @@
 	// and retrieve those characters
 	n = a[6]                // n is now "W"
 	n = a[-7]               // n is now "o"
+	n = a[0...4]            // n is now "Hello"
+	n = a[-5...-1]          // n is now "World"
+	n = a[-5...10]          // n is now "World"
+	n = a[-1...-5]          // n is now "dlroW"
 			</code></pre>
 			
 			<h4 class="section-h4">Bool</h4>

+ 49 - 12
src/runtime/gravity_core.c

@@ -1637,18 +1637,55 @@ static bool string_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 	#pragma unused(nargs)
 	gravity_string_t *string = VALUE_AS_STRING(GET_VALUE(0));
 	gravity_value_t value = GET_VALUE(1);
-	if (!VALUE_ISA_INT(value)) RETURN_ERROR("An integer index is required to access a string item.");
-	
-	int32_t index = (int32_t)VALUE_AS_INT(value);
-	
-	if (index < 0) index = string->len + index;
-	if ((index < 0) || ((uint32_t)index >= string->len)) RETURN_ERROR("Out of bounds error: index %d beyond bounds 0...%d", index, string->len-1);
 
-	// this code is not UTF-8 safe
-	char c[2] = "\0";
-	c[0] = string->s[index];
-	
-	RETURN_VALUE(VALUE_FROM_STRING(vm, c, 1), rindex);
+	int32_t first_index;
+	int32_t second_index;
+
+	if (VALUE_ISA_INT(value)) {
+		first_index = (int32_t)VALUE_AS_INT(value);
+		second_index = first_index;
+	}
+	else if (VALUE_ISA_RANGE(value)) {
+		gravity_range_t *range = VALUE_AS_RANGE(value);
+		first_index = range->from;
+		second_index = range->to;
+	}
+	else {
+		RETURN_ERROR("An integer index or index range is required to access string items.");
+	}
+
+	if (first_index < 0) first_index = string->len + first_index;
+	if ((first_index < 0) || ((uint32_t)first_index >= string->len)) RETURN_ERROR("Out of bounds error: first_index %d beyond bounds 0...%d", first_index, string->len-1);
+
+	if (second_index < 0) second_index = string->len + second_index;
+	if ((second_index < 0) || ((uint32_t)second_index >= string->len)) RETURN_ERROR("Out of bounds error: second_index %d beyond bounds 0...%d", second_index, string->len-1);
+
+	uint32_t substr_len = first_index < second_index ? second_index - first_index + 1 : first_index - second_index + 1;
+
+	bool is_forward = first_index <= second_index;
+	if (!is_forward) {
+		char original[string->len];
+		// without copying it, we would be modifying the original string
+		strncpy((char *)original, string->s, string->len);
+
+		// Reverse the string, and reverse the indices
+		first_index = strlen(original) - first_index -1;
+		second_index = strlen(original) - second_index -1;
+
+		// reverse the String
+		int i = strlen(original) - 1;
+		int j = 0;
+		char c;
+		while (i > j) {
+			c = original[i];
+			original[i] = original[j];
+			original[j] = c;
+			--i;
+			++j;
+		}
+		RETURN_VALUE(VALUE_FROM_STRING(vm, original + first_index, substr_len), rindex);
+	}
+	RETURN_VALUE(VALUE_FROM_STRING(vm, string->s + first_index, substr_len), rindex);
 }
 
 static bool string_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
@@ -2108,7 +2145,7 @@ static void gravity_core_init (void) {
 	gravity_class_bind(gravity_class_string, "upper", NEW_CLOSURE_VALUE(string_upper));
 	gravity_class_bind(gravity_class_string, "lower", NEW_CLOSURE_VALUE(string_lower));
 	gravity_class_bind(gravity_class_string, "split", NEW_CLOSURE_VALUE(string_split));
-	
+
 	// FIBER CLASS
 	gravity_class_t *fiber_meta = gravity_class_get_meta(gravity_class_fiber);
 	gravity_class_bind(fiber_meta, "create", NEW_CLOSURE_VALUE(fiber_create));

+ 7 - 4
test/string/loadat.gravity

@@ -6,8 +6,11 @@
 
 func main () {
 	var s = "Hello World"
-	if (s[6] == s[-5] and s[6] == "W") {
-		return true
-	}
-	return false
+	var ret = s[6] == s[-5] and s[6] == "W"
+
+	ret = ret and s[-1...0] == "dlroW olleH"
+	ret = ret and s[0...4] == "Hello"
+	ret = ret and s[-5...-1] == "World"
+
+	return ret
 }

+ 2 - 1
test/string/loadat_error.gravity

@@ -5,5 +5,6 @@
 
 func main () {
 	var s = "Hello World"
-	return s[11]
+	// out of bounds
+	return s[0...11]
 }