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.

at mir/inline-method 421 lines 11 kB view raw
1#include "utils.h" 2#include "messages.h" 3 4#include <oxc.h> 5#include <stdio.h> 6#include <stdbool.h> 7#include <sys/stat.h> 8#include <crprintf.h> 9 10const char *const module_resolve_extensions[] = { 11 ".js", ".mjs", ".cjs", 12 ".ts", ".mts", ".cts", 13 ".json", ".node", NULL 14}; 15 16int hex_digit(char c) { 17 static const int8_t lookup[256] = { 18 ['0']=0, ['1']=1, ['2']=2, ['3']=3, ['4']=4, ['5']=5, ['6']=6, ['7']=7, ['8']=8, ['9']=9, 19 ['a']=10, ['b']=11, ['c']=12, ['d']=13, ['e']=14, ['f']=15, 20 ['A']=10, ['B']=11, ['C']=12, ['D']=13, ['E']=14, ['F']=15, 21 }; 22 int8_t val = lookup[(unsigned char)c]; 23 return val ? val : (c == '0' ? 0 : -1); 24} 25 26char hex_char(int v) { 27 return "0123456789abcdef"[v & 0x0f]; 28} 29 30uint64_t hash_key(const char *key, size_t len) { 31 uint64_t hash = 14695981039346656037ULL; 32 size_t i = 0; 33 34 for (; i + 8 <= len; i += 8) { 35 uint64_t word; 36 memcpy(&word, key + i, 8); 37 hash ^= word; 38 hash *= 1099511628211ULL; 39 } 40 41 for (; i < len; i++) { 42 hash ^= (uint8_t)key[i]; 43 hash *= 1099511628211ULL; 44 } 45 46 return hash; 47} 48 49double half_to_double(uint16_t bits16) { 50 uint32_t sign = ((uint32_t)bits16 & 0x8000u) << 16; 51 uint32_t exp = ((uint32_t)bits16 >> 10) & 0x1fu; 52 uint32_t mant = (uint32_t)bits16 & 0x03ffu; 53 54 uint32_t bits32 = 0; 55 float out = 0.0f; 56 57 if (exp == 0) { 58 if (mant == 0) { 59 bits32 = sign; 60 } else { 61 uint32_t exp32 = 113; 62 while ((mant & 0x0400u) == 0) { 63 mant <<= 1; 64 exp32--; 65 } 66 mant &= 0x03ffu; 67 bits32 = sign | (exp32 << 23) | (mant << 13); 68 }} 69 70 else if (exp == 0x1fu) bits32 = sign | 0x7f800000u | (mant << 13); 71 else bits32 = sign | ((exp + 112u) << 23) | (mant << 13); 72 73 memcpy(&out, &bits32, sizeof(out)); 74 return (double)out; 75} 76 77uint16_t double_to_half(double value) { 78 float input = (float)value; 79 80 uint32_t bits32 = 0; 81 uint32_t sign = 0; 82 uint32_t exp = 0; 83 uint32_t mant = 0; 84 int32_t exp16 = 0; 85 uint16_t out = 0; 86 87 memcpy(&bits32, &input, sizeof(bits32)); 88 sign = (bits32 >> 16) & 0x8000u; 89 exp = (bits32 >> 23) & 0xffu; 90 mant = bits32 & 0x007fffffu; 91 92 if (exp == 0xffu) { 93 if (mant != 0) return (uint16_t)(sign | 0x7e00u); 94 return (uint16_t)(sign | 0x7c00u); 95 } 96 97 exp16 = (int32_t)exp - 127 + 15; 98 if (exp16 >= 0x1f) return (uint16_t)(sign | 0x7c00u); 99 100 if (exp16 <= 0) { 101 if (exp16 < -10) return (uint16_t)sign; 102 mant |= 0x00800000u; 103 uint32_t shift = (uint32_t)(14 - exp16); 104 uint16_t sub = (uint16_t)(mant >> shift); 105 if ((mant >> (shift - 1)) & 1u) sub++; 106 return (uint16_t)(sign | sub); 107 } 108 109 out = (uint16_t)(sign | ((uint32_t)exp16 << 10) | (mant >> 13)); 110 if (mant & 0x00001000u) out++; 111 112 return out; 113} 114 115int is_typescript_file(const char *filename) { 116 if (filename == NULL) return 0; 117 size_t len = strlen(filename); 118 if (len < 3) return 0; 119 120 const char *ext = filename + len; 121 while (ext > filename && *(ext - 1) != '.' && *(ext - 1) != '/') ext--; 122 if (ext == filename || *(ext - 1) != '.') return 0; 123 ext--; 124 125 return (strcmp(ext, ".ts") == 0 || strcmp(ext, ".mts") == 0 || strcmp(ext, ".cts") == 0); 126} 127 128int strip_typescript_inplace( 129 char **buffer, 130 size_t len, 131 const char *filename, 132 int is_module, 133 size_t *out_len, 134 const char **error_detail 135) { 136 if (out_len) *out_len = len; 137 if (error_detail) *error_detail = NULL; 138 if (!is_typescript_file(filename)) return 0; 139 140 if (!buffer || !*buffer) { 141 if (error_detail) *error_detail = "null input/output passed"; 142 return OXC_ERR_NULL_INPUT; 143 } 144 145 char *input = *buffer; 146 char error_buf[256] = {0}; 147 size_t stripped_len = 0; 148 149 int strip_error = OXC_ERR_TRANSFORM_FAILED; 150 char *stripped = OXC_strip_types_owned( 151 input, filename, is_module, 152 &stripped_len, &strip_error, 153 error_buf, sizeof(error_buf) 154 ); 155 156 if (!stripped) { 157 if (error_buf[0] != '\0') { 158 size_t msg_len = strlen(error_buf); 159 size_t copy_len = msg_len > len ? len : msg_len; 160 memcpy(input, error_buf, copy_len); 161 input[copy_len] = '\0'; 162 } else input[0] = '\0'; 163 164 if (error_detail) { 165 *error_detail = input[0] != '\0' ? input : "unknown strip error"; 166 } 167 168 return strip_error; 169 } 170 171 char *next = realloc(input, stripped_len + 1); 172 if (!next) { 173 free(stripped); 174 if (error_detail) *error_detail = "out of memory while resizing strip output buffer"; 175 return OXC_ERR_OUTPUT_TOO_LARGE; 176 } 177 178 memcpy(next, stripped, stripped_len + 1); 179 free(stripped); 180 181 *buffer = next; 182 if (out_len) *out_len = stripped_len; 183 184 return 0; 185} 186 187static bool is_entrypoint_script_extension(const char *ext) { 188 return 189 ext && 190 strcmp(ext, ".json") != 0 && 191 strcmp(ext, ".node") != 0; 192} 193 194static bool has_js_extension(const char *filename) { 195 const char *slash = strrchr(filename, '/'); 196 const char *base = slash ? slash + 1 : filename; 197 const char *dot = strrchr(base, '.'); 198 if (!dot) return false; 199 for (const char *const *ext = module_resolve_extensions; *ext; ext++) { 200 if (!is_entrypoint_script_extension(*ext)) continue; 201 if (strcmp(dot, *ext) == 0) return true; 202 } 203 return false; 204} 205 206char *resolve_js_file(const char *filename) { 207 extern bool esm_is_url(const char *path); 208 if (!filename) return NULL; 209 if (esm_is_url(filename)) return strdup(filename); 210 211 struct stat st; 212 if (stat(filename, &st) == 0) { 213 if (S_ISREG(st.st_mode)) { 214 const char *slash = strrchr(filename, '/'); 215 const char *base = slash ? slash + 1 : filename; 216 const char *dot = strrchr(base, '.'); 217 if (dot && !has_js_extension(filename)) return NULL; 218 return strdup(filename); 219 } 220 if (!S_ISDIR(st.st_mode)) return NULL; 221 222 size_t len = strlen(filename); 223 int has_slash = (len > 0 && filename[len - 1] == '/'); 224 225 for (const char *const *ext = module_resolve_extensions; *ext; ext++) { 226 if (!is_entrypoint_script_extension(*ext)) continue; 227 size_t ext_len = strlen(*ext); 228 char *index_path = try_oom(len + 7 + ext_len + 1); 229 sprintf(index_path, "%s%sindex%s", filename, has_slash ? "" : "/", *ext); 230 if (stat(index_path, &st) == 0 && S_ISREG(st.st_mode)) return index_path; 231 free(index_path); 232 } 233 234 return NULL; 235 } 236 237 if (has_js_extension(filename)) return NULL; 238 size_t base_len = strlen(filename); 239 240 for (const char *const *ext = module_resolve_extensions; *ext; ext++) { 241 if (!is_entrypoint_script_extension(*ext)) continue; 242 size_t ext_len = strlen(*ext); 243 char *test_path = try_oom(base_len + ext_len + 1); 244 245 memcpy(test_path, filename, base_len); 246 memcpy(test_path + base_len, *ext, ext_len + 1); 247 248 if (stat(test_path, &st) == 0 && S_ISREG(st.st_mode)) { 249 return test_path; 250 } free(test_path); 251 } 252 253 return NULL; 254} 255 256char *resolve_typescript_source_fallback(const char *filename) { 257 if (!filename) return NULL; 258 259 const char *mapped_ext = NULL; 260 size_t trim_len = 0; 261 262 size_t len = strlen(filename); 263 if (len > 3 && strcmp(filename + len - 3, ".js") == 0) { 264 mapped_ext = ".ts"; 265 trim_len = 3; 266 } else if (len > 4 && strcmp(filename + len - 4, ".mjs") == 0) { 267 mapped_ext = ".mts"; 268 trim_len = 4; 269 } else if (len > 4 && strcmp(filename + len - 4, ".cjs") == 0) { 270 mapped_ext = ".cts"; 271 trim_len = 4; 272 } else return NULL; 273 274 size_t mapped_len = strlen(mapped_ext); 275 char *mapped = try_oom(len - trim_len + mapped_len + 1); 276 memcpy(mapped, filename, len - trim_len); 277 memcpy(mapped + len - trim_len, mapped_ext, mapped_len + 1); 278 279 return mapped; 280} 281 282typedef struct { 283 const char *repl; size_t repl_len; size_t *ri; 284 const char *matched; size_t matched_len; 285 const char *str; size_t str_len; size_t position; 286 const repl_capture_t *caps; int ncaptures; 287 char **buf; size_t *buf_len; size_t *buf_cap; 288} rt_ctx_t; 289 290static bool rt_append(rt_ctx_t *c, const char *data, size_t dlen) { 291 if (dlen == 0) return true; 292 if (*c->buf_len > SIZE_MAX - dlen - 1) return false; 293 294 if (*c->buf_len + dlen >= *c->buf_cap) { 295 size_t needed = *c->buf_len + dlen + 1; 296 size_t new_cap = needed * 2; 297 if (new_cap < needed) new_cap = needed; 298 299 char *next = realloc(*c->buf, new_cap); 300 if (!next) return false; 301 *c->buf = next; 302 *c->buf_cap = new_cap; 303 } 304 305 memcpy(*c->buf + *c->buf_len, data, dlen); 306 *c->buf_len += dlen; 307 return true; 308} 309 310static bool rt_dollar(rt_ctx_t *c) { 311 *c->ri += 2; 312 return rt_append(c, "$", 1); 313} 314 315static bool rt_match(rt_ctx_t *c) { 316 *c->ri += 2; 317 return rt_append(c, c->matched, c->matched_len); 318} 319 320static bool rt_prefix(rt_ctx_t *c) { 321 *c->ri += 2; 322 return rt_append(c, c->str, c->position); 323} 324 325static bool rt_suffix(rt_ctx_t *c) { 326 size_t after = c->position + c->matched_len; 327 bool ok = true; 328 if (after < c->str_len) 329 ok = rt_append(c, c->str + after, c->str_len - after); 330 *c->ri += 2; 331 return ok; 332} 333 334static bool rt_capture(rt_ctx_t *c) { 335 char nc = c->repl[*c->ri + 1]; 336 int gn = nc - '0'; 337 *c->ri += 2; 338 339 if (*c->ri < c->repl_len && c->repl[*c->ri] >= '0' && c->repl[*c->ri] <= '9') { 340 int two = gn * 10 + (c->repl[*c->ri] - '0'); 341 if (two <= c->ncaptures) { gn = two; (*c->ri)++; } 342 } 343 344 if (gn > 0 && gn <= c->ncaptures && c->caps[gn - 1].ptr) 345 return rt_append(c, c->caps[gn - 1].ptr, c->caps[gn - 1].len); 346 347 if (gn == 0 || gn > c->ncaptures) 348 return rt_append(c, "$", 1) && rt_append(c, &nc, 1); 349 350 return true; 351} 352 353typedef bool (*rt_handler_t)(rt_ctx_t *); 354static rt_handler_t rt_dispatch[128]; 355static bool rt_dispatch_init = false; 356 357static void rt_init_dispatch(void) { 358 if (rt_dispatch_init) return; 359 rt_dispatch['$'] = rt_dollar; 360 rt_dispatch['&'] = rt_match; 361 rt_dispatch['`'] = rt_prefix; 362 rt_dispatch['\''] = rt_suffix; 363 for (int i = '0'; i <= '9'; i++) rt_dispatch[i] = rt_capture; 364 rt_dispatch_init = true; 365} 366 367bool repl_template( 368 const char *repl, size_t repl_len, 369 const char *matched, size_t matched_len, 370 const char *str, size_t str_len, size_t position, 371 const repl_capture_t *caps, int ncaptures, 372 char **buf, size_t *buf_len, size_t *buf_cap 373) { 374 rt_init_dispatch(); 375 rt_ctx_t c = { 376 repl, repl_len, NULL, 377 matched, matched_len, 378 str, str_len, position, 379 caps, ncaptures, 380 buf, buf_len, buf_cap, 381 }; 382 383 for (size_t ri = 0; ri < repl_len; ) { 384 if (repl[ri] == '$' && ri + 1 < repl_len) { 385 unsigned char nc = (unsigned char)repl[ri + 1]; 386 c.ri = &ri; 387 rt_handler_t h = nc < 128 ? rt_dispatch[nc] : NULL; 388 if (h) { if (!h(&c)) return false; continue; } 389 } 390 if (!rt_append(&c, &repl[ri], 1)) return false; 391 ri++; 392 } 393 394 return true; 395} 396 397void *try_oom(size_t size) { 398 void *p = malloc(size); 399 if (!p) { 400 crfprintf(stderr, msg.oom_fatal); 401 exit(EXIT_FAILURE); 402 } return p; 403} 404 405void cstr_free(cstr_buf_t *buf) { 406 if (buf->heap) free(buf->heap); 407} 408 409char *cstr_init(cstr_buf_t *buf, char *stack, size_t stack_size, const char *src, size_t len) { 410 if (len < stack_size) { 411 buf->ptr = stack; 412 buf->heap = NULL; 413 } else { 414 buf->heap = malloc(len + 1); 415 if (!buf->heap) return NULL; 416 buf->ptr = buf->heap; 417 } 418 memcpy(buf->ptr, src, len); 419 buf->ptr[len] = '\0'; 420 return buf->ptr; 421}