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 embedding examples

+369 -12
+324
examples/embed/embed.c
··· 1 + /** 2 + * Ant JavaScript Engine - Embedding Example 3 + * This demonstrates how to embed the Ant JS engine in a C application. 4 + * 5 + * meson setup build -Dbuild_examples=true 6 + * meson compile -C build 7 + * 8 + * ./build/embed_example 9 + */ 10 + 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <string.h> 14 + #include <ant.h> 15 + 16 + #define SEPARATOR "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" 17 + #define SUBSEP "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" 18 + 19 + static void print_header(int num, const char *title) { 20 + printf("\n%s\n", SEPARATOR); 21 + printf(" Example %d: %s\n", num, title); 22 + printf("%s\n\n", SUBSEP); 23 + } 24 + 25 + static void example_basic_eval(void) { 26 + print_header(1, "Basic Evaluation"); 27 + 28 + struct js *js = js_create_dynamic(0, 0); 29 + if (!js) { 30 + fprintf(stderr, "Failed to create JS runtime\n"); 31 + return; 32 + } 33 + 34 + js_mkscope(js); 35 + 36 + const char *code = "1 + 2 * 3"; 37 + jsval_t result = js_eval(js, code, strlen(code)); 38 + 39 + if (js_type(result) == JS_NUM) { 40 + printf(" Result: %g\n", js_getnum(result)); 41 + } else if (js_type(result) == JS_ERR) { 42 + printf(" Error: %s\n", js_str(js, result)); 43 + } 44 + 45 + js_destroy(js); 46 + } 47 + 48 + static jsval_t my_add(struct js *js, jsval_t *args, int nargs) { 49 + if (!js_chkargs(args, nargs, "dd")) { 50 + return js_mkerr(js, "add() expects two numbers"); 51 + } 52 + 53 + double a = js_getnum(args[0]); 54 + double b = js_getnum(args[1]); 55 + 56 + return js_mknum(a + b); 57 + } 58 + 59 + static jsval_t my_greet(struct js *js, jsval_t *args, int nargs) { 60 + if (nargs < 1 || js_type(args[0]) != JS_STR) { 61 + return js_mkerr(js, "greet() expects a string"); 62 + } 63 + 64 + size_t len; 65 + char *name = js_getstr(js, args[0], &len); 66 + 67 + char buf[256]; 68 + snprintf(buf, sizeof(buf), "Hello, %s!", name); 69 + 70 + return js_mkstr(js, buf, strlen(buf)); 71 + } 72 + 73 + static jsval_t my_create_point(struct js *js, jsval_t *args, int nargs) { 74 + if (!js_chkargs(args, nargs, "dd")) { 75 + return js_mkerr(js, "createPoint() expects two numbers"); 76 + } 77 + 78 + jsval_t obj = js_mkobj(js); 79 + js_set(js, obj, "x", args[0]); 80 + js_set(js, obj, "y", args[1]); 81 + 82 + return obj; 83 + } 84 + 85 + static void example_c_functions(void) { 86 + print_header(2, "C Functions"); 87 + 88 + struct js *js = js_create_dynamic(0, 0); 89 + if (!js) return; 90 + 91 + js_mkscope(js); 92 + 93 + jsval_t global = js_glob(js); 94 + js_set(js, global, "add", js_mkfun(my_add)); 95 + js_set(js, global, "greet", js_mkfun(my_greet)); 96 + js_set(js, global, "createPoint", js_mkfun(my_create_point)); 97 + 98 + const char *code1 = "add(10, 32)"; 99 + jsval_t r1 = js_eval(js, code1, strlen(code1)); 100 + printf(" add(10, 32) = %g\n", js_getnum(r1)); 101 + 102 + const char *code2 = "greet('World')"; 103 + jsval_t r2 = js_eval(js, code2, strlen(code2)); 104 + printf(" greet('World') = %s\n", js_str(js, r2)); 105 + 106 + const char *code3 = "let p = createPoint(3, 4); p.x * p.x + p.y * p.y"; 107 + jsval_t r3 = js_eval(js, code3, strlen(code3)); 108 + printf(" distanceยฒ = %g\n", js_getnum(r3)); 109 + 110 + js_destroy(js); 111 + } 112 + 113 + static void example_objects_arrays(void) { 114 + print_header(3, "Objects and Arrays"); 115 + 116 + struct js *js = js_create_dynamic(0, 0); 117 + if (!js) return; 118 + 119 + js_mkscope(js); 120 + jsval_t global = js_glob(js); 121 + 122 + jsval_t config = js_mkobj(js); 123 + js_set(js, config, "debug", js_mktrue()); 124 + js_set(js, config, "version", js_mknum(1.0)); 125 + js_set(js, config, "name", js_mkstr(js, "MyApp", 5)); 126 + js_set(js, global, "config", config); 127 + 128 + jsval_t arr = js_mkarr(js); 129 + js_arr_push(js, arr, js_mknum(10)); 130 + js_arr_push(js, arr, js_mknum(20)); 131 + js_arr_push(js, arr, js_mknum(30)); 132 + js_set(js, global, "numbers", arr); 133 + 134 + const char *code = "config.name + ' v' + config.version + ' - sum: ' + numbers.reduce((a,b) => a+b, 0)"; 135 + jsval_t result = js_eval(js, code, strlen(code)); 136 + printf(" Result: %s\n", js_str(js, result)); 137 + 138 + jsval_t name_val = js_get(js, config, "name"); 139 + printf(" config.name from C: %s\n", js_str(js, name_val)); 140 + 141 + js_destroy(js); 142 + } 143 + 144 + static void example_error_handling(void) { 145 + print_header(4, "Error Handling"); 146 + 147 + struct js *js = js_create_dynamic(0, 0); 148 + if (!js) return; 149 + 150 + js_mkscope(js); 151 + 152 + const char *bad_code = "let x = {"; 153 + jsval_t r1 = js_eval(js, bad_code, strlen(bad_code)); 154 + if (js_type(r1) == JS_ERR) { 155 + printf(" Syntax error: %s\n", js_str(js, r1)); 156 + } 157 + 158 + const char *ref_err = "undefinedVariable + 1"; 159 + jsval_t r2 = js_eval(js, ref_err, strlen(ref_err)); 160 + if (js_type(r2) == JS_ERR) { 161 + printf(" Reference error: %s\n", js_str(js, r2)); 162 + } 163 + 164 + jsval_t global = js_glob(js); 165 + js_set(js, global, "add", js_mkfun(my_add)); 166 + 167 + const char *type_err = "add('not', 'numbers')"; 168 + jsval_t r3 = js_eval(js, type_err, strlen(type_err)); 169 + if (js_type(r3) == JS_ERR) { 170 + printf(" Type error: %s\n", js_str(js, r3)); 171 + } 172 + 173 + js_destroy(js); 174 + } 175 + 176 + static void example_call_js_from_c(void) { 177 + print_header(5, "Calling JS from C"); 178 + 179 + struct js *js = js_create_dynamic(0, 0); 180 + if (!js) return; 181 + 182 + jsval_t scope = js_mkscope(js); 183 + 184 + const char *code = 185 + "function multiply(a, b) {" 186 + " return a * b;" 187 + "}" 188 + 189 + "function formatName(first, last) {" 190 + " return last + ', ' + first;" 191 + "}"; 192 + 193 + js_eval(js, code, strlen(code)); 194 + 195 + jsval_t multiply_fn = js_get(js, scope, "multiply"); 196 + jsval_t format_fn = js_get(js, scope, "formatName"); 197 + 198 + jsval_t args1[] = { js_mknum(6), js_mknum(7) }; 199 + jsval_t result1 = js_call(js, multiply_fn, args1, 2); 200 + printf(" multiply(6, 7) = %g\n", js_getnum(result1)); 201 + 202 + jsval_t args2[] = { 203 + js_mkstr(js, "John", 4), 204 + js_mkstr(js, "Doe", 3) 205 + }; 206 + 207 + jsval_t result2 = js_call(js, format_fn, args2, 2); 208 + printf(" formatName('John', 'Doe') = %s\n", js_str(js, result2)); 209 + 210 + js_destroy(js); 211 + } 212 + 213 + static void example_iterate_properties(void) { 214 + print_header(6, "Iterating Properties"); 215 + 216 + struct js *js = js_create_dynamic(0, 0); 217 + if (!js) return; 218 + 219 + js_mkscope(js); 220 + 221 + const char *code = "({ name: 'Alice', age: 30, city: 'NYC' })"; 222 + jsval_t obj = js_eval(js, code, strlen(code)); 223 + 224 + js_prop_iter_t iter = js_prop_iter_begin(js, obj); 225 + const char *key; 226 + size_t key_len; 227 + jsval_t value; 228 + 229 + printf(" Object properties:\n"); 230 + while (js_prop_iter_next(&iter, &key, &key_len, &value)) { 231 + printf(" โ€ข %.*s = %s\n", (int)key_len, key, js_str(js, value)); 232 + } 233 + js_prop_iter_end(&iter); 234 + 235 + js_destroy(js); 236 + } 237 + 238 + static jsval_t method_get_full_name(struct js *js, jsval_t *args, int nargs) { 239 + (void)args; (void)nargs; 240 + 241 + jsval_t this_obj = js_getthis(js); 242 + 243 + jsval_t first = js_get(js, this_obj, "firstName"); 244 + jsval_t last = js_get(js, this_obj, "lastName"); 245 + 246 + size_t first_len, last_len; 247 + char *first_str = js_getstr(js, first, &first_len); 248 + char *last_str = js_getstr(js, last, &last_len); 249 + 250 + char buf[256]; 251 + snprintf(buf, sizeof(buf), "%s %s", first_str, last_str); 252 + 253 + return js_mkstr(js, buf, strlen(buf)); 254 + } 255 + 256 + static void example_this_context(void) { 257 + print_header(7, "'this' Context"); 258 + 259 + struct js *js = js_create_dynamic(0, 0); 260 + if (!js) return; 261 + 262 + js_mkscope(js); 263 + 264 + jsval_t person = js_mkobj(js); 265 + js_set(js, person, "firstName", js_mkstr(js, "Jane", 4)); 266 + js_set(js, person, "lastName", js_mkstr(js, "Smith", 5)); 267 + js_set(js, person, "getFullName", js_mkfun(method_get_full_name)); 268 + 269 + js_set(js, js_glob(js), "person", person); 270 + 271 + const char *code = "person.getFullName()"; 272 + jsval_t result = js_eval(js, code, strlen(code)); 273 + printf(" person.getFullName() = %s\n", js_str(js, result)); 274 + 275 + js_destroy(js); 276 + } 277 + 278 + static void example_stateful_session(void) { 279 + print_header(8, "Stateful Session"); 280 + 281 + struct js *js = js_create_dynamic(0, 0); 282 + if (!js) return; 283 + 284 + js_mkscope(js); 285 + 286 + const char *scripts[] = { 287 + "let counter = 0;", 288 + "function increment() { return ++counter; }", 289 + "function getCount() { return counter; }", 290 + "increment(); increment(); increment();", 291 + "getCount()" 292 + }; 293 + 294 + jsval_t result = js_mkundef(); 295 + for (int i = 0; i < 5; i++) { 296 + result = js_eval(js, scripts[i], strlen(scripts[i])); 297 + if (js_type(result) == JS_ERR) { 298 + printf(" Error in script %d: %s\n", i, js_str(js, result)); 299 + break; 300 + } 301 + } 302 + 303 + printf(" Final count: %g\n", js_getnum(result)); 304 + 305 + js_destroy(js); 306 + } 307 + 308 + 309 + int main(void) { 310 + printf("\n%s\n", SEPARATOR); 311 + printf(" Ant JavaScript Engine - Embedding Examples\n"); 312 + printf("%s\n", SEPARATOR); 313 + 314 + example_basic_eval(); 315 + example_c_functions(); 316 + example_objects_arrays(); 317 + example_error_handling(); 318 + example_call_js_from_c(); 319 + example_iterate_properties(); 320 + example_this_context(); 321 + example_stateful_session(); 322 + 323 + return EXIT_SUCCESS; 324 + }
+2 -1
include/ant.h
··· 51 51 struct js *js_create_dynamic(size_t initial_size, size_t max_size); 52 52 53 53 jsval_t js_glob(struct js *); 54 + jsval_t js_mkscope(struct js *); 55 + jsval_t js_getscope(struct js *); 54 56 jsval_t js_eval(struct js *, const char *, size_t); 55 57 56 58 void js_destroy(struct js *); 57 - void js_mkscope(struct js *); 58 59 void js_delscope(struct js *); 59 60 bool js_truthy(struct js *, jsval_t); 60 61 void js_setmaxcss(struct js *, size_t);
+6
maidfile.toml
··· 47 47 bash -c 'CC="ccache $(which clang)" \ 48 48 meson setup build --wipe -Doptimization=0 -Db_lto=false -Dstrip=false -Db_lundef=false -Dunity=off -Ddebug=true' 49 49 '''] 50 + 51 + [tasks.embed_example] 52 + script = [''' 53 + bash -c 'CC="ccache $(which clang)" \ 54 + meson setup build -Dbuild_examples=true 2>/dev/null || true' 55 + ''', "meson compile -C build", "./build/embed_example"]
+29 -5
meson.build
··· 14 14 check: true 15 15 ).stdout().strip().split() 16 16 17 - sources = files( 18 - 'src/main.c', 17 + lib_sources = files( 19 18 'src/utils.c', 20 19 'src/ant.c', 21 20 'src/gc.c', ··· 234 233 235 234 ant_deps = [ 236 235 libffi_dep, bdwgc_dep, uuid_dep, 237 - llhttp, pcre2_dep, libuv_dep, oxc_dep, 236 + llhttp, pcre2_dep, libuv_dep, 238 237 argtable3_dep, tlsuv_dep, libsodium_dep, 239 238 yyjson_dep, minicoro_dep, uuidv7_dep, 240 239 openssl_dep, zlib_dep, uthash_dep, ··· 250 249 if get_option('static_link') 251 250 link_args += ['-static'] 252 251 endif 252 + 253 + libant = static_library( 254 + 'ant', 255 + lib_sources + [snapshot_h], 256 + include_directories: [include, build_include, strip_include], 257 + dependencies: ant_deps, 258 + install: true 259 + ) 260 + 261 + libant_dep = declare_dependency( 262 + link_with: libant, 263 + include_directories: [include, build_include], 264 + dependencies: ant_deps + [oxc_dep] 265 + ) 253 266 254 267 executable( 255 268 'ant', 256 - sources + [snapshot_h], 269 + files('src/main.c') + [snapshot_h], 257 270 include_directories: [include, build_include, strip_include], 258 - dependencies: ant_deps, 271 + link_with: libant, 272 + dependencies: ant_deps + [oxc_dep], 259 273 link_args: link_args 260 274 ) 275 + 276 + if get_option('build_examples') 277 + executable( 278 + 'embed_example', 279 + files('examples/embed/embed.c'), 280 + include_directories: [include, build_include], 281 + link_with: libant, 282 + dependencies: ant_deps + [oxc_dep] 283 + ) 284 + endif
+1
meson_options.txt
··· 2 2 option('build_timestamp', type: 'string', value: '', description: 'build timestamp (defaults to current time if empty)') 3 3 option('tls_library', type: 'combo', choices: ['openssl', 'mbedtls'], value: 'openssl', description: 'TLS library to use') 4 4 option('deps_prefix_cmake', type: 'string', value: '', description: 'prefix path for finding dependencies in cmake subprojects') 5 + option('build_examples', type: 'boolean', value: false, description: 'build embedding examples')
+7 -6
src/ant.c
··· 4583 4583 return bare; 4584 4584 } 4585 4585 4586 - void js_mkscope(struct js *js) { 4586 + jsval_t js_mkscope(struct js *js) { 4587 4587 assert((js->flags & F_NOEXEC) == 0); 4588 4588 if (global_scope_stack == NULL) utarray_new(global_scope_stack, &jsoff_icd); 4589 4589 jsoff_t prev = (jsoff_t) vdata(js->scope); 4590 4590 utarray_push_back(global_scope_stack, &prev); 4591 4591 js->scope = mkobj(js, prev); 4592 + 4593 + return js->scope; 4592 4594 } 4593 4595 4594 4596 void js_delscope(struct js *js) { ··· 4596 4598 jsoff_t *prev = (jsoff_t *)utarray_back(global_scope_stack); 4597 4599 js->scope = mkval(T_OBJ, *prev); 4598 4600 utarray_pop_back(global_scope_stack); 4599 - } else { 4600 - js->scope = upper(js, js->scope); 4601 - } 4601 + } else js->scope = upper(js, js->scope); 4602 4602 } 4603 4603 4604 - static void mkscope(struct js *js) { js_mkscope(js); } 4605 - static void delscope(struct js *js) { js_delscope(js); } 4604 + static void mkscope(struct js *js) { (void)js_mkscope(js); } 4605 + static void delscope(struct js *js) { (void)js_delscope(js); } 4606 4606 4607 4607 static inline bool push_this(jsval_t this_value) { 4608 4608 if (global_this_stack.depth >= global_this_stack.capacity) { ··· 22047 22047 inline jsval_t js_mknum(double value) { return tov(value); } 22048 22048 inline jsval_t js_mkobj(struct js *js) { return mkobj(js, 0); } 22049 22049 inline jsval_t js_glob(struct js *js) { (void) js; return mkval(T_OBJ, 0); } 22050 + inline jsval_t js_getscope(struct js *js) { return js->scope; } 22050 22051 inline jsval_t js_mkfun(jsval_t (*fn)(struct js *, jsval_t *, int)) { return mkval(T_CFUNC, (size_t) (void *) fn); } 22051 22052 22052 22053 inline jsval_t js_getthis(struct js *js) { return js->this_val; }