Browse Source

Merge pull request #97 from hallzy/string_methods

String methods
Marco Bambini 8 years ago
parent
commit
abe9935903

+ 23 - 3
docs/types.html

@@ -101,11 +101,31 @@
 			<h4 class="section-h4">String</h4>
 			<h4 class="section-h4">String</h4>
 			<p>Strings are an immutable sequence of characters. String literals can be surrounded in double or single quotes.</p>
 			<p>Strings are an immutable sequence of characters. String literals can be surrounded in double or single quotes.</p>
 			<pre><code class="swift">
 			<pre><code class="swift">
-	var a = "Hello World";	// double quotes
-	var b = 'Hello World';	// single quotes
+	var a = "Hello World";  // double quotes
+	var b = 'Hello World';  // single quotes
 	
 	
 	// Strings have also a length property
 	// Strings have also a length property
-	var n = b.length;	// n is now 11
+	var n = b.length;       // n is now 11
+
+	// Strings also have some built in methods
+	n = b.index("Wor")      // n is now 6.
+
+	n = b.count("l")        // n is now 3.
+	n = b.count("llo")      // n is now 1.
+
+	n = "A".string_repeat(10) // n is now "AAAAAAAAAA"
+
+	n = b.upper()           // n is now "HELLO WORLD"
+	n = b.lower()           // n is now "hello world"
+
+	// You are also able to edit strings by character...
+	b[0] = "Z"              // b is now "Zello World"
+	b[1] = "abc"            // b is now "Zabco World"
+	b[-7] = "QWERTY"        // b is now "ZabcQWERTYd"
+
+	// and retrieve those characters
+	n = a[6]                // n is now "W"
+	n = a[-7]               // n is now "o"
 			</code></pre>
 			</code></pre>
 			
 			
 			<h4 class="section-h4">Bool</h4>
 			<h4 class="section-h4">Bool</h4>

+ 172 - 0
src/runtime/gravity_core.c

@@ -1450,6 +1450,171 @@ static bool operator_string_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t
 	RETURN_VALUE(VALUE_FROM_INT(strcmp(s1->s, s2->s)), rindex);
 	RETURN_VALUE(VALUE_FROM_INT(strcmp(s1->s, s2->s)), rindex);
 }
 }
 
 
