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 proper module snapshot support

+378 -25
+2 -1
include/snapshot.h
··· 1 1 #ifndef ANT_SNAPSHOT_LOADER_H 2 2 #define ANT_SNAPSHOT_LOADER_H 3 3 4 + #include <stdint.h> 4 5 #include "ant.h" 5 6 6 7 jsval_t ant_load_snapshot(struct js *js); 7 - const char *ant_get_snapshot_source(size_t *len); 8 + const uint8_t *ant_get_snapshot_source(size_t *len); 8 9 9 10 #endif
+1 -1
meson.build
··· 44 44 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 45 45 46 46 version_conf = configuration_data() 47 - version_conf.set('ANT_VERSION', '0.0.6.14') 47 + version_conf.set('ANT_VERSION', '0.0.6.15') 48 48 version_conf.set('ANT_GIT_HASH', git_hash) 49 49 version_conf.set('ANT_BUILD_DATE', build_date) 50 50
+2
src/core/index.js
··· 1 1 Ant.version = '{{VERSION}}'; 2 2 Ant.revision = '{{GIT_HASH}}'; 3 3 Ant.buildDate = '{{BUILD_DATE}}'; 4 + 5 + Ant.meow = snapshot_include('./meow.js').meow;
+1
src/core/meow.js
··· 1 + export const meow = 'meow';
+2 -2
src/snapshot.c
··· 6 6 7 7 jsval_t ant_load_snapshot(struct js *js) { 8 8 if (!js) return js_mkerr(js, "invalid js runtime"); 9 - jsval_t result = js_eval(js, ant_snapshot_source, ant_snapshot_source_len); 9 + jsval_t result = js_eval(js, (const char *)ant_snapshot_source, ant_snapshot_source_len); 10 10 11 11 if (js_type(result) == JS_ERR) return result; 12 12 return js_mktrue(); 13 13 } 14 14 15 - const char *ant_get_snapshot_source(size_t *len) { 15 + const uint8_t *ant_get_snapshot_source(size_t *len) { 16 16 if (len) *len = ant_snapshot_source_len; 17 17 return ant_snapshot_source; 18 18 }
+370 -21
src/tools/gen_snapshot.c
··· 1 1 #include <stdio.h> 2 2 #include <stdlib.h> 3 3 #include <string.h> 4 + #include <libgen.h> 5 + #include <limits.h> 4 6 5 7 #include "ant.h" 6 8 #include "runtime.h" ··· 10 12 char *value; 11 13 } replacement_t; 12 14 15 + typedef struct { 16 + char **paths; 17 + int count; 18 + int capacity; 19 + } module_cache_t; 20 + 21 + static char *resolve_path(const char *base_path, const char *import_path) { 22 + char *resolved = malloc(PATH_MAX); 23 + if (!resolved) return NULL; 24 + 25 + char *base_dir = strdup(base_path); 26 + char *dir = dirname(base_dir); 27 + 28 + snprintf(resolved, PATH_MAX, "%s/%s", dir, import_path); 29 + free(base_dir); 30 + 31 + return resolved; 32 + } 33 + 34 + static char *read_file(const char *path, size_t *len) { 35 + FILE *f = fopen(path, "r"); 36 + if (!f) return NULL; 37 + 38 + fseek(f, 0, SEEK_END); 39 + long size = ftell(f); 40 + fseek(f, 0, SEEK_SET); 41 + 42 + char *content = malloc(size + 1); 43 + if (!content) { 44 + fclose(f); 45 + return NULL; 46 + } 47 + 48 + fread(content, 1, size, f); 49 + content[size] = '\0'; 50 + fclose(f); 51 + 52 + if (len) *len = size; 53 + return content; 54 + } 55 + 56 + static int module_already_processed(module_cache_t *cache, const char *path) { 57 + for (int i = 0; i < cache->count; i++) { 58 + if (strcmp(cache->paths[i], path) == 0) { 59 + return 1; 60 + } 61 + } 62 + return 0; 63 + } 64 + 65 + static void add_to_cache(module_cache_t *cache, const char *path) { 66 + if (cache->count >= cache->capacity) { 67 + cache->capacity = cache->capacity == 0 ? 10 : cache->capacity * 2; 68 + cache->paths = realloc(cache->paths, sizeof(char *) * cache->capacity); 69 + } 70 + 71 + cache->paths[cache->count] = strdup(path); 72 + cache->count++; 73 + } 74 + 75 + static char *process_snapshot_includes(const char *file_path, const char *content, size_t content_len, module_cache_t *cache, size_t *output_len); 76 + 77 + static char *wrap_module(const char *content, size_t content_len, size_t *output_len) { 78 + size_t output_capacity = content_len + 1024; 79 + char *output = malloc(output_capacity); 80 + if (!output) return NULL; 81 + 82 + size_t output_pos = 0; 83 + const char *pos = content; 84 + const char *end = content + content_len; 85 + 86 + const char *iife_start = "(function() {\n"; 87 + memcpy(output + output_pos, iife_start, strlen(iife_start)); 88 + output_pos += strlen(iife_start); 89 + 90 + char **exports = NULL; 91 + int export_count = 0; 92 + int export_capacity = 0; 93 + 94 + while (pos < end) { 95 + const char *export_start = strstr(pos, "export "); 96 + if (!export_start || export_start >= end) { 97 + size_t remaining = end - pos; 98 + if (output_pos + remaining >= output_capacity) { 99 + output_capacity = (output_pos + remaining) * 2; 100 + output = realloc(output, output_capacity); 101 + } 102 + memcpy(output + output_pos, pos, remaining); 103 + output_pos += remaining; 104 + break; 105 + } 106 + 107 + memcpy(output + output_pos, pos, export_start - pos); 108 + output_pos += export_start - pos; 109 + 110 + const char *decl_start = export_start + 7; 111 + while (*decl_start == ' ') decl_start++; 112 + 113 + const char *const_pos = strstr(decl_start, "const "); 114 + const char *let_pos = strstr(decl_start, "let "); 115 + const char *var_pos = strstr(decl_start, "var "); 116 + const char *function_pos = strstr(decl_start, "function "); 117 + 118 + const char *keyword_start = NULL; 119 + const char *name_start = NULL; 120 + 121 + if (const_pos == decl_start) { 122 + keyword_start = const_pos; 123 + name_start = const_pos + 6; 124 + } else if (let_pos == decl_start) { 125 + keyword_start = let_pos; 126 + name_start = let_pos + 4; 127 + } else if (var_pos == decl_start) { 128 + keyword_start = var_pos; 129 + name_start = var_pos + 4; 130 + } else if (function_pos == decl_start) { 131 + keyword_start = function_pos; 132 + name_start = function_pos + 9; 133 + } 134 + 135 + if (keyword_start) { 136 + while (*name_start == ' ') name_start++; 137 + 138 + const char *name_end = name_start; 139 + while (*name_end && (*name_end == '_' || (*name_end >= 'a' && *name_end <= 'z') || 140 + (*name_end >= 'A' && *name_end <= 'Z') || (*name_end >= '0' && *name_end <= '9'))) { 141 + name_end++; 142 + } 143 + 144 + size_t name_len = name_end - name_start; 145 + if (name_len > 0) { 146 + if (export_count >= export_capacity) { 147 + export_capacity = export_capacity == 0 ? 10 : export_capacity * 2; 148 + exports = realloc(exports, sizeof(char *) * export_capacity); 149 + } 150 + 151 + exports[export_count] = malloc(name_len + 1); 152 + memcpy(exports[export_count], name_start, name_len); 153 + exports[export_count][name_len] = '\0'; 154 + export_count++; 155 + } 156 + 157 + const char *stmt_start = keyword_start; 158 + const char *line_end = strchr(export_start, ';'); 159 + if (!line_end) line_end = strchr(export_start, '\n'); 160 + if (line_end) { 161 + size_t stmt_len = line_end - stmt_start + 1; 162 + if (output_pos + stmt_len >= output_capacity) { 163 + output_capacity = (output_pos + stmt_len) * 2; 164 + output = realloc(output, output_capacity); 165 + } 166 + memcpy(output + output_pos, stmt_start, stmt_len); 167 + output_pos += stmt_len; 168 + pos = line_end + 1; 169 + } else { 170 + pos = export_start + 7; 171 + } 172 + } else { 173 + pos = export_start + 7; 174 + } 175 + } 176 + 177 + if (export_count > 0) { 178 + const char *return_start = "\nreturn { "; 179 + if (output_pos + strlen(return_start) >= output_capacity) { 180 + output_capacity = (output_pos + strlen(return_start) + 1024) * 2; 181 + output = realloc(output, output_capacity); 182 + } 183 + memcpy(output + output_pos, return_start, strlen(return_start)); 184 + output_pos += strlen(return_start); 185 + 186 + for (int i = 0; i < export_count; i++) { 187 + size_t name_len = strlen(exports[i]); 188 + 189 + if (output_pos + name_len * 2 + 10 >= output_capacity) { 190 + output_capacity = (output_pos + name_len * 2 + 10) * 2; 191 + output = realloc(output, output_capacity); 192 + } 193 + 194 + memcpy(output + output_pos, exports[i], name_len); 195 + output_pos += name_len; 196 + 197 + if (i < export_count - 1) { 198 + memcpy(output + output_pos, ", ", 2); 199 + output_pos += 2; 200 + } 201 + } 202 + 203 + const char *return_end = " };\n})()"; 204 + memcpy(output + output_pos, return_end, strlen(return_end)); 205 + output_pos += strlen(return_end); 206 + } else { 207 + const char *iife_end = "})()"; 208 + memcpy(output + output_pos, iife_end, strlen(iife_end)); 209 + output_pos += strlen(iife_end); 210 + } 211 + 212 + for (int i = 0; i < export_count; i++) { 213 + free(exports[i]); 214 + } 215 + free(exports); 216 + 217 + output[output_pos] = '\0'; 218 + *output_len = output_pos; 219 + return output; 220 + } 221 + 222 + static char *process_snapshot_includes(const char *file_path, const char *content, size_t content_len, module_cache_t *cache, size_t *output_len) { 223 + size_t output_capacity = content_len * 2; 224 + char *output = malloc(output_capacity); 225 + if (!output) return NULL; 226 + 227 + size_t output_pos = 0; 228 + const char *pos = content; 229 + const char *end = content + content_len; 230 + 231 + while (pos < end) { 232 + const char *include_start = strstr(pos, "snapshot_include("); 233 + if (!include_start || include_start >= end) { 234 + size_t remaining = end - pos; 235 + if (output_pos + remaining >= output_capacity) { 236 + output_capacity = (output_pos + remaining) * 2; 237 + output = realloc(output, output_capacity); 238 + } 239 + memcpy(output + output_pos, pos, remaining); 240 + output_pos += remaining; 241 + break; 242 + } 243 + 244 + memcpy(output + output_pos, pos, include_start - pos); 245 + output_pos += include_start - pos; 246 + 247 + const char *quote_start = strchr(include_start, '\''); 248 + if (!quote_start) quote_start = strchr(include_start, '"'); 249 + if (!quote_start) { 250 + pos = include_start + 17; 251 + continue; 252 + } 253 + 254 + char quote_char = *quote_start; 255 + const char *quote_end = strchr(quote_start + 1, quote_char); 256 + if (!quote_end) { 257 + pos = include_start + 17; 258 + continue; 259 + } 260 + 261 + size_t path_len = quote_end - quote_start - 1; 262 + char *import_path = malloc(path_len + 1); 263 + memcpy(import_path, quote_start + 1, path_len); 264 + import_path[path_len] = '\0'; 265 + 266 + char *resolved_path = resolve_path(file_path, import_path); 267 + free(import_path); 268 + 269 + if (!resolved_path) { 270 + pos = include_start + 17; 271 + continue; 272 + } 273 + 274 + if (module_already_processed(cache, resolved_path)) { 275 + fprintf(stderr, "Warning: Circular dependency detected: %s\n", resolved_path); 276 + free(resolved_path); 277 + pos = quote_end + 2; 278 + continue; 279 + } 280 + 281 + add_to_cache(cache, resolved_path); 282 + 283 + size_t module_len; 284 + char *module_content = read_file(resolved_path, &module_len); 285 + 286 + if (!module_content) { 287 + fprintf(stderr, "Error: Cannot read module: %s\n", resolved_path); 288 + free(resolved_path); 289 + free(output); 290 + return NULL; 291 + } 292 + 293 + size_t processed_len; 294 + char *processed = process_snapshot_includes(resolved_path, module_content, module_len, cache, &processed_len); 295 + free(module_content); 296 + 297 + if (!processed) { 298 + free(resolved_path); 299 + free(output); 300 + return NULL; 301 + } 302 + 303 + size_t wrapped_len; 304 + char *wrapped = wrap_module(processed, processed_len, &wrapped_len); 305 + free(processed); 306 + free(resolved_path); 307 + 308 + if (!wrapped) { 309 + free(output); 310 + return NULL; 311 + } 312 + 313 + if (output_pos + wrapped_len >= output_capacity) { 314 + output_capacity = (output_pos + wrapped_len) * 2; 315 + output = realloc(output, output_capacity); 316 + } 317 + 318 + memcpy(output + output_pos, wrapped, wrapped_len); 319 + output_pos += wrapped_len; 320 + free(wrapped); 321 + 322 + const char *paren_close = strchr(quote_end, ')'); 323 + if (paren_close) { 324 + pos = paren_close + 1; 325 + } else { 326 + pos = quote_end + 1; 327 + } 328 + } 329 + 330 + output[output_pos] = '\0'; 331 + *output_len = output_pos; 332 + return output; 333 + } 334 + 13 335 static char *replace_templates(const char *input, size_t input_len, replacement_t *replacements, int num_replacements, size_t *output_len) { 14 336 size_t output_size = input_len; 15 337 ··· 127 449 js_code_original[file_size] = '\0'; 128 450 fclose(in); 129 451 452 + module_cache_t cache = {0}; 453 + 454 + size_t bundled_len; 455 + char *bundled_code = process_snapshot_includes(input_file, js_code_original, file_size, &cache, &bundled_len); 456 + 457 + if (!bundled_code) { 458 + fprintf(stderr, "Error: Module bundling failed\n"); 459 + free(js_code_original); 460 + return 1; 461 + } 462 + 130 463 size_t processed_len; 131 - char *js_code = replace_templates(js_code_original, file_size, replacements, num_replacements, &processed_len); 464 + char *js_code = replace_templates(bundled_code, bundled_len, replacements, num_replacements, &processed_len); 132 465 133 466 if (!js_code) { 134 467 fprintf(stderr, "Error: Template replacement failed\n"); 135 468 free(js_code_original); 469 + free(bundled_code); 136 470 return 1; 137 471 } 138 472 139 473 free(js_code_original); 474 + free(bundled_code); 475 + 476 + char *compacted = malloc(processed_len + 1); 477 + if (!compacted) { 478 + fprintf(stderr, "Error: Memory allocation failed for compaction\n"); 479 + free(js_code); 480 + return 1; 481 + } 482 + 483 + size_t compact_pos = 0; 484 + for (size_t i = 0; i < processed_len; i++) { 485 + if (js_code[i] != '\n' && js_code[i] != '\r') { 486 + compacted[compact_pos++] = js_code[i]; 487 + } 488 + } 489 + compacted[compact_pos] = '\0'; 490 + 491 + free(js_code); 492 + js_code = compacted; 493 + processed_len = compact_pos; 494 + 495 + for (int i = 0; i < cache.count; i++) { 496 + free(cache.paths[i]); 497 + } 498 + free(cache.paths); 140 499 141 500 struct js *js = js_create_dynamic(1024 * 1024, 10 * 1024 * 1024); 142 501 if (!js) { ··· 171 530 fprintf(out, "/* DO NOT EDIT - Generated during build */\n\n"); 172 531 fprintf(out, "#ifndef ANT_SNAPSHOT_DATA_H\n"); 173 532 fprintf(out, "#define ANT_SNAPSHOT_DATA_H\n\n"); 174 - fprintf(out, "#include <stddef.h>\n\n"); 533 + fprintf(out, "#include <stddef.h>\n"); 534 + fprintf(out, "#include <stdint.h>\n\n"); 175 535 176 - fprintf(out, "static const char ant_snapshot_source[] = \n"); 177 - fprintf(out, "\""); 536 + fprintf(out, "static const uint8_t ant_snapshot_source[] = {"); 178 537 179 538 for (size_t i = 0; i < processed_len; i++) { 180 - char c = js_code[i]; 181 - switch (c) { 182 - case '\n': fprintf(out, "\\n"); break; 183 - case '\r': fprintf(out, "\\r"); break; 184 - case '\t': fprintf(out, "\\t"); break; 185 - case '\\': fprintf(out, "\\\\"); break; 186 - case '"': fprintf(out, "\\\""); break; 187 - default: 188 - if (c >= 32 && c < 127) { 189 - fputc(c, out); 190 - } else { 191 - fprintf(out, "\\x%02x", (unsigned char)c); 192 - } 193 - break; 539 + if (i % 16 == 0) { 540 + fprintf(out, "\n "); 541 + } 542 + fprintf(out, "0x%02x", (unsigned char)js_code[i]); 543 + if (i < processed_len - 1) { 544 + fprintf(out, ", "); 194 545 } 195 - 196 - if (i > 0 && i % 80 == 0) fprintf(out, "\"\n\""); 197 546 } 198 547 199 - fprintf(out, "\";\n\n"); 548 + fprintf(out, "\n};\n\n"); 200 549 fprintf(out, "static const size_t ant_snapshot_source_len = %zu;\n\n", processed_len); 201 550 fprintf(out, "/* memory usage after evaluation: %zu bytes */\n", used_mem); 202 551 fprintf(out, "/* total memory: %zu bytes */\n", total_mem);