Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615#include <compat.h> // IWYU pragma: keep
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <ctype.h>#include <inttypes.h>#ifndef ANT_WASM_EMBED#include <uv.h>#endif#ifdef _WIN32#include <io.h>#ifndef STDOUT_FILENO#define STDOUT_FILENO 1#endif#ifndef STDERR_FILENO#define STDERR_FILENO 2#endif#else#include <unistd.h>#endif
#include "ascii.h"#include "cfunc.h"#include "common.h"#include "builder.h"#include "stringify.h"#include "gc/roots.h"#include "errors.h"#include "output.h"#include "internal.h"#include "utils.h"#ifdef ANT_WASM_EMBED#include "wasm_embed.h"#else#include "inspector.h"#endif#include "silver/call.h"#include "modules/io.h"#include "modules/util.h"#include "sandbox/sandbox.h"
#ifdef ANT_WASM_EMBEDbool io_no_color = true;#elsebool io_no_color = false;#endif
static bool g_sandbox_terminal_enabled = false;static uint32_t g_sandbox_terminal_capabilities = 0;
static bool io_fd_is_tty(int fd) { if (g_sandbox_terminal_enabled) { if (fd == STDOUT_FILENO) return (g_sandbox_terminal_capabilities & ANT_SANDBOX_CAP_STDOUT_TTY) != 0; if (fd == STDERR_FILENO) return (g_sandbox_terminal_capabilities & ANT_SANDBOX_CAP_STDERR_TTY) != 0; }#ifdef _WIN32 return _isatty(fd) != 0;#else return isatty(fd) != 0;#endif}
int io_color_override(void) { if (g_sandbox_terminal_enabled) { if (g_sandbox_terminal_capabilities & ANT_SANDBOX_CAP_COLOR_STRIP) return 0; if (g_sandbox_terminal_capabilities & ANT_SANDBOX_CAP_COLOR_FORCE) return 1; } if (io_no_color) return 0; const char *force_color = getenv("FORCE_COLOR"); if (force_color) return ant_env_bool(force_color, true); const char *no_color = getenv("NO_COLOR"); if (no_color && *no_color) return 0; return -1;}
bool io_should_color_fd(int fd) { int forced = io_color_override(); return forced >= 0 ? forced : io_fd_is_tty(fd);}
void io_set_sandbox_terminal(uint32_t capabilities) { g_sandbox_terminal_enabled = true; g_sandbox_terminal_capabilities = capabilities; io_no_color = (capabilities & ANT_SANDBOX_CAP_COLOR_STRIP) != 0;}
#define JSON_KEY "\x1b[0m"#define JSON_STRING "\x1b[32m"#define JSON_NUMBER "\x1b[33m"#define JSON_BOOL "\x1b[35m"#define JSON_NULL "\x1b[90m"#define JSON_BRACE "\x1b[37m"#define JSON_FUNC "\x1b[36m"#define JSON_TAG "\x1b[34m"#define JSON_REF "\x1b[90m"#define JSON_WHITE "\x1b[97m"#define JSON_PROPERTY "\x1b[35m"
static inline bool io_is_hex_byte(const char *p) { return isxdigit((unsigned char)p[0]) && isxdigit((unsigned char)p[1]) && (p[2] == ' ' || p[2] == '>');}
static const char *io_color_hex_bytes(const char *p, ant_output_stream_t *out) { while (true) { if (io_is_hex_byte(p)) { ant_output_stream_append_cstr(out, JSON_NUMBER); ant_output_stream_putc(out, *p++); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); continue; }
if (p[0] == ' ' && io_is_hex_byte(p + 1)) { ant_output_stream_putc(out, *p++); continue; }
return p; }}
static size_t io_binary_type_len(const char *p) { #define MATCH_BINARY_TYPE(name) do { \ size_t len = sizeof(name) - 1; \ if (strncmp(p, name, len) == 0 && \ (p[len] == '(' || p[len] == ' ' || p[len] == '{')) return len; \ } while (0)
switch (*p) { case 'A': MATCH_BINARY_TYPE("ArrayBuffer"); break; case 'S': MATCH_BINARY_TYPE("SharedArrayBuffer"); break; case 'D': MATCH_BINARY_TYPE("DataView"); break; case 'I': MATCH_BINARY_TYPE("Int8Array"); MATCH_BINARY_TYPE("Int16Array"); MATCH_BINARY_TYPE("Int32Array"); break; case 'U': MATCH_BINARY_TYPE("Uint8Array"); MATCH_BINARY_TYPE("Uint8ClampedArray"); MATCH_BINARY_TYPE("Uint16Array"); MATCH_BINARY_TYPE("Uint32Array"); break; case 'F': MATCH_BINARY_TYPE("Float16Array"); MATCH_BINARY_TYPE("Float32Array"); MATCH_BINARY_TYPE("Float64Array"); break; case 'B': MATCH_BINARY_TYPE("BigInt64Array"); MATCH_BINARY_TYPE("BigUint64Array"); MATCH_BINARY_TYPE("Buffer"); break; case 'T': MATCH_BINARY_TYPE("TypedArray"); break; }
#undef MATCH_BINARY_TYPE return 0;}
static bool io_print_to_output_n(const char *str, size_t len, ant_output_stream_t *out, bool no_color) { if (!no_color) return ant_output_stream_append(out, str, len);
static void *states[] = {&&normal, &&esc, &&csi, &&done}; const char *p = str, *end = str + len; char c;
goto *states[0];
normal: { if (p == end) goto *states[3]; c = *p++; if (!c) goto *states[3]; if (c == '\x1b') goto *states[1]; if (!ant_output_stream_putc(out, c)) return false; goto *states[0]; }
esc: { if (p == end) goto *states[3]; c = *p++; if (!c) goto *states[3]; if (c == '[') goto *states[2]; if (!ant_output_stream_putc(out, '\x1b')) return false; if (!ant_output_stream_putc(out, c)) return false; goto *states[0]; }
csi: { if (p == end) goto *states[3]; c = *p++; if (!c) goto *states[3]; if ((c >= '0' && c <= '9') || c == ';') goto *states[2]; if (c != 'm' && !ant_output_stream_putc(out, c)) return false; goto *states[0]; }
done: return true;}
static bool io_print_to_output(const char *str, ant_output_stream_t *out, bool no_color) { return io_print_to_output_n(str, strlen(str), out, no_color);}
enum char_class { CC_OTHER, CC_NUL, CC_QUOTE, CC_ESCAPE, CC_LBRACE, CC_RBRACE, CC_LBRACK, CC_RBRACK, CC_COLON, CC_COMMA, CC_NEWLINE, CC_DIGIT, CC_MINUS, CC_ALPHA, CC_IDENT, CC_LT, CC_GT};
static const uint8_t char_class_table[256] = { [0] = CC_NUL, ['\n'] = CC_NEWLINE, ['"'] = CC_QUOTE, ['\''] = CC_QUOTE, ['\\'] = CC_ESCAPE, ['{'] = CC_LBRACE, ['}'] = CC_RBRACE, ['['] = CC_LBRACK, [']'] = CC_RBRACK, [':'] = CC_COLON, [','] = CC_COMMA, ['-'] = CC_MINUS, ['<'] = CC_LT, ['>'] = CC_GT, ['_'] = CC_IDENT, ['$'] = CC_IDENT, ['0'] = CC_DIGIT, ['1'] = CC_DIGIT, ['2'] = CC_DIGIT, ['3'] = CC_DIGIT, ['4'] = CC_DIGIT, ['5'] = CC_DIGIT, ['6'] = CC_DIGIT, ['7'] = CC_DIGIT, ['8'] = CC_DIGIT, ['9'] = CC_DIGIT, ['a'] = CC_ALPHA, ['b'] = CC_ALPHA, ['c'] = CC_ALPHA, ['d'] = CC_ALPHA, ['e'] = CC_ALPHA, ['f'] = CC_ALPHA, ['g'] = CC_ALPHA, ['h'] = CC_ALPHA, ['i'] = CC_ALPHA, ['j'] = CC_ALPHA, ['k'] = CC_ALPHA, ['l'] = CC_ALPHA, ['m'] = CC_ALPHA, ['n'] = CC_ALPHA, ['o'] = CC_ALPHA, ['p'] = CC_ALPHA, ['q'] = CC_ALPHA, ['r'] = CC_ALPHA, ['s'] = CC_ALPHA, ['t'] = CC_ALPHA, ['u'] = CC_ALPHA, ['v'] = CC_ALPHA, ['w'] = CC_ALPHA, ['x'] = CC_ALPHA, ['y'] = CC_ALPHA, ['z'] = CC_ALPHA, ['A'] = CC_ALPHA, ['B'] = CC_ALPHA, ['C'] = CC_ALPHA, ['D'] = CC_ALPHA, ['E'] = CC_ALPHA, ['F'] = CC_ALPHA, ['G'] = CC_ALPHA, ['H'] = CC_ALPHA, ['I'] = CC_ALPHA, ['J'] = CC_ALPHA, ['K'] = CC_ALPHA, ['L'] = CC_ALPHA, ['M'] = CC_ALPHA, ['N'] = CC_ALPHA, ['O'] = CC_ALPHA, ['P'] = CC_ALPHA, ['Q'] = CC_ALPHA, ['R'] = CC_ALPHA, ['S'] = CC_ALPHA, ['T'] = CC_ALPHA, ['U'] = CC_ALPHA, ['V'] = CC_ALPHA, ['W'] = CC_ALPHA, ['X'] = CC_ALPHA, ['Y'] = CC_ALPHA, ['Z'] = CC_ALPHA,};
static int io_iso_utc_token_len(const char *p) { int i = 0;
if (*p == '+' || *p == '-') { i++; for (int d = 0; d < 6; d++, i++) if (!ant_ascii_is_digit(p[i])) return 0; } else for (int d = 0; d < 4; d++, i++) if (!ant_ascii_is_digit(p[i])) return 0;
if (p[i++] != '-') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != '-') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != 'T') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != ':') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != ':') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != '.') return 0; if (!ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++]) || !ant_ascii_is_digit(p[i++])) return 0; if (p[i++] != 'Z') return 0;
char boundary = p[i]; if ( !(boundary == '\0' || boundary == ' ' || boundary == '\t' || boundary == '\n' || boundary == ',' || boundary == ']' || boundary == '}' || boundary == ')' || boundary == '>') ) return 0;
return i;}
#define KEYWORD(kw, color) \ if (memcmp(p, kw, sizeof(kw) - 1) == 0 && !isalnum((unsigned char)p[sizeof(kw) - 1]) && p[sizeof(kw) - 1] != '_') { \ ant_output_stream_append_cstr(out, color); ant_output_stream_append_cstr(out, kw); ant_output_stream_append_cstr(out, C_RESET); \ p += sizeof(kw) - 1; goto next; \ }
#define EMIT_UNTIL(end_char, color) \ ant_output_stream_append_cstr(out, color); \ while (*p && *p != end_char) ant_output_stream_putc(out, *p++); \ if (*p == end_char) ant_output_stream_putc(out, *p++); \ ant_output_stream_append_cstr(out, C_RESET); goto next;
#define EMIT_UNTIL_BEFORE(end_char, color) \ ant_output_stream_append_cstr(out, color); \ while (*p && *p != end_char) ant_output_stream_putc(out, *p++);
#define EMIT_TYPE(tag, len, color) \ if (!(is_key && brace_depth > 0) && memcmp(p, tag, len) == 0) { \ ant_output_stream_append_cstr(out, color); ant_output_stream_append_cstr(out, tag); ant_output_stream_append_cstr(out, C_RESET); \ p += len; goto next; \ }
static void print_value_colored_to_output( const char *str, ant_output_stream_t *out, bool no_color) { if (no_color) { io_print_to_output(str, out, true); return; }
static void *dispatch[] = { [CC_NUL] = &&done, [CC_QUOTE] = &"e, [CC_ESCAPE] = &&other, [CC_LBRACE] = &&lbrace, [CC_RBRACE] = &&rbrace, [CC_LBRACK] = &&lbrack, [CC_RBRACK] = &&rbrack, [CC_COLON] = &&colon, [CC_COMMA] = &&separator, [CC_NEWLINE] = &&separator, [CC_DIGIT] = &&number, [CC_MINUS] = &&minus, [CC_ALPHA] = &&alpha, [CC_IDENT] = &&ident, [CC_LT] = &<, [CC_GT] = &>, [CC_OTHER] = &&other };
const char *p = str; char string_char = 0; int brace_depth = 0, array_depth = 0; bool is_key = true;
goto next;
next: goto *dispatch[char_class_table[(unsigned char)*p]];
done: return;
quote: string_char = *p; ant_output_stream_append_cstr(out, (is_key && brace_depth > 0) ? JSON_KEY : JSON_STRING); ant_output_stream_putc(out, *p++); while (*p) { if (*p == '\\' && p[1]) { ant_output_stream_putc(out, *p++); ant_output_stream_putc(out, *p++); continue; } if (*p == string_char) { ant_output_stream_putc(out, *p++); break; } ant_output_stream_putc(out, *p++); } ant_output_stream_append_cstr(out, C_RESET); goto next;
lbrace: ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); brace_depth++; is_key = true; goto next;
rbrace: ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); brace_depth--; is_key = false; goto next;
lbrack: switch (p[1]) { case 'A': if ( memcmp(p + 2, "syncFunction", 7) == 0 || memcmp(p + 2, "syncGeneratorFunction", 21) == 0 ) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'b': if (memcmp(p + 2, "yte", 3) == 0 || memcmp(p + 2, "uffer]", 6) == 0) { EMIT_UNTIL(']', JSON_STRING) } break; case 'F': if (memcmp(p + 2, "unction", 7) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'c': if (memcmp(p + 2, "lass ", 5) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'n': if (memcmp(p + 2, "ative code", 10) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'C': if (memcmp(p + 2, "ircular", 7) == 0) { EMIT_UNTIL(']', JSON_REF) } break; case 'G': if ( memcmp(p + 2, "etter/Setter]", 13) == 0 || memcmp(p + 2, "etter]", 6) == 0 || memcmp(p + 2, "eneratorFunction", 16) == 0 ) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'S': if (memcmp(p + 2, "etter]", 6) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'O': if (memcmp(p + 2, "bject: null prototype]", 22) == 0) { EMIT_UNTIL(']', JSON_TAG) } break; case 'M': if (memcmp(p + 2, "odule]", 6) == 0) { EMIT_UNTIL(']', JSON_TAG) } break; case 'U': if (memcmp(p + 2, "int8Contents]", 13) == 0) { EMIT_UNTIL(']', JSON_FUNC) } break; case 'P': if (memcmp(p + 2, "romise]", 7) == 0) { EMIT_UNTIL(']', JSON_TAG) } break; } ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); array_depth++; is_key = false; goto next;
rbrack: ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); array_depth--; is_key = false; goto next;
colon: ant_output_stream_putc(out, *p++); is_key = false; goto next;
separator: ant_output_stream_putc(out, *p++); is_key = (brace_depth > 0 && array_depth == 0); goto next;
number: { int iso_len = io_iso_utc_token_len(p); if (iso_len > 0) { ant_output_stream_append_cstr(out, C_MAGENTA); for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; } } ant_output_stream_append_cstr(out, JSON_NUMBER); while ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' || *p == '+' || *p == '-') ant_output_stream_putc(out, *p++); if (*p == 'n' && !isalnum((unsigned char)p[1]) && p[1] != '_' && p[1] != '$') ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next;
minus: { int iso_len = io_iso_utc_token_len(p); if (iso_len > 0) { ant_output_stream_append_cstr(out, C_MAGENTA); for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; } } if (memcmp(p + 1, "Infinity", 8) == 0 && !isalnum((unsigned char)p[9]) && p[9] != '_') { ant_output_stream_append_cstr(out, JSON_NUMBER); ant_output_stream_append_cstr(out, "-Infinity"); ant_output_stream_append_cstr(out, C_RESET); p += 9; goto next; } if (p[1] >= '0' && p[1] <= '9') { ant_output_stream_append_cstr(out, JSON_NUMBER); ant_output_stream_putc(out, *p++); while ((*p >= '0' && *p <= '9') || *p == '.' || *p == 'e' || *p == 'E' || *p == '+' || *p == '-') ant_output_stream_putc(out, *p++); if (*p == 'n' && !isalnum((unsigned char)p[1]) && p[1] != '_' && p[1] != '$') ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; } ant_output_stream_putc(out, *p++); goto next;
lt: if (memcmp(p, "<ref", 4) == 0) { EMIT_UNTIL('>', JSON_REF) } if (memcmp(p, "<pen", 4) == 0) { is_key = false; EMIT_UNTIL('>', C_CYAN) } if (memcmp(p, "<rej", 4) == 0) { is_key = false; EMIT_UNTIL('>', C_CYAN) }
if (strncmp(p, "<Buffer", 7) == 0 && (p[7] == ' ' || p[7] == '>')) { ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); ant_output_stream_append(out, p, 6); p += 6; p = io_color_hex_bytes(p, out); goto next; }
if (p[1] == '>' || io_is_hex_byte(p + 1)) { ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); p = io_color_hex_bytes(p, out); if (*p == '>') { ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); } goto next; }
ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next;
gt: ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next;
alpha: if (memcmp(p, "Object [", 8) == 0) { EMIT_UNTIL(']', JSON_TAG) } if (memcmp(p, "Symbol(", 7) == 0) { ant_output_stream_append_cstr(out, JSON_FUNC); ant_output_stream_append(out, "Symbol", 6); ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, '('); p += 7; if (memcmp(p, "Symbol.", 7) == 0) { ant_output_stream_append_cstr(out, JSON_FUNC); ant_output_stream_append(out, "Symbol", 6); ant_output_stream_append_cstr(out, JSON_BRACE); ant_output_stream_putc(out, '.'); p += 7; EMIT_UNTIL_BEFORE(')', JSON_PROPERTY) } else if (*p != ')') { EMIT_UNTIL_BEFORE(')', JSON_KEY) } ant_output_stream_append_cstr(out, JSON_BRACE); if (*p == ')') ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; }
size_t type_len = io_binary_type_len(p); if (type_len > 0) { ant_output_stream_append(out, p, type_len); p += type_len; goto next; }
EMIT_TYPE("Map", 3, JSON_STRING) EMIT_TYPE("Set", 3, JSON_STRING)
KEYWORD("true", JSON_BOOL) KEYWORD("false", JSON_BOOL) KEYWORD("null", JSON_NULL) KEYWORD("undefined", JSON_NULL) KEYWORD("Infinity", JSON_NUMBER) KEYWORD("NaN", JSON_NUMBER)
ident: if (is_key && brace_depth > 0) { ant_output_stream_append_cstr(out, JSON_KEY); while (isalnum((unsigned char)*p) || *p == '_' || *p == '$') ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; } ant_output_stream_putc(out, *p++); goto next;
other: if (*p == '+') { int iso_len = io_iso_utc_token_len(p); if (iso_len > 0) { ant_output_stream_append_cstr(out, C_MAGENTA); for (int k = 0; k < iso_len; k++) ant_output_stream_putc(out, *p++); ant_output_stream_append_cstr(out, C_RESET); goto next; } } ant_output_stream_putc(out, *p++); goto next;}
#undef KEYWORD#undef EMIT_UNTIL#undef EMIT_TYPE
void print_value_colored(const char *str, FILE *stream) { ant_output_stream_t *out = ant_output_stream(stream); ant_output_stream_begin(out); print_value_colored_to_output(str, out, io_no_color); ant_output_stream_flush(out);}
void print_repl_value(ant_t *js, ant_value_t val, FILE *stream) { ant_output_stream_t *out = ant_output_stream(stream);
if (vtype(val) == kTypeString) { char cbuf[512]; js_cstr_t quoted = js_inspect_cstr(js, val, cbuf, sizeof(cbuf)); ant_output_stream_begin(out); ant_output_stream_append_cstr(out, C(JSON_STRING)); ant_output_stream_append_cstr(out, quoted.ptr); ant_output_stream_append_cstr(out, C(C_RESET)); ant_output_stream_putc(out, '\n'); ant_output_stream_flush(out); if (quoted.needs_free) free((void *)quoted.ptr); return; }
if (vtype(val) == kTypeObject && vtype(js_get_slot(val, SLOT_ERR_TYPE)) != kTypeUndefined) { ant_value_t stack = js_getprop_fallback_len(js, val, "stack", 5); if (vtype(stack) == kTypeString) { ant_output_stream_begin(out); io_print_error_stack(js, out, val, stack, !io_should_color_fd(fileno(stream))); ant_output_stream_putc(out, '\n'); ant_output_stream_flush(out); return; } }
char cbuf[512]; js_cstr_t cstr = js_to_cstr(js, val, cbuf, sizeof(cbuf));
if (vtype(val) == kTypeError) { ant_output_stream_t *err_out = ant_output_stream(stderr); ant_output_stream_begin(err_out); ant_output_stream_append_cstr(err_out, cstr.ptr); ant_output_stream_putc(err_out, '\n'); ant_output_stream_flush(err_out); } else { ant_output_stream_begin(out); print_value_colored_to_output(cstr.ptr, out, io_no_color); ant_output_stream_putc(out, '\n'); ant_output_stream_flush(out); }
if (cstr.needs_free) free((void *)cstr.ptr);}
static ant_value_t console_get_process_stream(ant_t *js, const char *name) { ant_value_t process_obj = js_get(js, js_glob(js), "process"); return js_get(js, process_obj, name);}
static ant_value_t console_get_effective_this(ant_t *js, ant_value_t this_obj) { if (is_special_object(this_obj)) return this_obj; ant_value_t console_obj = js_get(js, js_glob(js), "console"); if (is_special_object(console_obj)) return console_obj; return this_obj;}
static ant_value_t console_get_target_stream(ant_t *js, ant_value_t this_obj, bool use_stderr) { if (is_special_object(this_obj)) { ant_value_t direct = js_get_slot(this_obj, use_stderr ? SLOT_CONSOLE_STDERR : SLOT_CONSOLE_STDOUT); if (is_special_object(direct)) return direct; } return console_get_process_stream(js, use_stderr ? "stderr" : "stdout");}
static bool console_write_to_stream_obj(ant_t *js, ant_value_t stream_obj, const char *data, size_t len) { if (!is_special_object(stream_obj)) return false;
ant_value_t write_fn = js_get(js, stream_obj, "write"); if (!is_callable(write_fn)) return false;
bool was_pending = Ant_Exception_Pending(js); ant_value_t argv[1] = { js_mkstr(js, data, len) }; ant_value_t result = sv_call_value(js, write_fn, stream_obj, argv, 1); if (is_err(result)) return false; if (Ant_Exception_Pending(js) && !was_pending) return false; return true;}
static bool console_write_string( ant_t *js, ant_value_t this_obj, bool use_stderr, const char *data, size_t len) { ant_value_t stream_obj = console_get_target_stream(js, this_obj, use_stderr); if (console_write_to_stream_obj(js, stream_obj, data, len)) return true;
ant_output_stream_t *out = ant_output_stream(use_stderr ? stderr : stdout); ant_output_stream_begin(out); if (!ant_output_stream_append(out, data, len)) return false; return ant_output_stream_flush(out);}
static bool console_output_put_indent(ant_output_stream_t *out, int total) { for (int i = 0; i < total; i++) if (!ant_output_stream_putc(out, ' ')) return false; return true;}
static int console_get_group_indentation(ant_t *js, ant_value_t this_obj) { ant_value_t value = is_special_object(this_obj) ? js_get_slot(this_obj, SLOT_CONSOLE_GROUP_INDENT) : js_mkundef(); return vtype(value) == kTypeNumber ? (int)js_getnum(value) : 2;}
static int console_get_group_level(ant_t *js, ant_value_t this_obj) { ant_value_t value = is_special_object(this_obj) ? js_get_slot(this_obj, SLOT_CONSOLE_GROUP_LEVEL) : js_mkundef(); return vtype(value) == kTypeNumber ? (int)js_getnum(value) : 0;}
static void console_set_group_level(ant_t *js, ant_value_t this_obj, int level) { if (!is_special_object(this_obj)) return; if (level < 0) level = 0; js_set_slot(this_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum((double)level));}
static ant_value_t console_get_state_map(ant_t *js, ant_value_t this_obj, const char *name) { internal_slot_t slot = SLOT_NONE;
if (!is_special_object(this_obj)) return js_mkundef(); if (strcmp(name, "counts") == 0) slot = SLOT_CONSOLE_COUNTS; else if (strcmp(name, "timers") == 0) slot = SLOT_CONSOLE_TIMERS; else return js_mkundef();
ant_value_t map = js_get_slot(this_obj, slot); if (is_special_object(map)) return map;
map = Ant_Object_CreateBare(js); js_set_slot_wb(js, this_obj, slot, map);
return map;}
typedef struct { ant_t *js; ant_output_stream_t *out; bool color_values; bool ok;} console_format_ctx_t;
static bool console_emit_value(console_format_ctx_t *c, ant_value_t value, bool plain) { char cbuf[512]; js_cstr_t cstr = js_to_cstr(c->js, value, cbuf, sizeof(cbuf));
if (plain) c->ok = io_print_to_output_n(cstr.ptr, cstr.len, c->out, io_no_color); else print_value_colored_to_output(cstr.ptr, c->out, io_no_color || !c->color_values);
if (cstr.needs_free) free((void *)cstr.ptr); return c->ok;}
static bool console_format_text(void *ctx, const char *s, size_t len) { console_format_ctx_t *c = (console_format_ctx_t *)ctx; c->ok = c->ok && ant_output_stream_append(c->out, s, len); return c->ok;}
static bool console_emit_inspected(console_format_ctx_t *c, ant_value_t value, bool show_hidden) { char cbuf[256]; js_cstr_t cstr = show_hidden ? js_inspect_cstr_opts(c->js, value, cbuf, sizeof(cbuf), 4, ANT_INSPECT_SHOW_HIDDEN) : js_inspect_cstr(c->js, value, cbuf, sizeof(cbuf));
c->ok = io_print_to_output(cstr.ptr, c->out, io_no_color); if (cstr.needs_free) free((void *)cstr.ptr); return c->ok;}
static bool console_format_value(void *ctx, ant_value_t value, char spec) { console_format_ctx_t *c = (console_format_ctx_t *)ctx; if (spec == 'o') return console_emit_inspected(c, value, true); if (spec == 'O' && vtype(value) == kTypeString) return console_emit_inspected(c, value, false); return console_emit_value(c, value, spec == 's' && vtype(value) == kTypeString);}
static const ant_format_sink_t console_format_sink = { console_format_text, console_format_value};
bool io_print_error_header(ant_t *js, ant_output_stream_t *out, ant_value_t err, bool plain) { GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, err); ant_value_t name, message; if (is_err(js_error_header_parts(js, err, &name, &message))) { js_take_thrown(js, js_mkundef()); name = js_mkstr(js, "Error", 5); message = js_mkstr(js, "", 0); } GC_ROOT_PIN(js, name); GC_ROOT_PIN(js, message);
size_t name_len = 0, message_len = 0; const char *name_text = js_getstr(js, name, &name_len); const char *message_text = js_getstr(js, message, &message_len); ant_offset_t class_len = 0; const char *class_name = get_class_name(js, err, &class_len, "Object"); bool class_differs = name_len && class_name && class_len > 0 && ((size_t)class_len != name_len || memcmp(class_name, name_text, name_len) != 0);
ant_value_t display = js_error_display_name(js, err, name); if (!is_err(display) && display != name) { GC_ROOT_PIN(js, display); name_text = js_getstr(js, display, &name_len); }
const char *red = plain ? "" : C_RED; const char *bold = plain ? "" : C_BOLD; const char *reset = plain ? "" : C_RESET;
bool ok = true; if (class_differs) { ok = ant_output_stream_appendf(out, "%s%.*s [%.*s]%s", red, (int)class_len, class_name, (int)name_len, name_text, reset); } else if (name_len) ok = ant_output_stream_appendf(out, "%s%.*s%s", red, (int)name_len, name_text, reset); if (ok && message_len) ok = ant_output_stream_appendf(out, "%s%s%.*s%s", name_len ? ": " : "", bold, (int)message_len, message_text, reset);
GC_ROOT_RESTORE(js, root_mark); return ok;}
bool io_print_error_stack( ant_t *js, ant_output_stream_t *out, ant_value_t err, ant_value_t stack, bool plain) { GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, err); GC_ROOT_PIN(js, stack);
size_t len = 0, header_at = 0; char *pretty = js_error_render_pretty(js, err, stack, &len, &header_at); bool ok;
if (pretty) { ok = io_print_to_output_n(pretty, header_at, out, plain); if (ok) ok = io_print_error_header(js, out, err, plain); if (ok) ok = io_print_to_output_n(pretty + header_at, len - header_at, out, plain); free(pretty); } else { const char *text = js_getstr(js, stack, &len); ok = text && io_print_to_output_n(text, len, out, plain); } if (ok) ok = io_print_error_props(js, out, err, plain); GC_ROOT_RESTORE(js, root_mark); return ok;}
bool io_print_error_props(ant_t *js, ant_output_stream_t *out, ant_value_t err, bool plain) { if (vtype(err) != kTypeObject) return true;
js_inspect_builder_t builder; if (!js_inspect_builder_init_dynamic(&builder, js, 128)) return false; builder.bare_mode = true;
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, err);
ant_value_t stack = js_get_slot(err, SLOT_ERROR_STACK_TEXT); if (vtype(stack) == kTypeString) { GC_ROOT_PIN(js, stack); builder.error_stack = js_getstr(js, stack, &builder.error_stack_len); }
ant_stringify_ctx_t ctx; ant_stringify_enter(js, &ctx, ANT_INSPECT_MAX_DEPTH); ctx.stack[ctx.depth++] = err;
bool ok = js_inspect_object_body(&builder, err); Ant_List_Remove(&ctx); if (ok) print_value_colored_to_output(builder.buf, out, plain);
js_inspect_builder_dispose(&builder); GC_ROOT_RESTORE(js, root_mark);
return ok && !out->buffer.failed;}
static bool console_write_args_to_stream( ant_t *js, ant_output_stream_t *out, ant_value_t *args, int nargs, bool color_values) { console_format_ctx_t ctx = { js, out, color_values, true }; int start = ant_format_walk(js, args, nargs, 0, &console_format_sink, &ctx); if (!ctx.ok) return false;
for (int i = start; i < nargs; i++) { if ((i || start) && !ant_output_stream_putc(out, ' ')) return false;
ant_value_t stack = vtype(args[i]) == kTypeObject ? js_getprop_fallback_len(js, args[i], "stack", 5) : js_mkundef();
if (vtype(stack) == kTypeString) { if (!io_print_error_stack(js, out, args[i], stack, io_no_color || !color_values)) return false; continue; }
if (!console_emit_value(&ctx, args[i], vtype(args[i]) == kTypeString)) return false; }
return true;}
static ant_value_t console_emit_to_output( ant_t *js, ant_value_t this_obj, const char *prefix, ant_value_t *args, int nargs, ant_output_stream_t *out, bool use_stderr) { bool color_values = io_should_color_fd(use_stderr ? STDERR_FILENO : STDOUT_FILENO);
int group_level = console_get_group_level(js, this_obj); int indent = console_get_group_indentation(js, this_obj); int total_indent = group_level * indent;
if (!console_output_put_indent(out, total_indent)) goto oom; if (prefix && !ant_output_stream_append_cstr(out, prefix)) goto oom; if (prefix && nargs > 0 && !ant_output_stream_putc(out, ' ')) goto oom; if (!console_write_args_to_stream(js, out, args, nargs, color_values)) goto oom; if (!ant_output_stream_putc(out, '\n')) goto oom;
return js_mkundef(); oom: return js_mkerr(js, "Out of memory");}
static inline ant_value_t console_emit_with_this( ant_t *js, ant_value_t this_obj, bool use_stderr, const char *prefix, ant_value_t *args, int nargs) { this_obj = console_get_effective_this(js, this_obj); ant_output_stream_t out = {0}; ant_output_stream_begin(&out);
ant_value_t result = console_emit_to_output( js, this_obj, prefix, args, nargs, &out, use_stderr ); if (!is_err(result)) console_write_string( js, this_obj, use_stderr, out.buffer.data ? out.buffer.data : "", out.buffer.len );
free(out.buffer.data); return result;}
ant_value_t console_emit( ant_t *js, bool use_stderr, const char *prefix, ant_value_t *args, int nargs) { return console_emit_with_this(js, js_mkundef(), use_stderr, prefix, args, nargs);}
ant_value_t console_emit_current( ant_t *js, bool use_stderr, const char *prefix, ant_value_t *args, int nargs) { return console_emit_with_this(js, js_getthis(js), use_stderr, prefix, args, nargs);}
static ant_value_t js_console_log(ant_params_t) {#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "log", args, nargs);#endif return console_emit_current(js, false, NULL, args, nargs);}
static ant_value_t js_console_error(ant_params_t) {#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "error", args, nargs);#endif return console_emit_current(js, true, NULL, args, nargs);}
static ant_value_t js_console_warn(ant_params_t) {#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "warning", args, nargs);#endif return console_emit_current(js, true, NULL, args, nargs);}
static ant_value_t js_console_info(ant_params_t) {#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "info", args, nargs);#endif return console_emit_current(js, false, NULL, args, nargs);}
static ant_value_t js_console_debug(ant_params_t) {#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "debug", args, nargs);#endif return console_emit_current(js, false, NULL, args, nargs);}
static ant_value_t js_console_assert(ant_params_t) { if (nargs < 1) return js_mkundef(); bool is_truthy = js_truthy(js, args[0]); if (is_truthy) return js_mkundef();#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "assert", args + 1, nargs - 1);#endif return console_emit_current(js, true, "Assertion failed:", args + 1, nargs - 1);}
static ant_value_t js_console_trace(ant_params_t) { ant_value_t this_obj = console_get_effective_this(js, js_getthis(js));#ifndef ANT_WASM_EMBED ant_inspector_console_api_called(js, "trace", args, nargs);#endif console_emit_current(js, true, "Trace:", args, nargs); ant_value_t stack = js_capture_raw_stack(js); if (vtype(stack) == kTypeString) { size_t stack_len = 0; const char *stack_str = js_getstr(js, stack, &stack_len); console_write_string(js, this_obj, true, stack_str, stack_len); } else js_print_stack_trace_vm(js, stderr); return js_mkundef();}
static ant_value_t js_console_clear(ant_params_t) { ant_value_t this_obj = js_getthis(js); if (!io_no_color) console_write_string(js, this_obj, false, "\033[2J\033[H", 7); return js_mkundef();}
static double console_now_ms(void) {#ifdef ANT_WASM_EMBED return ant_wasm_now_ms();#else return (double)uv_hrtime() / 1e6;#endif}
static ant_value_t js_console_time(ant_params_t) { ant_value_t this_obj = js_getthis(js); const char *label = "default"; if (nargs > 0 && vtype(args[0]) == kTypeString) label = js_getstr(js, args[0], NULL); ant_value_t timers = console_get_state_map(js, this_obj, "timers"); if (is_special_object(timers) && vtype(js_get(js, timers, label)) != kTypeUndefined) { ant_value_t warn_args[1] = { js_mkstr(js, "Timer already exists", 20) }; return console_emit_current(js, true, NULL, warn_args, 1); } js_set(js, timers, label, js_mknum(console_now_ms())); return js_mkundef();}
static ant_value_t js_console_timeEnd(ant_params_t) { ant_value_t this_obj = js_getthis(js); const char *label = "default"; if (nargs > 0 && vtype(args[0]) == kTypeString) label = js_getstr(js, args[0], NULL); ant_value_t timers = console_get_state_map(js, this_obj, "timers"); ant_value_t start = is_special_object(timers) ? js_get(js, timers, label) : js_mkundef(); if (vtype(start) != kTypeNumber) { ant_value_t warn_args[1] = { js_mkstr(js, "Timer does not exist", 19) }; return console_emit_current(js, true, NULL, warn_args, 1); } double elapsed = console_now_ms() - js_getnum(start); js_delete_prop(js, timers, label, strlen(label)); char buf[256]; int len = snprintf(buf, sizeof(buf), "%s: %.3fms", label, elapsed); ant_value_t out_args[1] = { js_mkstr(js, buf, (size_t)(len > 0 ? len : 0)) }; return console_emit_current(js, false, NULL, out_args, 1);}
static ant_value_t js_console_timeLog(ant_params_t) { ant_value_t this_obj = js_getthis(js); const char *label = "default"; int extra_start = 0; if (nargs > 0 && vtype(args[0]) == kTypeString) { label = js_getstr(js, args[0], NULL); extra_start = 1; } ant_value_t timers = console_get_state_map(js, this_obj, "timers"); ant_value_t start = is_special_object(timers) ? js_get(js, timers, label) : js_mkundef(); if (vtype(start) != kTypeNumber) { ant_value_t warn_args[1] = { js_mkstr(js, "Timer does not exist", 19) }; return console_emit_current(js, true, NULL, warn_args, 1); } char buf[256]; double elapsed = console_now_ms() - js_getnum(start); int len = snprintf(buf, sizeof(buf), "%s: %.3fms", label, elapsed); ant_value_t *out_args = malloc((size_t)(nargs - extra_start + 1) * sizeof(ant_value_t)); if (!out_args) return js_mkerr(js, "Out of memory"); GC_ROOT_SAVE(root_mark, js); out_args[0] = js_mkstr(js, buf, (size_t)(len > 0 ? len : 0)); GC_ROOT_PIN(js, out_args[0]); for (int i = extra_start; i < nargs; i++) out_args[i - extra_start + 1] = args[i]; ant_value_t result = console_emit_current(js, false, NULL, out_args, nargs - extra_start + 1); GC_ROOT_RESTORE(js, root_mark); free(out_args); return result;}
static ant_value_t js_console_count(ant_params_t) { ant_value_t this_obj = js_getthis(js); const char *label = "default"; if (nargs > 0 && vtype(args[0]) == kTypeString) label = js_getstr(js, args[0], NULL); ant_value_t counts = console_get_state_map(js, this_obj, "counts"); ant_value_t current = is_special_object(counts) ? js_get(js, counts, label) : js_mkundef(); double next = vtype(current) == kTypeNumber ? js_getnum(current) + 1 : 1; js_set(js, counts, label, js_mknum(next)); char buf[256]; int len = snprintf(buf, sizeof(buf), "%s: %.0f", label, next); ant_value_t out_args[1] = { js_mkstr(js, buf, (size_t)(len > 0 ? len : 0)) }; return console_emit_current(js, false, NULL, out_args, 1);}
static ant_value_t js_console_countReset(ant_params_t) { ant_value_t this_obj = js_getthis(js); const char *label = "default"; if (nargs > 0 && vtype(args[0]) == kTypeString) label = js_getstr(js, args[0], NULL); ant_value_t counts = console_get_state_map(js, this_obj, "counts"); js_delete_prop(js, counts, label, strlen(label)); return js_mkundef();}
static ant_value_t js_console_group(ant_params_t) { ant_value_t this_obj = js_getthis(js); if (nargs > 0) console_emit_current(js, false, NULL, args, nargs); console_set_group_level(js, this_obj, console_get_group_level(js, this_obj) + 1); return js_mkundef();}
static ant_value_t js_console_group_end(ant_params_t) { ant_value_t this_obj = js_getthis(js); console_set_group_level(js, this_obj, console_get_group_level(js, this_obj) - 1); return js_mkundef();}
static ant_value_t js_console_group_collapsed(ant_params_t) { return js_console_group(js, args, nargs, js_mkundef());}
static const char *get_slot_name(internal_slot_t slot) { #define ANT_SLOT_NAME(name) [name] = &#name[5], static const char *slot_names[] = { ANT_INTERNAL_SLOT_LIST(ANT_SLOT_NAME) }; #undef ANT_SLOT_NAME
if (slot < sizeof(slot_names) / sizeof(slot_names[0]) && slot_names[slot]) { return slot_names[slot]; } return "UNKNOWN";}
static const char *get_type_name(int type) { static const char *type_names[] = { [kTypeObject] = "object", [kTypeString] = "string", [kTypeArray] = "array", [kTypeFunction] = "function", [kTypeBuiltin] = "function", [kTypePromise] = "Promise", [kTypeGenerator] = "Generator", [kTypeUndefined] = "undefined", [kTypeNull] = "null", [kTypeBool] = "boolean", [kTypeNumber] = "number", [kTypeBigInt] = "bigint", [kTypeSymbol] = "symbol", [kTypeError] = "error", [kTypeTypedArray] = "TypedArray", [kTypeFunctionInfo] = "functioninfo", [kTypeSourceCode] = "sourcecode", [kTypeMap] = "map", [kTypeSet] = "set", [kTypeWeakMap] = "weakmap", [kTypeWeakSet] = "weakset" }; size_t num_types = sizeof(type_names) / sizeof(type_names[0]); if (type < 0 || (size_t)type >= num_types) return "unknown"; return type_names[type] ? type_names[type] : "unknown";}
static bool inspect_was_visited(inspect_visited_t *v, uintptr_t off) { for (int i = 0; i < v->count; i++) if (v->visited[i] == off) return true; return false;}
static void inspect_print_indent(FILE *stream, int depth) { for (int i = 0; i < depth; i++) fprintf(stream, " ");}
static void inspect_mark_visited(inspect_visited_t *v, uintptr_t off) { if (v->count >= v->capacity) { v->capacity = v->capacity ? v->capacity * 2 : 32; v->visited = realloc(v->visited, v->capacity * sizeof(uintptr_t)); } v->visited[v->count++] = off;}
static const char *inspect_ascii_state(uint8_t state) {switch (state) { case STR_ASCII_YES: return "yes"; case STR_ASCII_NO: return "no"; default: return "unknown";}}
static void inspect_string_bytes(FILE *stream, const char *bytes, size_t len) { size_t limit = len > 96 ? 96 : len; fprintf(stream, "\""); for (size_t i = 0; i < limit; i++) { unsigned char c = (unsigned char)bytes[i]; switch (c) { case '\n': fprintf(stream, "\\n"); break; case '\r': fprintf(stream, "\\r"); break; case '\t': fprintf(stream, "\\t"); break; case '\\': fprintf(stream, "\\\\"); break; case '"': fprintf(stream, "\\\""); break; default: if (c < 0x20 || c == 0x7f) fprintf(stream, "\\x%02x", c); else fputc(c, stream); break; } } if (limit < len) fprintf(stream, "...<%zu bytes truncated>", len - limit); fprintf(stream, "\"");}
static void inspect_string_value( ant_t *js, ant_value_t val, FILE *stream, int depth, inspect_visited_t *visited) { uint64_t raw_value = (uint64_t)val; uint64_t raw_data = (uint64_t)vdata(val); uintptr_t tag = (uintptr_t)(vdata(val) & STR_HEAP_TAG_MASK);
if (tag == STR_HEAP_TAG_FLAT) { ant_flat_string_t *flat = ant_str_flat_ptr(val); fprintf( stream, "<String flat value=0x%016" PRIx64 " data=0x%012" PRIx64 " ptr=%p", raw_value, raw_data, (void *)flat ); if (!flat) { fprintf(stream, ">"); return; }
fprintf( stream, " len=%" PRIu64 " ascii=%s bytes=", (uint64_t)flat->len, inspect_ascii_state(str_flat_ascii_state(flat)) ); inspect_string_bytes(stream, flat->bytes, (size_t)flat->len); fprintf(stream, ">"); return; }
if (tag == STR_HEAP_TAG_ROPE) { ant_rope_heap_t *rope = ant_str_rope_ptr(val); fprintf( stream, "<String rope value=0x%016" PRIx64 " data=0x%012" PRIx64 " ptr=%p", raw_value, raw_data, (void *)rope ); if (!rope) { fprintf(stream, ">"); return; }
fprintf( stream, " len=%" PRIu64 " depth=%u cached=", (uint64_t)rope->len, (unsigned)rope->depth ); if (vtype(rope->cached) == kTypeUndefined) fprintf(stream, "undefined"); else inspect_value(js, rope->cached, stream, depth + 1, visited); fprintf(stream, "> {\n");
inspect_print_indent(stream, depth + 1); fprintf(stream, "left: "); if (depth > 10) fprintf(stream, "<String ...>"); else inspect_value(js, rope->left, stream, depth + 1, visited); fprintf(stream, "\n");
inspect_print_indent(stream, depth + 1); fprintf(stream, "right: "); if (depth > 10) fprintf(stream, "<String ...>"); else inspect_value(js, rope->right, stream, depth + 1, visited); fprintf(stream, "\n");
inspect_print_indent(stream, depth); fprintf(stream, "}"); return; }
if (tag == STR_HEAP_TAG_BUILDER) { ant_string_builder_t *builder = ant_str_builder_ptr(val); fprintf( stream, "<String builder value=0x%016" PRIx64 " data=0x%012" PRIx64 " ptr=%p", raw_value, raw_data, (void *)builder ); if (!builder) { fprintf(stream, ">"); return; }
fprintf( stream, " len=%" PRIu64 " ascii=%s head=%p chunk_tail=%p tail_len=%u cached=", (uint64_t)builder->len, inspect_ascii_state(builder->ascii_state), (void *)builder->head, (void *)builder->chunk_tail, (unsigned)builder->tail_len ); if (vtype(builder->cached) == kTypeUndefined) fprintf(stream, "undefined"); else inspect_value(js, builder->cached, stream, depth + 1, visited); fprintf(stream, "> {\n");
int chunk_index = 0; for (ant_builder_chunk_t *chunk = builder->head; chunk; chunk = chunk->next) { if (chunk_index >= 64) { inspect_print_indent(stream, depth + 1); fprintf(stream, "...<builder chunks truncated>\n"); break; }
inspect_print_indent(stream, depth + 1); fprintf(stream, "chunk[%d] @%p next=%p value: ", chunk_index, (void *)chunk, (void *)chunk->next); if (depth > 10) fprintf(stream, "<String ...>"); else inspect_value(js, chunk->value, stream, depth + 1, visited); fprintf(stream, "\n"); chunk_index++; }
inspect_print_indent(stream, depth + 1); fprintf(stream, "tail: "); inspect_string_bytes(stream, builder->tail, builder->tail_len); fprintf(stream, "\n");
inspect_print_indent(stream, depth); fprintf(stream, "}"); return; }
fprintf(stream, "<String unknown-tag=%" PRIuPTR " value=0x%016" PRIx64 " data=0x%012" PRIx64 ">", tag, raw_value, raw_data);}
void inspect_value(ant_t *js, ant_value_t val, FILE *stream, int depth, inspect_visited_t *visited) { int t = vtype(val); if (t == kTypeUndefined) { fprintf(stream, "undefined"); return; } if (t == kTypeNull) { fprintf(stream, "null"); return; } if (t == kTypeBool) { fprintf(stream, val == js_true ? "true" : "false"); return; } if (t == kTypeNumber) { fprintf(stream, "%g", js_getnum(val)); return; } if (t == kTypeError) { fprintf(stream, "[Error]"); return; } if (t == kTypeString) { inspect_string_value(js, val, stream, depth, visited); return; } if (t == kTypeSymbol) { const char *desc = js_sym_desc(val); fprintf(stream, "Symbol(%s)", desc ? desc : ""); return; } if (t == kTypeObject || t == kTypeFunction || t == kTypePromise || t == kTypeArray) { if (depth > 10) fprintf(stream, "<%s @%" PRIu64 " ...>", get_type_name(t), (uint64_t)vdata(js_as_obj(val))); else inspect_object(js, val, stream, depth, visited); return; } if (t == kTypeBuiltin) { ant_value_t promoted = js_cfunc_lookup_promoted(js, val); if (vtype(promoted) == kTypeFunction) { if (depth > 10) fprintf(stream, "<Function @%" PRIu64 " ...>", (uint64_t)vdata(js_as_obj(promoted))); else inspect_object(js, promoted, stream, depth, visited); return; } const ant_cfunc_meta_t *meta = js_as_cfunc_meta(val); const char *name = (meta && meta->name) ? meta->name : NULL; uint32_t length = js_cfunc_length(val); bool has_prototype = meta && (meta->flags & CFUNC_HAS_PROTOTYPE) != 0; if (name) fprintf(stream, "[Function: %s]", name); else fprintf(stream, "[Function]"); fprintf(stream, " <native ptr 0x%" PRIx64 ", length=%u", (uint64_t)vdata(val), length); if (has_prototype) fprintf(stream, ", prototype"); fprintf(stream, ">"); return; } fprintf(stream, "<%s rawtype=%d data=%" PRIu64 ">", get_type_name(t), vtype(val), (uint64_t)vdata(val));}
void inspect_object(ant_t *js, ant_value_t obj, FILE *stream, int depth, inspect_visited_t *visited) { int type = vtype(obj); obj = js_as_obj(obj); uintptr_t obj_off = (uintptr_t)vdata(obj); if (inspect_was_visited(visited, obj_off)) { fprintf(stream, "[Circular *%llu]", (u64)obj_off); return; } inspect_mark_visited(visited, obj_off); fprintf(stream, "<%s @%llu> {\n", type == kTypeFunction ? "Function" : (type == kTypePromise ? "Promise" : "Object"), (u64)obj_off); int inner_depth = depth + 1; inspect_print_indent(stream, inner_depth); fprintf(stream, "[[Slots]]: {\n"); for (int slot = SLOT_NONE + 1; slot < SLOT_MAX; slot++) { ant_value_t slot_val = js_get_slot(obj, (internal_slot_t)slot); int t = vtype(slot_val); if (t == kTypeUndefined) continue; inspect_print_indent(stream, inner_depth + 1); fprintf(stream, "[[%s]]: ", get_slot_name((internal_slot_t)slot)); switch (slot) { case SLOT_CODE: if (t == kTypeString) { ant_offset_t code_len = 0; vstr(js, slot_val, &code_len); fprintf(stream, "<source, %llu bytes>", (unsigned long long)code_len); break; } fprintf(stream, "<native ptr 0x%" PRIx64 ">", (uint64_t)vdata(slot_val)); break; case SLOT_CFUNC: fprintf(stream, "<native ptr 0x%" PRIx64 ">", (uint64_t)vdata(slot_val)); break; case SLOT_CODE_LEN: fprintf(stream, "%.0f", js_getnum(slot_val)); break; default: if ((t == kTypeObject || t == kTypeFunction || t == kTypePromise) && inspect_was_visited(visited, (uintptr_t)vdata(js_as_obj(slot_val)))) fprintf(stream, "[Circular *%llu]", (u64)vdata(js_as_obj(slot_val))); else if (t == kTypeObject || t == kTypeFunction || t == kTypePromise) fprintf(stream, "<%s @%llu>", get_type_name(t), (u64)vdata(js_as_obj(slot_val))); else inspect_value(js, slot_val, stream, inner_depth + 1, visited); break; } fprintf(stream, "\n"); } inspect_print_indent(stream, inner_depth); fprintf(stream, "}\n"); inspect_print_indent(stream, inner_depth); fprintf(stream, "[[Properties]]: {\n"); ant_iter_t iter = js_prop_iter_begin(js, obj); const char *key; size_t key_len; ant_value_t value; while (js_prop_iter_next(&iter, &key, &key_len, &value)) { inspect_print_indent(stream, inner_depth + 1); fprintf(stream, "\"%.*s\": ", (int)key_len, key); inspect_value(js, value, stream, inner_depth + 1, visited); fprintf(stream, "\n"); } js_prop_iter_end(&iter); inspect_print_indent(stream, inner_depth); fprintf(stream, "}\n"); ant_value_t proto = js_get_proto(js, obj); inspect_print_indent(stream, inner_depth); fprintf(stream, "[[Prototype]]: "); if (vtype(proto) == kTypeNull) { fprintf(stream, "null\n"); } else { fprintf(stream, "\n"); inspect_print_indent(stream, inner_depth); inspect_value(js, proto, stream, inner_depth, visited); fprintf(stream, "\n"); } inspect_print_indent(stream, depth); fprintf(stream, "}");}
static ant_value_t js_console_inspect(ant_params_t) { FILE *stream = stdout; inspect_visited_t visited = {0}; for (int i = 0; i < nargs; i++) { if (i > 0) fprintf(stream, " "); inspect_value(js, args[i], stream, 0, &visited); }
fprintf(stream, "\n"); if (visited.visited) free(visited.visited);
return js_mkundef();}
// TODO: replace stub with realstatic ant_value_t js_console_dir(ant_params_t) { return js_console_log(js, args, nargs, js_mkundef());}
// TODO: replace stub with realstatic ant_value_t js_console_dirxml(ant_params_t) { return js_console_log(js, args, nargs, js_mkundef());}
// TODO: replace stub with realstatic ant_value_t js_console_table(ant_params_t) { return js_console_log(js, args, nargs, js_mkundef());}
static void console_apply_methods(ant_t *js, ant_value_t console_obj) { js_set(js, console_obj, "log", Ant_Function_Create(js_console_log)); js_set(js, console_obj, "error", Ant_Function_Create(js_console_error)); js_set(js, console_obj, "warn", Ant_Function_Create(js_console_warn)); js_set(js, console_obj, "info", Ant_Function_Create(js_console_info)); js_set(js, console_obj, "debug", Ant_Function_Create(js_console_debug)); js_set(js, console_obj, "assert", Ant_Function_CreateWithArity(js_console_assert, 1)); js_set(js, console_obj, "dir", Ant_Function_CreateWithArity(js_console_dir, 2)); js_set(js, console_obj, "dirxml", Ant_Function_Create(js_console_dirxml)); js_set(js, console_obj, "table", Ant_Function_CreateWithArity(js_console_table, 2)); js_set(js, console_obj, "trace", Ant_Function_Create(js_console_trace)); js_set(js, console_obj, "count", Ant_Function_Create(js_console_count)); js_set(js, console_obj, "countReset", Ant_Function_Create(js_console_countReset)); js_set(js, console_obj, "time", Ant_Function_Create(js_console_time)); js_set(js, console_obj, "timeLog", Ant_Function_Create(js_console_timeLog)); js_set(js, console_obj, "timeEnd", Ant_Function_Create(js_console_timeEnd)); js_set(js, console_obj, "group", Ant_Function_Create(js_console_group)); js_set(js, console_obj, "groupCollapsed", Ant_Function_Create(js_console_group_collapsed)); js_set(js, console_obj, "groupEnd", Ant_Function_Create(js_console_group_end)); js_set(js, console_obj, "clear", Ant_Function_Create(js_console_clear)); js_set(js, console_obj, "inspect", Ant_Function_Create(js_console_inspect));}
static ant_value_t js_console_constructor(ant_params_t) { ant_value_t proto = js_instance_proto_from_new_target(js, js->builtins.console_proto, call_new_target); ant_value_t console_obj = Ant_Object_CreateBare(js); js_set_proto_init(console_obj, is_special_object(proto) ? proto : js->builtins.console_proto);
ant_value_t stdout_obj = js_mkundef(); ant_value_t stderr_obj = js_mkundef(); int group_indentation = 2;
if (nargs >= 1 && is_special_object(args[0]) && nargs == 1) { ant_value_t options = args[0]; stdout_obj = js_get(js, options, "stdout"); stderr_obj = js_get(js, options, "stderr"); ant_value_t gi = js_get(js, options, "groupIndentation"); if (vtype(gi) == kTypeNumber) group_indentation = (int)js_getnum(gi); } else { if (nargs >= 1) stdout_obj = args[0]; if (nargs >= 2) stderr_obj = args[1]; }
if (vtype(stderr_obj) == kTypeUndefined) stderr_obj = stdout_obj; js_set_slot_wb(js, console_obj, SLOT_CONSOLE_STDOUT, stdout_obj); js_set_slot_wb(js, console_obj, SLOT_CONSOLE_STDERR, stderr_obj); js_set_slot_wb(js, console_obj, SLOT_CONSOLE_COUNTS, Ant_Object_CreateBare(js)); js_set_slot_wb(js, console_obj, SLOT_CONSOLE_TIMERS, Ant_Object_CreateBare(js)); js_set_slot(console_obj, SLOT_CONSOLE_GROUP_INDENT, js_mknum((double)group_indentation)); js_set_slot(console_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum(0)); return console_obj;}
static void console_ensure_constructor(ant_t *js) { if (js->builtins.console_ctor) return; js->builtins.console_proto = Ant_Object_CreateBare(js); console_apply_methods(js, js->builtins.console_proto); js_set_tostringtag(js, js->builtins.console_proto, js_mkstr(js, "console", 7)); js->builtins.console_ctor = Ant_Function_CreateConstructor(js, js_console_constructor, js->builtins.console_proto, "Console", 1);}
static ant_value_t console_create_default(ant_t *js) { console_ensure_constructor(js); ant_value_t console_obj = Ant_Object_CreateBare(js); js_set_proto_init(console_obj, js->builtins.console_proto); js_set_slot_wb(js, console_obj, SLOT_CONSOLE_COUNTS, Ant_Object_CreateBare(js)); js_set_slot_wb(js, console_obj, SLOT_CONSOLE_TIMERS, Ant_Object_CreateBare(js)); js_set_slot(console_obj, SLOT_CONSOLE_GROUP_INDENT, js_mknum(2)); js_set_slot(console_obj, SLOT_CONSOLE_GROUP_LEVEL, js_mknum(0)); js_set_tostringtag(js, console_obj, js_mkstr(js, "console", 7)); return console_obj;}
ant_value_t console_library(ant_t *js) { ant_value_t console_obj = console_create_default(js); js_set(js, console_obj, "Console", js->builtins.console_ctor); js_set(js, console_obj, "default", console_obj); return console_obj;}
void init_console_module(ant_t *js) { ant_value_t console_obj = console_create_default(js); console_apply_methods(js, console_obj); js_set(js, console_obj, "Console", js->builtins.console_ctor); js_set_global_builtin(js, "console", console_obj);}