+static bool string_index (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs)
+	gravity_string_t *main_str     = VALUE_AS_STRING(GET_VALUE(0));
+
+	if (nargs != 2) {
+		RETURN_ERROR("String.index() expects 1 argument");
+	}
+	if (!VALUE_ISA_STRING(GET_VALUE(1))) {
+		RETURN_ERROR("String.index() expects a string as an argument");
+	}
+
+	gravity_string_t *str_to_index = VALUE_AS_STRING(GET_VALUE(1));
+
+	char *ptr;
+
+	// Search for the string
+	ptr = strstr(main_str->s, str_to_index->s);
+
+	// If it doesn't exist, return null
+	if (ptr == NULL) {
+		RETURN_VALUE(VALUE_FROM_NULL, rindex);
+	}
+	// Otherwise, return the difference, which is the index that the string starts at
+	else {
+		RETURN_VALUE(VALUE_FROM_INT(ptr-main_str->s), rindex);
+	}
+}
+
+static bool string_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs)
+	gravity_string_t *main_str     = VALUE_AS_STRING(GET_VALUE(0));
+
+	if (nargs != 2) {
+		RETURN_ERROR("String.count() expects 1 argument");
+	}
+	if (!VALUE_ISA_STRING(GET_VALUE(1))) {
+		RETURN_ERROR("String.count() expects a string as an argument");
+	}
+	gravity_string_t *str_to_count = VALUE_AS_STRING(GET_VALUE(1));
+
+	int j = 0;
+	int count = 0;
+
+	// Iterate through whole string
+	for (int i = 0; i < main_str->len; i++) {
+		if (main_str->s[i] == str_to_count->s[j]) {
+			// If the characters match and we are on the last character of the search
+			// string, then we have found a match
+			if (j == str_to_count->len - 1) {
+				count++;
+				j = 0;
+				continue;
+			}
+		}
+		// Reset if it isn't a match
+		else {
+			j = 0;
+			continue;
+		}
+		// Move forward in the search string if we found a match but we aren't
+		// finished checking all the characters of the search string yet
+		j++;
+	}
+
+	RETURN_VALUE(VALUE_FROM_INT(count), rindex);
+}
+
+
+static bool string_repeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs)
+	gravity_string_t *main_str = VALUE_AS_STRING(GET_VALUE(0));
+
+	if (nargs != 2) {
+		RETURN_ERROR("String.string_repeat() expects 1 argument");
+	}
+	if (!VALUE_ISA_INT(GET_VALUE(1))) {
+		RETURN_ERROR("String.string_repeat() expects an integer as an argument");
+	}
+	gravity_int_t times_to_repeat = VALUE_AS_INT(GET_VALUE(1));
+
+	if (times_to_repeat < 1) {
+		RETURN_ERROR("String.string_repeat() expects an integer >=1");
+	}
+
+	// Figure out the size of the array we need to make to hold the new string
+	int new_size = main_str->len*times_to_repeat;
+	char new_str[new_size];
+	strcpy(new_str, main_str->s);
+	for (int i = 0; i < times_to_repeat-1; i++) {
+		strcat(new_str, main_str->s);
+	}
+
+	RETURN_VALUE(VALUE_FROM_STRING(vm, new_str, strlen(new_str)), rindex);
+}
+
+static bool string_upper (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs)
+	gravity_string_t *main_str = VALUE_AS_STRING(GET_VALUE(0));
+
+	if (nargs != 1) {
+		RETURN_ERROR("String.upper() expects no argument");
+	}
+
+	for (int i = 0; i < main_str->len; i++) {
+		main_str->s[i] = toupper(main_str->s[i]);
+	}
+
+	RETURN_VALUE(VALUE_FROM_STRING(vm, main_str->s, main_str->len), rindex);
+}
+
+static bool string_lower (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs)
+	gravity_string_t *main_str = VALUE_AS_STRING(GET_VALUE(0));
+
+	if (nargs != 1) {
+		RETURN_ERROR("String.lower() expects no argument");
+	}
+
+	for (int i = 0; i < main_str->len; i++) {
+		main_str->s[i] = tolower(main_str->s[i]);
+	}
+
+	RETURN_VALUE(VALUE_FROM_STRING(vm, main_str->s, main_str->len), rindex);
+}
+
+static bool string_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, 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.");
+	
+	register 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);
+
+	char c[2] = "\0";
+	c[0] = string->s[index];
+	
+	RETURN_VALUE(VALUE_FROM_STRING(vm, c, 1), rindex);
+}
+
+static bool string_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(vm, nargs, rindex)
+	gravity_string_t *string = VALUE_AS_STRING(GET_VALUE(0));
+	gravity_value_t idxvalue = GET_VALUE(1);
+	if (!VALUE_ISA_INT(idxvalue)) RETURN_ERROR("An integer index is required to access a string item.");
+	if (!VALUE_ISA_STRING(GET_VALUE(2))) RETURN_ERROR("A string needs to be assigned to a string index");
+
+	gravity_string_t *value = VALUE_AS_STRING(GET_VALUE(2));
+
+	/* if (value->len != 1) RETURN_ERROR("Assigned string must be one character long."); */
+	
+	register int32_t index = (int32_t)VALUE_AS_INT(idxvalue);
+	
+	if (index < 0) index = string->len + index;
+	if (index < 0 || index >= string->len) RETURN_ERROR("Out of bounds error: index %d beyond bounds 0...%d", index, string->len-1);
+	if (index+value->len - 1 >= string->len) RETURN_ERROR("Out of bounds error: End of inserted string exceeds the length of the initial string");
+
+	for (int i = index; i < index+value->len; i++) {
+	 string->s[i] = value->s[i-index];
+	}
+	RETURN_NOVALUE();
+}
+
 // MARK: - Fiber Class -
 // MARK: - Fiber Class -
 
 
 static bool fiber_create (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 static bool fiber_create (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
@@ -1840,7 +2005,14 @@ static void gravity_core_init (void) {
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_OR_NAME,  NEW_CLOSURE_VALUE(operator_string_or));
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_OR_NAME,  NEW_CLOSURE_VALUE(operator_string_or));
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_string_cmp));
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_string_cmp));
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_string_neg));
 	gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_string_neg));
