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 matchAll

+126
+3
include/common.h
··· 81 81 SLOT_RESPONSE_HEADERS, 82 82 SLOT_RESPONSE_BODY_STREAM, 83 83 SLOT_PIPE_ABORT_LISTENER, 84 + SLOT_MATCHALL_RX, 85 + SLOT_MATCHALL_STR, 86 + SLOT_MATCHALL_DONE, 84 87 SLOT_MAX = 255 85 88 } internal_slot_t; 86 89
+1
include/modules/symbol.h
··· 43 43 X(replace, "Symbol.replace") \ 44 44 X(search, "Symbol.search") \ 45 45 X(split, "Symbol.split") \ 46 + X(matchAll, "Symbol.matchAll") \ 46 47 X(isConcatSpreadable, "Symbol.isConcatSpreadable") \ 47 48 X(observable, "Symbol.observable") \ 48 49 X(toPrimitive, "Symbol.toPrimitive") \
+122
src/modules/regex.c
··· 27 27 } regex_cache_entry_t; 28 28 29 29 static regex_cache_entry_t *regex_cache = NULL; 30 + static ant_value_t regexp_matchall_iter_proto_val = 0; 31 + 30 32 static size_t regex_cache_count = 0; 31 33 static size_t regex_cache_cap = 0; 32 34 ··· 1037 1039 } 1038 1040 } 1039 1041 1042 + 1043 + static ant_value_t regexp_matchall_next(ant_t *js, ant_value_t *args, int nargs) { 1044 + ant_value_t iter = js->this_val; 1045 + ant_value_t rx = js_get_slot(iter, SLOT_MATCHALL_RX); 1046 + ant_value_t str = js_get_slot(iter, SLOT_MATCHALL_STR); 1047 + ant_value_t done_val = js_get_slot(iter, SLOT_MATCHALL_DONE); 1048 + 1049 + if (js_truthy(js, done_val)) 1050 + return js_iter_result(js, false, js_mkundef()); 1051 + 1052 + ant_value_t result = regexp_exec_abstract(js, rx, str); 1053 + if (is_err(result)) return result; 1054 + 1055 + if (vtype(result) == T_NULL) { 1056 + js_set_slot(iter, SLOT_MATCHALL_DONE, js_true); 1057 + return js_iter_result(js, false, js_mkundef()); 1058 + } 1059 + 1060 + ant_value_t global_val = js_getprop_fallback(js, rx, "global"); 1061 + if (js_truthy(js, global_val)) { 1062 + ant_value_t match_str = js_tostring_val(js, js_arr_get(js, result, 0)); 1063 + if (is_err(match_str)) return match_str; 1064 + ant_offset_t mlen; 1065 + vstr(js, match_str, &mlen); 1066 + if (mlen == 0) { 1067 + ant_value_t li_val = js_getprop_fallback(js, rx, "lastIndex"); 1068 + double li = vtype(li_val) == T_NUM ? tod(li_val) : 0; 1069 + js_setprop(js, rx, js_mkstr(js, "lastIndex", 9), tov(li + 1)); 1070 + } 1071 + } else js_set_slot(iter, SLOT_MATCHALL_DONE, js_true); 1072 + 1073 + return js_iter_result(js, true, result); 1074 + } 1075 + 1076 + static ant_value_t builtin_regexp_symbol_matchAll(ant_t *js, ant_value_t *args, int nargs) { 1077 + ant_value_t rx = js->this_val; 1078 + if (!is_object_type(rx)) 1079 + return js_mkerr_typed(js, JS_ERR_TYPE, "RegExp.prototype[@@matchAll] called on non-object"); 1080 + 1081 + ant_value_t str = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "undefined", 9); 1082 + if (is_err(str)) return str; 1083 + 1084 + ant_value_t flags_val = js_getprop_fallback(js, rx, "flags"); 1085 + if (is_err(flags_val)) return flags_val; 1086 + ant_value_t flags_str = js_tostring_val(js, flags_val); 1087 + if (is_err(flags_str)) return flags_str; 1088 + 1089 + ant_value_t source_val = js_getprop_fallback(js, rx, "source"); 1090 + if (is_err(source_val)) return source_val; 1091 + 1092 + ant_value_t ctor_args[2] = { source_val, flags_str }; 1093 + ant_value_t regexp_ctor = js_get(js, js_glob(js), "RegExp"); 1094 + ant_value_t new_rx = sv_vm_call(js->vm, js, regexp_ctor, js_mkundef(), ctor_args, 2, NULL, true); 1095 + if (is_err(new_rx)) return new_rx; 1096 + 1097 + ant_value_t li_val = js_getprop_fallback(js, rx, "lastIndex"); 1098 + js_setprop(js, new_rx, js_mkstr(js, "lastIndex", 9), li_val); 1099 + 1100 + ant_value_t iter = js_mkobj(js); 1101 + js_set_slot(iter, SLOT_MATCHALL_RX, new_rx); 1102 + js_set_slot(iter, SLOT_MATCHALL_STR, str); 1103 + js_set_slot(iter, SLOT_MATCHALL_DONE, js_false); 1104 + 1105 + js_set_proto_init(iter, regexp_matchall_iter_proto_val); 1106 + 1107 + return iter; 1108 + } 1109 + 1110 + static ant_value_t builtin_string_matchAll(ant_t *js, ant_value_t *args, int nargs) { 1111 + ant_value_t this_unwrapped = unwrap_primitive(js, js->this_val); 1112 + ant_value_t str = js_tostring_val(js, this_unwrapped); 1113 + if (is_err(str)) return str; 1114 + if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "matchAll requires at least 1 argument"); 1115 + 1116 + if (is_object_type(args[0])) { 1117 + ant_value_t is_re = is_regexp_like(js, args[0]); 1118 + if (js_truthy(js, is_re)) { 1119 + ant_value_t flags_val = js_getprop_fallback(js, args[0], "flags"); 1120 + if (is_err(flags_val)) return flags_val; 1121 + 1122 + ant_value_t flags_str = js_tostring_val(js, flags_val); 1123 + ant_offset_t flen, foff = vstr(js, flags_str, &flen); 1124 + 1125 + const char *fp = (const char *)(uintptr_t)(foff); 1126 + bool has_g = false; 1127 + for (ant_offset_t i = 0; i < flen; i++) if (fp[i] == 'g') has_g = true; 1128 + if (!has_g) return js_mkerr_typed(js, JS_ERR_TYPE, "String.prototype.matchAll called with a non-global RegExp"); 1129 + } 1130 + 1131 + bool called = false; 1132 + ant_value_t call_args[1] = { str }; 1133 + ant_value_t dispatched = maybe_call_symbol_method( 1134 + js, args[0], get_matchAll_sym(), args[0], call_args, 1, &called 1135 + ); 1136 + 1137 + if (is_err(dispatched)) return dispatched; 1138 + if (called) return dispatched; 1139 + } 1140 + 1141 + ant_value_t pattern_str = js_tostring_val(js, args[0]); 1142 + if (is_err(pattern_str)) return pattern_str; 1143 + 1144 + ant_value_t ctor_args[2] = { pattern_str, js_mkstr(js, "g", 1) }; 1145 + ant_value_t regexp_ctor = js_get(js, js_glob(js), "RegExp"); 1146 + ant_value_t rx = sv_vm_call(js->vm, js, regexp_ctor, js_mkundef(), ctor_args, 2, NULL, true); 1147 + if (is_err(rx)) return rx; 1148 + 1149 + ant_value_t ma_args[1] = { str }; 1150 + js->this_val = rx; 1151 + 1152 + return builtin_regexp_symbol_matchAll(js, ma_args, 1); 1153 + } 1154 + 1040 1155 static ant_value_t builtin_regexp_symbol_replace(ant_t *js, ant_value_t *args, int nargs) { 1041 1156 ant_value_t rx = js->this_val; 1042 1157 if (!is_object_type(rx)) ··· 1758 1873 1759 1874 js_set_sym(js, regexp_proto, get_split_sym(), js_mkfun(builtin_regexp_symbol_split)); 1760 1875 js_set_sym(js, regexp_proto, get_match_sym(), js_mkfun(builtin_regexp_symbol_match)); 1876 + js_set_sym(js, regexp_proto, get_matchAll_sym(), js_mkfun(builtin_regexp_symbol_matchAll)); 1877 + 1878 + regexp_matchall_iter_proto_val = js_mkobj(js); 1879 + js_set_proto_init(regexp_matchall_iter_proto_val, js->sym.iterator_proto); 1880 + defmethod(js, regexp_matchall_iter_proto_val, "next", 4, js_mkfun(regexp_matchall_next)); 1881 + js_set_sym(js, regexp_matchall_iter_proto_val, get_iterator_sym(), js_mkfun(sym_this_cb)); 1761 1882 js_set_sym(js, regexp_proto, get_replace_sym(), js_mkfun(builtin_regexp_symbol_replace)); 1762 1883 js_set_sym(js, regexp_proto, get_search_sym(), js_mkfun(builtin_regexp_symbol_search)); 1763 1884 js_set_sym(js, regexp_proto, get_toStringTag_sym(), js_mkstr(js, "RegExp", 6)); ··· 1792 1913 1793 1914 defmethod(js, string_proto, "search", 6, js_mkfun(builtin_string_search)); 1794 1915 defmethod(js, string_proto, "match", 5, js_mkfun(builtin_string_match)); 1916 + defmethod(js, string_proto, "matchAll", 8, js_mkfun(builtin_string_matchAll)); 1795 1917 defmethod(js, string_proto, "replace", 7, js_mkfun(builtin_string_replace)); 1796 1918 defmethod(js, string_proto, "replaceAll", 10, js_mkfun(builtin_string_replaceAll)); 1797 1919 }