MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

allow non-posix regex

+156 -5
+1 -1
meson.build
··· 74 74 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 75 75 76 76 version_conf = configuration_data() 77 - version_conf.set('ANT_VERSION', '0.1.1.7') 77 + version_conf.set('ANT_VERSION', '0.1.1.8') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+155 -4
src/ant.c
··· 456 456 static jsval_t builtin_string_endsWith(struct js *js, jsval_t *args, int nargs); 457 457 static jsval_t builtin_string_replace(struct js *js, jsval_t *args, int nargs); 458 458 static jsval_t builtin_string_replaceAll(struct js *js, jsval_t *args, int nargs); 459 + static jsval_t builtin_string_match(struct js *js, jsval_t *args, int nargs); 459 460 static jsval_t builtin_string_template(struct js *js, jsval_t *args, int nargs); 460 461 static jsval_t builtin_string_charCodeAt(struct js *js, jsval_t *args, int nargs); 461 462 static jsval_t builtin_string_toLowerCase(struct js *js, jsval_t *args, int nargs); ··· 12193 12194 const char *repl_ptr = (char *) &js->mem[repl_off]; 12194 12195 12195 12196 if (search_len == 0) { 12196 - // Empty search string: insert replacement between each character 12197 12197 size_t total_len = str_len + (str_len + 1) * repl_len; 12198 12198 char *result = (char *)ANT_GC_MALLOC(total_len + 1); 12199 12199 if (!result) return js_mkerr(js, "oom"); ··· 12211 12211 return ret; 12212 12212 } 12213 12213 12214 - // Count occurrences first 12215 12214 jsoff_t count = 0; 12216 12215 for (jsoff_t i = 0; i <= str_len - search_len; i++) { 12217 12216 if (memcmp(str_ptr + i, search_ptr, search_len) == 0) { ··· 12222 12221 12223 12222 if (count == 0) return str; 12224 12223 12225 - // Calculate result length 12226 12224 size_t result_total = str_len - (count * search_len) + (count * repl_len); 12227 12225 char *result = (char *)ANT_GC_MALLOC(result_total + 1); 12228 12226 if (!result) return js_mkerr(js, "oom"); ··· 12240 12238 } 12241 12239 } 12242 12240 12243 - // Copy remaining characters 12244 12241 while (str_pos < str_len) { 12245 12242 result[result_pos++] = str_ptr[str_pos++]; 12246 12243 } ··· 12248 12245 jsval_t ret = js_mkstr(js, result, result_pos); 12249 12246 ANT_GC_FREE(result); 12250 12247 return ret; 12248 + } 12249 + 12250 + static size_t js_regex_to_posix(const char *src, size_t src_len, char *dst, size_t dst_size) { 12251 + size_t di = 0; 12252 + for (size_t si = 0; si < src_len && di < dst_size - 1; si++) { 12253 + if (src[si] != '\\' || si + 1 >= src_len) goto copy_char; 12254 + 12255 + const char *r = NULL; 12256 + char c = 0; 12257 + switch (src[si + 1]) { 12258 + case 'd': r = "[0-9]"; break; 12259 + case 'D': r = "[^0-9]"; break; 12260 + case 'w': r = "[a-zA-Z0-9_]"; break; 12261 + case 'W': r = "[^a-zA-Z0-9_]"; break; 12262 + case 's': r = "[ \t\n\r\f\v]"; break; 12263 + case 'S': r = "[^ \t\n\r\f\v]"; break; 12264 + case 'b': r = "[[:<:]]|[[:>:]]"; break; 12265 + case 'n': c = '\n'; break; 12266 + case 'r': c = '\r'; break; 12267 + case 't': c = '\t'; break; 12268 + default: goto copy_char; 12269 + } 12270 + si++; 12271 + if (c) { dst[di++] = c; continue; } 12272 + size_t rlen = strlen(r); 12273 + if (di + rlen >= dst_size - 1) continue; 12274 + memcpy(dst + di, r, rlen); 12275 + di += rlen; 12276 + continue; 12277 + 12278 + copy_char: 12279 + dst[di++] = src[si]; 12280 + } 12281 + dst[di] = '\0'; 12282 + return di; 12283 + } 12284 + 12285 + static jsval_t do_regex_match(struct js *js, const char *pattern_str, const char *str_ptr, jsoff_t str_len, char *str_buf, bool global_flag, bool ignore_case) { 12286 + regex_t regex; 12287 + int cflags = REG_EXTENDED; 12288 + 12289 + if (ignore_case) cflags |= REG_ICASE; 12290 + if (regcomp(&regex, pattern_str, cflags) != 0) return js_mknull(); 12291 + 12292 + jsval_t result_arr = js_mkarr(js); 12293 + if (is_err(result_arr)) { 12294 + regfree(&regex); 12295 + return result_arr; 12296 + } 12297 + 12298 + regmatch_t match; 12299 + jsoff_t pos = 0; 12300 + int match_count = 0; 12301 + 12302 + while (pos < str_len) { 12303 + int ret = regexec(&regex, str_buf + pos, 1, &match, 0); 12304 + if (ret != 0 || match.rm_so < 0) break; 12305 + 12306 + jsoff_t match_start = pos + (jsoff_t)match.rm_so; 12307 + jsoff_t match_len = (jsoff_t)(match.rm_eo - match.rm_so); 12308 + 12309 + jsval_t match_str = js_mkstr(js, str_ptr + match_start, match_len); 12310 + if (is_err(match_str)) { 12311 + regfree(&regex); 12312 + return match_str; 12313 + } 12314 + 12315 + js_arr_push(js, result_arr, match_str); 12316 + match_count++; 12317 + 12318 + if (!global_flag) break; 12319 + 12320 + if (match.rm_eo == 0) { 12321 + pos++; 12322 + } else { 12323 + pos += (jsoff_t)match.rm_eo; 12324 + } 12325 + } 12326 + 12327 + regfree(&regex); 12328 + 12329 + if (match_count == 0) return js_mknull(); 12330 + return result_arr; 12331 + } 12332 + 12333 + static jsval_t builtin_string_match(struct js *js, jsval_t *args, int nargs) { 12334 + jsval_t str = js->this_val; 12335 + if (vtype(str) != T_STR) return js_mkerr(js, "match called on non-string"); 12336 + if (nargs < 1) return js_mknull(); 12337 + 12338 + jsval_t pattern = args[0]; 12339 + char pattern_buf[256]; 12340 + jsoff_t pattern_len = 0; 12341 + bool global_flag = false; 12342 + bool ignore_case = false; 12343 + 12344 + if (vtype(pattern) == T_OBJ) goto parse_regex_obj; 12345 + if (vtype(pattern) == T_STR) goto parse_string; 12346 + return js_mknull(); 12347 + 12348 + parse_regex_obj:; 12349 + jsoff_t source_off = lkp(js, pattern, "source", 6); 12350 + if (source_off == 0) return js_mknull(); 12351 + 12352 + jsval_t source_val = resolveprop(js, mkval(T_PROP, source_off)); 12353 + if (vtype(source_val) != T_STR) return js_mknull(); 12354 + 12355 + jsoff_t plen, poff = vstr(js, source_val, &plen); 12356 + pattern_len = plen < sizeof(pattern_buf) - 1 ? plen : sizeof(pattern_buf) - 1; 12357 + memcpy(pattern_buf, &js->mem[poff], pattern_len); 12358 + pattern_buf[pattern_len] = '\0'; 12359 + 12360 + jsoff_t flags_off = lkp(js, pattern, "flags", 5); 12361 + if (flags_off == 0) goto do_match; 12362 + 12363 + jsval_t flags_val = resolveprop(js, mkval(T_PROP, flags_off)); 12364 + if (vtype(flags_val) != T_STR) goto do_match; 12365 + 12366 + jsoff_t flen, foff = vstr(js, flags_val, &flen); 12367 + const char *flags_str = (char *) &js->mem[foff]; 12368 + for (jsoff_t i = 0; i < flen; i++) { 12369 + if (flags_str[i] == 'g') global_flag = true; 12370 + if (flags_str[i] == 'i') ignore_case = true; 12371 + } 12372 + goto do_match; 12373 + 12374 + parse_string:; 12375 + jsoff_t slen, soff = vstr(js, pattern, &slen); 12376 + pattern_len = slen < sizeof(pattern_buf) - 1 ? slen : sizeof(pattern_buf) - 1; 12377 + memcpy(pattern_buf, &js->mem[soff], pattern_len); 12378 + pattern_buf[pattern_len] = '\0'; 12379 + 12380 + do_match:; 12381 + jsoff_t str_len, str_off = vstr(js, str, &str_len); 12382 + const char *str_ptr = (char *) &js->mem[str_off]; 12383 + 12384 + char *str_buf = (char *)ANT_GC_MALLOC(str_len + 1); 12385 + if (!str_buf) return js_mkerr(js, "oom"); 12386 + memcpy(str_buf, str_ptr, str_len); 12387 + str_buf[str_len] = '\0'; 12388 + 12389 + jsval_t result = do_regex_match(js, pattern_buf, str_ptr, str_len, str_buf, global_flag, ignore_case); 12390 + if (vtype(result) != T_NULL) goto cleanup; 12391 + 12392 + char posix_pattern[512]; 12393 + js_regex_to_posix(pattern_buf, pattern_len, posix_pattern, sizeof(posix_pattern)); 12394 + if (strcmp(pattern_buf, posix_pattern) == 0) goto cleanup; 12395 + 12396 + result = do_regex_match(js, posix_pattern, str_ptr, str_len, str_buf, global_flag, ignore_case); 12397 + 12398 + cleanup: 12399 + ANT_GC_FREE(str_buf); 12400 + return result; 12251 12401 } 12252 12402 12253 12403 static jsval_t builtin_string_template(struct js *js, jsval_t *args, int nargs) { ··· 14861 15011 setprop(js, string_proto, js_mkstr(js, "endsWith", 8), js_mkfun(builtin_string_endsWith)); 14862 15012 setprop(js, string_proto, js_mkstr(js, "replace", 7), js_mkfun(builtin_string_replace)); 14863 15013 setprop(js, string_proto, js_mkstr(js, "replaceAll", 10), js_mkfun(builtin_string_replaceAll)); 15014 + setprop(js, string_proto, js_mkstr(js, "match", 5), js_mkfun(builtin_string_match)); 14864 15015 setprop(js, string_proto, js_mkstr(js, "template", 8), js_mkfun(builtin_string_template)); 14865 15016 setprop(js, string_proto, js_mkstr(js, "charCodeAt", 10), js_mkfun(builtin_string_charCodeAt)); 14866 15017 setprop(js, string_proto, js_mkstr(js, "toLowerCase", 11), js_mkfun(builtin_string_toLowerCase));