+	gravity_class_bind(gravity_class_string, GRAVITY_INTERNAL_LOADAT_NAME, NEW_CLOSURE_VALUE(string_loadat));
+	gravity_class_bind(gravity_class_string, GRAVITY_INTERNAL_STOREAT_NAME, NEW_CLOSURE_VALUE(string_storeat));
 	gravity_class_bind(gravity_class_string, "length", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(string_length), NULL)));
 	gravity_class_bind(gravity_class_string, "length", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(string_length), NULL)));
+	gravity_class_bind(gravity_class_string, "index", NEW_CLOSURE_VALUE(string_index));
+	gravity_class_bind(gravity_class_string, "count", NEW_CLOSURE_VALUE(string_count));
+	gravity_class_bind(gravity_class_string, "string_repeat", NEW_CLOSURE_VALUE(string_repeat));
+	gravity_class_bind(gravity_class_string, "upper", NEW_CLOSURE_VALUE(string_upper));
+	gravity_class_bind(gravity_class_string, "lower", NEW_CLOSURE_VALUE(string_lower));
 	
 	
 	// FIBER CLASS
 	// FIBER CLASS
 	gravity_class_t *fiber_meta = gravity_class_get_meta(gravity_class_fiber);
 	gravity_class_t *fiber_meta = gravity_class_get_meta(gravity_class_fiber);

+ 10 - 0
test/string/count_method.gravity

@@ -0,0 +1,10 @@
+#unittest {
+	name: "count() method for string";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	return s.count("l") == 3 and s.count("World") == 1 and s.count("xyz") == 0
+}

+ 13 - 0
test/string/index_method.gravity

@@ -0,0 +1,13 @@
+#unittest {
+	name: "index() method for string";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	if (s.index("H")==s.index("Hel") and s.index("H")==0 and s.index("d")==10) {
+		return true;
+	}
+	return false;
+}

+ 9 - 0
test/string/index_method_error.gravity

@@ -0,0 +1,9 @@
+#unittest {
+	name: "index() method for string - error";
+	error: RUNTIME;
+};
+
+func main () {
+	var s = "Hello World"
+	return s.index(2)
+}

+ 10 - 0
test/string/index_method_notfound.gravity

@@ -0,0 +1,10 @@
+#unittest {
+	name: "index() method for string - not found";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	return s.index("qwerty") == null
+}

+ 13 - 0
test/string/loadat.gravity

@@ -0,0 +1,13 @@
+#unittest {
+	name: "Loadat an index for string";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	if (s[6] == s[-5] and s[6] == "W") {
+		return true
+	}
+	return false
+}

+ 9 - 0
test/string/loadat_error.gravity

@@ -0,0 +1,9 @@
+#unittest {
+	name: "Loadat an index for string - error";
+	error: RUNTIME;
+};
+
+func main () {
+	var s = "Hello World"
+	return s[11]
+}

+ 12 - 0
test/string/storeat.gravity

@@ -0,0 +1,12 @@
+#unittest {
+	name: "storeat an index for string";
+	error: NONE;
+	result: "Hzllqwertyd";
+};
+
+func main () {
+	var s = "Hello World";
+	s[1] = "z";
+	s[-7] = "qwerty"
+	return s;
+}

+ 10 - 0
test/string/storeat_error.gravity

@@ -0,0 +1,10 @@
+#unittest {
+	name: "storeat an index for string - error";
+	error: RUNTIME;
+};
+
+func main () {
+	var s = "Hello World";
+	s[11] = "z";
+	return s;
+}

+ 12 - 0
test/string/string_repeat_method.gravity

@@ -0,0 +1,12 @@
+#unittest {
+	name: "string_repeat() method for string";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	var b = s.string_repeat(3) == "Hello WorldHello WorldHello World"
+	var c = s.string_repeat(1) == s
+	return b && c
+}

+ 9 - 0
test/string/string_repeat_method_error.gravity

@@ -0,0 +1,9 @@
+#unittest {
+	name: "string_repeat() method for string - error";
+	error: RUNTIME;
+};
+
+func main () {
+	var s = "Hello World"
+	return s.string_repeat(0)
+}

+ 12 - 0
test/string/upper_lower_method.gravity

@@ -0,0 +1,12 @@
+#unittest {
+	name: "upper() and lower methods for string";
+	error: NONE;
+	result: true;
+};
+
+func main () {
+	var s = "Hello World"
+	var u = s.upper() == "HELLO WORLD"
+	var l = s.lower() == "hello world"
+	return u && l
+}