MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include <compat.h> // IWYU pragma: keep
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <stdbool.h>
7#include <ctype.h>
8#include <inttypes.h>
9#include <uv.h>
10
11#include "common.h"
12#include "errors.h"
13#include "output.h"
14#include "internal.h"
15#include "runtime.h"
16#include "gc/roots.h"
17#include "silver/engine.h"
18#include "modules/io.h"
19#include "modules/symbol.h"
20
21bool io_no_color = false;
22
23static ant_value_t g_console_proto = 0;
24static ant_value_t g_console_ctor = 0;
25
26#define JSON_KEY "\x1b[0m"
27#define JSON_STRING "\x1b[32m"
28#define JSON_NUMBER "\x1b[33m"
29#define JSON_BOOL "\x1b[35m"
30#define JSON_NULL "\x1b[90m"
31#define JSON_BRACE "\x1b[37m"
32#define JSON_FUNC "\x1b[36m"
33#define JSON_TAG "\x1b[34m"
34#define JSON_REF "\x1b[90m"
35#define JSON_WHITE "\x1b[97m"
36
37static inline bool io_is_digit_ascii(char c) {
38 return c >= '0' && c <= '9';
39}
40
41static bool io_print_to_output(const char *str, ant_output_stream_t *out) {
42 if (!io_no_color) {
43 return ant_output_stream_append_cstr(out, str);
44 }
45
46 static void *states[] = {&&normal, &&esc, &&csi, &&done};
47 const char *p = str; char c;
48
49 goto *states[0];
50
51 normal: {
52 c = *p++;
53 if (!c) goto *states[3];
54 if (c == '\x1b') goto *states[1];
55 if (!ant_output_stream_putc(out, c)) return false;
56 goto *states[0];
57 }
58
59 esc: {
60 c = *p++;
61 if (!c) goto *states[3];
62 if (c == '[') goto *states[2];
63 if (!ant_output_stream_putc(out, '\x1b')) return false;
64 if (!ant_output_stream_putc(out, c)) return false;
65 goto *states[0];
66 }
67
68 csi: {
69 c = *p++;
70 if (!c) goto *states[3];
71 if ((c >= '0' && c <= '9') || c == ';') goto *states[2];
72 if (c != 'm' && !ant_output_stream_putc(out, c)) return false;
73 goto *states[0];
74 }
75
76 done: return true;
77}
78
79enum char_class {
80 CC_OTHER, CC_NUL, CC_QUOTE, CC_ESCAPE, CC_LBRACE, CC_RBRACE,
81 CC_LBRACK, CC_RBRACK, CC_COLON, CC_COMMA, CC_NEWLINE,
82 CC_DIGIT, CC_MINUS, CC_ALPHA, CC_IDENT, CC_LT, CC_GT
83};
84
85static const uint8_t char_class_table[256] = {
86 [0] = CC_NUL,
87 ['\n'] = CC_NEWLINE, ['"'] = CC_QUOTE, ['\''] = CC_QUOTE, ['\\'] = CC_ESCAPE,
88 ['{'] = CC_LBRACE, ['}'] = CC_RBRACE, ['['] = CC_LBRACK, [']'] = CC_RBRACK,
89 [':'] = CC_COLON, [','] = CC_COMMA, ['-'] = CC_MINUS, ['<'] = CC_LT, ['>'] = CC_GT,
90 ['_'] = CC_IDENT, ['$'] = CC_IDENT,
91 ['0'] = CC_DIGIT, ['1'] = CC_DIGIT, ['2'] = CC_DIGIT, ['3'] = CC_DIGIT,
92 ['4'] = CC_DIGIT, ['5'] = CC_DIGIT, ['6'] = CC_DIGIT, ['7'] = CC_DIGIT,
93 ['8'] = CC_DIGIT, ['9'] = CC_DIGIT,
94 ['a'] = CC_ALPHA, ['b'] = CC_ALPHA, ['c'] = CC_ALPHA, ['d'] = CC_ALPHA,
95 ['e'] = CC_ALPHA, ['f'] = CC_ALPHA, ['g'] = CC_ALPHA, ['h'] = CC_ALPHA,
96 ['i'] = CC_ALPHA, ['j'] = CC_ALPHA, ['k'] = CC_ALPHA, ['l'] = CC_ALPHA,
97 ['m'] = CC_ALPHA, ['n'] = CC_ALPHA, ['o'] = CC_ALPHA, ['p'] = CC_ALPHA,
98 ['q'] = CC_ALPHA, ['r'] = CC_ALPHA, ['s'] = CC_ALPHA, ['t'] = CC_ALPHA,
99 ['u'] = CC_ALPHA, ['v'] = CC_ALPHA, ['w'] = CC_ALPHA, ['x'] = CC_ALPHA,
100 ['y'] = CC_ALPHA, ['z'] = CC_ALPHA,
101 ['A'] = CC_ALPHA, ['B'] = CC_ALPHA, ['C'] = CC_ALPHA, ['D'] = CC_ALPHA,
102 ['E'] = CC_ALPHA, ['F'] = CC_ALPHA, ['G'] = CC_ALPHA, ['H'] = CC_ALPHA,
103 ['I'] = CC_ALPHA, ['J'] = CC_ALPHA, ['K'] = CC_ALPHA, ['L'] = CC_ALPHA,
104 ['M'] = CC_ALPHA, ['N'] = CC_ALPHA, ['O'] = CC_ALPHA, ['P'] = CC_ALPHA,
105 ['Q'] = CC_ALPHA, ['R'] = CC_ALPHA, ['S'] = CC_ALPHA, ['T'] = CC_ALPHA,
106 ['U'] = CC_ALPHA, ['V'] = CC_ALPHA, ['W'] = CC_ALPHA, ['X'] = CC_ALPHA,
107 ['Y'] = CC_ALPHA, ['Z'] = CC_ALPHA,
108};
109
110static int io_iso_utc_token_len(const char *p) {
111 int i = 0;
112
113 if (*p == '+' || *p == '-') {
114 i++;
115 for (int d = 0; d < 6; d++, i++) if (!io_is_digit_ascii(p[i])) return 0;
116 } else for (int d = 0; d < 4; d++, i++) if (!io_is_digit_ascii(p[i])) return 0;
117
118 if (p[i++] != '-') return 0;
119 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
120 if (p[i++] != '-') return 0;
121 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
122 if (p[i++] != 'T') return 0;
123 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
124 if (p[i++] != ':') return 0;
125 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
126 if (p[i++] != ':') return 0;
127 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
128 if (p[i++] != '.') return 0;
129 if (!io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++]) || !io_is_digit_ascii(p[i++])) return 0;
130 if (p[i++] != 'Z') return 0;
131
132 char boundary = p[i];
133 if (
134 !(boundary == '\0'
135 || boundary == ' '
136 || boundary == '\t'
137 || boundary == '\n'
138 || boundary == ','
139 || boundary == ']'
140 || boundary == '}'
141 || boundary == ')'
142 || boundary == '>')
143 ) return 0;
144
145 return i;
146}
147
148#define KEYWORD(kw, color) \
149 if (memcmp(p, kw, sizeof(kw) - 1) == 0 && !isalnum((unsigned char)p[sizeof(kw) - 1]) && p[sizeof(kw) - 1] != '_') { \
150 ant_output_stream_append_cstr(out, color); ant_output_stream_append_cstr(out, kw); ant_output_stream_append_cstr(out, C_RESET); \
151 p += sizeof(kw) - 1; goto next; \
152 }
153
154#define EMIT_UNTIL(end_char, color) \
155 ant_output_stream_append_cstr(out, color); \
156 while (*p && *p != end_char) ant_output_stream_putc(out, *p++); \
157 if (*p == end_char) ant_output_stream_putc(out, *p++); \
158 ant_output_stream_append_cstr(out, C_RESET); goto next;
159
160#define EMIT_TYPE(tag, len, color) \
161 if (!(is_key && brace_depth > 0) && memcmp(p, tag, len) == 0) { \
162 ant_output_stream_append_cstr(out, color); ant_output_stream_append_cstr(out, tag); ant_output_stream_append_cstr(out, C_RESET); \
163 p += len; goto next; \
164 }
165
166static void print_value_colored_to_output(const char *str, ant_output_stream_t *out) {
167 if (io_no_color) { io_print_to_output(str, out); return; }
168
169 static void *dispatch[] = {
170 [CC_NUL] = &&done, [CC_QUOTE] = &"e, [CC_ESCAPE] = &&other,
171 [CC_LBRACE] = &&lbrace, [CC_RBRACE] = &&rbrace,
172 [CC_LBRACK] = &&lbrack, [CC_RBRACK] = &&rbrack,
173 [CC_COLON] = &&colon, [CC_COMMA] = &&separator, [CC_NEWLINE] = &&separator,
174 [CC_DIGIT] = &&number, [CC_MINUS] = &&minus,
175 [CC_ALPHA] = &&alpha, [CC_IDENT] = &&ident, [CC_LT] = &<, [CC_GT] = &>, [CC_OTHER] = &&other
176 };
177
178 const char *p = str;
179 char string_char = 0;
180 int brace_depth = 0, array_depth = 0;
181 bool is_key = true;
182
183 goto next;
184
185next:
186 goto *dispatch[char_class_table[(unsigned char)*p]];
187
188done:
189 return;
190
191quote:
192 string_char = *p;
193 ant_output_stream_append_cstr(out, (is_key && brace_depth > 0) ? JSON_KEY : JSON_STRING);
194 ant_output_stream_putc(out, *p++);
195 while (*p) {
196 if (*p == '\\' && p[1]) { ant_output_stream_putc(out, *p++); ant_output_stream_putc(out, *p++); continue; }
197 if (*p == string_char) { ant_output_stream_putc(out, *p++); break; }
198 ant_output_stream_putc(out, *p++);
199 }
200 ant_output_stream_append_cstr(out, C_RESET);
201 goto next;
202
203lbrace:
204 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
205 brace_depth++; is_key = true; goto next;
206
207rbrace:
208 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
209 brace_depth--; is_key = false; goto next;
210
211lbrack:
212 switch (p[1]) {
213 case 'A': if (memcmp(p + 2, "syncFunction", 7) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
214 case 'b': if (memcmp(p + 2, "yte", 3) == 0 || memcmp(p + 2, "uffer]", 6) == 0) { EMIT_UNTIL(']', JSON_STRING) } break;
215 case 'F': if (memcmp(p + 2, "unction", 7) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
216 case 'n': if (memcmp(p + 2, "ative code", 10) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
217 case 'C': if (memcmp(p + 2, "ircular", 7) == 0) { EMIT_UNTIL(']', JSON_REF) } break;
218 case 'G': if (memcmp(p + 2, "etter/Setter]", 13) == 0 || memcmp(p + 2, "etter]", 6) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
219 case 'S': if (memcmp(p + 2, "etter]", 6) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
220 case 'O': if (memcmp(p + 2, "bject: null prototype]", 22) == 0) { EMIT_UNTIL(']', JSON_TAG) } break;
221 case 'M': if (memcmp(p + 2, "odule]", 6) == 0) { EMIT_UNTIL(']', JSON_TAG) } break;
222 case 'U': if (memcmp(p + 2, "int8Contents]", 13) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break;
223 case 'P': if (memcmp(p + 2, "romise]", 7) == 0) { EMIT_UNTIL(']', JSON_TAG) } break;
224 }
225 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
226 array_depth++; is_key = false; goto next;
227
228rbrack:
229 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
230 array_depth--; is_key = false; goto next;
231
232colon:
233 ant_output_stream_putc(out, *p++); is_key = false; goto next;
234
235separator:
236 ant_output_stream_putc(out, *p++);
237 is_key = (brace_depth > 0 && array_depth == 0);
238 goto next;
239
240number: {
241 int iso_len = io_iso_utc_token_len(p);
242 if (iso_len > 0) {
243 ant_output_stream_append_cstr(out, C_MAGENTA);
244 for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++);
245 ant_output_stream_append_cstr(out, C_RESET);
246 goto next;
247 }
248 }
249 ant_output_stream_append_cstr(out, JSON_NUMBER);
250 while ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' || *p == '+' || *p == '-')
251 ant_output_stream_putc(out, *p++);
252 ant_output_stream_append_cstr(out, C_RESET);
253 goto next;
254
255minus: {
256 int iso_len = io_iso_utc_token_len(p);
257 if (iso_len > 0) {
258 ant_output_stream_append_cstr(out, C_MAGENTA);
259 for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++);
260 ant_output_stream_append_cstr(out, C_RESET);
261 goto next;
262 }
263 }
264 if (memcmp(p + 1, "Infinity", 8) == 0 && !isalnum((unsigned char)p[9]) && p[9] != '_') {
265 ant_output_stream_append_cstr(out, JSON_NUMBER); ant_output_stream_append_cstr(out, "-Infinity"); ant_output_stream_append_cstr(out, C_RESET);
266 p += 9; goto next;
267 }
268 if (p[1] >= '0' && p[1] <= '9') {
269 ant_output_stream_append_cstr(out, JSON_NUMBER); ant_output_stream_putc(out, *p++);
270 while ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' || *p == '+' || *p == '-')
271 ant_output_stream_putc(out, *p++);
272 ant_output_stream_append_cstr(out, C_RESET);
273 goto next;
274 }
275 ant_output_stream_putc(out, *p++); goto next;
276
277lt:
278 if (memcmp(p, "<ref", 4) == 0) { EMIT_UNTIL('>', JSON_REF) }
279 if (memcmp(p, "<pen", 4) == 0) { is_key = false; EMIT_UNTIL('>', C_CYAN) }
280 if (memcmp(p, "<rej", 4) == 0) { is_key = false; EMIT_UNTIL('>', C_CYAN) }
281
282 if (p[1] == '>' || (isxdigit((unsigned char)p[1]) && isxdigit((unsigned char)p[2]))) {
283 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++);
284 ant_output_stream_append_cstr(out, JSON_WHITE);
285 while (*p && *p != '>') ant_output_stream_putc(out, *p++);
286 ant_output_stream_append_cstr(out, C_RESET);
287 if (*p == '>') { ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); }
288 goto next;
289 }
290
291 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
292 goto next;
293
294gt:
295 ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET);
296 goto next;
297
298alpha:
299 if (memcmp(p, "Object [", 8) == 0) { EMIT_UNTIL(']', JSON_TAG) }
300 if (memcmp(p, "Symbol(", 7) == 0) { EMIT_UNTIL(')', JSON_STRING) }
301
302 EMIT_TYPE("Map", 3, JSON_STRING)
303 EMIT_TYPE("Set", 3, JSON_STRING)
304
305 KEYWORD("true", JSON_BOOL)
306 KEYWORD("false", JSON_BOOL)
307 KEYWORD("null", JSON_NULL)
308 KEYWORD("undefined", JSON_NULL)
309 KEYWORD("Infinity", JSON_NUMBER)
310 KEYWORD("NaN", JSON_NUMBER)
311
312ident:
313 if (is_key && brace_depth > 0) {
314 ant_output_stream_append_cstr(out, JSON_KEY);
315 while (isalnum((unsigned char)*p) || *p == '_' || *p == '$') ant_output_stream_putc(out, *p++);
316 ant_output_stream_append_cstr(out, C_RESET);
317 goto next;
318 }
319 ant_output_stream_putc(out, *p++); goto next;
320
321other:
322 if (*p == '+') {
323 int iso_len = io_iso_utc_token_len(p);
324 if (iso_len > 0) {
325 ant_output_stream_append_cstr(out, C_MAGENTA);
326 for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++);
327 ant_output_stream_append_cstr(out, C_RESET);
328 goto next;
329 }
330 }
331 ant_output_stream_putc(out, *p++); goto next;
332}
333
334#undef KEYWORD
335#undef EMIT_UNTIL
336#undef EMIT_TYPE
337
338void print_value_colored(const char *str, FILE *stream) {
339 ant_output_stream_t *out = ant_output_stream(stream);
340 ant_output_stream_begin(out);
341 print_value_colored_to_output(str, out);
342 ant_output_stream_flush(out);
343}
344
345void print_repl_value(ant_t *js, ant_value_t val, FILE *stream) {
346 ant_output_stream_t *out = ant_output_stream(stream);
347
348 if (vtype(val) == T_STR) {
349 char *str = js_getstr(js, val, NULL);
350 ant_output_stream_begin(out);
351 ant_output_stream_append_cstr(out, C(JSON_STRING));
352 ant_output_stream_putc(out, '\'');
353 ant_output_stream_append_cstr(out, str ? str : "");
354 ant_output_stream_putc(out, '\'');
355 ant_output_stream_append_cstr(out, C(C_RESET));
356 ant_output_stream_putc(out, '\n');
357 ant_output_stream_flush(out);
358 return;
359 }
360
361 if (vtype(val) == T_OBJ && vtype(js_get_slot(val, SLOT_ERR_TYPE)) != T_UNDEF) {
362 const char *stack = get_str_prop(js, val, "stack", 5, NULL);
363
364 if (stack) {
365 ant_output_stream_begin(out);
366 io_print_to_output(stack, out);
367 ant_output_stream_putc(out, '\n');
368 ant_output_stream_flush(out);
369 return;
370 }}
371
372 char cbuf[512];
373 js_cstr_t cstr = js_to_cstr(js, val, cbuf, sizeof(cbuf));
374
375 if (vtype(val) == T_ERR) {
376 ant_output_stream_t *err_out = ant_output_stream(stderr);
377 ant_output_stream_begin(err_out);
378 ant_output_stream_append_cstr(err_out, cstr.ptr);
379 ant_output_stream_putc(err_out, '\n');
380 ant_output_stream_flush(err_out);
381 } else {
382 ant_output_stream_begin(out);
383 print_value_colored_to_output(cstr.ptr, out);
384 ant_output_stream_putc(out, '\n');
385 ant_output_stream_flush(out);
386 }
387
388 if (cstr.needs_free) free((void *)cstr.ptr);
389}
390
391static ant_value_t console_call_value(
392 ant_t *js, ant_value_t fn,
393 ant_value_t this_val,
394 ant_value_t *args, int nargs
395) {
396 ant_value_t saved_this = js->this_val;
397 ant_value_t result = js_mkundef();
398
399 js->this_val = this_val;
400 if (vtype(fn) == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs);
401 else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false);
402 js->this_val = saved_this;
403
404 return result;
405}
406
407static ant_value_t console_get_process_stream(ant_t *js, const char *name) {
408 ant_value_t process_obj = js_get(js, js_glob(js), "process");
409 return js_get(js, process_obj, name);
410}
411
412static ant_value_t console_get_effective_this(ant_t *js, ant_value_t this_obj) {
413 if (is_special_object(this_obj)) return this_obj;
414 ant_value_t console_obj = js_get(js, js_glob(js), "console");
415 if (is_special_object(console_obj)) return console_obj;
416 return this_obj;
417}
418
419static ant_value_t console_get_target_stream(ant_t *js, ant_value_t this_obj, bool use_stderr) {
420 if (is_special_object(this_obj)) {
421 ant_value_t direct = js_get_slot(this_obj, use_stderr ? SLOT_CONSOLE_STDERR : SLOT_CONSOLE_STDOUT);
422 if (is_special_object(direct)) return direct;
423 }
424 return console_get_process_stream(js, use_stderr ? "stderr" : "stdout");
425}
426
427static bool console_write_to_stream_obj(ant_t *js, ant_value_t stream_obj, const char *data, size_t len) {
428 if (!is_special_object(stream_obj)) return false;
429
430 ant_value_t write_fn = js_get(js, stream_obj, "write");
431 if (!is_callable(write_fn)) return false;
432
433 ant_value_t argv[1] = { js_mkstr(js, data, len) };
434 ant_value_t result = console_call_value(js, write_fn, stream_obj, argv, 1);
435 if (is_err(result) || js->thrown_exists) return false;
436 return true;
437}
438
439static bool console_write_string(
440 ant_t *js, ant_value_t this_obj,
441 bool use_stderr, const char *data, size_t len
442) {
443 ant_value_t stream_obj = console_get_target_stream(js, this_obj, use_stderr);
444 if (console_write_to_stream_obj(js, stream_obj, data, len)) return true;
445
446 ant_output_stream_t *out = ant_output_stream(use_stderr ? stderr : stdout);
447 ant_output_stream_begin(out);
448 if (!ant_output_stream_append(out, data, len)) return false;
449 return ant_output_stream_flush(out);
450}
451
452static bool console_output_put_indent(ant_output_stream_t *out, int total) {
453 for (int i = 0; i < total; i++) if (!ant_output_stream_putc(out, ' ')) return false;
454 return true;
455}
456
457static int console_get_group_indentation(ant_t *js, ant_value_t this_obj) {
458 ant_value_t value = is_special_object(this_obj) ? js_get_slot(this_obj, SLOT_CONSOLE_GROUP_INDENT) : js_mkundef();
459 return vtype(value) == T_NUM ? (int)js_getnum(value) : 2;
460}
461
462static int console_get_group_level(ant_t *js, ant_value_t this_obj) {
463 ant_value_t value = is_special_object(this_obj) ? js_get_slot(this_obj, SLOT_CONSOLE_GROUP_LEVEL) : js_mkundef();
464 return vtype(value) == T_NUM ? (int)js_getnum(value) : 0;
465}
466
467static void console_set_group_level(ant_t *js, ant_value_t this_obj, int level) {
468 if (!is_special_object(this_obj)) return;
469 if (level < 0) level = 0;
470 js_set_slot(this_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum((double)level));
471}
472
473static ant_value_t console_get_state_map(ant_t *js, ant_value_t this_obj, const char *name) {
474 internal_slot_t slot = SLOT_NONE;
475
476 if (!is_special_object(this_obj)) return js_mkundef();
477 if (strcmp(name, "counts") == 0) slot = SLOT_CONSOLE_COUNTS;
478 else if (strcmp(name, "timers") == 0) slot = SLOT_CONSOLE_TIMERS;
479 else return js_mkundef();
480
481 ant_value_t map = js_get_slot(this_obj, slot);
482 if (is_special_object(map)) return map;
483
484 map = js_mkobj(js);
485 js_set_slot_wb(js, this_obj, slot, map);
486
487 return map;
488}
489
490static bool console_write_args_to_stream(
491 ant_t *js, ant_output_stream_t *out,
492 ant_value_t *args, int nargs, bool color_values
493) {
494 for (int i = 0; i < nargs; i++) {
495 if (i && !ant_output_stream_putc(out, ' ')) return false;
496
497 if (vtype(args[i]) == T_OBJ) {
498 const char *stack = get_str_prop(js, args[i], "stack", 5, NULL);
499 if (stack) {
500 if (!io_print_to_output(stack, out)) return false;
501 continue;
502 }}
503
504 char cbuf[512];
505 js_cstr_t cstr = js_to_cstr(js, args[i], cbuf, sizeof(cbuf));
506 bool ok = true;
507
508 if (vtype(args[i]) == T_STR) ok = io_print_to_output(cstr.ptr, out);
509 else {
510 bool saved_no_color = io_no_color;
511 io_no_color = saved_no_color || !color_values;
512 if (ok) print_value_colored_to_output(cstr.ptr, out);
513 io_no_color = saved_no_color;
514 }
515
516 if (cstr.needs_free) free((void *)cstr.ptr);
517 if (!ok) return false;
518 }
519
520 return true;
521}
522
523static ant_value_t console_emit_to_output(
524 ant_t *js, ant_value_t this_obj,
525 const char *prefix, ant_value_t *args,
526 int nargs,
527 ant_output_stream_t *out
528) {
529 bool color_values = !io_no_color;
530
531 int group_level = console_get_group_level(js, this_obj);
532 int indent = console_get_group_indentation(js, this_obj);
533 int total_indent = group_level * indent;
534
535 if (!console_output_put_indent(out, total_indent)) goto oom;
536 if (prefix && !ant_output_stream_append_cstr(out, prefix)) goto oom;
537 if (prefix && nargs > 0 && !ant_output_stream_putc(out, ' ')) goto oom;
538 if (!console_write_args_to_stream(js, out, args, nargs, color_values)) goto oom;
539 if (!ant_output_stream_putc(out, '\n')) goto oom;
540
541 return js_mkundef();
542 oom: return js_mkerr(js, "Out of memory");
543}
544
545static inline ant_value_t console_emit_with_this(
546 ant_t *js,
547 ant_value_t this_obj,
548 bool use_stderr, const char *prefix,
549 ant_value_t *args, int nargs
550) {
551 this_obj = console_get_effective_this(js, this_obj);
552 ant_output_stream_t out = {0};
553 ant_output_stream_begin(&out);
554
555 ant_value_t result = console_emit_to_output(js, this_obj, prefix, args, nargs, &out);
556 if (!is_err(result)) console_write_string(
557 js, this_obj, use_stderr,
558 out.buffer.data ? out.buffer.data : "", out.buffer.len
559 );
560
561 free(out.buffer.data);
562 return result;
563}
564
565ant_value_t console_emit(
566 ant_t *js,
567 bool use_stderr, const char *prefix,
568 ant_value_t *args, int nargs
569) {
570 return console_emit_with_this(js, js_mkundef(), use_stderr, prefix, args, nargs);
571}
572
573ant_value_t console_emit_current(
574 ant_t *js,
575 bool use_stderr, const char *prefix,
576 ant_value_t *args, int nargs
577) {
578 return console_emit_with_this(js, js_getthis(js), use_stderr, prefix, args, nargs);
579}
580
581static void console_write_args_to_output(ant_t *js, ant_output_stream_t *out, ant_value_t *args, int nargs) {
582for (int i = 0; i < nargs; i++) {
583 if (i) ant_output_stream_putc(out, ' ');
584
585 if (vtype(args[i]) == T_OBJ) {
586 const char *stack = get_str_prop(js, args[i], "stack", 5, NULL);
587 if (stack) {
588 io_print_to_output(stack, out);
589 continue;
590 }}
591
592 char cbuf[512];
593 js_cstr_t cstr = js_to_cstr(js, args[i], cbuf, sizeof(cbuf));
594
595 if (vtype(args[i]) == T_STR) io_print_to_output(cstr.ptr, out);
596 else print_value_colored_to_output(cstr.ptr, out);
597
598 if (cstr.needs_free) free((void *)cstr.ptr);
599}}
600
601static ant_value_t js_console_log(ant_t *js, ant_value_t *args, int nargs) {
602 return console_emit_current(js, false, NULL, args, nargs);
603}
604
605static ant_value_t js_console_error(ant_t *js, ant_value_t *args, int nargs) {
606 return console_emit_current(js, true, NULL, args, nargs);
607}
608
609static ant_value_t js_console_warn(ant_t *js, ant_value_t *args, int nargs) {
610 return console_emit_current(js, true, NULL, args, nargs);
611}
612
613static ant_value_t js_console_info(ant_t *js, ant_value_t *args, int nargs) {
614 return console_emit_current(js, false, NULL, args, nargs);
615}
616
617static ant_value_t js_console_debug(ant_t *js, ant_value_t *args, int nargs) {
618 return console_emit_current(js, false, NULL, args, nargs);
619}
620
621static ant_value_t js_console_assert(ant_t *js, ant_value_t *args, int nargs) {
622 if (nargs < 1) return js_mkundef();
623 bool is_truthy = js_truthy(js, args[0]);
624 if (is_truthy) return js_mkundef();
625 return console_emit_current(js, true, "Assertion failed:", args + 1, nargs - 1);
626}
627
628static ant_value_t js_console_trace(ant_t *js, ant_value_t *args, int nargs) {
629 ant_value_t this_obj = console_get_effective_this(js, js_getthis(js));
630 console_emit_current(js, true, "Trace:", args, nargs);
631 ant_value_t stack = js_capture_raw_stack(js);
632 if (vtype(stack) == T_STR) {
633 size_t stack_len = 0;
634 const char *stack_str = js_getstr(js, stack, &stack_len);
635 console_write_string(js, this_obj, true, stack_str, stack_len);
636 } else js_print_stack_trace_vm(js, stderr);
637 return js_mkundef();
638}
639
640static ant_value_t js_console_clear(ant_t *js, ant_value_t *args, int nargs) {
641 ant_value_t this_obj = js_getthis(js);
642 if (!io_no_color) console_write_string(js, this_obj, false, "\033[2J\033[H", 7);
643 return js_mkundef();
644}
645
646static ant_value_t js_console_time(ant_t *js, ant_value_t *args, int nargs) {
647 ant_value_t this_obj = js_getthis(js);
648 const char *label = "default";
649
650 if (nargs > 0 && vtype(args[0]) == T_STR) label = js_getstr(js, args[0], NULL);
651 ant_value_t timers = console_get_state_map(js, this_obj, "timers");
652 if (is_special_object(timers) && vtype(js_get(js, timers, label)) != T_UNDEF) {
653 ant_value_t warn_args[1] = { js_mkstr(js, "Timer already exists", 20) };
654 return console_emit_current(js, true, NULL, warn_args, 1);
655 }
656
657 js_set(js, timers, label, js_mknum((double)uv_hrtime() / 1e6));
658 return js_mkundef();
659}
660
661static ant_value_t js_console_timeEnd(ant_t *js, ant_value_t *args, int nargs) {
662 ant_value_t this_obj = js_getthis(js);
663 const char *label = "default";
664
665 if (nargs > 0 && vtype(args[0]) == T_STR) label = js_getstr(js, args[0], NULL);
666 ant_value_t timers = console_get_state_map(js, this_obj, "timers");
667 ant_value_t start = is_special_object(timers) ? js_get(js, timers, label) : js_mkundef();
668
669 if (vtype(start) != T_NUM) {
670 ant_value_t warn_args[1] = { js_mkstr(js, "Timer does not exist", 19) };
671 return console_emit_current(js, true, NULL, warn_args, 1);
672 }
673
674 double elapsed = ((double)uv_hrtime() / 1e6) - js_getnum(start);
675 js_delete_prop(js, timers, label, strlen(label));
676 char buf[256];
677
678 int len = snprintf(buf, sizeof(buf), "%s: %.3fms", label, elapsed);
679 ant_value_t out_args[1] = { js_mkstr(js, buf, (size_t)(len > 0 ? len : 0)) };
680
681 return console_emit_current(js, false, NULL, out_args, 1);
682}
683
684static ant_value_t js_console_timeLog(ant_t *js, ant_value_t *args, int nargs) {
685 ant_value_t this_obj = js_getthis(js);
686 const char *label = "default";
687 int extra_start = 0;
688
689 if (nargs > 0 && vtype(args[0]) == T_STR) {
690 label = js_getstr(js, args[0], NULL);
691 extra_start = 1;
692 }
693
694 ant_value_t timers = console_get_state_map(js, this_obj, "timers");
695 ant_value_t start = is_special_object(timers) ? js_get(js, timers, label) : js_mkundef();
696
697 if (vtype(start) != T_NUM) {
698 ant_value_t warn_args[1] = { js_mkstr(js, "Timer does not exist", 19) };
699 return console_emit_current(js, true, NULL, warn_args, 1);
700 }
701
702 char buf[256];
703 double elapsed = ((double)uv_hrtime() / 1e6) - js_getnum(start);
704 int len = snprintf(buf, sizeof(buf), "%s: %.3fms", label, elapsed);
705
706 ant_value_t *out_args = malloc((size_t)(nargs - extra_start + 1) * sizeof(ant_value_t));
707 if (!out_args) return js_mkerr(js, "Out of memory");
708
709 out_args[0] = js_mkstr(js, buf, (size_t)(len > 0 ? len : 0));
710 for (int i = extra_start; i < nargs; i++) out_args[i - extra_start + 1] = args[i];
711 ant_value_t result = console_emit_current(js, false, NULL, out_args, nargs - extra_start + 1);
712 free(out_args);
713
714 return result;
715}
716
717static ant_value_t js_console_count(ant_t *js, ant_value_t *args, int nargs) {
718 ant_value_t this_obj = js_getthis(js);
719 const char *label = "default";
720
721 if (nargs > 0 && vtype(args[0]) == T_STR) label = js_getstr(js, args[0], NULL);
722 ant_value_t counts = console_get_state_map(js, this_obj, "counts");
723 ant_value_t current = is_special_object(counts) ? js_get(js, counts, label) : js_mkundef();
724
725 double next = vtype(current) == T_NUM ? js_getnum(current) + 1 : 1;
726 js_set(js, counts, label, js_mknum(next));
727
728 char buf[256];
729 int len = snprintf(buf, sizeof(buf), "%s: %.0f", label, next);
730 ant_value_t out_args[1] = { js_mkstr(js, buf, (size_t)(len > 0 ? len : 0)) };
731
732 return console_emit_current(js, false, NULL, out_args, 1);
733}
734
735static ant_value_t js_console_countReset(ant_t *js, ant_value_t *args, int nargs) {
736 ant_value_t this_obj = js_getthis(js);
737 const char *label = "default";
738 if (nargs > 0 && vtype(args[0]) == T_STR) label = js_getstr(js, args[0], NULL);
739 ant_value_t counts = console_get_state_map(js, this_obj, "counts");
740 js_delete_prop(js, counts, label, strlen(label));
741 return js_mkundef();
742}
743
744static ant_value_t js_console_group(ant_t *js, ant_value_t *args, int nargs) {
745 ant_value_t this_obj = js_getthis(js);
746 if (nargs > 0) console_emit_current(js, false, NULL, args, nargs);
747 console_set_group_level(js, this_obj, console_get_group_level(js, this_obj) + 1);
748 return js_mkundef();
749}
750
751static ant_value_t js_console_group_end(ant_t *js, ant_value_t *args, int nargs) {
752 ant_value_t this_obj = js_getthis(js);
753 console_set_group_level(js, this_obj, console_get_group_level(js, this_obj) - 1);
754 return js_mkundef();
755}
756
757static ant_value_t js_console_group_collapsed(ant_t *js, ant_value_t *args, int nargs) {
758 return js_console_group(js, args, nargs);
759}
760
761static const char *get_slot_name(internal_slot_t slot) {
762 #define ANT_SLOT_NAME(name) [name] = &#name[5],
763 static const char *slot_names[] = {
764 ANT_INTERNAL_SLOT_LIST(ANT_SLOT_NAME)
765 };
766 #undef ANT_SLOT_NAME
767
768 if (slot < sizeof(slot_names) / sizeof(slot_names[0]) && slot_names[slot]) {
769 return slot_names[slot];
770 }
771
772 return "UNKNOWN";
773}
774
775static const char *get_type_name(int type) {
776 static const char *type_names[] = {
777 [T_OBJ] = "object",
778 [T_STR] = "string",
779 [T_ARR] = "array",
780 [T_FUNC] = "function",
781 [T_CFUNC] = "function",
782 [T_PROMISE] = "Promise",
783 [T_GENERATOR] = "Generator",
784 [T_UNDEF] = "undefined",
785 [T_NULL] = "null",
786 [T_BOOL] = "boolean",
787 [T_NUM] = "number",
788 [T_BIGINT] = "bigint",
789 [T_SYMBOL] = "symbol",
790 [T_ERR] = "error",
791 [T_TYPEDARRAY] = "TypedArray",
792 [T_NTARG] = "ntarg",
793 [T_MAP] = "map",
794 [T_SET] = "set",
795 [T_WEAKMAP] = "weakmap",
796 [T_WEAKSET] = "weakset"
797 };
798
799 size_t num_types = sizeof(type_names) / sizeof(type_names[0]);
800 if (type < 0 || (size_t)type >= num_types) return "unknown";
801
802 return type_names[type] ? type_names[type] : "unknown";
803}
804
805static bool inspect_was_visited(inspect_visited_t *v, uintptr_t off) {
806 for (int i = 0; i < v->count; i++) if (v->visited[i] == off) return true;
807 return false;
808}
809
810static void inspect_print_indent(FILE *stream, int depth) {
811 for (int i = 0; i < depth; i++) fprintf(stream, " ");
812}
813
814static void inspect_mark_visited(inspect_visited_t *v, uintptr_t off) {
815 if (v->count >= v->capacity) {
816 v->capacity = v->capacity ? v->capacity * 2 : 32;
817 v->visited = realloc(v->visited, v->capacity * sizeof(uintptr_t));
818 }
819 v->visited[v->count++] = off;
820}
821
822void inspect_value(ant_t *js, ant_value_t val, FILE *stream, int depth, inspect_visited_t *visited) {
823 int t = vtype(val);
824
825 if (t == T_UNDEF) { fprintf(stream, "undefined"); return; }
826 if (t == T_NULL) { fprintf(stream, "null"); return; }
827 if (t == T_BOOL) { fprintf(stream, val == js_true ? "true" : "false"); return; }
828 if (t == T_NUM) { fprintf(stream, "%g", js_getnum(val)); return; }
829 if (t == T_ERR) { fprintf(stream, "[Error]"); return; }
830
831 if (t == T_STR) {
832 size_t len;
833 char *str = js_getstr(js, val, &len);
834 fprintf(stream, "\"%.*s\"", (int)len, str ? str : "");
835 return;
836 }
837
838 if (t == T_SYMBOL) {
839 const char *desc = js_sym_desc(val);
840 fprintf(stream, "Symbol(%s)", desc ? desc : "");
841 return;
842 }
843
844 if (t == T_OBJ || t == T_FUNC || t == T_PROMISE || t == T_ARR) {
845 if (depth > 10) fprintf(stream, "<%s @%" PRIu64 " ...>", get_type_name(t), (uint64_t)vdata(js_as_obj(val)));
846 else inspect_object(js, val, stream, depth, visited);
847 return;
848 }
849
850 if (t == T_CFUNC) {
851 ant_value_t promoted = js_cfunc_lookup_promoted(js, val);
852 if (vtype(promoted) == T_FUNC) {
853 if (depth > 10) fprintf(stream, "<Function @%" PRIu64 " ...>", (uint64_t)vdata(js_as_obj(promoted)));
854 else inspect_object(js, promoted, stream, depth, visited);
855 return;
856 }
857
858 const ant_cfunc_meta_t *meta = js_as_cfunc_meta(val);
859 const char *name = (meta && meta->name) ? meta->name : NULL;
860 uint32_t length = js_cfunc_length(val);
861 bool has_prototype = meta && (meta->flags & CFUNC_HAS_PROTOTYPE) != 0;
862
863 if (name) fprintf(stream, "[Function: %s]", name);
864 else fprintf(stream, "[Function]");
865
866 fprintf(stream, " <native ptr 0x%" PRIx64 ", length=%u", (uint64_t)vdata(val), length);
867 if (has_prototype) fprintf(stream, ", prototype");
868 fprintf(stream, ">");
869
870 return;
871 }
872
873 fprintf(stream, "<%s rawtype=%d data=%" PRIu64 ">", get_type_name(t), vtype(val), (uint64_t)vdata(val));
874}
875
876void inspect_object(ant_t *js, ant_value_t obj, FILE *stream, int depth, inspect_visited_t *visited) {
877 int type = vtype(obj);
878 obj = js_as_obj(obj);
879 uintptr_t obj_off = (uintptr_t)vdata(obj);
880
881 if (inspect_was_visited(visited, obj_off)) {
882 fprintf(stream, "[Circular *%llu]", (u64)obj_off);
883 return;
884 }
885
886 inspect_mark_visited(visited, obj_off);
887 fprintf(stream, "<%s @%llu> {\n", type == T_FUNC ? "Function" : (type == T_PROMISE ? "Promise" : "Object"), (u64)obj_off);
888
889 int inner_depth = depth + 1;
890 inspect_print_indent(stream, inner_depth);
891 fprintf(stream, "[[Slots]]: {\n");
892
893 for (int slot = SLOT_NONE + 1; slot < SLOT_MAX; slot++) {
894 ant_value_t slot_val = js_get_slot(obj, (internal_slot_t)slot);
895 int t = vtype(slot_val);
896 if (t == T_UNDEF) continue;
897
898 inspect_print_indent(stream, inner_depth + 1);
899 fprintf(stream, "[[%s]]: ", get_slot_name((internal_slot_t)slot));
900
901 switch (slot) {
902 case SLOT_CODE:
903 case SLOT_CFUNC:
904 fprintf(stream, "<native ptr 0x%" PRIx64 ">", (uint64_t)vdata(slot_val));
905 break;
906 case SLOT_CODE_LEN:
907 fprintf(stream, "%.0f", js_getnum(slot_val));
908 break;
909 default:
910 if ((t == T_OBJ || t == T_FUNC || t == T_PROMISE) && inspect_was_visited(visited, (uintptr_t)vdata(js_as_obj(slot_val))))
911 fprintf(stream, "[Circular *%llu]", (u64)vdata(js_as_obj(slot_val)));
912 else if (t == T_OBJ || t == T_FUNC || t == T_PROMISE)
913 fprintf(stream, "<%s @%llu>", get_type_name(t), (u64)vdata(js_as_obj(slot_val)));
914 else
915 inspect_value(js, slot_val, stream, inner_depth + 1, visited);
916 break;
917 }
918
919 fprintf(stream, "\n");
920 }
921
922 inspect_print_indent(stream, inner_depth);
923 fprintf(stream, "}\n");
924
925 inspect_print_indent(stream, inner_depth);
926 fprintf(stream, "[[Properties]]: {\n");
927
928 ant_iter_t iter = js_prop_iter_begin(js, obj);
929 const char *key;
930 size_t key_len;
931 ant_value_t value;
932
933 while (js_prop_iter_next(&iter, &key, &key_len, &value)) {
934 inspect_print_indent(stream, inner_depth + 1);
935 fprintf(stream, "\"%.*s\": ", (int)key_len, key);
936 inspect_value(js, value, stream, inner_depth + 1, visited);
937 fprintf(stream, "\n");
938 }
939
940 js_prop_iter_end(&iter);
941 inspect_print_indent(stream, inner_depth);
942 fprintf(stream, "}\n");
943
944 ant_value_t proto = js_get_proto(js, obj);
945 inspect_print_indent(stream, inner_depth);
946 fprintf(stream, "[[Prototype]]: ");
947 if (vtype(proto) == T_NULL) {
948 fprintf(stream, "null\n");
949 } else {
950 fprintf(stream, "\n");
951 inspect_print_indent(stream, inner_depth);
952 inspect_value(js, proto, stream, inner_depth, visited);
953 fprintf(stream, "\n");
954 }
955
956 inspect_print_indent(stream, depth);
957 fprintf(stream, "}");
958}
959
960static ant_value_t js_console_inspect(ant_t *js, ant_value_t *args, int nargs) {
961 FILE *stream = stdout;
962 inspect_visited_t visited = {0};
963
964 for (int i = 0; i < nargs; i++) {
965 if (i > 0) fprintf(stream, " ");
966 inspect_value(js, args[i], stream, 0, &visited);
967 }
968
969 fprintf(stream, "\n");
970 if (visited.visited) free(visited.visited);
971
972 return js_mkundef();
973}
974
975// TODO: replace stub with real
976static ant_value_t js_console_dir(ant_t *js, ant_value_t *args, int nargs) {
977 return js_console_log(js, args, nargs);
978}
979
980// TODO: replace stub with real
981static ant_value_t js_console_dirxml(ant_t *js, ant_value_t *args, int nargs) {
982 return js_console_log(js, args, nargs);
983}
984
985// TODO: replace stub with real
986static ant_value_t js_console_table(ant_t *js, ant_value_t *args, int nargs) {
987 return js_console_log(js, args, nargs);
988}
989
990static void console_apply_methods(ant_t *js, ant_value_t console_obj) {
991 js_set(js, console_obj, "log", js_mkfun(js_console_log));
992 js_set(js, console_obj, "error", js_mkfun(js_console_error));
993 js_set(js, console_obj, "warn", js_mkfun(js_console_warn));
994 js_set(js, console_obj, "info", js_mkfun(js_console_info));
995 js_set(js, console_obj, "debug", js_mkfun(js_console_debug));
996 js_set(js, console_obj, "assert", js_mkfun(js_console_assert));
997 js_set(js, console_obj, "dir", js_mkfun(js_console_dir));
998 js_set(js, console_obj, "dirxml", js_mkfun(js_console_dirxml));
999 js_set(js, console_obj, "table", js_mkfun(js_console_table));
1000 js_set(js, console_obj, "trace", js_mkfun(js_console_trace));
1001 js_set(js, console_obj, "count", js_mkfun(js_console_count));
1002 js_set(js, console_obj, "countReset", js_mkfun(js_console_countReset));
1003 js_set(js, console_obj, "time", js_mkfun(js_console_time));
1004 js_set(js, console_obj, "timeLog", js_mkfun(js_console_timeLog));
1005 js_set(js, console_obj, "timeEnd", js_mkfun(js_console_timeEnd));
1006 js_set(js, console_obj, "group", js_mkfun(js_console_group));
1007 js_set(js, console_obj, "groupCollapsed", js_mkfun(js_console_group_collapsed));
1008 js_set(js, console_obj, "groupEnd", js_mkfun(js_console_group_end));
1009 js_set(js, console_obj, "clear", js_mkfun(js_console_clear));
1010 js_set(js, console_obj, "inspect", js_mkfun(js_console_inspect));
1011}
1012
1013static ant_value_t js_console_constructor(ant_t *js, ant_value_t *args, int nargs) {
1014 ant_value_t proto = js_instance_proto_from_new_target(js, g_console_proto);
1015 ant_value_t console_obj = js_mkobj(js);
1016 js_set_proto_init(console_obj, is_special_object(proto) ? proto : g_console_proto);
1017
1018 ant_value_t stdout_obj = js_mkundef();
1019 ant_value_t stderr_obj = js_mkundef();
1020 int group_indentation = 2;
1021
1022 if (nargs >= 1 && is_special_object(args[0]) && nargs == 1) {
1023 ant_value_t options = args[0];
1024 stdout_obj = js_get(js, options, "stdout");
1025 stderr_obj = js_get(js, options, "stderr");
1026 ant_value_t gi = js_get(js, options, "groupIndentation");
1027 if (vtype(gi) == T_NUM) group_indentation = (int)js_getnum(gi);
1028 } else {
1029 if (nargs >= 1) stdout_obj = args[0];
1030 if (nargs >= 2) stderr_obj = args[1];
1031 }
1032
1033 if (vtype(stderr_obj) == T_UNDEF) stderr_obj = stdout_obj;
1034 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_STDOUT, stdout_obj);
1035 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_STDERR, stderr_obj);
1036 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_COUNTS, js_mkobj(js));
1037 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_TIMERS, js_mkobj(js));
1038
1039 js_set_slot(console_obj, SLOT_CONSOLE_GROUP_INDENT, js_mknum((double)group_indentation));
1040 js_set_slot(console_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum(0));
1041
1042 return console_obj;
1043}
1044
1045ant_value_t console_library(ant_t *js) {
1046 if (!g_console_ctor) {
1047 g_console_proto = js_mkobj(js);
1048 console_apply_methods(js, g_console_proto);
1049 js_set_sym(js, g_console_proto, get_toStringTag_sym(), js_mkstr(js, "console", 7));
1050 g_console_ctor = js_make_ctor(js, js_console_constructor, g_console_proto, "Console", 7);
1051 gc_register_root(&g_console_proto);
1052 gc_register_root(&g_console_ctor);
1053 }
1054
1055 ant_value_t console_obj = js_mkobj(js);
1056 js_set_proto_init(console_obj, g_console_proto);
1057 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_COUNTS, js_mkobj(js));
1058 js_set_slot_wb(js, console_obj, SLOT_CONSOLE_TIMERS, js_mkobj(js));
1059 js_set_slot(console_obj, SLOT_CONSOLE_GROUP_INDENT, js_mknum(2));
1060 js_set_slot(console_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum(0));
1061
1062 js_set(js, console_obj, "Console", g_console_ctor);
1063 js_set(js, console_obj, "default", console_obj);
1064 js_set_sym(js, console_obj, get_toStringTag_sym(), js_mkstr(js, "console", 7));
1065
1066 return console_obj;
1067}
1068
1069void init_console_module() {
1070 ant_t *js = rt->js;
1071 ant_value_t console_obj = console_library(js);
1072 js_set(js, js_glob(js), "console", console_obj);
1073}