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.

for-of and -e

+325 -6
+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.22') 77 + version_conf.set('ANT_VERSION', '0.0.7.23') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+133 -1
src/ant.c
··· 234 234 TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE, TOK_LBRACKET, TOK_RBRACKET, 235 235 TOK_ASYNC = 50, TOK_AWAIT, TOK_BREAK, TOK_CASE, TOK_CATCH, TOK_CLASS, TOK_CONST, TOK_CONTINUE, 236 236 TOK_DEFAULT, TOK_DELETE, TOK_DO, TOK_ELSE, TOK_EXPORT, TOK_FINALLY, TOK_FOR, TOK_FROM, TOK_FUNC, 237 - TOK_IF, TOK_IMPORT, TOK_IN, TOK_INSTANCEOF, TOK_LET, TOK_NEW, TOK_RETURN, TOK_SWITCH, 237 + TOK_IF, TOK_IMPORT, TOK_IN, TOK_INSTANCEOF, TOK_LET, TOK_NEW, TOK_OF, TOK_RETURN, TOK_SWITCH, 238 238 TOK_THIS, TOK_THROW, TOK_TRY, TOK_VAR, TOK_VOID, TOK_WHILE, TOK_WITH, 239 239 TOK_YIELD, TOK_UNDEF, TOK_NULL, TOK_TRUE, TOK_FALSE, TOK_AS, TOK_STATIC, 240 240 TOK_DOT = 100, TOK_CALL, TOK_BRACKET, TOK_POSTINC, TOK_POSTDEC, TOK_NOT, TOK_TILDA, ··· 1695 1695 case 'i': if (streq("if", 2, buf, len)) return TOK_IF; if (streq("import", 6, buf, len)) return TOK_IMPORT; if (streq("in", 2, buf, len)) return TOK_IN; if (streq("instanceof", 10, buf, len)) return TOK_INSTANCEOF; break; 1696 1696 case 'l': if (streq("let", 3, buf, len)) return TOK_LET; break; 1697 1697 case 'n': if (streq("new", 3, buf, len)) return TOK_NEW; if (streq("null", 4, buf, len)) return TOK_NULL; break; 1698 + case 'o': if (streq("of", 2, buf, len)) return TOK_OF; break; 1698 1699 case 'r': if (streq("return", 6, buf, len)) return TOK_RETURN; break; 1699 1700 case 's': if (streq("switch", 6, buf, len)) return TOK_SWITCH; if (streq("static", 6, buf, len)) return TOK_STATIC; break; 1700 1701 case 't': if (streq("try", 3, buf, len)) return TOK_TRY; if (streq("this", 4, buf, len)) return TOK_THIS; if (streq("throw", 5, buf, len)) return TOK_THROW; if (streq("true", 4, buf, len)) return TOK_TRUE; if (streq("typeof", 6, buf, len)) return TOK_TYPEOF; break; ··· 4520 4521 if (!expect(js, TOK_LPAREN, &res)) goto done; 4521 4522 4522 4523 bool is_for_in = false; 4524 + bool is_for_of = false; 4523 4525 jsoff_t var_name_off = 0, var_name_len = 0; 4524 4526 bool is_const_var = false; 4525 4527 ··· 4538 4540 js->consumed = 1; 4539 4541 if (next(js) == TOK_IN) { 4540 4542 is_for_in = true; 4543 + js->consumed = 1; 4544 + } else if (next(js) == TOK_OF) { 4545 + is_for_of = true; 4541 4546 js->consumed = 1; 4542 4547 } else { 4543 4548 js->pos = var_name_off; ··· 4556 4561 js->consumed = 1; 4557 4562 if (next(js) == TOK_IN) { 4558 4563 is_for_in = true; 4564 + js->consumed = 1; 4565 + } else if (next(js) == TOK_OF) { 4566 + is_for_of = true; 4559 4567 js->consumed = 1; 4560 4568 } else { 4561 4569 js->pos = var_name_off; ··· 4627 4635 } 4628 4636 4629 4637 prop_off = loadoff(js, prop_off) & ~(3U | CONSTMASK); 4638 + } 4639 + } 4640 + 4641 + js->pos = body_end; 4642 + js->tok = TOK_SEMICOLON; 4643 + js->consumed = 0; 4644 + goto done; 4645 + } 4646 + 4647 + if (is_for_of) { 4648 + jsval_t iter_expr = js_expr(js); 4649 + if (is_err2(&iter_expr, &res)) goto done; 4650 + if (!expect(js, TOK_RPAREN, &res)) goto done; 4651 + 4652 + jsoff_t body_start = js->pos; 4653 + js->flags |= F_NOEXEC; 4654 + v = js_block_or_stmt(js); 4655 + if (is_err2(&v, &res)) goto done; 4656 + jsoff_t body_end = js->pos; 4657 + 4658 + if (exe) { 4659 + jsval_t iterable = resolveprop(js, iter_expr); 4660 + uint8_t itype = vtype(iterable); 4661 + 4662 + if (itype == T_ARR) { 4663 + jsoff_t next_prop = loadoff(js, (jsoff_t) vdata(iterable)) & ~(3U | CONSTMASK); 4664 + jsoff_t length = 0; 4665 + jsoff_t scan = next_prop; 4666 + 4667 + while (scan < js->brk && scan != 0) { 4668 + jsoff_t koff = loadoff(js, scan + (jsoff_t) sizeof(scan)); 4669 + jsoff_t klen = offtolen(loadoff(js, koff)); 4670 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 4671 + 4672 + if (streq(key, klen, "length", 6)) { 4673 + jsval_t val = loadval(js, scan + (jsoff_t) (sizeof(scan) + sizeof(koff))); 4674 + if (vtype(val) == T_NUM) length = (jsoff_t) tod(val); 4675 + break; 4676 + } 4677 + scan = loadoff(js, scan) & ~(3U | CONSTMASK); 4678 + } 4679 + 4680 + for (jsoff_t i = 0; i < length; i++) { 4681 + char idx[16]; 4682 + snprintf(idx, sizeof(idx), "%u", (unsigned) i); 4683 + jsoff_t idxlen = (jsoff_t) strlen(idx); 4684 + jsoff_t prop = next_prop; 4685 + jsval_t val = js_mkundef(); 4686 + 4687 + while (prop < js->brk && prop != 0) { 4688 + jsoff_t koff = loadoff(js, prop + (jsoff_t) sizeof(prop)); 4689 + jsoff_t klen = offtolen(loadoff(js, koff)); 4690 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 4691 + if (streq(key, klen, idx, idxlen)) { 4692 + val = loadval(js, prop + (jsoff_t) (sizeof(prop) + sizeof(koff))); 4693 + break; 4694 + } 4695 + prop = loadoff(js, prop) & ~(3U | CONSTMASK); 4696 + } 4697 + 4698 + const char *var_name = &js->code[var_name_off]; 4699 + jsoff_t existing = lkp(js, js->scope, var_name, var_name_len); 4700 + if (existing > 0) { 4701 + saveval(js, existing + sizeof(jsoff_t) * 2, val); 4702 + } else { 4703 + jsval_t x = mkprop(js, js->scope, js_mkstr(js, var_name, var_name_len), val, is_const_var); 4704 + if (is_err(x)) { 4705 + res = x; 4706 + goto done; 4707 + } 4708 + } 4709 + 4710 + js->pos = body_start; 4711 + js->consumed = 1; 4712 + js->flags = (flags & ~F_NOEXEC) | F_LOOP; 4713 + v = js_block_or_stmt(js); 4714 + if (is_err(v)) { 4715 + res = v; 4716 + goto done; 4717 + } 4718 + 4719 + if (js->flags & F_BREAK) break; 4720 + if (js->flags & F_RETURN) { 4721 + res = v; 4722 + goto done; 4723 + } 4724 + } 4725 + } else if (itype == T_STR) { 4726 + jsoff_t slen, soff = vstr(js, iterable, &slen); 4727 + const char *str = (char *) &js->mem[soff]; 4728 + 4729 + for (jsoff_t i = 0; i < slen; i++) { 4730 + jsval_t char_str = js_mkstr(js, &str[i], 1); 4731 + 4732 + const char *var_name = &js->code[var_name_off]; 4733 + jsoff_t existing = lkp(js, js->scope, var_name, var_name_len); 4734 + if (existing > 0) { 4735 + saveval(js, existing + sizeof(jsoff_t) * 2, char_str); 4736 + } else { 4737 + jsval_t x = mkprop(js, js->scope, js_mkstr(js, var_name, var_name_len), char_str, is_const_var); 4738 + if (is_err(x)) { 4739 + res = x; 4740 + goto done; 4741 + } 4742 + } 4743 + 4744 + js->pos = body_start; 4745 + js->consumed = 1; 4746 + js->flags = (flags & ~F_NOEXEC) | F_LOOP; 4747 + v = js_block_or_stmt(js); 4748 + if (is_err(v)) { 4749 + res = v; 4750 + goto done; 4751 + } 4752 + 4753 + if (js->flags & F_BREAK) break; 4754 + if (js->flags & F_RETURN) { 4755 + res = v; 4756 + goto done; 4757 + } 4758 + } 4759 + } else { 4760 + res = js_mkerr(js, "for-of requires iterable"); 4761 + goto done; 4630 4762 } 4631 4763 } 4632 4764
+28 -4
src/main.c
··· 25 25 26 26 int js_result = EXIT_SUCCESS; 27 27 28 + static void eval_code(struct js *js, struct arg_str *eval, struct arg_lit *print) { 29 + const char *script = eval->sval[0]; 30 + size_t len = strlen(script); 31 + 32 + js_set_filename(js, "<eval>"); 33 + js_mkscope(js); 34 + js_protect_init_memory(js); 35 + 36 + jsval_t result = js_eval(js, script, len); 37 + 38 + if (js_type(result) == JS_ERR) { 39 + fprintf(stderr, "%s\n", js_str(js, result)); 40 + js_result = EXIT_FAILURE; 41 + } else if (print->count > 0) { 42 + const char *str = js_str(js, result); 43 + if (str && strcmp(str, "undefined") != 0) printf("%s\n", str); 44 + } 45 + 46 + js_run_event_loop(js); 47 + } 48 + 28 49 static int execute_module(struct js *js, const char *filename) { 29 50 char *filename_copy = strdup(filename); 30 51 char *dir = dirname(filename_copy); ··· 76 97 struct arg_lit *help = arg_lit0("h", "help", "display this help and exit"); 77 98 struct arg_lit *version = arg_lit0("v", "version", "display version information and exit"); 78 99 struct arg_lit *debug = arg_litn("d", "debug", 0, 10, "dump VM state (can be repeated for more detail)"); 100 + struct arg_str *eval = arg_str0("e", "eval", "<script>", "evaluate script"); 101 + struct arg_lit *print = arg_lit0("p", "print", "evaluate script and print result"); 79 102 struct arg_int *gct = arg_int0(NULL, "gct", "<threshold>", "set garbage collection threshold"); 80 103 struct arg_int *initial_mem = arg_int0(NULL, "initial-mem", "<size>", "initial memory size in MB (default: 4)"); 81 104 struct arg_int *max_mem = arg_int0(NULL, "max-mem", "<size>", "maximum memory size in MB (default: 512)"); 82 105 struct arg_file *file = arg_file0(NULL, NULL, "<module.js>", "JavaScript module file to execute"); 83 106 struct arg_end *end = arg_end(20); 84 107 85 - void *argtable[] = {help, version, debug, gct, initial_mem, max_mem, file, end}; 108 + void *argtable[] = {help, version, debug, eval, print, gct, initial_mem, max_mem, file, end}; 86 109 int nerrors = arg_parse(argc, argv, argtable); 87 110 88 111 if (help->count > 0) { ··· 108 131 return EXIT_FAILURE; 109 132 } 110 133 111 - bool repl_mode = (file->count == 0); 112 - const char *module_file = repl_mode ? NULL : file->filename[0]; 134 + bool repl_mode = (file->count == 0 && eval->count == 0); 135 + const char *module_file = repl_mode ? NULL : (file->count > 0 ? file->filename[0] : NULL); 113 136 dump = debug->count; 114 137 115 138 size_t initial_size = 4 * 1024 * 1024; ··· 144 167 ant_register_library("ant:path", path_library); 145 168 ant_register_library("ant:ffi", ffi_library); 146 169 147 - if (repl_mode) ant_repl_run(); else { 170 + if (eval->count > 0) eval_code(js, eval, print); 171 + else if (repl_mode) ant_repl_run(); else { 148 172 js_result = execute_module(js, module_file); 149 173 js_run_event_loop(js); 150 174 }
+2
src/repl.c
··· 191 191 192 192 void ant_repl_run() { 193 193 struct js *js = rt->js; 194 + 195 + js_mkscope(js); 194 196 js_protect_init_memory(js); 195 197 196 198 printf("Welcome to Ant JavaScript v%s\n", ANT_VERSION);
+161
tests/for_of.cjs
··· 1 + // Test for-of loop functionality 2 + 3 + console.log("=== For-Of Loop Tests ===\n"); 4 + 5 + // Test 1: Basic for-of with array 6 + console.log("Test 1: Basic for-of with array"); 7 + const fruits = ["apple", "banana", "cherry"]; 8 + let collected = []; 9 + for (const fruit of fruits) { 10 + collected.push(fruit); 11 + } 12 + console.log(" Collected:", collected); 13 + 14 + // Test 2: for-of with Object.keys() 15 + console.log("\nTest 2: for-of with Object.keys()"); 16 + const person = { name: "Alice", age: 30, city: "NYC" }; 17 + let keys = []; 18 + for (const key of Object.keys(person)) { 19 + keys.push(key); 20 + } 21 + console.log(" Keys:", keys); 22 + 23 + // Test 3: for-of with Object.keys() accessing values 24 + console.log("\nTest 3: for-of accessing object values"); 25 + const scores = { math: 95, english: 88, science: 92 }; 26 + let total = 0; 27 + for (const key of Object.keys(scores)) { 28 + console.log(" " + key + ":", scores[key]); 29 + total = total + scores[key]; 30 + } 31 + console.log(" Total:", total); 32 + 33 + // Test 4: for-of with let (mutable variable) 34 + console.log("\nTest 4: for-of with let"); 35 + const numbers = [1, 2, 3, 4, 5]; 36 + let sum = 0; 37 + for (let num of numbers) { 38 + num = num * 2; 39 + sum = sum + num; 40 + } 41 + console.log(" Sum of doubled:", sum); 42 + 43 + // Test 5: for-of with string iteration 44 + console.log("\nTest 5: for-of with string"); 45 + const str = "hello"; 46 + let chars = []; 47 + for (const char of str) { 48 + chars.push(char); 49 + } 50 + console.log(" Characters:", chars); 51 + 52 + // Test 6: Nested for-of loops 53 + console.log("\nTest 6: Nested for-of loops"); 54 + const matrix = [[1, 2], [3, 4], [5, 6]]; 55 + let flatSum = 0; 56 + for (const row of matrix) { 57 + for (const val of row) { 58 + flatSum = flatSum + val; 59 + } 60 + } 61 + console.log(" Matrix sum:", flatSum); 62 + 63 + // Test 7: for-of with break 64 + console.log("\nTest 7: for-of with break"); 65 + const items = [10, 20, 30, 40, 50]; 66 + let breakSum = 0; 67 + for (const item of items) { 68 + if (item > 25) { 69 + console.log(" Breaking at:", item); 70 + break; 71 + } 72 + breakSum = breakSum + item; 73 + } 74 + console.log(" Sum before break:", breakSum); 75 + 76 + // Test 8: for-of with continue 77 + console.log("\nTest 8: for-of with continue"); 78 + const mixed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 79 + let evenSum = 0; 80 + for (const n of mixed) { 81 + if (n % 2 === 1) { 82 + continue; 83 + } 84 + evenSum = evenSum + n; 85 + } 86 + console.log(" Sum of evens:", evenSum); 87 + 88 + // Test 9: for-of in function with return 89 + console.log("\nTest 9: for-of with return"); 90 + function findValue(arr, target) { 91 + for (const val of arr) { 92 + if (val === target) { 93 + return true; 94 + } 95 + } 96 + return false; 97 + } 98 + console.log(" Contains 30:", findValue([10, 20, 30, 40], 30)); 99 + console.log(" Contains 99:", findValue([10, 20, 30, 40], 99)); 100 + 101 + // Test 10: for-of with empty array 102 + console.log("\nTest 10: for-of with empty array"); 103 + const empty = []; 104 + let emptyCount = 0; 105 + for (const x of empty) { 106 + emptyCount = emptyCount + 1; 107 + } 108 + console.log(" Iterations on empty:", emptyCount); 109 + 110 + // Test 11: for-of building new array 111 + console.log("\nTest 11: for-of building new array"); 112 + const source = [1, 2, 3, 4, 5]; 113 + const squared = []; 114 + for (const n of source) { 115 + squared.push(n * n); 116 + } 117 + console.log(" Squared:", squared); 118 + 119 + // Test 12: for-of with complex objects in array 120 + console.log("\nTest 12: for-of with objects in array"); 121 + const users = [ 122 + { id: 1, name: "Alice" }, 123 + { id: 2, name: "Bob" }, 124 + { id: 3, name: "Charlie" } 125 + ]; 126 + let names = []; 127 + for (const user of users) { 128 + names.push(user.name); 129 + } 130 + console.log(" Names:", names); 131 + 132 + // Test 13: for-of with Object.keys() building result object 133 + console.log("\nTest 13: for-of building result object"); 134 + const original = { a: 1, b: 2, c: 3 }; 135 + const doubled = {}; 136 + for (const key of Object.keys(original)) { 137 + doubled[key] = original[key] * 2; 138 + } 139 + console.log(" Doubled object:", doubled); 140 + 141 + // Test 14: for-of scope isolation 142 + console.log("\nTest 14: for-of scope isolation"); 143 + const vals = [100, 200, 300]; 144 + const results = []; 145 + for (const v of vals) { 146 + const computed = v / 10; 147 + results.push(computed); 148 + } 149 + console.log(" Results:", results); 150 + 151 + // Test 15: Chained for-of operations 152 + console.log("\nTest 15: Chained for-of"); 153 + const data = { x: 10, y: 20, z: 30 }; 154 + const dataKeys = Object.keys(data); 155 + let product = 1; 156 + for (const k of dataKeys) { 157 + product = product * data[k]; 158 + } 159 + console.log(" Product of values:", product); 160 + 161 + console.log("\n=== All for-of tests completed ===");