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.

static classes

+267 -2
+1 -1
meson.build
··· 74 74 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 75 75 76 76 version_conf = configuration_data() 77 - version_conf.set('ANT_VERSION', '0.0.7.24') 77 + version_conf.set('ANT_VERSION', '0.0.7.26') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+139 -1
src/ant.c
··· 5905 5905 uint8_t save_flags = js->flags; 5906 5906 js->flags |= F_NOEXEC; 5907 5907 5908 - typedef struct { jsoff_t name_off, name_len, fn_start, fn_end; bool is_async; } MethodInfo; 5908 + typedef struct { 5909 + jsoff_t name_off, name_len, fn_start, fn_end; 5910 + bool is_async; 5911 + bool is_static; 5912 + bool is_field; 5913 + jsoff_t field_start, field_end; 5914 + } MethodInfo; 5915 + 5909 5916 MethodInfo methods[32]; 5910 5917 int method_count = 0; 5911 5918 5912 5919 while (next(js) != TOK_RBRACE && next(js) != TOK_EOF && method_count < 32) { 5913 5920 bool is_async_method = false; 5921 + bool is_static_member = false; 5922 + 5923 + if (next(js) == TOK_STATIC) { 5924 + is_static_member = true; 5925 + js->consumed = 1; 5926 + } 5914 5927 if (next(js) == TOK_ASYNC) { 5915 5928 is_async_method = true; 5916 5929 js->consumed = 1; ··· 5921 5934 } 5922 5935 jsoff_t method_name_off = js->toff, method_name_len = js->tlen; 5923 5936 js->consumed = 1; 5937 + 5938 + if (next(js) == TOK_ASSIGN) { 5939 + js->consumed = 1; 5940 + jsoff_t field_start = js->pos; 5941 + int depth = 0; 5942 + bool done = false; 5943 + while (!done && next(js) != TOK_EOF) { 5944 + uint8_t tok = next(js); 5945 + if (depth == 0 && (tok == TOK_SEMICOLON || tok == TOK_RBRACE || 5946 + (tok == TOK_IDENTIFIER && js->pos > field_start + 1))) { 5947 + if (tok != TOK_SEMICOLON && tok != TOK_RBRACE) { 5948 + js->consumed = 0; 5949 + } 5950 + done = true; 5951 + } else if (tok == TOK_LPAREN || tok == TOK_LBRACKET || tok == TOK_LBRACE) { 5952 + depth++; 5953 + js->consumed = 1; 5954 + } else if (tok == TOK_RPAREN || tok == TOK_RBRACKET || tok == TOK_RBRACE) { 5955 + if (depth == 0) { 5956 + done = true; 5957 + } else { 5958 + depth--; 5959 + js->consumed = 1; 5960 + } 5961 + } else { 5962 + js->consumed = 1; 5963 + } 5964 + } 5965 + jsoff_t field_end = js->pos; 5966 + if (next(js) == TOK_SEMICOLON) js->consumed = 1; 5967 + 5968 + methods[method_count].name_off = method_name_off; 5969 + methods[method_count].name_len = method_name_len; 5970 + methods[method_count].is_static = is_static_member; 5971 + methods[method_count].is_async = false; 5972 + methods[method_count].is_field = true; 5973 + methods[method_count].field_start = field_start; 5974 + methods[method_count].field_end = field_end; 5975 + methods[method_count].fn_start = 0; 5976 + methods[method_count].fn_end = 0; 5977 + method_count++; 5978 + continue; 5979 + } 5980 + 5981 + if (next(js) == TOK_SEMICOLON || (next(js) != TOK_LPAREN && next(js) == TOK_IDENTIFIER)) { 5982 + if (next(js) == TOK_SEMICOLON) js->consumed = 1; 5983 + methods[method_count].name_off = method_name_off; 5984 + methods[method_count].name_len = method_name_len; 5985 + methods[method_count].is_static = is_static_member; 5986 + methods[method_count].is_async = false; 5987 + methods[method_count].is_field = true; 5988 + methods[method_count].field_start = 0; 5989 + methods[method_count].field_end = 0; 5990 + methods[method_count].fn_start = 0; 5991 + methods[method_count].fn_end = 0; 5992 + method_count++; 5993 + continue; 5994 + } 5995 + 5924 5996 EXPECT(TOK_LPAREN, js->flags = save_flags); 5925 5997 jsoff_t method_params_start = js->pos - 1; 5926 5998 for (bool comma = false; next(js) != TOK_EOF; comma = true) { ··· 5973 6045 methods[method_count].fn_start = method_params_start; 5974 6046 methods[method_count].fn_end = method_body_end; 5975 6047 methods[method_count].is_async = is_async_method; 6048 + methods[method_count].is_static = is_static_member; 6049 + methods[method_count].is_field = false; 6050 + methods[method_count].field_start = 0; 6051 + methods[method_count].field_end = 0; 5976 6052 method_count++; 5977 6053 } 5978 6054 js->consumed = 1; ··· 6029 6105 } 6030 6106 } 6031 6107 for (int i = 0; i < method_count; i++) { 6108 + if (methods[i].is_static) continue; 6109 + if (methods[i].is_field) continue; 6032 6110 if (wp > 0 && wrapper[wp - 1] != ';' && wrapper[wp - 1] != '{') { 6033 6111 wrapper[wp++] = ';'; 6034 6112 } ··· 6086 6164 } 6087 6165 jsval_t x = mkprop(js, js->scope, js_mkstr(js, class_name, class_name_len), constructor, false); 6088 6166 if (is_err(x)) return x; 6167 + 6168 + for (int i = 0; i < method_count; i++) { 6169 + if (!methods[i].is_static) continue; 6170 + 6171 + jsval_t member_name = js_mkstr(js, &js->code[methods[i].name_off], methods[i].name_len); 6172 + if (is_err(member_name)) return member_name; 6173 + 6174 + if (methods[i].is_field) { 6175 + jsval_t field_val = js_mkundef(); 6176 + if (methods[i].field_start > 0 && methods[i].field_end > methods[i].field_start) { 6177 + const char *saved_code = js->code; 6178 + jsoff_t saved_clen = js->clen; 6179 + jsoff_t saved_pos = js->pos; 6180 + uint8_t saved_tok = js->tok; 6181 + uint8_t saved_consumed = js->consumed; 6182 + jsoff_t saved_toff = js->toff; 6183 + jsoff_t saved_tlen = js->tlen; 6184 + 6185 + jsoff_t field_len = methods[i].field_end - methods[i].field_start; 6186 + js->code = &saved_code[methods[i].field_start]; 6187 + js->clen = field_len; 6188 + js->pos = 0; 6189 + js->consumed = 1; 6190 + 6191 + field_val = js_expr(js); 6192 + field_val = resolveprop(js, field_val); 6193 + 6194 + js->code = saved_code; 6195 + js->clen = saved_clen; 6196 + js->pos = saved_pos; 6197 + js->tok = saved_tok; 6198 + js->consumed = saved_consumed; 6199 + js->toff = saved_toff; 6200 + js->tlen = saved_tlen; 6201 + } 6202 + jsval_t set_res = setprop(js, func_obj, member_name, field_val); 6203 + if (is_err(set_res)) return set_res; 6204 + } else { 6205 + jsoff_t mlen = methods[i].fn_end - methods[i].fn_start; 6206 + jsval_t method_code = js_mkstr(js, &js->code[methods[i].fn_start], mlen); 6207 + if (is_err(method_code)) return method_code; 6208 + 6209 + jsval_t method_obj = mkobj(js, 0); 6210 + if (is_err(method_obj)) return method_obj; 6211 + 6212 + jsval_t mcode_key = js_mkstr(js, "__code", 6); 6213 + if (is_err(mcode_key)) return mcode_key; 6214 + jsval_t mres = setprop(js, method_obj, mcode_key, method_code); 6215 + if (is_err(mres)) return mres; 6216 + 6217 + jsval_t mscope_key = js_mkstr(js, "__scope", 7); 6218 + if (is_err(mscope_key)) return mscope_key; 6219 + jsval_t mscope_res = setprop(js, method_obj, mscope_key, func_scope); 6220 + if (is_err(mscope_res)) return mscope_res; 6221 + 6222 + jsval_t method_func = mkval(T_FUNC, (unsigned long) vdata(method_obj)); 6223 + jsval_t set_res = setprop(js, func_obj, member_name, method_func); 6224 + if (is_err(set_res)) return set_res; 6225 + } 6226 + } 6089 6227 6090 6228 (void) class_body_start; 6091 6229 return constructor;
+127
tests/test_static.js
··· 1 + let passed = 0; 2 + let failed = 0; 3 + 4 + function test(name, actual, expected) { 5 + if (actual === expected) { 6 + console.log('PASS:', name); 7 + passed++; 8 + } else { 9 + console.log('FAIL:', name, '- expected', expected, 'got', actual); 10 + failed++; 11 + } 12 + } 13 + 14 + console.log('=== Static Properties ==='); 15 + 16 + class ClassWithStaticProperty { 17 + static staticProperty = "someValue"; 18 + } 19 + 20 + test('static property access', ClassWithStaticProperty.staticProperty, "someValue"); 21 + 22 + console.log('\n=== Static Methods ==='); 23 + 24 + class ClassWithStaticMethod { 25 + static staticMethod() { 26 + return "static method called"; 27 + } 28 + } 29 + 30 + test('static method call', ClassWithStaticMethod.staticMethod(), "static method called"); 31 + 32 + console.log('\n=== Static and Instance Together ==='); 33 + 34 + class Triple { 35 + static customName = "Tripler"; 36 + static description = "I triple any number you provide"; 37 + 38 + static calculate(n) { 39 + return n * 3; 40 + } 41 + 42 + constructor(value) { 43 + this.value = value; 44 + } 45 + 46 + getValue() { 47 + return this.value; 48 + } 49 + } 50 + 51 + test('static property customName', Triple.customName, "Tripler"); 52 + test('static property description', Triple.description, "I triple any number you provide"); 53 + test('static method calculate(1)', Triple.calculate(1), 3); 54 + test('static method calculate(6)', Triple.calculate(6), 18); 55 + 56 + let t = new Triple(42); 57 + test('instance property', t.getValue(), 42); 58 + 59 + console.log('\n=== Static Not on Instance ==='); 60 + 61 + test('static not on instance', t.customName, undefined); 62 + test('static method not on instance', t.calculate, undefined); 63 + 64 + console.log('\n=== Subclass with Static ==='); 65 + 66 + class SquaredTriple extends Triple { 67 + static description = "I square the triple of any number you provide"; 68 + 69 + static calculate(n) { 70 + return super.calculate(n) * super.calculate(n); 71 + } 72 + } 73 + 74 + test('subclass static calculate(3)', SquaredTriple.calculate(3), 81); 75 + test('subclass overrides static description', SquaredTriple.description, "I square the triple of any number you provide"); 76 + 77 + console.log('\n=== Static with this reference ==='); 78 + 79 + class StaticMethodCall { 80 + static staticProperty = "static property"; 81 + 82 + static staticMethod() { 83 + return "Static method and " + this.staticProperty + " has been called"; 84 + } 85 + 86 + static anotherStaticMethod() { 87 + return this.staticMethod() + " from another static method"; 88 + } 89 + } 90 + 91 + test('static method using this.staticProperty', StaticMethodCall.staticMethod(), "Static method and static property has been called"); 92 + test('static method calling another static method', StaticMethodCall.anotherStaticMethod(), "Static method and static property has been called from another static method"); 93 + 94 + console.log('\n=== Static Field Without Initializer ==='); 95 + 96 + class ClassWithUndefinedStatic { 97 + static undefinedField; 98 + static definedField = "defined"; 99 + } 100 + 101 + test('static field without initializer', ClassWithUndefinedStatic.undefinedField, undefined); 102 + test('static field with initializer', ClassWithUndefinedStatic.definedField, "defined"); 103 + 104 + console.log('\n=== Static with Computed Values ==='); 105 + 106 + class MathHelper { 107 + static PI = 3.14159; 108 + static TWO_PI = 3.14159 * 2; 109 + 110 + static circleArea(r) { 111 + return this.PI * r * r; 112 + } 113 + } 114 + 115 + test('static computed value TWO_PI', MathHelper.TWO_PI, 3.14159 * 2); 116 + test('static method using static property', MathHelper.circleArea(1), 3.14159); 117 + 118 + console.log('\n=== Summary ==='); 119 + console.log('Passed:', passed); 120 + console.log('Failed:', failed); 121 + console.log('Total:', passed + failed); 122 + 123 + if (failed > 0) { 124 + console.log('\nSome tests FAILED!'); 125 + } else { 126 + console.log('\nAll tests PASSED!'); 127 + }