1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.stdlib..string; 7 8 import std..string; 9 import std.conv : to; 10 import grimoire.assembly, grimoire.compiler, grimoire.runtime; 11 12 package(grimoire.stdlib) void grLoadStdLibString(GrLibrary library) { 13 library.addPrimitive(&_empty, "empty?", [grString], [grBool]); 14 library.addPrimitive(&_unshift, "unshift", [grString, grString], [grString]); 15 library.addPrimitive(&_push, "push", [grString, grString], [grString]); 16 library.addPrimitive(&_shift, "shift", [grString], [grString]); 17 library.addPrimitive(&_pop, "pop", [grString], [grString]); 18 library.addPrimitive(&_shift1, "shift", [grString, grInt], [grString]); 19 library.addPrimitive(&_pop1, "pop", [grString, grInt], [grString]); 20 library.addPrimitive(&_first, "first", [grString], [grString]); 21 library.addPrimitive(&_last, "last", [grString], [grString]); 22 library.addPrimitive(&_remove, "remove", [grString, grInt], [grString]); 23 library.addPrimitive(&_remove2, "remove", [grString, grInt, grInt], [ 24 grString 25 ]); 26 library.addPrimitive(&_slice, "slice", [grString, grInt, grInt], [grString]); 27 library.addPrimitive(&_reverse, "reverse", [grString], [grString]); 28 library.addPrimitive(&_insert, "insert", [grString, grInt, grString], [ 29 grString 30 ]); 31 library.addPrimitive(&_findFirst, "findFirst", [grString, grString], [grInt]); 32 library.addPrimitive(&_findLast, "findLast", [grString, grString], [grInt]); 33 library.addPrimitive(&_has, "has?", [grString, grString], [grBool]); 34 35 GrType stringIterType = library.addForeign("StringIter"); 36 library.addPrimitive(&_each, "each", [grString], [stringIterType]); 37 library.addPrimitive(&_next, "next", [stringIterType], [grBool, grString]); 38 } 39 40 private void _empty(GrCall call) { 41 call.setBool(call.getString(0).length == 0); 42 } 43 44 private void _unshift(GrCall call) { 45 GrString str = call.getString(0); 46 str = call.getString(1) ~ str; 47 call.setString(str); 48 } 49 50 private void _push(GrCall call) { 51 GrString str = call.getString(0); 52 str ~= call.getString(1); 53 call.setString(str); 54 } 55 56 private void _shift(GrCall call) { 57 GrString str = call.getString(0); 58 if (!str.length) { 59 call.setString(str); 60 return; 61 } 62 call.setString(str[1 .. $]); 63 } 64 65 private void _pop(GrCall call) { 66 GrString str = call.getString(0); 67 if (!str.length) { 68 call.setString(str); 69 return; 70 } 71 str.length--; 72 call.setString(str); 73 } 74 75 private void _shift1(GrCall call) { 76 GrString str = call.getString(0); 77 GrInt size = call.getInt(1); 78 if (size < 0) { 79 call.raise("IndexError"); 80 return; 81 } 82 if (str.length < size) { 83 str.length = 0; 84 call.setString(str); 85 return; 86 } 87 if (!str.length) { 88 call.setString(str); 89 return; 90 } 91 call.setString(str[size .. $]); 92 } 93 94 private void _pop1(GrCall call) { 95 GrString str = call.getString(0); 96 GrInt size = call.getInt(1); 97 if (size < 0) { 98 call.raise("IndexError"); 99 return; 100 } 101 if (str.length < size) { 102 str.length = 0; 103 call.setString(str); 104 return; 105 } 106 if (!str.length) { 107 call.setString(str); 108 return; 109 } 110 str.length -= size; 111 call.setString(str); 112 } 113 114 private void _first(GrCall call) { 115 GrString str = call.getString(0); 116 if (!str.length) { 117 call.raise("IndexError"); 118 return; 119 } 120 call.setString(to!GrString(str[0])); 121 } 122 123 private void _last(GrCall call) { 124 GrString str = call.getString(0); 125 if (!str.length) { 126 call.raise("IndexError"); 127 return; 128 } 129 call.setString(to!GrString(str[$ - 1])); 130 } 131 132 private void _remove(GrCall call) { 133 GrString str = call.getString(0); 134 GrInt index = call.getInt(1); 135 if (index < 0) 136 index = (cast(GrInt) str.length) + index; 137 if (!str.length || index >= str.length || index < 0) { 138 call.setString(str); 139 return; 140 } 141 if (index + 1 == str.length) { 142 str.length--; 143 call.setString(str); 144 return; 145 } 146 if (index == 0) { 147 call.setString(str[1 .. $]); 148 return; 149 } 150 call.setString(str[0 .. index] ~ str[index + 1 .. $]); 151 } 152 153 private void _remove2(GrCall call) { 154 GrString str = call.getString(0); 155 GrInt index1 = call.getInt(1); 156 GrInt index2 = call.getInt(2); 157 if (index1 < 0) 158 index1 = (cast(GrInt) str.length) + index1; 159 if (index2 < 0) 160 index2 = (cast(GrInt) str.length) + index2; 161 162 if (index2 < index1) { 163 const GrInt temp = index1; 164 index1 = index2; 165 index2 = temp; 166 } 167 168 if (!str.length || index1 >= str.length || index2 < 0) { 169 call.setString(str); 170 return; 171 } 172 173 if (index1 < 0) 174 index1 = 0; 175 if (index2 >= str.length) 176 index2 = (cast(GrInt) str.length) - 1; 177 178 if (index1 == 0 && (index2 + 1) == str.length) { 179 call.setString(""); 180 return; 181 } 182 if (index1 == 0) { 183 call.setString(str[(index2 + 1) .. $]); 184 return; 185 } 186 if ((index2 + 1) == str.length) { 187 call.setString(str[0 .. index1]); 188 return; 189 } 190 call.setString(str[0 .. index1] ~ str[(index2 + 1) .. $]); 191 } 192 193 private void _slice(GrCall call) { 194 GrString str = call.getString(0); 195 GrInt index1 = call.getInt(1); 196 GrInt index2 = call.getInt(2); 197 if (index1 < 0) 198 index1 = (cast(GrInt) str.length) + index1; 199 if (index2 < 0) 200 index2 = (cast(GrInt) str.length) + index2; 201 202 if (index2 < index1) { 203 const GrInt temp = index1; 204 index1 = index2; 205 index2 = temp; 206 } 207 208 if (!str.length || index1 >= str.length || index2 < 0) { 209 call.setString(""); 210 return; 211 } 212 213 if (index1 < 0) 214 index1 = 0; 215 if (index2 >= str.length) 216 index2 = (cast(GrInt) str.length - 1); 217 218 if (index1 == 0 && (index2 + 1) == str.length) { 219 call.setString(str); 220 return; 221 } 222 call.setString(str[index1 .. index2 + 1]); 223 } 224 225 private void _reverse(GrCall call) { 226 import std.algorithm.mutation : reverse; 227 228 call.setString(call.getString(0).dup.reverse); 229 } 230 231 private void _insert(GrCall call) { 232 GrString str = call.getString(0); 233 GrInt index = call.getInt(1); 234 GrString value = call.getString(2); 235 if (index < 0) 236 index = (cast(GrInt) str.length) + index; 237 if (!str.length || index >= str.length || index < 0) { 238 call.raise("IndexError"); 239 return; 240 } 241 if (index + 1 == str.length) { 242 call.setString(str[0 .. index] ~ value ~ str[$ - 1]); 243 return; 244 } 245 if (index == 0) { 246 call.setString(value ~ str); 247 return; 248 } 249 call.setString(str[0 .. index] ~ value ~ str[index .. $]); 250 } 251 252 private void _findFirst(GrCall call) { 253 GrString str = call.getString(0); 254 GrString value = call.getString(1); 255 call.setInt(cast(GrInt) str.indexOf(value)); 256 } 257 258 private void _findLast(GrCall call) { 259 GrString str = call.getString(0); 260 GrString value = call.getString(1); 261 call.setInt(cast(GrInt) str.lastIndexOf(value)); 262 } 263 264 private void _has(GrCall call) { 265 GrString str = call.getString(0); 266 GrString value = call.getString(1); 267 call.setBool(str.indexOf(value) != -1); 268 } 269 270 private final class StringIter { 271 GrString value; 272 size_t index; 273 } 274 275 private void _each(GrCall call) { 276 StringIter iter = new StringIter; 277 iter.value = call.getString(0); 278 call.setForeign(iter); 279 } 280 281 private void _next(GrCall call) { 282 StringIter iter = call.getForeign!(StringIter)(0); 283 if (!iter) { 284 call.raise("NullError"); 285 return; 286 } 287 if (iter.index >= iter.value.length) { 288 call.setBool(false); 289 call.setString(""); 290 return; 291 } 292 call.setBool(true); 293 call.setString(to!GrString(iter.value[iter.index])); 294 iter.index++; 295 }