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 type-hints-typescript 462 lines 17 kB view raw
1#include <stdlib.h> 2#include <string.h> 3 4#include "ant.h" 5#include "errors.h" 6#include "runtime.h" 7#include "internal.h" 8#include "descriptors.h" 9 10#include "modules/symbol.h" 11#include "modules/buffer.h" 12#include "modules/textcodec.h" 13#include "streams/codec.h" 14#include "streams/transform.h" 15 16ant_value_t g_tes_proto; 17ant_value_t g_tds_proto; 18 19typedef struct { 20 uint8_t pending[3]; 21 uint8_t pending_len; 22} tes_state_t; 23 24static ant_value_t tes_get_ts(ant_value_t obj) { 25 return js_get_slot(obj, SLOT_ENTRIES); 26} 27 28static ant_value_t tds_get_ts(ant_value_t obj) { 29 return js_get_slot(obj, SLOT_ENTRIES); 30} 31 32bool tes_is_stream(ant_value_t obj) { 33 return is_object_type(obj) 34 && vtype(js_get_slot(obj, SLOT_DATA)) == T_NUM 35 && ts_is_stream(tes_get_ts(obj)); 36} 37 38bool tds_is_stream(ant_value_t obj) { 39 return is_object_type(obj) 40 && vtype(js_get_slot(obj, SLOT_DATA)) == T_NUM 41 && ts_is_stream(tds_get_ts(obj)); 42} 43 44ant_value_t tes_stream_readable(ant_value_t obj) { 45 return ts_stream_readable(tes_get_ts(obj)); 46} 47 48ant_value_t tes_stream_writable(ant_value_t obj) { 49 return ts_stream_writable(tes_get_ts(obj)); 50} 51 52ant_value_t tds_stream_readable(ant_value_t obj) { 53 return ts_stream_readable(tds_get_ts(obj)); 54} 55 56ant_value_t tds_stream_writable(ant_value_t obj) { 57 return ts_stream_writable(tds_get_ts(obj)); 58} 59 60static void tes_state_finalize(ant_t *js, ant_object_t *obj) { 61 if (!obj->extra_slots) return; 62 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 63 for (uint8_t i = 0; i < obj->extra_count; i++) { 64 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 65 free((tes_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 66 return; 67 }} 68} 69 70static void tds_state_finalize(ant_t *js, ant_object_t *obj) { 71 if (!obj->extra_slots) return; 72 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 73 for (uint8_t i = 0; i < obj->extra_count; i++) { 74 if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 75 free((td_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 76 return; 77 }} 78} 79 80static ant_value_t codec_transform_controller(ant_value_t *args, int nargs) { 81 return (nargs > 1) ? args[1] : js_mkundef(); 82} 83 84static ant_value_t codec_flush_controller(ant_value_t *args, int nargs) { 85 return (nargs > 0) ? args[0] : js_mkundef(); 86} 87 88static ant_value_t tes_transform(ant_t *js, ant_value_t *args, int nargs) { 89 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 90 ant_value_t state_val = js_get_slot(wrapper, SLOT_DATA); 91 92 tes_state_t *st = (tes_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 93 ant_value_t ctrl_obj = codec_transform_controller(args, nargs); 94 ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef(); 95 96 size_t str_len = 0; 97 const char *str = NULL; 98 99 if (vtype(chunk) == T_STR) { 100 str = js_getstr(js, chunk, &str_len); 101 } else { 102 ant_value_t sv = js_tostring_val(js, chunk); 103 if (is_err(sv)) return sv; 104 str = js_getstr(js, sv, &str_len); 105 } 106 if (!str) { str = ""; str_len = 0; } 107 108 const uint8_t *s = (const uint8_t *)str; 109 size_t total = st->pending_len + str_len; 110 111 if (total == 0) return js_mkundef(); 112 113 uint8_t *buf = malloc(total); 114 if (!buf) return js_mkerr(js, "out of memory"); 115 116 size_t off = 0; 117 if (st->pending_len > 0) { 118 memcpy(buf, st->pending, st->pending_len); 119 off = st->pending_len; 120 st->pending_len = 0; 121 } 122 memcpy(buf + off, s, str_len); 123 124 size_t out_len = total; 125 if (out_len >= 3) { 126 uint8_t b0 = buf[out_len - 3], b1 = buf[out_len - 2], b2 = buf[out_len - 1]; 127 if (b0 == 0xED && b1 >= 0xA0 && b1 <= 0xAF) { 128 st->pending[0] = b0; 129 st->pending[1] = b1; 130 st->pending[2] = b2; 131 st->pending_len = 3; 132 out_len -= 3; 133 }} 134 135 if (out_len == 0) { 136 free(buf); 137 return js_mkundef(); 138 } 139 140 uint8_t *out = malloc(out_len * 4 / 3 + 4); 141 if (!out) { free(buf); return js_mkerr(js, "out of memory"); } 142 143 size_t i = 0, o = 0; 144 while (i < out_len) { 145 if (i + 5 < out_len && 146 buf[i] == 0xED && buf[i+1] >= 0xA0 && buf[i+1] <= 0xAF && 147 buf[i+3] == 0xED && buf[i+4] >= 0xB0 && buf[i+4] <= 0xBF) { 148 uint32_t hi_cp = ((uint32_t)0x0D << 12) | ((uint32_t)(buf[i+1] & 0x3F) << 6) | (buf[i+2] & 0x3F); 149 uint32_t lo_cp = ((uint32_t)0x0D << 12) | ((uint32_t)(buf[i+4] & 0x3F) << 6) | (buf[i+5] & 0x3F); 150 uint32_t cp = 0x10000 + ((hi_cp - 0xD800) << 10) + (lo_cp - 0xDC00); 151 out[o++] = (uint8_t)(0xF0 | (cp >> 18)); 152 out[o++] = (uint8_t)(0x80 | ((cp >> 12) & 0x3F)); 153 out[o++] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F)); 154 out[o++] = (uint8_t)(0x80 | (cp & 0x3F)); 155 i += 6; 156 } else if (buf[i] == 0xED && i + 2 < out_len && buf[i+1] >= 0xA0 && buf[i+1] <= 0xBF) { 157 out[o++] = 0xEF; out[o++] = 0xBF; out[o++] = 0xBD; 158 i += 3; 159 } else out[o++] = buf[i++]; } 160 161 free(buf); 162 163 ArrayBufferData *ab = create_array_buffer_data(o); 164 if (!ab) { free(out); return js_mkerr(js, "out of memory"); } 165 memcpy(ab->data, out, o); 166 free(out); 167 168 ant_value_t result = create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, o, "Uint8Array"); 169 return ts_is_controller(ctrl_obj) 170 ? ts_ctrl_enqueue(js, ctrl_obj, result) 171 : js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStreamDefaultController"); 172} 173 174static ant_value_t tes_flush(ant_t *js, ant_value_t *args, int nargs) { 175 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 176 ant_value_t state_val = js_get_slot(wrapper, SLOT_DATA); 177 tes_state_t *st = (tes_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 178 ant_value_t ctrl_obj = codec_flush_controller(args, nargs); 179 180 if (st->pending_len > 0) { 181 uint8_t fffd[3] = { 0xEF, 0xBF, 0xBD }; 182 ArrayBufferData *ab = create_array_buffer_data(3); 183 if (!ab) return js_mkerr(js, "out of memory"); 184 memcpy(ab->data, fffd, 3); 185 st->pending_len = 0; 186 187 ant_value_t result = create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, 3, "Uint8Array"); 188 if (!ts_is_controller(ctrl_obj)) 189 return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStreamDefaultController"); 190 return ts_ctrl_enqueue(js, ctrl_obj, result); 191 } 192 193 return js_mkundef(); 194} 195 196static ant_value_t js_tes_get_encoding(ant_t *js, ant_value_t *args, int nargs) { 197 return js_mkstr(js, "utf-8", 5); 198} 199 200static ant_value_t js_tes_get_readable(ant_t *js, ant_value_t *args, int nargs) { 201 ant_value_t ts_obj = tes_get_ts(js->this_val); 202 if (!ts_is_stream(ts_obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TextEncoderStream"); 203 return ts_stream_readable(ts_obj); 204} 205 206static ant_value_t js_tes_get_writable(ant_t *js, ant_value_t *args, int nargs) { 207 ant_value_t ts_obj = tes_get_ts(js->this_val); 208 if (!ts_is_stream(ts_obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TextEncoderStream"); 209 return ts_stream_writable(ts_obj); 210} 211 212static ant_value_t js_tes_ctor(ant_t *js, ant_value_t *args, int nargs) { 213 if (vtype(js->new_target) == T_UNDEF) 214 return js_mkerr_typed(js, JS_ERR_TYPE, "TextEncoderStream constructor requires 'new'"); 215 216 tes_state_t *st = calloc(1, sizeof(tes_state_t)); 217 if (!st) return js_mkerr(js, "out of memory"); 218 219 ant_value_t obj = js_mkobj(js); 220 ant_value_t proto = js_instance_proto_from_new_target(js, g_tes_proto); 221 if (is_object_type(proto)) js_set_proto_init(obj, proto); 222 js_set_slot(obj, SLOT_DATA, ANT_PTR(st)); 223 js_set_finalizer(obj, tes_state_finalize); 224 225 ant_value_t wrapper = js_mkobj(js); 226 js_set_slot(wrapper, SLOT_DATA, ANT_PTR(st)); 227 228 ant_value_t transformer = js_mkobj(js); 229 ant_value_t transform_fn = js_heavy_mkfun(js, tes_transform, wrapper); 230 ant_value_t flush_fn = js_heavy_mkfun(js, tes_flush, wrapper); 231 js_set(js, transformer, "transform", transform_fn); 232 js_set(js, transformer, "flush", flush_fn); 233 234 ant_value_t ctor_args[1] = { transformer }; 235 ant_value_t saved_new_target = js->new_target; 236 ant_value_t saved_this = js->this_val; 237 js->new_target = js_mknum(1); 238 239 ant_value_t ts_obj = js_ts_ctor(js, ctor_args, 1); 240 js->new_target = saved_new_target; 241 js->this_val = saved_this; 242 243 if (is_err(ts_obj)) { free(st); return ts_obj; } 244 js_set_slot(obj, SLOT_ENTRIES, ts_obj); 245 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj); 246 247 return obj; 248} 249 250static ant_value_t tds_transform(ant_t *js, ant_value_t *args, int nargs) { 251 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 252 ant_value_t state_val = js_get_slot(wrapper, SLOT_DATA); 253 td_state_t *st = (td_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 254 ant_value_t ctrl_obj = codec_transform_controller(args, nargs); 255 256 ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef(); 257 const uint8_t *input = NULL; 258 size_t input_len = 0; 259 260 if (!is_object_type(chunk) || !buffer_source_get_bytes(js, chunk, &input, &input_len)) 261 return js_mkerr_typed(js, JS_ERR_TYPE, "The provided value is not of type '(ArrayBuffer or ArrayBufferView)'"); 262 263 ant_value_t result = td_decode(js, st, input, input_len, true); 264 if (is_err(result)) return result; 265 266 size_t slen = 0; 267 const char *sval = js_getstr(js, result, &slen); 268 if (sval && slen > 0) { 269 if (!ts_is_controller(ctrl_obj)) 270 return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStreamDefaultController"); 271 return ts_ctrl_enqueue(js, ctrl_obj, result); 272 } 273 274 return js_mkundef(); 275} 276 277static ant_value_t tds_flush(ant_t *js, ant_value_t *args, int nargs) { 278 ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 279 ant_value_t state_val = js_get_slot(wrapper, SLOT_DATA); 280 td_state_t *st = (td_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 281 ant_value_t ctrl_obj = codec_flush_controller(args, nargs); 282 283 ant_value_t result = td_decode(js, st, NULL, 0, false); 284 if (is_err(result)) return result; 285 286 size_t slen = 0; 287 const char *sval = js_getstr(js, result, &slen); 288 if (sval && slen > 0) { 289 if (!ts_is_controller(ctrl_obj)) 290 return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStreamDefaultController"); 291 return ts_ctrl_enqueue(js, ctrl_obj, result); 292 } 293 294 return js_mkundef(); 295} 296 297static ant_value_t js_tds_get_encoding(ant_t *js, ant_value_t *args, int nargs) { 298 ant_value_t state_val = js_get_slot(js->this_val, SLOT_DATA); 299 td_state_t *st = (td_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 300 if (!st) return js_mkstr(js, "utf-8", 5); 301 switch (st->encoding) { 302 case TD_ENC_UTF16LE: return js_mkstr(js, "utf-16le", 8); 303 case TD_ENC_UTF16BE: return js_mkstr(js, "utf-16be", 8); 304 case TD_ENC_WINDOWS_1252: return js_mkstr(js, "windows-1252", 12); 305 case TD_ENC_ISO_8859_2: return js_mkstr(js, "iso-8859-2", 10); 306 default: return js_mkstr(js, "utf-8", 5); 307 } 308} 309 310static ant_value_t js_tds_get_fatal(ant_t *js, ant_value_t *args, int nargs) { 311 ant_value_t state_val = js_get_slot(js->this_val, SLOT_DATA); 312 td_state_t *st = (td_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 313 return (st && st->fatal) ? js_true : js_false; 314} 315 316static ant_value_t js_tds_get_ignore_bom(ant_t *js, ant_value_t *args, int nargs) { 317 ant_value_t state_val = js_get_slot(js->this_val, SLOT_DATA); 318 td_state_t *st = (td_state_t *)(uintptr_t)(size_t)js_getnum(state_val); 319 return (st && st->ignore_bom) ? js_true : js_false; 320} 321 322static ant_value_t js_tds_get_readable(ant_t *js, ant_value_t *args, int nargs) { 323 ant_value_t ts_obj = tds_get_ts(js->this_val); 324 if (!ts_is_stream(ts_obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TextDecoderStream"); 325 return ts_stream_readable(ts_obj); 326} 327 328static ant_value_t js_tds_get_writable(ant_t *js, ant_value_t *args, int nargs) { 329 ant_value_t ts_obj = tds_get_ts(js->this_val); 330 if (!ts_is_stream(ts_obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TextDecoderStream"); 331 return ts_stream_writable(ts_obj); 332} 333 334static const char *tds_trim_label(const char *s, size_t len, size_t *out_len) { 335 while (len > 0 && (unsigned char)*s <= 0x20) { s++; len--; } 336 while (len > 0 && (unsigned char)s[len - 1] <= 0x20) { len--; } 337 *out_len = len; 338 return s; 339} 340 341static int tds_resolve_encoding(const char *s, size_t len) { 342 static const struct { const char *label; uint8_t label_len; td_encoding_t enc; } map[] = { 343 {"unicode-1-1-utf-8", 17, TD_ENC_UTF8}, {"unicode11utf8", 13, TD_ENC_UTF8}, 344 {"unicode20utf8", 13, TD_ENC_UTF8}, {"utf-8", 5, TD_ENC_UTF8}, 345 {"utf8", 4, TD_ENC_UTF8}, {"x-unicode20utf8",17, TD_ENC_UTF8}, 346 {"windows-1252", 12, TD_ENC_WINDOWS_1252}, {"ascii", 5, TD_ENC_WINDOWS_1252}, 347 {"unicodefffe", 11, TD_ENC_UTF16BE}, {"utf-16be", 8, TD_ENC_UTF16BE}, 348 {"csunicode", 9, TD_ENC_UTF16LE}, {"iso-10646-ucs-2",16, TD_ENC_UTF16LE}, 349 {"ucs-2", 5, TD_ENC_UTF16LE}, {"unicode", 7, TD_ENC_UTF16LE}, 350 {"unicodefeff", 11, TD_ENC_UTF16LE}, {"utf-16", 6, TD_ENC_UTF16LE}, 351 {"utf-16le", 8, TD_ENC_UTF16LE}, 352 {"iso-8859-2", 10, TD_ENC_ISO_8859_2}, 353 {NULL, 0, 0} 354 }; 355 for (int i = 0; map[i].label; i++) { 356 if (len == map[i].label_len && strncasecmp(s, map[i].label, len) == 0) return (int)map[i].enc; 357 } 358 return -1; 359} 360 361static ant_value_t js_tds_ctor(ant_t *js, ant_value_t *args, int nargs) { 362 if (vtype(js->new_target) == T_UNDEF) 363 return js_mkerr_typed(js, JS_ERR_TYPE, "TextDecoderStream constructor requires 'new'"); 364 365 td_encoding_t enc = TD_ENC_UTF8; 366 if (nargs > 0 && !is_undefined(args[0])) { 367 ant_value_t label = (vtype(args[0]) == T_STR) ? args[0] : coerce_to_str(js, args[0]); 368 if (is_err(label)) return label; 369 370 size_t llen; 371 const char *raw = js_getstr(js, label, &llen); 372 if (raw) { 373 size_t tlen; 374 const char *trimmed = tds_trim_label(raw, llen, &tlen); 375 int resolved = tds_resolve_encoding(trimmed, tlen); 376 if (resolved < 0) return js_mkerr_typed( 377 js, JS_ERR_RANGE, "Failed to construct 'TextDecoderStream': The encoding label provided ('%.*s') is invalid.", 378 (int)tlen, trimmed 379 ); 380 enc = (td_encoding_t)resolved; 381 } 382 } 383 384 bool fatal = false; 385 bool ignore_bom = false; 386 if (nargs > 1 && is_object_type(args[1])) { 387 ant_value_t fv = js_getprop_fallback(js, args[1], "fatal"); 388 if (is_err(fv)) return fv; 389 if (vtype(fv) != T_UNDEF) fatal = js_truthy(js, fv); 390 ant_value_t bv = js_getprop_fallback(js, args[1], "ignoreBOM"); 391 if (is_err(bv)) return bv; 392 if (vtype(bv) != T_UNDEF) ignore_bom = js_truthy(js, bv); 393 } 394 395 td_state_t *st = td_state_new(enc, fatal, ignore_bom); 396 if (!st) return js_mkerr(js, "out of memory"); 397 398 ant_value_t obj = js_mkobj(js); 399 ant_value_t proto = js_instance_proto_from_new_target(js, g_tds_proto); 400 if (is_object_type(proto)) js_set_proto_init(obj, proto); 401 js_set_slot(obj, SLOT_DATA, ANT_PTR(st)); 402 js_set_finalizer(obj, tds_state_finalize); 403 404 ant_value_t wrapper = js_mkobj(js); 405 js_set_slot(wrapper, SLOT_DATA, ANT_PTR(st)); 406 407 ant_value_t transformer = js_mkobj(js); 408 ant_value_t transform_fn = js_heavy_mkfun(js, tds_transform, wrapper); 409 ant_value_t flush_fn = js_heavy_mkfun(js, tds_flush, wrapper); 410 js_set(js, transformer, "transform", transform_fn); 411 js_set(js, transformer, "flush", flush_fn); 412 413 ant_value_t ctor_args[1] = { transformer }; 414 415 ant_value_t saved_new_target = js->new_target; 416 ant_value_t saved_this = js->this_val; 417 js->new_target = js_mknum(1); 418 419 ant_value_t ts_obj = js_ts_ctor(js, ctor_args, 1); 420 421 js->new_target = saved_new_target; 422 js->this_val = saved_this; 423 424 if (is_err(ts_obj)) { free(st); return ts_obj; } 425 426 js_set_slot(obj, SLOT_ENTRIES, ts_obj); 427 js_set_slot(wrapper, SLOT_ENTRIES, ts_obj); 428 429 return obj; 430} 431 432void init_codec_stream_module(void) { 433 ant_t *js = rt->js; 434 ant_value_t g = js_glob(js); 435 436 g_tes_proto = js_mkobj(js); 437 js_set_getter_desc(js, g_tes_proto, "encoding", 8, js_mkfun(js_tes_get_encoding), JS_DESC_C); 438 js_set_getter_desc(js, g_tes_proto, "readable", 8, js_mkfun(js_tes_get_readable), JS_DESC_C); 439 js_set_getter_desc(js, g_tes_proto, "writable", 8, js_mkfun(js_tes_get_writable), JS_DESC_C); 440 js_set_sym(js, g_tes_proto, get_toStringTag_sym(), js_mkstr(js, "TextEncoderStream", 17)); 441 442 ant_value_t tes_ctor = js_make_ctor(js, js_tes_ctor, g_tes_proto, "TextEncoderStream", 17); 443 js_set(js, g, "TextEncoderStream", tes_ctor); 444 js_set_descriptor(js, g, "TextEncoderStream", 17, JS_DESC_W | JS_DESC_C); 445 446 g_tds_proto = js_mkobj(js); 447 js_set_getter_desc(js, g_tds_proto, "encoding", 8, js_mkfun(js_tds_get_encoding), JS_DESC_C); 448 js_set_getter_desc(js, g_tds_proto, "fatal", 5, js_mkfun(js_tds_get_fatal), JS_DESC_C); 449 js_set_getter_desc(js, g_tds_proto, "ignoreBOM", 9, js_mkfun(js_tds_get_ignore_bom), JS_DESC_C); 450 js_set_getter_desc(js, g_tds_proto, "readable", 8, js_mkfun(js_tds_get_readable), JS_DESC_C); 451 js_set_getter_desc(js, g_tds_proto, "writable", 8, js_mkfun(js_tds_get_writable), JS_DESC_C); 452 js_set_sym(js, g_tds_proto, get_toStringTag_sym(), js_mkstr(js, "TextDecoderStream", 17)); 453 454 ant_value_t tds_ctor = js_make_ctor(js, js_tds_ctor, g_tds_proto, "TextDecoderStream", 17); 455 js_set(js, g, "TextDecoderStream", tds_ctor); 456 js_set_descriptor(js, g, "TextDecoderStream", 17, JS_DESC_W | JS_DESC_C); 457} 458 459void gc_mark_codec_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 460 mark(js, g_tes_proto); 461 mark(js, g_tds_proto); 462}