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.

add support for RegExp-like objects in RegExp constructor

+71 -104
+71 -104
src/ant.c
··· 15081 15081 } 15082 15082 15083 15083 static jsval_t builtin_RegExp(struct js *js, jsval_t *args, int nargs) { 15084 - jsval_t passthrough = should_regexp_passthrough(js, args, nargs); 15085 - if (is_err(passthrough)) return passthrough; 15086 - if (js_truthy(js, passthrough)) return args[0]; 15084 + bool pattern_is_regexp = false; 15085 + if (nargs > 0) { 15086 + jsval_t is_re = is_regexp_like(js, args[0]); 15087 + if (is_err(is_re)) return is_re; 15088 + pattern_is_regexp = js_truthy(js, is_re); 15089 + } 15090 + 15091 + if (vtype(js->new_target) == T_UNDEF && nargs > 0 && pattern_is_regexp) { 15092 + if (nargs < 2 || vtype(args[1]) == T_UNDEF) { 15093 + jsval_t ctor = js_getprop_fallback(js, args[0], "constructor"); 15094 + if (is_err(ctor)) return ctor; 15095 + jsval_t regexp_ctor = js_get(js, js_glob(js), "RegExp"); 15096 + if (is_err(regexp_ctor)) return regexp_ctor; 15097 + if (same_ctor_identity(js, ctor, regexp_ctor)) return args[0]; 15098 + } 15099 + } 15087 15100 15088 15101 jsval_t regexp_obj = js->this_val; 15089 15102 bool use_this = (vtype(js->new_target) != T_UNDEF && vtype(regexp_obj) == T_OBJ); ··· 15102 15115 } 15103 15116 15104 15117 jsval_t pattern = js_mkstr(js, "", 0); 15105 - if (nargs > 0) { 15106 - if (vtype(args[0]) == T_STR) pattern = args[0]; 15107 - else { 15108 - const char *str = js_str(js, args[0]); 15109 - pattern = js_mkstr(js, str, strlen(str)); 15110 - }} 15111 - 15112 15118 jsval_t flags = js_mkstr(js, "", 0); 15113 - if (nargs > 1 && vtype(args[1]) == T_STR) flags = args[1]; 15119 + if (nargs > 0) { 15120 + if (pattern_is_regexp) { 15121 + jsval_t src = js_getprop_fallback(js, args[0], "source"); 15122 + if (is_err(src)) return src; 15123 + pattern = js_tostring_val(js, src); 15124 + if (is_err(pattern)) return pattern; 15125 + if (nargs >= 2 && vtype(args[1]) != T_UNDEF) { 15126 + flags = js_tostring_val(js, args[1]); 15127 + } else { 15128 + jsval_t fl = js_getprop_fallback(js, args[0], "flags"); 15129 + if (is_err(fl)) return fl; 15130 + flags = js_tostring_val(js, fl); 15131 + } 15132 + if (is_err(flags)) return flags; 15133 + } else if (vtype(args[0]) == T_STR) { 15134 + pattern = args[0]; 15135 + if (nargs > 1 && vtype(args[1]) == T_STR) flags = args[1]; 15136 + } else if (vtype(args[0]) != T_UNDEF) { 15137 + jsval_t s = js_tostring_val(js, args[0]); 15138 + if (is_err(s)) return s; 15139 + pattern = s; 15140 + if (nargs > 1 && vtype(args[1]) == T_STR) flags = args[1]; 15141 + } 15142 + } 15114 15143 15115 15144 jsval_t source_key = js_mkstr(js, "source", 6); 15116 15145 js_setprop(js, regexp_obj, source_key, pattern); ··· 15140 15169 return regexp_obj; 15141 15170 } 15142 15171 15143 - static jsval_t builtin_regexp_test(struct js *js, jsval_t *args, int nargs) { 15144 - jsval_t regexp = js->this_val; 15145 - if (vtype(regexp) != T_OBJ) return js_mkerr(js, "test called on non-regexp"); 15146 - if (nargs < 1) return mkval(T_BOOL, 0); 15147 - 15148 - jsval_t str_arg = args[0]; 15149 - if (vtype(str_arg) != T_STR) return mkval(T_BOOL, 0); 15150 - 15151 - jsoff_t source_off = lkp(js, regexp, "source", 6); 15152 - if (source_off == 0) return mkval(T_BOOL, 0); 15153 - jsval_t source_val = resolveprop(js, mkval(T_PROP, source_off)); 15154 - if (vtype(source_val) != T_STR) return mkval(T_BOOL, 0); 15155 - 15156 - jsoff_t plen, poff = vstr(js, source_val, &plen); 15157 - const char *pattern_ptr = (char *) &js->mem[poff]; 15158 - 15159 - bool ignore_case = false, multiline = false; 15160 - jsoff_t flags_off = lkp(js, regexp, "flags", 5); 15161 - if (flags_off != 0) { 15162 - jsval_t flags_val = resolveprop(js, mkval(T_PROP, flags_off)); 15163 - if (vtype(flags_val) == T_STR) { 15164 - jsoff_t flen, foff = vstr(js, flags_val, &flen); 15165 - const char *flags_str = (char *) &js->mem[foff]; 15166 - for (jsoff_t i = 0; i < flen; i++) { 15167 - if (flags_str[i] == 'i') ignore_case = true; 15168 - if (flags_str[i] == 'm') multiline = true; 15169 - } 15170 - } 15171 - } 15172 - 15173 - jsoff_t str_len, str_off = vstr(js, str_arg, &str_len); 15174 - const char *str_ptr = (char *) &js->mem[str_off]; 15175 - 15176 - char pcre2_pattern[512]; 15177 - size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, plen, pcre2_pattern, sizeof(pcre2_pattern)); 15178 - 15179 - uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF; 15180 - if (ignore_case) options |= PCRE2_CASELESS; 15181 - if (multiline) options |= PCRE2_MULTILINE; 15182 - 15183 - int errcode; 15184 - PCRE2_SIZE erroffset; 15185 - pcre2_code *re = pcre2_compile((PCRE2_SPTR)pcre2_pattern, pcre2_len, options, &errcode, &erroffset, NULL); 15186 - if (re == NULL) return mkval(T_BOOL, 0); 15187 - 15188 - pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); 15189 - int rc = pcre2_match(re, (PCRE2_SPTR)str_ptr, str_len, 0, 0, match_data, NULL); 15190 - 15191 - pcre2_match_data_free(match_data); 15192 - pcre2_code_free(re); 15193 - 15194 - return mkval(T_BOOL, rc >= 0 ? 1 : 0); 15195 - } 15196 - 15197 15172 static jsval_t builtin_regexp_exec(struct js *js, jsval_t *args, int nargs) { 15198 15173 jsval_t regexp = js->this_val; 15199 15174 if (vtype(regexp) != T_OBJ) return js_mkerr(js, "exec called on non-regexp"); ··· 15294 15269 } 15295 15270 15296 15271 static jsval_t builtin_regexp_toString(struct js *js, jsval_t *args, int nargs) { 15297 - (void)args; (void)nargs; 15298 15272 jsval_t regexp = js->this_val; 15299 - if (vtype(regexp) != T_OBJ) return js_mkerr(js, "toString called on non-regexp"); 15273 + if (!is_object_type(regexp)) 15274 + return js_mkerr_typed(js, JS_ERR_TYPE, "toString called on non-object"); 15300 15275 15301 - jsoff_t source_off = lkp(js, regexp, "source", 6); 15302 - if (source_off == 0) return js_mkstr(js, "/undefined/", 11); 15303 - jsval_t source_val = resolveprop(js, mkval(T_PROP, source_off)); 15304 - if (vtype(source_val) != T_STR) return js_mkstr(js, "/undefined/", 11); 15276 + jsval_t source_val = js_getprop_fallback(js, regexp, "source"); 15277 + if (is_err(source_val)) return source_val; 15278 + jsval_t source_str = js_tostring_val(js, source_val); 15279 + if (is_err(source_str)) return source_str; 15305 15280 15306 - jsoff_t src_len; 15307 - jsoff_t src_off = vstr(js, source_val, &src_len); 15308 - const char *src_ptr = (const char *)(js->mem + src_off); 15281 + jsval_t flags_val = js_getprop_fallback(js, regexp, "flags"); 15282 + if (is_err(flags_val)) return flags_val; 15283 + jsval_t flags_str = js_tostring_val(js, flags_val); 15284 + if (is_err(flags_str)) return flags_str; 15309 15285 15310 - char flags[8] = {0}; 15311 - int fi = 0; 15312 - jsoff_t prop_off; 15313 - 15314 - prop_off = lkp(js, regexp, "global", 6); 15315 - if (prop_off && vdata(resolveprop(js, mkval(T_PROP, prop_off)))) flags[fi++] = 'g'; 15316 - 15317 - prop_off = lkp(js, regexp, "ignoreCase", 10); 15318 - if (prop_off && vdata(resolveprop(js, mkval(T_PROP, prop_off)))) flags[fi++] = 'i'; 15319 - 15320 - prop_off = lkp(js, regexp, "multiline", 9); 15321 - if (prop_off && vdata(resolveprop(js, mkval(T_PROP, prop_off)))) flags[fi++] = 'm'; 15322 - 15323 - prop_off = lkp(js, regexp, "dotAll", 6); 15324 - if (prop_off && vdata(resolveprop(js, mkval(T_PROP, prop_off)))) flags[fi++] = 's'; 15325 - 15326 - prop_off = lkp(js, regexp, "sticky", 6); 15327 - if (prop_off && vdata(resolveprop(js, mkval(T_PROP, prop_off)))) flags[fi++] = 'y'; 15286 + jsoff_t src_len, src_off = vstr(js, source_str, &src_len); 15287 + jsoff_t fl_len, fl_off = vstr(js, flags_str, &fl_len); 15328 15288 15329 - size_t result_len = 1 + src_len + 1 + fi; 15330 - char *result = (char *)malloc(result_len + 1); 15331 - if (!result) return js_mkerr(js, "out of memory"); 15332 - 15333 - result[0] = '/'; 15334 - memcpy(result + 1, src_ptr, src_len); 15335 - result[1 + src_len] = '/'; 15336 - memcpy(result + 2 + src_len, flags, fi); 15337 - result[result_len] = '\0'; 15289 + char static_buf[128]; 15290 + string_builder_t sb; 15291 + string_builder_init(&sb, static_buf, sizeof(static_buf)); 15292 + string_builder_append(&sb, "/", 1); 15293 + string_builder_append(&sb, (const char *)&js->mem[src_off], src_len); 15294 + string_builder_append(&sb, "/", 1); 15295 + string_builder_append(&sb, (const char *)&js->mem[fl_off], fl_len); 15338 15296 15339 - jsval_t ret = js_mkstr(js, result, result_len); 15340 - free(result); 15341 - return ret; 15297 + return string_builder_finalize(js, &sb); 15342 15298 } 15343 15299 15344 15300 static jsval_t maybe_call_symbol_method( ··· 15452 15408 js->this_val = saved; 15453 15409 15454 15410 return result; 15411 + } 15412 + 15413 + static jsval_t builtin_regexp_test(struct js *js, jsval_t *args, int nargs) { 15414 + jsval_t regexp = js->this_val; 15415 + if (!is_object_type(regexp)) 15416 + return js_mkerr_typed(js, JS_ERR_TYPE, "test called on non-object"); 15417 + jsval_t str_arg = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "undefined", 9); 15418 + if (is_err(str_arg)) return str_arg; 15419 + jsval_t result = regexp_exec_abstract(js, regexp, str_arg); 15420 + if (is_err(result)) return result; 15421 + return mkval(T_BOOL, vtype(result) != T_NULL ? 1 : 0); 15455 15422 } 15456 15423 15457 15424 jsval_t builtin_regexp_symbol_split(struct js *js, jsval_t *args, int nargs) {