Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4459923
io.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
io.c
View Options
#include
<compat.h>
// IWYU pragma: keep
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<stdbool.h>
#include
<ctype.h>
#include
<inttypes.h>
#include
<uv.h>
#include
"common.h"
#include
"errors.h"
#include
"output.h"
#include
"internal.h"
#include
"runtime.h"
#include
"gc/roots.h"
#include
"silver/engine.h"
#include
"modules/io.h"
#include
"modules/symbol.h"
bool
io_no_color
=
false
;
static
ant_value_t
g_console_proto
=
0
;
static
ant_value_t
g_console_ctor
=
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"
static
inline
bool
io_is_digit_ascii
(
char
c
)
{
return
c
>=
'0'
&&
c
<=
'9'
;
}
static
bool
io_print_to_output
(
const
char
*
str
,
ant_output_stream_t
*
out
)
{
if
(
!
io_no_color
)
{
return
ant_output_stream_append_cstr
(
out
,
str
);
}
static
void
*
states
[]
=
{
&&
normal
,
&&
esc
,
&&
csi
,
&&
done
};
const
char
*
p
=
str
;
char
c
;
goto
*
states
[
0
];
normal
:
{
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
:
{
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
:
{
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
;
}
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
(
!
io_is_digit_ascii
(
p
[
i
]))
return
0
;
}
else
for
(
int
d
=
0
;
d
<
4
;
d
++
,
i
++
)
if
(
!
io_is_digit_ascii
(
p
[
i
]))
return
0
;
if
(
p
[
i
++
]
!=
'-'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
]))
return
0
;
if
(
p
[
i
++
]
!=
'-'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
]))
return
0
;
if
(
p
[
i
++
]
!=
'T'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
]))
return
0
;
if
(
p
[
i
++
]
!=
':'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
]))
return
0
;
if
(
p
[
i
++
]
!=
':'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
]))
return
0
;
if
(
p
[
i
++
]
!=
'.'
)
return
0
;
if
(
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
p
[
i
++
])
||
!
io_is_digit_ascii
(
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_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
)
{
if
(
io_no_color
)
{
io_print_to_output
(
str
,
out
);
return
;
}
static
void
*
dispatch
[]
=
{
[
CC_NUL
]
=
&&
done
,
[
CC_QUOTE
]
=
&&
quote
,
[
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
]
=
&&
lt
,
[
CC_GT
]
=
&&
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
)
{
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
'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
)
{
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
++
);
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
++
);
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
(
p
[
1
]
==
'>'
||
(
isxdigit
((
unsigned
char
)
p
[
1
])
&&
isxdigit
((
unsigned
char
)
p
[
2
])))
{
ant_output_stream_append_cstr
(
out
,
JSON_BRACE
);
ant_output_stream_putc
(
out
,
*
p
++
);
ant_output_stream_append_cstr
(
out
,
JSON_WHITE
);
while
(
*
p
&&
*
p
!=
'>'
)
ant_output_stream_putc
(
out
,
*
p
++
);
ant_output_stream_append_cstr
(
out
,
C_RESET
);
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
)
{
EMIT_UNTIL
(
')'
,
JSON_STRING
)
}
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
);
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
)
==
T_STR
)
{
char
*
str
=
js_getstr
(
js
,
val
,
NULL
);
ant_output_stream_begin
(
out
);
ant_output_stream_append_cstr
(
out
,
C
(
JSON_STRING
));
ant_output_stream_putc
(
out
,
'\''
);
ant_output_stream_append_cstr
(
out
,
str
?
str
:
""
);
ant_output_stream_putc
(
out
,
'\''
);
ant_output_stream_append_cstr
(
out
,
C
(
C_RESET
));
ant_output_stream_putc
(
out
,
'\n'
);
ant_output_stream_flush
(
out
);
return
;
}
if
(
vtype
(
val
)
==
T_OBJ
&&
vtype
(
js_get_slot
(
val
,
SLOT_ERR_TYPE
))
!=
T_UNDEF
)
{
const
char
*
stack
=
get_str_prop
(
js
,
val
,
"stack"
,
5
,
NULL
);
if
(
stack
)
{
ant_output_stream_begin
(
out
);
io_print_to_output
(
stack
,
out
);
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
)
==
T_ERR
)
{
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
);
ant_output_stream_putc
(
out
,
'\n'
);
ant_output_stream_flush
(
out
);
}
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
}
static
ant_value_t
console_call_value
(
ant_t
*
js
,
ant_value_t
fn
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
saved_this
=
js
->
this_val
;
ant_value_t
result
=
js_mkundef
();
js
->
this_val
=
this_val
;
if
(
vtype
(
fn
)
==
T_CFUNC
)
result
=
js_as_cfunc
(
fn
)(
js
,
args
,
nargs
);
else
result
=
sv_vm_call
(
js
->
vm
,
js
,
fn
,
this_val
,
args
,
nargs
,
NULL
,
false
);
js
->
this_val
=
saved_this
;
return
result
;
}
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
;
ant_value_t
argv
[
1
]
=
{
js_mkstr
(
js
,
data
,
len
)
};
ant_value_t
result
=
console_call_value
(
js
,
write_fn
,
stream_obj
,
argv
,
1
);
if
(
is_err
(
result
)
||
js
->
thrown_exists
)
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
)
==
T_NUM
?
(
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
)
==
T_NUM
?
(
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
=
js_mkobj
(
js
);
js_set_slot_wb
(
js
,
this_obj
,
slot
,
map
);
return
map
;
}
static
bool
console_write_args_to_stream
(
ant_t
*
js
,
ant_output_stream_t
*
out
,
ant_value_t
*
args
,
int
nargs
,
bool
color_values
)
{
for
(
int
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
i
&&
!
ant_output_stream_putc
(
out
,
' '
))
return
false
;
if
(
vtype
(
args
[
i
])
==
T_OBJ
)
{
const
char
*
stack
=
get_str_prop
(
js
,
args
[
i
],
"stack"
,
5
,
NULL
);
if
(
stack
)
{
if
(
!
io_print_to_output
(
stack
,
out
))
return
false
;
continue
;
}}
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
args
[
i
],
cbuf
,
sizeof
(
cbuf
));
bool
ok
=
true
;
if
(
vtype
(
args
[
i
])
==
T_STR
)
ok
=
io_print_to_output
(
cstr
.
ptr
,
out
);
else
{
bool
saved_no_color
=
io_no_color
;
io_no_color
=
saved_no_color
||
!
color_values
;
if
(
ok
)
print_value_colored_to_output
(
cstr
.
ptr
,
out
);
io_no_color
=
saved_no_color
;
}
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
if
(
!
ok
)
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
color_values
=
!
io_no_color
;
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
);
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
void
console_write_args_to_output
(
ant_t
*
js
,
ant_output_stream_t
*
out
,
ant_value_t
*
args
,
int
nargs
)
{
for
(
int
i
=
0
;
i
<
nargs
;
i
++
)
{
if
(
i
)
ant_output_stream_putc
(
out
,
' '
);
if
(
vtype
(
args
[
i
])
==
T_OBJ
)
{
const
char
*
stack
=
get_str_prop
(
js
,
args
[
i
],
"stack"
,
5
,
NULL
);
if
(
stack
)
{
io_print_to_output
(
stack
,
out
);
continue
;
}}
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
args
[
i
],
cbuf
,
sizeof
(
cbuf
));
if
(
vtype
(
args
[
i
])
==
T_STR
)
io_print_to_output
(
cstr
.
ptr
,
out
);
else
print_value_colored_to_output
(
cstr
.
ptr
,
out
);
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
}}
static
ant_value_t
js_console_log
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
console_emit_current
(
js
,
false
,
NULL
,
args
,
nargs
);
}
static
ant_value_t
js_console_error
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
console_emit_current
(
js
,
true
,
NULL
,
args
,
nargs
);
}
static
ant_value_t
js_console_warn
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
console_emit_current
(
js
,
true
,
NULL
,
args
,
nargs
);
}
static
ant_value_t
js_console_info
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
console_emit_current
(
js
,
false
,
NULL
,
args
,
nargs
);
}
static
ant_value_t
js_console_debug
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
console_emit_current
(
js
,
false
,
NULL
,
args
,
nargs
);
}
static
ant_value_t
js_console_assert
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
bool
is_truthy
=
js_truthy
(
js
,
args
[
0
]);
if
(
is_truthy
)
return
js_mkundef
();
return
console_emit_current
(
js
,
true
,
"Assertion failed:"
,
args
+
1
,
nargs
-
1
);
}
static
ant_value_t
js_console_trace
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
console_get_effective_this
(
js
,
js_getthis
(
js
));
console_emit_current
(
js
,
true
,
"Trace:"
,
args
,
nargs
);
ant_value_t
stack
=
js_capture_raw_stack
(
js
);
if
(
vtype
(
stack
)
==
T_STR
)
{
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
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
ant_value_t
js_console_time
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
const
char
*
label
=
"default"
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
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
))
!=
T_UNDEF
)
{
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
((
double
)
uv_hrtime
()
/
1e6
));
return
js_mkundef
();
}
static
ant_value_t
js_console_timeEnd
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
const
char
*
label
=
"default"
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
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
)
!=
T_NUM
)
{
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
=
((
double
)
uv_hrtime
()
/
1e6
)
-
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
const
char
*
label
=
"default"
;
int
extra_start
=
0
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
{
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
)
!=
T_NUM
)
{
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
=
((
double
)
uv_hrtime
()
/
1e6
)
-
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"
);
out_args
[
0
]
=
js_mkstr
(
js
,
buf
,
(
size_t
)(
len
>
0
?
len
:
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
);
free
(
out_args
);
return
result
;
}
static
ant_value_t
js_console_count
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
const
char
*
label
=
"default"
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
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
)
==
T_NUM
?
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
const
char
*
label
=
"default"
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_console_group
(
js
,
args
,
nargs
);
}
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
[]
=
{
[
T_OBJ
]
=
"object"
,
[
T_STR
]
=
"string"
,
[
T_ARR
]
=
"array"
,
[
T_FUNC
]
=
"function"
,
[
T_CFUNC
]
=
"function"
,
[
T_PROMISE
]
=
"Promise"
,
[
T_GENERATOR
]
=
"Generator"
,
[
T_UNDEF
]
=
"undefined"
,
[
T_NULL
]
=
"null"
,
[
T_BOOL
]
=
"boolean"
,
[
T_NUM
]
=
"number"
,
[
T_BIGINT
]
=
"bigint"
,
[
T_SYMBOL
]
=
"symbol"
,
[
T_ERR
]
=
"error"
,
[
T_TYPEDARRAY
]
=
"TypedArray"
,
[
T_NTARG
]
=
"ntarg"
,
[
T_MAP
]
=
"map"
,
[
T_SET
]
=
"set"
,
[
T_WEAKMAP
]
=
"weakmap"
,
[
T_WEAKSET
]
=
"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
;
}
void
inspect_value
(
ant_t
*
js
,
ant_value_t
val
,
FILE
*
stream
,
int
depth
,
inspect_visited_t
*
visited
)
{
int
t
=
vtype
(
val
);
if
(
t
==
T_UNDEF
)
{
fprintf
(
stream
,
"undefined"
);
return
;
}
if
(
t
==
T_NULL
)
{
fprintf
(
stream
,
"null"
);
return
;
}
if
(
t
==
T_BOOL
)
{
fprintf
(
stream
,
val
==
js_true
?
"true"
:
"false"
);
return
;
}
if
(
t
==
T_NUM
)
{
fprintf
(
stream
,
"%g"
,
js_getnum
(
val
));
return
;
}
if
(
t
==
T_ERR
)
{
fprintf
(
stream
,
"[Error]"
);
return
;
}
if
(
t
==
T_STR
)
{
size_t
len
;
char
*
str
=
js_getstr
(
js
,
val
,
&
len
);
fprintf
(
stream
,
"
\"
%.*s
\"
"
,
(
int
)
len
,
str
?
str
:
""
);
return
;
}
if
(
t
==
T_SYMBOL
)
{
const
char
*
desc
=
js_sym_desc
(
val
);
fprintf
(
stream
,
"Symbol(%s)"
,
desc
?
desc
:
""
);
return
;
}
if
(
t
==
T_OBJ
||
t
==
T_FUNC
||
t
==
T_PROMISE
||
t
==
T_ARR
)
{
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
==
T_CFUNC
)
{
ant_value_t
promoted
=
js_cfunc_lookup_promoted
(
js
,
val
);
if
(
vtype
(
promoted
)
==
T_FUNC
)
{
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
==
T_FUNC
?
"Function"
:
(
type
==
T_PROMISE
?
"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
==
T_UNDEF
)
continue
;
inspect_print_indent
(
stream
,
inner_depth
+
1
);
fprintf
(
stream
,
"[[%s]]: "
,
get_slot_name
((
internal_slot_t
)
slot
));
switch
(
slot
)
{
case
SLOT_CODE
:
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
==
T_OBJ
||
t
==
T_FUNC
||
t
==
T_PROMISE
)
&&
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
==
T_OBJ
||
t
==
T_FUNC
||
t
==
T_PROMISE
)
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
)
==
T_NULL
)
{
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_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
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 real
static
ant_value_t
js_console_dir
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_console_log
(
js
,
args
,
nargs
);
}
// TODO: replace stub with real
static
ant_value_t
js_console_dirxml
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_console_log
(
js
,
args
,
nargs
);
}
// TODO: replace stub with real
static
ant_value_t
js_console_table
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_console_log
(
js
,
args
,
nargs
);
}
static
void
console_apply_methods
(
ant_t
*
js
,
ant_value_t
console_obj
)
{
js_set
(
js
,
console_obj
,
"log"
,
js_mkfun
(
js_console_log
));
js_set
(
js
,
console_obj
,
"error"
,
js_mkfun
(
js_console_error
));
js_set
(
js
,
console_obj
,
"warn"
,
js_mkfun
(
js_console_warn
));
js_set
(
js
,
console_obj
,
"info"
,
js_mkfun
(
js_console_info
));
js_set
(
js
,
console_obj
,
"debug"
,
js_mkfun
(
js_console_debug
));
js_set
(
js
,
console_obj
,
"assert"
,
js_mkfun
(
js_console_assert
));
js_set
(
js
,
console_obj
,
"dir"
,
js_mkfun
(
js_console_dir
));
js_set
(
js
,
console_obj
,
"dirxml"
,
js_mkfun
(
js_console_dirxml
));
js_set
(
js
,
console_obj
,
"table"
,
js_mkfun
(
js_console_table
));
js_set
(
js
,
console_obj
,
"trace"
,
js_mkfun
(
js_console_trace
));
js_set
(
js
,
console_obj
,
"count"
,
js_mkfun
(
js_console_count
));
js_set
(
js
,
console_obj
,
"countReset"
,
js_mkfun
(
js_console_countReset
));
js_set
(
js
,
console_obj
,
"time"
,
js_mkfun
(
js_console_time
));
js_set
(
js
,
console_obj
,
"timeLog"
,
js_mkfun
(
js_console_timeLog
));
js_set
(
js
,
console_obj
,
"timeEnd"
,
js_mkfun
(
js_console_timeEnd
));
js_set
(
js
,
console_obj
,
"group"
,
js_mkfun
(
js_console_group
));
js_set
(
js
,
console_obj
,
"groupCollapsed"
,
js_mkfun
(
js_console_group_collapsed
));
js_set
(
js
,
console_obj
,
"groupEnd"
,
js_mkfun
(
js_console_group_end
));
js_set
(
js
,
console_obj
,
"clear"
,
js_mkfun
(
js_console_clear
));
js_set
(
js
,
console_obj
,
"inspect"
,
js_mkfun
(
js_console_inspect
));
}
static
ant_value_t
js_console_constructor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_console_proto
);
ant_value_t
console_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
console_obj
,
is_special_object
(
proto
)
?
proto
:
g_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
)
==
T_NUM
)
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
)
==
T_UNDEF
)
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
,
js_mkobj
(
js
));
js_set_slot_wb
(
js
,
console_obj
,
SLOT_CONSOLE_TIMERS
,
js_mkobj
(
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
;
}
ant_value_t
console_library
(
ant_t
*
js
)
{
if
(
!
g_console_ctor
)
{
g_console_proto
=
js_mkobj
(
js
);
console_apply_methods
(
js
,
g_console_proto
);
js_set_sym
(
js
,
g_console_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"console"
,
7
));
g_console_ctor
=
js_make_ctor
(
js
,
js_console_constructor
,
g_console_proto
,
"Console"
,
7
);
gc_register_root
(
&
g_console_proto
);
gc_register_root
(
&
g_console_ctor
);
}
ant_value_t
console_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
console_obj
,
g_console_proto
);
js_set_slot_wb
(
js
,
console_obj
,
SLOT_CONSOLE_COUNTS
,
js_mkobj
(
js
));
js_set_slot_wb
(
js
,
console_obj
,
SLOT_CONSOLE_TIMERS
,
js_mkobj
(
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
(
js
,
console_obj
,
"Console"
,
g_console_ctor
);
js_set
(
js
,
console_obj
,
"default"
,
console_obj
);
js_set_sym
(
js
,
console_obj
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"console"
,
7
));
return
console_obj
;
}
void
init_console_module
()
{
ant_t
*
js
=
rt
->
js
;
ant_value_t
console_obj
=
console_library
(
js
);
js_set
(
js
,
js_glob
(
js
),
"console"
,
console_obj
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 4:25 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541581
Default Alt Text
io.c (37 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment