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 spec-shaped async generator prototype chain

+264 -63
+42 -4
examples/spec/async_iterators.js
··· 5 5 test('AsyncIterator global exists', typeof AsyncIterator, 'function'); 6 6 test('AsyncIterator prototype async iterator tag', AsyncIterator.prototype[Symbol.toStringTag], 'AsyncIterator'); 7 7 8 + async function* protoShapeAsyncGen() { 9 + yield 1; 10 + } 11 + const AsyncGeneratorFunction = protoShapeAsyncGen.constructor; 12 + const protoShapeAsyncIter = protoShapeAsyncGen(); 13 + const ownAsyncGeneratorProto = Object.getPrototypeOf(protoShapeAsyncIter); 14 + const sharedAsyncGeneratorProto = Object.getPrototypeOf(ownAsyncGeneratorProto); 15 + const inheritedAsyncIteratorProto = Object.getPrototypeOf(sharedAsyncGeneratorProto); 16 + test('async generator function has prototype property', protoShapeAsyncGen.hasOwnProperty('prototype'), true); 17 + test('async generator function constructor name', AsyncGeneratorFunction.name, 'AsyncGeneratorFunction'); 18 + test('async generator function prototype chain', Object.getPrototypeOf(protoShapeAsyncGen), AsyncGeneratorFunction.prototype); 19 + test('async generator function prototype tag', AsyncGeneratorFunction.prototype[Symbol.toStringTag], 'AsyncGeneratorFunction'); 20 + test('async generator function prototype prototype', AsyncGeneratorFunction.prototype.prototype, sharedAsyncGeneratorProto); 21 + test( 22 + 'new async generator function throws', 23 + (() => { 24 + try { 25 + new protoShapeAsyncGen(); 26 + return false; 27 + } catch (err) { 28 + return true; 29 + } 30 + })(), 31 + true 32 + ); 33 + test('async generator instance uses function prototype', ownAsyncGeneratorProto, protoShapeAsyncGen.prototype); 34 + test('async generator shared prototype tag', sharedAsyncGeneratorProto[Symbol.toStringTag], 'AsyncGenerator'); 35 + test('async generator shared prototype has next', sharedAsyncGeneratorProto.hasOwnProperty('next'), true); 36 + test('async generator shared prototype inherits AsyncIterator', inheritedAsyncIteratorProto, AsyncIterator.prototype); 37 + test('async generator Symbol.asyncIterator inherited from AsyncIterator', protoShapeAsyncIter[Symbol.asyncIterator](), protoShapeAsyncIter); 38 + test('async generator inherits AsyncIterator helpers', typeof protoShapeAsyncIter.map, 'function'); 39 + 40 + const dynamicAsyncGen = AsyncGeneratorFunction('yield 4;'); 41 + const dynamicAsyncIter = dynamicAsyncGen(); 42 + test('AsyncGeneratorFunction constructs async generator function', Object.getPrototypeOf(dynamicAsyncGen), AsyncGeneratorFunction.prototype); 43 + test('AsyncGeneratorFunction instance uses function prototype', Object.getPrototypeOf(dynamicAsyncIter), dynamicAsyncGen.prototype); 44 + test('AsyncGeneratorFunction yielded value', (await dynamicAsyncIter.next()).value, 4); 45 + 8 46 class CustomAsyncIterator extends AsyncIterator { 9 47 constructor(values) { 10 48 super(); ··· 57 95 }, 58 96 [Symbol.iterator]() { 59 97 return this; 60 - }, 98 + } 61 99 }; 62 100 test('AsyncIterator.from sync return awaits value', (await AsyncIterator.from(syncReturnSource).return()).value, 7); 63 101 ··· 70 108 }, 71 109 [Symbol.iterator]() { 72 110 return this; 73 - }, 111 + } 74 112 }; 75 113 test('AsyncIterator.from sync throw awaits value', (await AsyncIterator.from(syncThrowSource).throw(new Error('x'))).value, 8); 76 114 ··· 145 183 }, 146 184 [Symbol.asyncIterator]() { 147 185 return this; 148 - }, 186 + } 149 187 }; 150 188 } 151 189 ··· 193 231 }, 194 232 [Symbol.asyncIterator]() { 195 233 return this; 196 - }, 234 + } 197 235 }; 198 236 test('async iterator handles sync next results without recursive stack growth', (await AsyncIterator.from(syncAsyncLike).toArray()).length, 5000); 199 237
+1
include/common.h
··· 16 16 X(SLOT_FUNC_PROTO) \ 17 17 X(SLOT_ASYNC_PROTO) \ 18 18 X(SLOT_GENERATOR_PROTO) \ 19 + X(SLOT_ASYNC_GENERATOR_PROTO) \ 19 20 X(SLOT_AUX) \ 20 21 X(SLOT_TARGET_FUNC) \ 21 22 X(SLOT_MODULE_CTX) \
+1
include/internal.h
··· 199 199 ant_value_t array_iterator_proto; 200 200 ant_value_t string_iterator_proto; 201 201 ant_value_t generator_proto; 202 + ant_value_t async_generator_proto; 202 203 ant_value_t async_iterator_proto; 203 204 } sym; 204 205
+2 -2
include/tokens.h
··· 13 13 TOK_DEFAULT, TOK_DELETE, TOK_DO, TOK_DEBUGGER, TOK_ELSE, TOK_EXPORT, TOK_FINALLY, TOK_FOR, 14 14 TOK_FROM, TOK_FUNC, TOK_IF, TOK_IMPORT, TOK_IN, TOK_INSTANCEOF, TOK_LET, TOK_NEW, TOK_OF, 15 15 TOK_RETURN, TOK_SUPER, TOK_SWITCH, TOK_THIS, TOK_THROW, TOK_TRY, TOK_VAR, TOK_VOID, TOK_WHILE, TOK_WITH, 16 - TOK_YIELD, TOK_UNDEF, TOK_NULL, TOK_TRUE, TOK_FALSE, TOK_AS, TOK_STATIC, TOK_TYPEOF, 16 + TOK_YIELD, TOK_UNDEF, TOK_NULL, TOK_TRUE, TOK_FALSE, TOK_AS, TOK_STATIC, TOK_TYPEOF, TOK_USING, 17 17 TOK_WINDOW, TOK_GLOBAL_THIS, 18 18 TOK_IDENT_LIKE_END, 19 19 ··· 47 47 [TOK_EXP] = 14, 48 48 }; 49 49 50 - #endif 50 + #endif
+88 -17
src/ant.c
··· 5373 5373 if (is_err(func_obj)) return func_obj; 5374 5374 5375 5375 set_func_code_ptr(js, func_obj, "(){}", 4); 5376 - if (is_async) { 5376 + if (is_async && is_generator) { 5377 + set_slot(func_obj, SLOT_ASYNC, js_true); 5378 + ant_value_t async_generator_proto = get_slot(js_glob(js), SLOT_ASYNC_GENERATOR_PROTO); 5379 + if (vtype(async_generator_proto) == T_FUNC) js_set_proto_init(func_obj, async_generator_proto); 5380 + } 5381 + 5382 + else if (is_async) { 5377 5383 set_slot(func_obj, SLOT_ASYNC, js_true); 5378 5384 ant_value_t async_proto = get_slot(js_glob(js), SLOT_ASYNC_PROTO); 5379 5385 if (vtype(async_proto) == T_FUNC) js_set_proto_init(func_obj, async_proto); 5380 - } else if (is_generator) { 5386 + } 5387 + 5388 + else if (is_generator) { 5381 5389 ant_value_t generator_proto = get_slot(js_glob(js), SLOT_GENERATOR_PROTO); 5382 5390 if (vtype(generator_proto) == T_FUNC) js_set_proto_init(func_obj, generator_proto); 5383 - } else { 5391 + } 5392 + 5393 + else { 5384 5394 ant_value_t func_proto = get_slot(js_glob(js), SLOT_FUNC_PROTO); 5385 5395 ant_value_t instance_proto = js_instance_proto_from_new_target(js, func_proto); 5386 5396 if (is_object_type(instance_proto)) js_set_proto_init(func_obj, instance_proto); ··· 5389 5399 set_slot(func_obj, SLOT_CFUNC, js_mkfun(builtin_function_empty)); 5390 5400 ant_value_t func = js_obj_to_func(func_obj); 5391 5401 5392 - if (!is_async) { 5393 - ant_value_t proto_setup = setup_func_prototype(js, func); 5402 + if (!is_async || is_generator) { 5403 + ant_value_t proto_setup = is_generator 5404 + ? setup_func_prototype_property(js, func, false) 5405 + : setup_func_prototype(js, func); 5394 5406 if (is_err(proto_setup)) return proto_setup; 5407 + } 5408 + 5409 + if (is_generator) { 5410 + ant_value_t prototype = js_get(js, func, "prototype"); 5411 + ant_value_t parent_proto = is_async ? js->sym.async_generator_proto : js->sym.generator_proto; 5412 + if (is_object_type(prototype) && is_object_type(parent_proto)) js_set_proto_wb(js, prototype, parent_proto); 5395 5413 } 5396 5414 5397 5415 return func; ··· 5466 5484 memcpy(display + n, "\n) {\n", 5); n += 5; 5467 5485 memcpy(display + n, code_buf + 1 + params_len + 2, (size_t)body_len); n += (size_t)body_len; 5468 5486 memcpy(display + n, "\n}", 2); n += 2; 5487 + 5469 5488 display[n] = '\0'; 5470 5489 set_func_code(js, func_obj, display, display_len); 5490 + 5471 5491 free(display); 5472 5492 free(code_buf); 5473 5493 5474 - if (is_async) { 5494 + if (is_async && is_generator) { 5495 + set_slot(func_obj, SLOT_ASYNC, js_true); 5496 + ant_value_t async_generator_proto = get_slot(js_glob(js), SLOT_ASYNC_GENERATOR_PROTO); 5497 + if (vtype(async_generator_proto) == T_FUNC) js_set_proto_init(func_obj, async_generator_proto); 5498 + } 5499 + 5500 + else if (is_async) { 5475 5501 set_slot(func_obj, SLOT_ASYNC, js_true); 5476 5502 ant_value_t async_proto = get_slot(js_glob(js), SLOT_ASYNC_PROTO); 5477 5503 if (vtype(async_proto) == T_FUNC) js_set_proto_init(func_obj, async_proto); 5478 - } else if (is_generator) { 5504 + } 5505 + 5506 + else if (is_generator) { 5479 5507 ant_value_t generator_proto = get_slot(js_glob(js), SLOT_GENERATOR_PROTO); 5480 5508 if (vtype(generator_proto) == T_FUNC) js_set_proto_init(func_obj, generator_proto); 5481 - } else { 5509 + } 5510 + 5511 + else { 5482 5512 ant_value_t func_proto = get_slot(js_glob(js), SLOT_FUNC_PROTO); 5483 5513 ant_value_t instance_proto = js_instance_proto_from_new_target(js, func_proto); 5484 5514 if (is_object_type(instance_proto)) js_set_proto_init(func_obj, instance_proto); 5485 5515 } 5486 5516 5487 5517 ant_value_t func = mkval(T_FUNC, (uintptr_t)closure); 5488 - if (!is_async) { 5489 - ant_value_t proto_setup = setup_func_prototype(js, func); 5518 + if (!is_async || is_generator) { 5519 + ant_value_t proto_setup = is_generator 5520 + ? setup_func_prototype_property(js, func, false) 5521 + : setup_func_prototype(js, func); 5490 5522 if (is_err(proto_setup)) return proto_setup; 5491 5523 } 5492 5524 5493 5525 if (is_generator) { 5494 5526 ant_value_t prototype = js_get(js, func, "prototype"); 5495 - if (is_object_type(prototype) && is_object_type(js->sym.generator_proto)) 5496 - js_set_proto_wb(js, prototype, js->sym.generator_proto); 5527 + ant_value_t parent_proto = is_async ? js->sym.async_generator_proto : js->sym.generator_proto; 5528 + if (is_object_type(prototype) && is_object_type(parent_proto)) js_set_proto_wb(js, prototype, parent_proto); 5497 5529 } 5498 5530 5499 5531 return func; ··· 5505 5537 5506 5538 static ant_value_t builtin_AsyncFunction(ant_t *js, ant_value_t *args, int nargs) { 5507 5539 return build_dynamic_function(js, args, nargs, true, false); 5540 + } 5541 + 5542 + static ant_value_t builtin_AsyncGeneratorFunction(ant_t *js, ant_value_t *args, int nargs) { 5543 + if (nargs == 0) { 5544 + ant_value_t empty = js_mkstr(js, "", 0); 5545 + if (is_err(empty)) return empty; 5546 + return build_dynamic_function(js, &empty, 1, true, true); 5547 + } 5548 + return build_dynamic_function(js, args, nargs, true, true); 5508 5549 } 5509 5550 5510 5551 static ant_value_t builtin_GeneratorFunction(ant_t *js, ant_value_t *args, int nargs) { ··· 14978 15019 14979 15020 js_setprop(js, generator_func_proto_obj, js_mkstr(js, "constructor", 11), generator_func_ctor); 14980 15021 js_set_descriptor(js, generator_func_proto_obj, "constructor", 11, JS_DESC_W | JS_DESC_C); 15022 + 15023 + ant_value_t async_generator_func_proto_obj = js_mkobj(js); 15024 + set_proto(js, async_generator_func_proto_obj, function_proto); 15025 + set_slot(async_generator_func_proto_obj, SLOT_ASYNC, js_true); 15026 + 15027 + ant_value_t async_generator_func_proto = js_obj_to_func(async_generator_func_proto_obj); 15028 + set_slot(glob, SLOT_ASYNC_GENERATOR_PROTO, async_generator_func_proto); 15029 + 15030 + ant_value_t async_generator_func_ctor_obj = mkobj(js, 0); 15031 + set_proto(js, async_generator_func_ctor_obj, function_proto); 15032 + set_slot(async_generator_func_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_AsyncGeneratorFunction)); 15033 + js_setprop_nonconfigurable(js, async_generator_func_ctor_obj, "prototype", 9, async_generator_func_proto); 15034 + js_setprop(js, async_generator_func_ctor_obj, js->length_str, tov(1.0)); 15035 + js_set_descriptor(js, async_generator_func_ctor_obj, "length", 6, JS_DESC_C); 15036 + js_setprop(js, async_generator_func_ctor_obj, ANT_STRING("name"), ANT_STRING("AsyncGeneratorFunction")); 15037 + 15038 + ant_value_t async_generator_func_ctor = js_obj_to_func(async_generator_func_ctor_obj); 15039 + js_setprop(js, async_generator_func_proto_obj, js_mkstr(js, "constructor", 11), async_generator_func_ctor); 15040 + js_set_descriptor(js, async_generator_func_proto_obj, "constructor", 11, JS_DESC_W | JS_DESC_C); 14981 15041 14982 15042 ant_value_t str_ctor_obj = mkobj(js, 0); 14983 15043 set_proto(js, str_ctor_obj, function_proto); ··· 14987 15047 defmethod(js, str_ctor_obj, "fromCodePoint", 13, js_mkfun(builtin_string_fromCodePoint)); 14988 15048 defmethod(js, str_ctor_obj, "raw", 3, js_mkfun(builtin_string_raw)); 14989 15049 js_setprop(js, str_ctor_obj, ANT_STRING("name"), ANT_STRING("String")); 15050 + 14990 15051 ant_value_t str_ctor_func = js_obj_to_func(str_ctor_obj); 14991 15052 js_setprop(js, glob, js_mkstr(js, "String", 6), str_ctor_func); 14992 15053 ··· 15251 15312 } 15252 15313 15253 15314 static ant_value_t setup_func_prototype_property(ant_t *js, ant_value_t func, bool mark_constructor) { 15315 + ant_value_t func_obj = (vtype(func) == T_FUNC) 15316 + ? js_func_obj(func) 15317 + : js_as_obj(func); 15318 + 15254 15319 ant_value_t proto_obj = mkobj(js, 0); 15255 15320 if (is_err(proto_obj)) return proto_obj; 15256 15321 ··· 15267 15332 ant_value_t prototype_key = js_mkstr(js, "prototype", 9); 15268 15333 if (is_err(prototype_key)) return prototype_key; 15269 15334 15270 - res = js_setprop(js, func, prototype_key, proto_obj); 15271 - if (is_err(res)) return res; 15272 - js_set_descriptor(js, js_as_obj(func), "prototype", 9, JS_DESC_W); 15273 - 15274 - if (mark_constructor) js_mark_constructor(func, true); 15335 + ant_offset_t existing = lkp(js, func_obj, "prototype", 9); 15336 + if (existing > 0) { 15337 + if (is_const_prop(js, existing)) return js_mkerr(js, "assignment to constant"); 15338 + js_saveval(js, existing, proto_obj); 15339 + } else { 15340 + res = mkprop(js, func_obj, prototype_key, proto_obj, 0); 15341 + if (is_err(res)) return res; 15342 + } 15343 + 15344 + js_set_descriptor(js, func_obj, "prototype", 9, JS_DESC_W); 15345 + if (mark_constructor) js_mark_constructor(func_obj, true); 15275 15346 15276 15347 return js_mkundef(); 15277 15348 }
+13 -9
src/highlight/iter.c
··· 6 6 #include "highlight/regex.h" 7 7 #include "silver/lexer.h" 8 8 9 - typedef struct { const char *op; int len; hl_token_class cls; } op_entry_t; 9 + typedef struct { 10 + const char *op; 11 + int len; 12 + hl_token_class cls; 13 + } op_entry_t; 10 14 11 15 static const op_entry_t operators[] = { 12 16 { "===", 3, HL_OPERATOR }, ··· 169 173 wstart = i; 170 174 wlen = wend - i; 171 175 172 - return (wlen == 5 && memcmp(input + wstart, "const", 5) == 0) || 173 - (wlen == 3 && memcmp(input + wstart, "let", 3) == 0) || 174 - (wlen == 3 && memcmp(input + wstart, "var", 3) == 0); 176 + return 177 + (wlen == 5 && memcmp(input + wstart, "const", 5) == 0) || 178 + (wlen == 3 && memcmp(input + wstart, "let", 3) == 0) || 179 + (wlen == 5 && memcmp(input + wstart, "using", 5) == 0) || 180 + (wlen == 3 && memcmp(input + wstart, "var", 3) == 0); 175 181 } 176 182 177 183 static bool is_assigned_arrow_function(const char *input, size_t input_len, size_t ident_start, size_t ident_end) { 178 184 if (!has_declaration_keyword_before(input, ident_start)) return false; 179 - 180 185 size_t i = skip_inline_ws_forward(input, input_len, ident_end); 186 + 181 187 if (i >= input_len || input[i] != '=') return false; 182 188 if (i + 1 < input_len && input[i + 1] == '>') return false; 183 - i++; 184 - 185 - i = skip_inline_ws_forward(input, input_len, i); 189 + i++; i = skip_inline_ws_forward(input, input_len, i); 190 + 186 191 if (i >= input_len) return false; 187 - 188 192 if (is_arrow_after(input, input_len, i)) return false; 189 193 190 194 if (is_ident_begin((unsigned char)input[i])) {
+32 -7
src/modules/generator.c
··· 476 476 return generator_is_async(gen) ? generator_async_wrap_result(js, result) : result; 477 477 } 478 478 479 + static ant_value_t generator_async_dispose(ant_t *js, ant_value_t *args, int nargs) { 480 + ant_value_t gen = js->this_val; 481 + if (vtype(gen) != T_GENERATOR || !generator_is_async(gen)) return js_mkerr_typed( 482 + js, JS_ERR_TYPE, 483 + "AsyncGenerator.prototype[Symbol.asyncDispose] called on incompatible receiver" 484 + ); 485 + 486 + return generator_return(js, NULL, 0); 487 + } 488 + 479 489 void init_generator_module(void) { 480 490 ant_t *js = rt->js; 481 491 ant_value_t proto = js_mkobj(js); 482 492 483 493 js->sym.generator_proto = proto; 484 494 js_set_proto_init(proto, js->sym.iterator_proto); 485 - js_set_proto_wb(js, js->sym.async_iterator_proto, proto); 486 495 487 496 js_set(js, proto, "next", js_mkfun(generator_next)); 488 497 js_set(js, proto, "return", js_mkfun(generator_return)); 489 498 js_set(js, proto, "throw", js_mkfun(generator_throw)); 490 499 js_set_sym(js, proto, get_toStringTag_sym(), js_mkstr(js, "Generator", 9)); 500 + 501 + ant_value_t async_proto = js_mkobj(js); 502 + js->sym.async_generator_proto = async_proto; 503 + js_set_proto_init(async_proto, js->sym.async_iterator_proto); 504 + js_set(js, async_proto, "next", js_mkfun(generator_next)); 505 + js_set(js, async_proto, "return", js_mkfun(generator_return)); 506 + js_set(js, async_proto, "throw", js_mkfun(generator_throw)); 507 + js_set_sym(js, async_proto, get_toStringTag_sym(), js_mkstr(js, "AsyncGenerator", 14)); 508 + js_set_sym(js, async_proto, get_asyncDispose_sym(), js_mkfun(generator_async_dispose)); 509 + 510 + ant_value_t async_generator_func_proto = js_get_slot(js_glob(js), SLOT_ASYNC_GENERATOR_PROTO); 511 + if (is_object_type(async_generator_func_proto)) { 512 + js_set(js, async_generator_func_proto, "prototype", async_proto); 513 + js_set_descriptor(js, js_as_obj(async_generator_func_proto), "prototype", 9, JS_DESC_C); 514 + js_set(js, async_proto, "constructor", async_generator_func_proto); 515 + js_set_descriptor(js, async_proto, "constructor", 11, JS_DESC_C); 516 + } 517 + 491 518 init_async_iterator_helpers(); 492 519 } 493 520 ··· 577 604 js_set_native_tag(gen, GENERATOR_NATIVE_TAG); 578 605 js_set_finalizer(gen, generator_finalize); 579 606 580 - if (data->is_async && is_object_type(js->sym.async_iterator_proto)) 581 - js_set_proto_wb(js, gen, js->sym.async_iterator_proto); 582 - else { 583 - ant_value_t instance_proto = js_get(js, callee_func, "prototype"); 584 - if (is_object_type(instance_proto)) js_set_proto_wb(js, gen, instance_proto); 585 - } 607 + ant_value_t instance_proto = js_get(js, callee_func, "prototype"); 608 + if (is_object_type(instance_proto)) js_set_proto_wb(js, gen, instance_proto); 609 + else if (data->is_async && is_object_type(js->sym.async_generator_proto)) 610 + js_set_proto_wb(js, gen, js->sym.async_generator_proto); 586 611 587 612 return gen; 588 613 }
+6
src/modules/symbol.c
··· 305 305 js->sym.array_iterator_proto = js_mkundef(); 306 306 js->sym.string_iterator_proto = js_mkundef(); 307 307 js->sym.generator_proto = js_mkundef(); 308 + js->sym.async_generator_proto = js_mkundef(); 308 309 js->sym.async_iterator_proto = js_mkundef(); 309 310 310 311 gc_register_root(&js->sym.iterator_proto); 311 312 gc_register_root(&js->sym.array_iterator_proto); 312 313 gc_register_root(&js->sym.string_iterator_proto); 313 314 gc_register_root(&js->sym.generator_proto); 315 + gc_register_root(&js->sym.async_generator_proto); 314 316 gc_register_root(&js->sym.async_iterator_proto); 315 317 316 318 #define INIT_SYM(name, desc) g_##name = js_mksym_well_known(js, desc); ··· 372 374 373 375 ant_value_t async_func_proto = js_get_slot(js_glob(js), SLOT_ASYNC_PROTO); 374 376 js_set_sym(js, async_func_proto, g_toStringTag, js_mkstr(js, "AsyncFunction", 13)); 377 + 378 + ant_value_t async_generator_func_proto = js_get_slot(js_glob(js), SLOT_ASYNC_GENERATOR_PROTO); 379 + js_set_sym(js, async_generator_func_proto, g_toStringTag, js_mkstr(js, "AsyncGeneratorFunction", 22)); 375 380 376 381 js_define_species_getter(js, promise_ctor); 377 382 js_define_species_getter(js, array_ctor); ··· 382 387 mark(js, js->sym.array_iterator_proto); 383 388 mark(js, js->sym.string_iterator_proto); 384 389 mark(js, js->sym.generator_proto); 390 + mark(js, js->sym.async_generator_proto); 385 391 mark(js, js->sym.async_iterator_proto); 386 392 387 393 #define GC_SYM(name, _desc) mark(js, g_##name);
+10 -12
src/silver/ast.c
··· 192 192 193 193 static inline bool is_contextual_ident_tok(uint8_t tok) { 194 194 return 195 - tok == TOK_AS 196 - || tok == TOK_FROM 197 - || tok == TOK_OF 198 - || tok == TOK_ASYNC; 195 + tok == TOK_AS || 196 + tok == TOK_FROM || 197 + tok == TOK_OF || 198 + tok == TOK_ASYNC || 199 + tok == TOK_USING; 199 200 } 200 201 201 202 static inline const char *tok_ident_str(P, uint32_t *out_len) { ··· 208 209 209 210 static inline bool is_private_ident_like_tok(uint8_t tok) { 210 211 return tok >= TOK_IDENTIFIER && tok < TOK_IDENT_LIKE_END; 211 - } 212 - 213 - static inline bool is_using_tok(P) { 214 - return TOK == TOK_IDENTIFIER && TLEN == 5 && memcmp(tok_str(p), "using", 5) == 0; 215 212 } 216 213 217 214 static inline bool sv_strict_forbidden_binding_ident(const char *s, uint32_t len) { ··· 486 483 [TOK_AS] = &&l_ident, 487 484 [TOK_FROM] = &&l_ident, 488 485 [TOK_OF] = &&l_ident, 486 + [TOK_USING] = &&l_ident, 489 487 [TOK_LPAREN] = &&l_paren, 490 488 [TOK_LBRACKET] = &&l_array, 491 489 [TOK_LBRACE] = &&l_object, ··· 1880 1878 [TOK_IMPORT] = &&l_import, 1881 1879 }; 1882 1880 1883 - if (is_using_tok(p)) { 1881 + if (TOK == TOK_USING) { 1884 1882 CONSUME(); 1885 1883 sv_ast_t *n = parse_var_decl(p, SV_VAR_USING, false); 1886 1884 if (NEXT() == TOK_SEMICOLON) CONSUME(); ··· 1892 1890 sv_lexer_save_state(&p->lx, &saved); 1893 1891 CONSUME(); 1894 1892 NEXT(); 1895 - if (is_using_tok(p)) { 1893 + if (TOK == TOK_USING) { 1896 1894 CONSUME(); 1897 1895 sv_ast_t *n = parse_var_decl(p, SV_VAR_AWAIT_USING, false); 1898 1896 if (NEXT() == TOK_SEMICOLON) CONSUME(); ··· 1979 1977 sv_lexer_save_state(&p->lx, &saved); 1980 1978 CONSUME(); 1981 1979 NEXT(); 1982 - if (is_using_tok(p)) { 1980 + if (TOK == TOK_USING) { 1983 1981 CONSUME(); 1984 1982 p->no_in = true; 1985 1983 init_node = parse_var_decl(p, SV_VAR_AWAIT_USING, true); ··· 1987 1985 } else sv_lexer_restore_state(&p->lx, &saved); 1988 1986 } 1989 1987 1990 - if (!init_node && is_using_tok(p)) { 1988 + if (!init_node && TOK == TOK_USING) { 1991 1989 CONSUME(); 1992 1990 p->no_in = true; 1993 1991 init_node = parse_var_decl(p, SV_VAR_USING, true);
+1 -1
src/silver/compiler.c
··· 5220 5220 ); 5221 5221 5222 5222 const char *prefix = is_async 5223 - ? "(async function" 5223 + ? (is_generator ? "(async function*" : "(async function") 5224 5224 : (is_generator ? "(function*" : "(function"); 5225 5225 5226 5226 size_t prefix_len = strlen(prefix);
+17 -5
src/silver/glue.c
··· 632 632 js_set_slot_wb(js, func_obj, SLOT_MODULE_CTX, module_ctx); 633 633 634 634 ant_value_t func_val = mkval(T_FUNC, (uintptr_t)closure); 635 - if (!child->is_arrow && !child->is_method && !child->is_async) { 636 - ant_value_t parent_proto = child->is_generator ? js->sym.generator_proto : js->sym.object_proto; 635 + if (!child->is_arrow && !child->is_method && (!child->is_async || child->is_generator)) { 636 + ant_value_t parent_proto = child->is_async 637 + ? js->sym.async_generator_proto 638 + : (child->is_generator ? js->sym.generator_proto : js->sym.object_proto); 637 639 sv_setup_function_prototype_with_parent(js, func_obj, func_val, parent_proto); 638 640 } 639 641 640 - if (child->is_async) { 642 + if (child->is_async && child->is_generator) { 643 + js_set_slot(func_obj, SLOT_ASYNC, js_true); 644 + ant_value_t async_generator_proto = js_get_slot(js->global, SLOT_ASYNC_GENERATOR_PROTO); 645 + if (vtype(async_generator_proto) == T_FUNC) js_set_proto_init(func_obj, async_generator_proto); 646 + } 647 + 648 + else if (child->is_async) { 641 649 js_set_slot(func_obj, SLOT_ASYNC, js_true); 642 650 ant_value_t async_proto = js_get_slot(js->global, SLOT_ASYNC_PROTO); 643 651 if (vtype(async_proto) == T_FUNC) js_set_proto_init(func_obj, async_proto); 644 - } else if (child->is_generator) { 652 + } 653 + 654 + else if (child->is_generator) { 645 655 ant_value_t generator_proto = js_get_slot(js->global, SLOT_GENERATOR_PROTO); 646 656 if (vtype(generator_proto) == T_FUNC) js_set_proto_init(func_obj, generator_proto); 647 - } else { 657 + } 658 + 659 + else { 648 660 ant_value_t func_proto = js_get_slot(js->global, SLOT_FUNC_PROTO); 649 661 if (vtype(func_proto) == T_FUNC) js_set_proto_init(func_obj, func_proto); 650 662 }
+1 -1
src/silver/lexer.c
··· 305 305 break; 306 306 case 'u': 307 307 K("undefined", TOK_UNDEF); 308 + K("using", TOK_USING); 308 309 break; 309 310 case 'v': 310 311 K("var", TOK_VAR); ··· 1144 1145 1145 1146 return tok; 1146 1147 } 1147 -
+17 -5
src/silver/ops/upvalues.h
··· 139 139 js_set_descriptor(js, func_obj, "length", 6, JS_DESC_C); 140 140 141 141 if (is_object_type(module_ctx)) js_set_slot_wb(js, func_obj, SLOT_MODULE_CTX, module_ctx); 142 - if (!child->is_arrow && !child->is_method && !child->is_async) { 143 - ant_value_t parent_proto = child->is_generator ? js->sym.generator_proto : js->sym.object_proto; 142 + if (!child->is_arrow && !child->is_method && (!child->is_async || child->is_generator)) { 143 + ant_value_t parent_proto = child->is_async 144 + ? js->sym.async_generator_proto 145 + : (child->is_generator ? js->sym.generator_proto : js->sym.object_proto); 144 146 sv_setup_function_prototype_with_parent(js, func_obj, func_val, parent_proto); 145 147 } 146 148 147 - if (child->is_async) { 149 + if (child->is_async && child->is_generator) { 150 + js_set_slot(func_obj, SLOT_ASYNC, js_true); 151 + ant_value_t async_generator_proto = js_get_slot(js->global, SLOT_ASYNC_GENERATOR_PROTO); 152 + if (vtype(async_generator_proto) == T_FUNC) js_set_proto_init(func_obj, async_generator_proto); 153 + } 154 + 155 + else if (child->is_async) { 148 156 js_set_slot(func_obj, SLOT_ASYNC, js_true); 149 157 ant_value_t async_proto = js_get_slot(js->global, SLOT_ASYNC_PROTO); 150 158 if (vtype(async_proto) == T_FUNC) js_set_proto_init(func_obj, async_proto); 151 - } else if (child->is_generator) { 159 + } 160 + 161 + else if (child->is_generator) { 152 162 ant_value_t generator_proto = js_get_slot(js->global, SLOT_GENERATOR_PROTO); 153 163 if (vtype(generator_proto) == T_FUNC) js_set_proto_init(func_obj, generator_proto); 154 - } else { 164 + } 165 + 166 + else { 155 167 ant_value_t func_proto = js_get_slot(js->global, SLOT_FUNC_PROTO); 156 168 if (vtype(func_proto) == T_FUNC) js_set_proto_init(func_obj, func_proto); 157 169 }
+33
tests/test_highlight_keyword_using.cjs
··· 1 + function assertEq(actual, expected, label) { 2 + if (actual !== expected) throw new Error(`${label}: expected ${JSON.stringify(expected)} got ${JSON.stringify(actual)}`); 3 + } 4 + 5 + const usingDeclaration = Ant.highlight.tags('using handle = resource;'); 6 + assertEq( 7 + usingDeclaration, 8 + '<#65B2FF>using</> handle <#8CB2D8>=</> resource<#B2CCE5>;</>', 9 + 'using declaration keyword' 10 + ); 11 + 12 + const awaitUsingDeclaration = Ant.highlight.tags('await using handle = resource;'); 13 + assertEq( 14 + awaitUsingDeclaration, 15 + '<#65B2FF>await</> <#65B2FF>using</> handle <#8CB2D8>=</> resource<#B2CCE5>;</>', 16 + 'await using declaration keyword' 17 + ); 18 + 19 + const usingArrowDeclaration = Ant.highlight.tags('using cleanup = () => {};'); 20 + assertEq( 21 + usingArrowDeclaration, 22 + '<#65B2FF>using</> <#30E8AA>cleanup</> <#8CB2D8>=</> <#8CB2D8>(</><#8CB2D8>)</> <#8CB2D8>=>></> <#8CB2D8>{</><#8CB2D8>}</><#B2CCE5>;</>', 23 + 'using arrow declaration name' 24 + ); 25 + 26 + const propertyAccess = Ant.highlight.tags('resource.using();'); 27 + assertEq( 28 + propertyAccess, 29 + 'resource.<#30E8AA>using</><#8CB2D8>(</><#8CB2D8>)</><#B2CCE5>;</>', 30 + 'using property access remains method-highlighted' 31 + ); 32 + 33 + console.log('ok');