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.

at type-hints-typescript 475 lines 13 kB view raw
1/** 2 * Ant JavaScript Engine - Embedding Example 3 * This demonstrates how to embed the Ant JS engine in a C application. 4 * 5 * to build: 6 * ./libant/build.sh 7 * ./libant/example.sh 8 * 9 * to run: 10 * ./libant/dist/embed 11 */ 12 13#include <ant.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17 18#define SEPARATOR "════════════════════════════════════════════════════════════" 19#define SUBSEP "────────────────────────────────────────────────────────────" 20 21static void print_header(int num, const char *title) { 22 printf("\n%s\n", SEPARATOR); 23 printf(" Example %d: %s\n", num, title); 24 printf("%s\n\n", SUBSEP); 25} 26 27static ant_t *create_js_runtime(void *stack_base) { 28 ant_t *js = js_create_dynamic(); 29 if (!js) { 30 fprintf(stderr, "Failed to create JS runtime\n"); 31 return NULL; 32 } 33 34 js_setstackbase(js, stack_base); 35 36 static char *default_argv[] = { "embed_example", NULL }; 37 ant_runtime_init(js, 1, default_argv, NULL); 38 39 return js; 40} 41 42static void example_basic_eval(void) { 43 print_header(1, "Basic Evaluation"); 44 45 volatile char stack_base; 46 ant_t *js = create_js_runtime((void *)&stack_base); 47 if (!js) return; 48 49 50 51 const char *code = "1 + 2 * 3"; 52 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 53 54 if (vtype(result) == T_NUM) { 55 printf(" Result: %g\n", js_getnum(result)); 56 } else if (vtype(result) == T_ERR) { 57 printf(" Error: %s\n", js_str(js, result)); 58 } 59 60 js_destroy(js); 61} 62 63static ant_value_t my_add(ant_t *js, ant_value_t *args, int nargs) { 64 if (!js_chkargs(args, nargs, "dd")) { 65 return js_mkerr(js, "add() expects two numbers"); 66 } 67 68 double a = js_getnum(args[0]); 69 double b = js_getnum(args[1]); 70 71 return js_mknum(a + b); 72} 73 74static ant_value_t my_greet(ant_t *js, ant_value_t *args, int nargs) { 75 if (nargs < 1 || vtype(args[0]) != T_STR) { 76 return js_mkerr(js, "greet() expects a string"); 77 } 78 79 size_t len; 80 char *name = js_getstr(js, args[0], &len); 81 82 char buf[256]; 83 snprintf(buf, sizeof(buf), "Hello, %s!", name); 84 85 return js_mkstr(js, buf, strlen(buf)); 86} 87 88static ant_value_t my_create_point(ant_t *js, ant_value_t *args, int nargs) { 89 if (!js_chkargs(args, nargs, "dd")) { 90 return js_mkerr(js, "createPoint() expects two numbers"); 91 } 92 93 ant_value_t obj = js_mkobj(js); 94 js_set(js, obj, "x", args[0]); 95 js_set(js, obj, "y", args[1]); 96 97 return obj; 98} 99 100static void example_c_functions(void) { 101 print_header(2, "C Functions"); 102 103 volatile char stack_base; 104 ant_t *js = create_js_runtime((void *)&stack_base); 105 if (!js) return; 106 107 108 109 ant_value_t global = js_glob(js); 110 js_set(js, global, "add", js_mkfun(my_add)); 111 js_set(js, global, "greet", js_mkfun(my_greet)); 112 js_set(js, global, "createPoint", js_mkfun(my_create_point)); 113 114 const char *code1 = "add(10, 32)"; 115 ant_value_t r1 = js_eval_bytecode_eval(js, code1, strlen(code1)); 116 printf(" add(10, 32) = %g\n", js_getnum(r1)); 117 118 const char *code2 = "greet('World')"; 119 ant_value_t r2 = js_eval_bytecode_eval(js, code2, strlen(code2)); 120 printf(" greet('World') = %s\n", js_str(js, r2)); 121 122 const char *code3 = "let p = createPoint(3, 4); p.x * p.x + p.y * p.y"; 123 ant_value_t r3 = js_eval_bytecode_eval(js, code3, strlen(code3)); 124 printf(" distance² = %g\n", js_getnum(r3)); 125 126 js_destroy(js); 127} 128 129static void example_objects_arrays(void) { 130 print_header(3, "Objects and Arrays"); 131 132 volatile char stack_base; 133 ant_t *js = create_js_runtime((void *)&stack_base); 134 if (!js) return; 135 136 137 ant_value_t global = js_glob(js); 138 139 ant_value_t config = js_mkobj(js); 140 js_set(js, config, "debug", js_true); 141 js_set(js, config, "version", js_mknum(1.0)); 142 js_set(js, config, "name", js_mkstr(js, "MyApp", 5)); 143 js_set(js, global, "config", config); 144 145 ant_value_t arr = js_mkarr(js); 146 js_arr_push(js, arr, js_mknum(10)); 147 js_arr_push(js, arr, js_mknum(20)); 148 js_arr_push(js, arr, js_mknum(30)); 149 js_set(js, global, "numbers", arr); 150 151 const char *code = "config.name + ' v' + config.version + ' - sum: ' + numbers.reduce((a,b) => a+b, 0)"; 152 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 153 printf(" Result: %s\n", js_str(js, result)); 154 155 ant_value_t name_val = js_get(js, config, "name"); 156 printf(" config.name: %s\n", js_str(js, name_val)); 157 158 ant_value_t debug_val = js_get(js, config, "debug"); 159 printf(" config.debug: %s\n", js_str(js, debug_val)); 160 161 js_destroy(js); 162} 163 164static void example_error_handling(void) { 165 print_header(4, "Error Handling"); 166 167 volatile char stack_base; 168 ant_t *js = create_js_runtime((void *)&stack_base); 169 if (!js) return; 170 171 172 173 const char *bad_code = "let x = {"; 174 ant_value_t r1 = js_eval_bytecode_eval(js, bad_code, strlen(bad_code)); 175 if (vtype(r1) == T_ERR) { 176 printf(" Syntax error: %s\n", js_str(js, r1)); 177 } 178 179 const char *ref_err = "undefinedVariable + 1"; 180 ant_value_t r2 = js_eval_bytecode_eval(js, ref_err, strlen(ref_err)); 181 if (vtype(r2) == T_ERR) { 182 printf(" Reference error: %s\n", js_str(js, r2)); 183 } 184 185 ant_value_t global = js_glob(js); 186 js_set(js, global, "add", js_mkfun(my_add)); 187 188 const char *type_err = "add('not', 'numbers')"; 189 ant_value_t r3 = js_eval_bytecode_eval(js, type_err, strlen(type_err)); 190 if (vtype(r3) == T_ERR) { 191 printf(" Type error: %s\n", js_str(js, r3)); 192 } 193 194 js_destroy(js); 195} 196 197static void example_call_js_from_c(void) { 198 print_header(5, "Calling JS from C"); 199 200 volatile char stack_base; 201 ant_t *js = create_js_runtime((void *)&stack_base); 202 if (!js) return; 203 204 const char *code = 205 "function multiply(a, b) {" 206 " return a * b;" 207 "}" 208 "function formatName(first, last) {" 209 " return last + ', ' + first;" 210 "}"; 211 212 js_eval_bytecode_eval(js, code, strlen(code)); 213 214 ant_value_t glob = js_glob(js); 215 ant_value_t multiply_fn = js_get(js, glob, "multiply"); 216 ant_value_t format_fn = js_get(js, glob, "formatName"); 217 218 ant_value_t args1[] = { js_mknum(6), js_mknum(7) }; 219 ant_value_t result1 = sv_vm_call(js->vm, js, multiply_fn, js_mkundef(), args1, 2, NULL, false); 220 printf(" multiply(6, 7) = %g\n", js_getnum(result1)); 221 222 ant_value_t args2[] = { 223 js_mkstr(js, "John", 4), 224 js_mkstr(js, "Doe", 3) 225 }; 226 227 ant_value_t result2 = sv_vm_call(js->vm, js, format_fn, js_mkundef(), args2, 2, NULL, false); 228 printf(" formatName('John', 'Doe') = %s\n", js_str(js, result2)); 229 230 js_destroy(js); 231} 232 233static void example_iterate_properties(void) { 234 print_header(6, "Iterating Properties"); 235 236 volatile char stack_base; 237 ant_t *js = create_js_runtime((void *)&stack_base); 238 if (!js) return; 239 240 const char *code = "({ name: 'Alice', age: 30, city: 'NYC' })"; 241 ant_value_t obj = js_eval_bytecode_eval(js, code, strlen(code)); 242 243 ant_iter_t iter = js_prop_iter_begin(js, obj); 244 const char *key; 245 size_t key_len; 246 ant_value_t value; 247 248 printf(" Object properties:\n"); 249 while (js_prop_iter_next(&iter, &key, &key_len, &value)) { 250 printf(" • %.*s = %s\n", (int)key_len, key, js_str(js, value)); 251 } 252 js_prop_iter_end(&iter); 253 254 js_destroy(js); 255} 256 257static ant_value_t method_get_full_name(ant_t *js, ant_value_t *args, int nargs) { 258 (void)args; (void)nargs; 259 260 ant_value_t this_obj = js_getthis(js); 261 262 ant_value_t first = js_get(js, this_obj, "firstName"); 263 ant_value_t last = js_get(js, this_obj, "lastName"); 264 265 size_t first_len, last_len; 266 char *first_str = js_getstr(js, first, &first_len); 267 char *last_str = js_getstr(js, last, &last_len); 268 269 char buf[256]; 270 snprintf(buf, sizeof(buf), "%s %s", first_str, last_str); 271 272 return js_mkstr(js, buf, strlen(buf)); 273} 274 275static void example_this_context(void) { 276 print_header(7, "'this' Context"); 277 278 volatile char stack_base; 279 ant_t *js = create_js_runtime((void *)&stack_base); 280 if (!js) return; 281 282 283 284 ant_value_t person = js_mkobj(js); 285 js_set(js, person, "firstName", js_mkstr(js, "Jane", 4)); 286 js_set(js, person, "lastName", js_mkstr(js, "Smith", 5)); 287 js_set(js, person, "getFullName", js_mkfun(method_get_full_name)); 288 289 js_set(js, js_glob(js), "person", person); 290 291 const char *code = "person.getFullName()"; 292 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 293 printf(" person.getFullName() = %s\n", js_str(js, result)); 294 295 js_destroy(js); 296} 297 298static void example_stateful_session(void) { 299 print_header(8, "Stateful Session"); 300 301 volatile char stack_base; 302 ant_t *js = create_js_runtime((void *)&stack_base); 303 if (!js) return; 304 305 306 307 const char *scripts[] = { 308 "let counter = 0;", 309 "function increment() { return ++counter; }", 310 "function getCount() { return counter; }", 311 "increment(); increment(); increment();", 312 "getCount()" 313 }; 314 315 ant_value_t result = js_mkundef(); 316 for (int i = 0; i < 5; i++) { 317 result = js_eval_bytecode_eval(js, scripts[i], strlen(scripts[i])); 318 if (vtype(result) == T_ERR) { 319 printf(" Error in script %d: %s\n", i, js_str(js, result)); 320 break; 321 } 322 } 323 324 printf(" Final count: %g\n", js_getnum(result)); 325 326 js_destroy(js); 327} 328 329static void example_async_event_loop(void) { 330 print_header(9, "Async & Event Loop"); 331 332 volatile char stack_base; 333 ant_t *js = create_js_runtime((void *)&stack_base); 334 if (!js) return; 335 336 init_symbol_module(); 337 init_builtin_module(); 338 init_timer_module(); 339 340 const char *code = 341 "let results = [];" 342 "" 343 "setTimeout(() => {" 344 " results.push('timer 1 (50ms)');" 345 "}, 50);" 346 "" 347 "setTimeout(() => {" 348 " results.push('timer 2 (10ms)');" 349 "}, 10);" 350 "" 351 "Promise.resolve('promise 1').then(v => {" 352 " results.push(v);" 353 "});" 354 "" 355 "queueMicrotask(() => {" 356 " results.push('microtask');" 357 "});" 358 "" 359 "results.push('sync');"; 360 361 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 362 if (vtype(result) == T_ERR) { 363 printf(" Error: %s\n", js_str(js, result)); 364 js_destroy(js); 365 return; 366 } 367 368 js_run_event_loop(js); 369 370 ant_value_t results = js_get(js, js_glob(js), "results"); 371 372 printf(" Execution order:\n"); 373 ant_offset_t len = js_arr_len(js, results); 374 for (ant_offset_t i = 0; i < len; i++) { 375 ant_value_t item = js_arr_get(js, results, i); 376 printf(" %llu. %s\n", (unsigned long long)i + 1, js_str(js, item)); 377 } 378 379 js_destroy(js); 380} 381 382static void example_console_logging(void) { 383 print_header(10, "Console Logging"); 384 385 volatile char stack_base; 386 ant_t *js = create_js_runtime((void *)&stack_base); 387 if (!js) return; 388 389 init_console_module(); 390 391 392 const char *code = 393 "console.log('Hello from JavaScript!');" 394 "console.log('Number:', 42, 'Boolean:', true);" 395 "console.log('Object:', { name: 'test', value: 123 });" 396 "console.log('Array:', [1, 2, 3]);" 397 "console.warn('This is a warning');" 398 "console.error('This is an error');" 399 "'done'"; 400 401 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 402 if (vtype(result) == T_ERR) { 403 printf(" Error: %s\n", js_str(js, result)); 404 } 405 406 js_destroy(js); 407} 408 409static void example_global_this(void) { 410 print_header(11, "GlobalThis"); 411 412 volatile char stack_base; 413 ant_t *js = create_js_runtime((void *)&stack_base); 414 if (!js) return; 415 416 init_console_module(); 417 418 419 ant_value_t global = js_glob(js); 420 js_set(js, global, "myNumber", js_mknum(42)); 421 js_set(js, global, "myString", js_mkstr(js, "hello from C", 12)); 422 js_set(js, global, "myBool", js_true); 423 424 ant_value_t myObj = js_mkobj(js); 425 js_set(js, myObj, "a", js_mknum(1)); 426 js_set(js, myObj, "b", js_mknum(2)); 427 js_set(js, global, "myObject", myObj); 428 429 const char *code = 430 "console.log('globalThis.myNumber:', globalThis.myNumber);" 431 "console.log('globalThis.myString:', globalThis.myString);" 432 "console.log('globalThis.myBool:', globalThis.myBool);" 433 "console.log('globalThis.myObject:', globalThis.myObject);" 434 "" 435 "globalThis.addedFromJS = 'I was added from JavaScript';" 436 "console.log('globalThis.addedFromJS:', globalThis.addedFromJS);" 437 "" 438 "console.log('\\nAll custom globals:');" 439 "console.log(' myNumber:', myNumber);" 440 "console.log(' myString:', myString);" 441 "console.log(' myBool:', myBool);" 442 "console.log(' myObject:', myObject);" 443 "console.log(' addedFromJS:', addedFromJS);" 444 "console.log(this)"; 445 446 ant_value_t result = js_eval_bytecode_eval(js, code, strlen(code)); 447 if (vtype(result) == T_ERR) { 448 printf(" Error: %s\n", js_str(js, result)); 449 } 450 451 ant_value_t added = js_get(js, global, "addedFromJS"); 452 printf("\n Read from C: addedFromJS = %s\n", js_str(js, added)); 453 454 js_destroy(js); 455} 456 457int main(void) { 458 printf("\n%s\n", SEPARATOR); 459 printf(" Ant JavaScript Engine - Embedding Examples\n"); 460 printf("%s\n", SEPARATOR); 461 462 example_basic_eval(); 463 example_c_functions(); 464 example_objects_arrays(); 465 example_error_handling(); 466 example_call_js_from_c(); 467 example_iterate_properties(); 468 example_this_context(); 469 example_stateful_session(); 470 example_async_event_loop(); 471 example_console_logging(); 472 example_global_this(); 473 474 return EXIT_SUCCESS; 475}