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 regexp index group support

+175 -13
examples/npm/djot/ant.lockb

This is a binary file and will not be displayed.

+9
examples/npm/djot/index.ts
··· 1 + import djot from '@djot/djot'; 2 + 3 + const parsed = djot.parse('hi _there_'); 4 + const ast = djot.renderAST(parsed); 5 + const html = djot.renderHTML(parsed); 6 + 7 + console.log(parsed); 8 + console.log(ast); 9 + console.log(html);
+12
examples/npm/djot/package.json
··· 1 + { 2 + "name": "djot", 3 + "type": "module", 4 + "main": "index.ts", 5 + "scripts": { 6 + "start": "ant index.ts" 7 + }, 8 + "dependencies": { 9 + "@djot/djot": "^0.3.2" 10 + }, 11 + "devDependencies": {} 12 + }
+54 -13
src/ant.c
··· 1211 1211 return out; 1212 1212 } 1213 1213 1214 + static inline char *js_inspect_builder_write_ptr(js_inspect_builder_t *builder, size_t *avail) { 1215 + if (!builder->buf || builder->len == 0) { 1216 + if (avail) *avail = 0; 1217 + return NULL; 1218 + } 1219 + 1220 + size_t write_index = builder->n < builder->len ? builder->n : builder->len - 1; 1221 + if (avail) *avail = builder->len - write_index; 1222 + return builder->buf + write_index; 1223 + } 1224 + 1214 1225 static bool js_inspect_builder_reserve(js_inspect_builder_t *builder, size_t extra) { 1215 1226 if (!builder->growable) return true; 1216 1227 ··· 1238 1249 return true; 1239 1250 } 1240 1251 1241 - builder->n += cpy(builder->buf + builder->n, REMAIN(builder->n, builder->len), src, srclen); 1252 + size_t avail = 0; 1253 + char *dst = js_inspect_builder_write_ptr(builder, &avail); 1254 + builder->n += cpy(dst, avail, src, srclen); 1255 + 1242 1256 return true; 1243 1257 } 1244 1258 ··· 1256 1270 return true; 1257 1271 } 1258 1272 1259 - int needed = vsnprintf(builder->buf + builder->n, REMAIN(builder->n, builder->len), fmt, args); 1273 + size_t avail = 0; 1274 + char *dst = js_inspect_builder_write_ptr(builder, &avail); 1275 + int needed = vsnprintf(dst, avail, fmt, args); 1276 + 1260 1277 if (needed < 0) return false; 1261 1278 builder->n += (size_t)needed; 1262 1279 ··· 1279 1296 1280 1297 static bool js_inspect_append_tostr(js_inspect_builder_t *builder, ant_value_t value) { 1281 1298 if (!builder->growable) { 1282 - builder->n += tostr(builder->js, value, builder->buf + builder->n, REMAIN(builder->n, builder->len)); 1299 + size_t avail = 0; 1300 + char *dst = js_inspect_builder_write_ptr(builder, &avail); 1301 + builder->n += tostr(builder->js, value, dst, avail); 1283 1302 return true; 1284 1303 } 1285 1304 ··· 1308 1327 1309 1328 static bool js_inspect_append_key_interned(js_inspect_builder_t *builder, const char *key, size_t klen) { 1310 1329 if (!builder->growable) { 1311 - builder->n += strkey_interned(builder->js, key, klen, builder->buf + builder->n, REMAIN(builder->n, builder->len)); 1330 + size_t avail = 0; 1331 + char *dst = js_inspect_builder_write_ptr(builder, &avail); 1332 + builder->n += strkey_interned(builder->js, key, klen, dst, avail); 1312 1333 return true; 1313 1334 } 1314 1335 ··· 2190 2211 ant_offset_t slen, off = vstr(js, value, &slen); 2191 2212 const char *str = (const char *)(uintptr_t)off; 2192 2213 size_t n = 0; 2193 - n += cpy(buf + n, REMAIN(n, len), "'", 1); 2194 - for (ant_offset_t i = 0; i < slen && n < len - 1; i++) { 2214 + 2215 + size_t avail = 0; 2216 + char *dst = NULL; 2217 + 2218 + dst = (len == 0) ? NULL : (buf + (n < len ? n : len - 1)); 2219 + avail = (len == 0) ? 0 : (len - (n < len ? n : len - 1)); 2220 + n += cpy(dst, avail, "'", 1); 2221 + 2222 + for (ant_offset_t i = 0; i < slen; i++) { 2195 2223 char c = str[i]; 2196 - if (c == '\n') { n += cpy(buf + n, REMAIN(n, len), "\\n", 2); } 2197 - else if (c == '\r') { n += cpy(buf + n, REMAIN(n, len), "\\r", 2); } 2198 - else if (c == '\t') { n += cpy(buf + n, REMAIN(n, len), "\\t", 2); } 2199 - else if (c == '\\') { n += cpy(buf + n, REMAIN(n, len), "\\\\", 2); } 2200 - else if (c == '\'') { n += cpy(buf + n, REMAIN(n, len), "\\'", 2); } 2201 - else { if (n < len) buf[n++] = c; } 2224 + dst = (len == 0) ? NULL : (buf + (n < len ? n : len - 1)); 2225 + avail = (len == 0) ? 0 : (len - (n < len ? n : len - 1)); 2226 + 2227 + if (c == '\n') n += cpy(dst, avail, "\\n", 2); 2228 + else if (c == '\r') n += cpy(dst, avail, "\\r", 2); 2229 + else if (c == '\t') n += cpy(dst, avail, "\\t", 2); 2230 + else if (c == '\\') n += cpy(dst, avail, "\\\\", 2); 2231 + else if (c == '\'') n += cpy(dst, avail, "\\'", 2); 2232 + 2233 + else { 2234 + if (avail > 1) { 2235 + *dst = c; 2236 + dst[1] = '\0'; 2237 + } else if (avail == 1) *dst = '\0'; 2238 + n++; 2239 + } 2202 2240 } 2203 - n += cpy(buf + n, REMAIN(n, len), "'", 1); 2241 + 2242 + dst = (len == 0) ? NULL : (buf + (n < len ? n : len - 1)); 2243 + avail = (len == 0) ? 0 : (len - (n < len ? n : len - 1)); 2244 + n += cpy(dst, avail, "'", 1); 2204 2245 2205 2246 return n; 2206 2247 }
+71
src/modules/regex.c
··· 781 781 return groups; 782 782 } 783 783 784 + static ant_value_t regexp_build_indices_pair(ant_t *js, PCRE2_SIZE start, PCRE2_SIZE end) { 785 + if (start == PCRE2_UNSET) return js_mkundef(); 786 + 787 + ant_value_t pair = js_mkarr(js); 788 + if (is_err(pair)) return pair; 789 + js_arr_push(js, pair, tov((double)start)); 790 + js_arr_push(js, pair, tov((double)end)); 791 + 792 + return pair; 793 + } 794 + 795 + static ant_value_t regexp_build_indices_groups( 796 + ant_t *js, 797 + ant_value_t groups_meta, 798 + ant_value_t indices_arr 799 + ) { 800 + ant_value_t groups = js_mkobj(js); 801 + if (is_err(groups)) return groups; 802 + js_set_proto_init(groups, js_mknull()); 803 + 804 + for (ant_offset_t i = 0; ; i += 2) { 805 + ant_value_t name = js_arr_get(js, groups_meta, i); 806 + if (vtype(name) == T_UNDEF) break; 807 + 808 + ant_value_t index_val = js_arr_get(js, groups_meta, i + 1); 809 + ant_offset_t index = (vtype(index_val) == T_NUM) ? (ant_offset_t)tod(index_val) : 0; 810 + char idxstr[16]; 811 + (void)uint_to_str(idxstr, sizeof(idxstr), (uint64_t)index); 812 + 813 + ant_value_t value = js_getprop_fallback(js, indices_arr, idxstr); 814 + ant_offset_t name_len, name_off = vstr(js, name, &name_len); 815 + ant_value_t status = setprop_cstr(js, groups, (const char *)(uintptr_t)name_off, (size_t)name_len, value); 816 + if (is_err(status)) return status; 817 + } 818 + 819 + return groups; 820 + } 821 + 822 + static ant_value_t regexp_build_indices_result( 823 + ant_t *js, 824 + ant_value_t regexp, 825 + PCRE2_SIZE *ovector, 826 + uint32_t ovcount 827 + ) { 828 + ant_value_t indices_arr = js_mkarr(js); 829 + if (is_err(indices_arr)) return indices_arr; 830 + 831 + for (uint32_t i = 0; i < ovcount && i < 32; i++) { 832 + ant_value_t pair = regexp_build_indices_pair(js, ovector[2*i], ovector[2*i+1]); 833 + if (is_err(pair)) return pair; 834 + js_arr_push(js, indices_arr, pair); 835 + } 836 + 837 + ant_value_t groups_meta = js_get_slot(regexp, SLOT_REGEXP_NAMED_GROUPS); 838 + if (is_object_type(groups_meta)) { 839 + ant_value_t groups = regexp_build_indices_groups(js, groups_meta, indices_arr); 840 + if (is_err(groups)) return groups; 841 + if (is_err(setprop_cstr(js, indices_arr, "groups", 6, groups))) return js_mkerr(js, "oom"); 842 + } else if (is_err(setprop_cstr(js, indices_arr, "groups", 6, js_mkundef()))) return js_mkerr(js, "oom"); 843 + 844 + return indices_arr; 845 + } 846 + 784 847 static ant_value_t regexp_exec_internal(ant_t *js, ant_value_t regexp, ant_value_t str_arg, bool truthy_only) { 785 848 ant_offset_t str_len, str_off = vstr(js, str_arg, &str_len); 786 849 const char *str_ptr = (char *)(uintptr_t)(str_off); 787 850 uint8_t flags_mask = regexp_flags_mask(js, regexp); 851 + 788 852 bool global_flag = (flags_mask & REGEXP_FLAG_GLOBAL) != 0; 853 + bool has_indices = (flags_mask & REGEXP_FLAG_HAS_INDICES) != 0; 789 854 bool sticky_flag = (flags_mask & REGEXP_FLAG_STICKY) != 0; 790 855 791 856 // TODO: reduce nesting ··· 857 922 js_set_slot(result_arr, SLOT_REGEXP_GROUPS_CACHE, js_mkundef()); 858 923 js_set_getter_desc(js, js_as_obj(result_arr), "groups", 6, js_mkfun(builtin_regexp_groups_getter), JS_DESC_E | JS_DESC_C); 859 924 } else if (is_err(setprop_cstr(js, result_arr, "groups", 6, js_mkundef()))) return js_mkerr(js, "oom"); 925 + 926 + if (has_indices) { 927 + ant_value_t indices = regexp_build_indices_result(js, regexp, ovector, ovcount); 928 + if (is_err(indices)) return indices; 929 + if (is_err(setprop_cstr(js, result_arr, "indices", 7, indices))) return js_mkerr(js, "oom"); 930 + } 860 931 861 932 return result_arr; 862 933 }
+15
tests/test_promise_inspect_long.cjs
··· 1 + const { inspect } = require('node:util'); 2 + 3 + function assert(cond, msg) { 4 + if (!cond) throw new Error(msg); 5 + } 6 + 7 + const longValue = '1234567890123456789012345678901234567890123456789012345678901234567890'; 8 + const promise = Promise.resolve({ a: longValue, b: 2 }); 9 + const rendered = inspect(promise); 10 + 11 + assert(rendered.includes(`a: '${longValue}'`), `expected full promise payload in inspect output, got: ${rendered}`); 12 + assert(rendered.includes('b: 2'), `expected secondary property in inspect output, got: ${rendered}`); 13 + assert(rendered.includes('Symbol(async_id):'), `expected promise metadata in inspect output, got: ${rendered}`); 14 + 15 + console.log('PASS');
+14
tests/test_regexp_exec_fast_paths.cjs
··· 105 105 'RegExp.prototype.flags should read observable flag properties in spec order' 106 106 ); 107 107 108 + const indicesMatch = /(?<word>a)(b)?/d.exec('ab'); 109 + assert(indicesMatch !== null, 'expected hasIndices regexp to match'); 110 + assert(Array.isArray(indicesMatch.indices), 'match.indices should be an array'); 111 + assert(indicesMatch.indices.length === 3, 'match.indices should include the full match and captures'); 112 + assert(indicesMatch.indices[0][0] === 0 && indicesMatch.indices[0][1] === 2, 'full match indices mismatch'); 113 + assert(indicesMatch.indices[1][0] === 0 && indicesMatch.indices[1][1] === 1, 'first capture indices mismatch'); 114 + assert(indicesMatch.indices[2][0] === 1 && indicesMatch.indices[2][1] === 2, 'second capture indices mismatch'); 115 + assert(indicesMatch.indices.groups.word[0] === 0 && indicesMatch.indices.groups.word[1] === 1, 116 + 'named capture indices mismatch'); 117 + 118 + const unmatchedIndices = /a(b)?/d.exec('a'); 119 + assert(unmatchedIndices !== null, 'expected optional capture regexp to match'); 120 + assert(unmatchedIndices.indices[1] === undefined, 'unmatched capture should expose undefined indices'); 121 + 108 122 console.log('regex exec fast path semantics ok');