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.

getters and setters

+288 -6
+134
examples/spec/getters.js
··· 1 + import { test, summary } from './helpers.js'; 2 + 3 + console.log('Getter/Setter Tests\n'); 4 + 5 + let obj1 = { 6 + get value() { 7 + return 42; 8 + } 9 + }; 10 + test('basic getter', obj1.value, 42); 11 + 12 + let obj2 = { 13 + _count: 0, 14 + get count() { 15 + return this._count; 16 + }, 17 + set count(val) { 18 + this._count = val; 19 + } 20 + }; 21 + test('getter initial value', obj2.count, 0); 22 + obj2.count = 10; 23 + test('setter updates value', obj2.count, 10); 24 + 25 + let obj3 = { 26 + firstName: 'John', 27 + lastName: 'Doe', 28 + get fullName() { 29 + return this.firstName + ' ' + this.lastName; 30 + } 31 + }; 32 + test('computed getter', obj3.fullName, 'John Doe'); 33 + 34 + let obj4 = { 35 + get 'special-key'() { 36 + return 'special'; 37 + } 38 + }; 39 + test('string key getter', obj4['special-key'], 'special'); 40 + 41 + let obj5 = { 42 + get 0() { 43 + return 'zero'; 44 + } 45 + }; 46 + test('number key getter', obj5[0], 'zero'); 47 + 48 + let obj6 = { 49 + _x: 0, 50 + _y: 0, 51 + get x() { 52 + return this._x; 53 + }, 54 + set x(v) { 55 + this._x = v; 56 + }, 57 + get y() { 58 + return this._y; 59 + }, 60 + set y(v) { 61 + this._y = v; 62 + } 63 + }; 64 + obj6.x = 5; 65 + obj6.y = 10; 66 + test('multiple getters x', obj6.x, 5); 67 + test('multiple getters y', obj6.y, 10); 68 + 69 + let obj7 = { 70 + get data() { 71 + return { a: 1, b: 2 }; 72 + } 73 + }; 74 + test('getter returns object', obj7.data.a, 1); 75 + 76 + let obj8 = { 77 + _age: 0, 78 + get age() { 79 + return this._age; 80 + }, 81 + set age(val) { 82 + if (val < 0) val = 0; 83 + this._age = val; 84 + } 85 + }; 86 + obj8.age = -5; 87 + test('setter validation', obj8.age, 0); 88 + obj8.age = 25; 89 + test('setter valid value', obj8.age, 25); 90 + 91 + let obj9 = { 92 + get readonly() { 93 + return 'constant'; 94 + } 95 + }; 96 + test('getter-only read', obj9.readonly, 'constant'); 97 + obj9.readonly = 'changed'; 98 + test('getter-only unchanged', obj9.readonly, 'constant'); 99 + 100 + let strictError = (function () { 101 + 'use strict'; 102 + try { 103 + let strictObj = { 104 + get x() { 105 + return 1; 106 + } 107 + }; 108 + strictObj.x = 2; 109 + return false; 110 + } catch (e) { 111 + return e instanceof TypeError; 112 + } 113 + })(); 114 + test('strict mode getter-only throws', strictError, true); 115 + 116 + let obj10 = { 117 + multiplier: 3, 118 + _value: 7, 119 + get computed() { 120 + return this._value * this.multiplier; 121 + } 122 + }; 123 + test('getter with this', obj10.computed, 21); 124 + 125 + let sideEffect = 0; 126 + let obj11 = { 127 + set trigger(val) { 128 + sideEffect = val * 2; 129 + } 130 + }; 131 + obj11.trigger = 5; 132 + test('setter side effect', sideEffect, 10); 133 + 134 + summary();
+1 -1
meson.build
··· 75 75 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 76 76 77 77 version_conf = configuration_data() 78 - version_conf.set('ANT_VERSION', '0.1.3.15') 78 + version_conf.set('ANT_VERSION', '0.1.3.16') 79 79 version_conf.set('ANT_GIT_HASH', git_hash) 80 80 version_conf.set('ANT_BUILD_DATE', build_date) 81 81
+153 -5
src/ant.c
··· 2757 2757 jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 2758 2758 if (vtype(desc_obj) != T_OBJ) goto do_update; 2759 2759 2760 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 2760 2761 jsoff_t set_off = lkp(js, desc_obj, "set", 3); 2762 + 2763 + if (get_off != 0 && set_off == 0) { 2764 + if (js->flags & F_STRICT) { 2765 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot set property which has only a getter"); 2766 + } 2767 + return mkval(T_PROP, existing); 2768 + } 2769 + 2761 2770 if (set_off != 0) { 2762 2771 jsval_t setter = resolveprop(js, mkval(T_PROP, set_off)); 2763 2772 if (vtype(setter) == T_FUNC || vtype(setter) == T_CFUNC) { ··· 4337 4346 lkp(js, obj, "__strict_args__", 15) != 0) { 4338 4347 return js_mkerr_typed(js, JS_ERR_TYPE, "'%.*s' not allowed on strict arguments", (int)keylen, keystr); 4339 4348 } 4349 + 4350 + jsoff_t own_off = lkp(js, obj, keystr, keylen); 4351 + if (own_off != 0) { 4352 + char desc_key[128]; 4353 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)keylen, keystr); 4354 + jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 4355 + if (desc_off != 0) { 4356 + jsval_t desc_obj = loadval(js, desc_off + sizeof(jsoff_t) * 2); 4357 + if (vtype(desc_obj) == T_OBJ) { 4358 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 4359 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 4360 + if (get_off != 0 || set_off != 0) { 4361 + jsval_t key = js_mkstr(js, keystr, keylen); 4362 + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); 4363 + } 4364 + } 4365 + } 4366 + return mkval(T_PROP, own_off); 4367 + } 4368 + 4369 + jsval_t accessor_result; 4370 + if (try_accessor_getter(js, obj, keystr, keylen, &accessor_result)) { 4371 + return accessor_result; 4372 + } 4373 + 4340 4374 jsoff_t off = lkp_proto(js, obj, keystr, keylen); 4341 4375 if (off == 0) { 4342 4376 jsval_t key = js_mkstr(js, keystr, keylen); ··· 6361 6395 continue; 6362 6396 } 6363 6397 6398 + bool is_getter = false, is_setter = false; 6364 6399 if (js->tok == TOK_IDENTIFIER) { 6365 - id_off = js->toff; 6366 - id_len = js->tlen; 6367 - if (exe) key = js_mkstr_ident(js, js->code + js->toff, js->tlen); 6400 + bool is_get = (js->tlen == 3 && memcmp(js->code + js->toff, "get", 3) == 0); 6401 + bool is_set = (js->tlen == 3 && memcmp(js->code + js->toff, "set", 3) == 0); 6402 + 6403 + if (is_get || is_set) { 6404 + jsoff_t saved_pos = js->pos; 6405 + uint8_t saved_tok = js->tok; 6406 + uint8_t saved_consumed = js->consumed; 6407 + jsoff_t saved_toff = js->toff; 6408 + jsoff_t saved_tlen = js->tlen; 6409 + 6410 + js->consumed = 1; 6411 + uint8_t peek = next(js); 6412 + 6413 + if (peek == TOK_IDENTIFIER || peek == TOK_STRING || peek == TOK_NUMBER || peek == TOK_LBRACKET) { 6414 + is_getter = is_get; 6415 + is_setter = is_set; 6416 + 6417 + if (peek == TOK_IDENTIFIER) { 6418 + id_off = js->toff; 6419 + id_len = js->tlen; 6420 + if (exe) key = js_mkstr_ident(js, js->code + js->toff, js->tlen); 6421 + } else if (peek == TOK_STRING) { 6422 + id_off = js->toff; 6423 + id_len = js->tlen; 6424 + if (exe) key = js_str_literal(js); 6425 + } else if (peek == TOK_NUMBER) { 6426 + id_off = js->toff; 6427 + id_len = js->tlen; 6428 + if (exe) { 6429 + double num = strtod(js->code + js->toff, NULL); 6430 + char buf[64]; 6431 + size_t n = strnum(tov(num), buf, sizeof(buf)); 6432 + key = js_mkstr(js, buf, n); 6433 + } 6434 + } else if (peek == TOK_LBRACKET) { 6435 + is_computed = true; 6436 + js->consumed = 1; 6437 + jsval_t key_expr = js_expr(js); 6438 + if (is_err(key_expr)) return key_expr; 6439 + 6440 + if (exe) { 6441 + jsval_t resolved_key = resolveprop(js, key_expr); 6442 + if (vtype(resolved_key) == T_STR) { 6443 + key = resolved_key; 6444 + } else { 6445 + char buf[64]; 6446 + size_t n = tostr(js, resolved_key, buf, sizeof(buf)); 6447 + key = js_mkstr(js, buf, n); 6448 + } 6449 + if (is_err(key)) return key; 6450 + } 6451 + 6452 + if (next(js) != TOK_RBRACKET) { 6453 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected after computed property name"); 6454 + } 6455 + } 6456 + } else { 6457 + js->pos = saved_pos; 6458 + js->tok = saved_tok; 6459 + js->consumed = saved_consumed; 6460 + js->toff = saved_toff; 6461 + js->tlen = saved_tlen; 6462 + 6463 + id_off = saved_toff; 6464 + id_len = saved_tlen; 6465 + if (exe) key = js_mkstr_ident(js, js->code + saved_toff, saved_tlen); 6466 + } 6467 + } else { 6468 + id_off = js->toff; 6469 + id_len = js->tlen; 6470 + if (exe) key = js_mkstr_ident(js, js->code + js->toff, js->tlen); 6471 + } 6368 6472 } else if (js->tok == TOK_STRING) { 6369 6473 if (exe) key = js_str_literal(js); 6370 6474 } else if (js->tok == TOK_NUMBER) { ··· 6419 6523 if (is_err(res)) return res; 6420 6524 } 6421 6525 } else if ( 6526 + (is_getter || is_setter) || 6422 6527 (!is_computed && id_len > 0 && next(js) == TOK_LPAREN) || 6423 6528 (is_computed && next(js) == TOK_LPAREN) 6424 6529 ) { ··· 6452 6557 jsval_t scope_key = js_mkstr(js, "__scope", 7); 6453 6558 setprop(js, func_obj, scope_key, js->scope); 6454 6559 jsval_t val = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 6455 - jsval_t res = setprop(js, obj, key, val); 6456 - if (is_err(res)) return res; 6560 + 6561 + if (is_getter || is_setter) { 6562 + js->has_descriptors = true; 6563 + jsoff_t key_len; 6564 + const char *key_str = NULL; 6565 + if (vtype(key) == T_STR) { 6566 + jsoff_t key_off = vstr(js, key, &key_len); 6567 + key_str = (char *)&js->mem[key_off]; 6568 + } 6569 + 6570 + char desc_key[128]; 6571 + if (key_str) { 6572 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)key_len, key_str); 6573 + } else { 6574 + snprintf(desc_key, sizeof(desc_key), "__desc_computed"); 6575 + } 6576 + 6577 + jsoff_t existing_desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 6578 + jsval_t desc_obj; 6579 + if (existing_desc_off != 0) { 6580 + desc_obj = resolveprop(js, mkval(T_PROP, existing_desc_off)); 6581 + } else { 6582 + desc_obj = mkobj(js, 0); 6583 + if (is_err(desc_obj)) return desc_obj; 6584 + } 6585 + 6586 + if (is_getter) { 6587 + setprop(js, desc_obj, js_mkstr(js, "get", 3), val); 6588 + } else { 6589 + setprop(js, desc_obj, js_mkstr(js, "set", 3), val); 6590 + } 6591 + setprop(js, desc_obj, js_mkstr(js, "enumerable", 10), js_mktrue()); 6592 + setprop(js, desc_obj, js_mkstr(js, "configurable", 12), js_mktrue()); 6593 + 6594 + jsval_t desc_key_str = js_mkstr(js, desc_key, strlen(desc_key)); 6595 + setprop(js, obj, desc_key_str, desc_obj); 6596 + 6597 + jsoff_t prop_off = lkp(js, obj, key_str, key_len); 6598 + if (prop_off == 0) { 6599 + setprop(js, obj, key, js_mkundef()); 6600 + } 6601 + } else { 6602 + jsval_t res = setprop(js, obj, key, val); 6603 + if (is_err(res)) return res; 6604 + } 6457 6605 } 6458 6606 } else { 6459 6607 EXPECT(TOK_COLON, );