56static void skip_to_eol(
const char *src,
size_t len,
size_t *pos);
57static int read_line_start(
const char *src,
size_t len,
size_t *pos,
int *out_indent);
58static void parse_block(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos,
int current_indent);
59static void calc_line_col(
const char *src,
size_t len,
size_t pos,
int *out_line,
int *out_col);
89 const char *v = getenv(name);
91 if (strcmp(v,
"1") == 0)
return 1;
92 if (strcmp(v,
"true") == 0)
return 1;
93 if (strcmp(v,
"TRUE") == 0)
return 1;
94 if (strcmp(v,
"yes") == 0)
return 1;
95 if (strcmp(v,
"YES") == 0)
return 1;
96 if (strcmp(v,
"on") == 0)
return 1;
97 if (strcmp(v,
"ON") == 0)
return 1;
124#define TYPE_META_STRING 10001
126#define TYPE_META_BOOLEAN 10002
128#define TYPE_META_NIL 10003
130#define TYPE_META_CLASS 10004
132#define TYPE_META_FLOAT 10005
134#define TYPE_META_ARRAY 10006
149 int line = 0, col = 0;
183static void calc_line_col(
const char *src,
size_t len,
size_t pos,
int *out_line,
int *out_col) {
184 int line = 1, col = 1;
185 size_t limit = pos < len ? pos : len;
186 for (
size_t i = 0; i < limit; ++i) {
187 if (src[i] ==
'\n') {
194 if (out_line) *out_line = line;
195 if (out_col) *out_col = col;
228 const char *marker =
"// __ns_alias__: ";
229 size_t mlen = strlen(marker);
235 while (i < len && src[i] !=
'\n')
239 if (i < len && src[i] ==
'\n') i++;
241 if (le - ls >= mlen && strncmp(src + ls, marker, mlen) == 0) {
242 size_t p = ls + mlen;
245 while (p < le && (src[p] ==
' ' || src[p] ==
'\t'))
247 if (p < le && (isalpha((
unsigned char)src[p]) || src[p] ==
'_')) {
249 while (q < le && (isalnum((
unsigned char)src[q]) || src[q] ==
'_'))
253 char *name = (
char *)malloc(n + 1);
255 memcpy(name, src + p, n);
287}
G = {{0}, {0}, {0}, 0};
296 for (
int i = 0; i <
G.count; ++i) {
297 if (strcmp(
G.names[i], name) == 0)
return i;
314 if (existing >= 0)
return existing;
319 G.names[
G.count] = strdup(name);
320 G.types[
G.count] = 0;
321 G.is_class[
G.count] = 0;
351 for (
int i = 0; i < e->
count; ++i) {
352 if (e->
names[i] && strcmp(e->
names[i], name) == 0)
return 1;
377 for (
int i = 0; i <
g_locals->count; ++i) {
378 if (strcmp(
g_locals->names[i], name) == 0)
return i;
396 g_locals->names[idx] = strdup(name);
420 if (*pos + 2 < len &&
starts_with(src, len, *pos,
"fn") && (src[*pos + 2] ==
'(' || src[*pos + 2] ==
' ' || src[*pos + 2] ==
'\t')) {
435 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
443 if (*pos < len && src[*pos] !=
')') {
453 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
462 if (*pos < len && src[*pos] ==
',') {
471 parser_fail(*pos,
"Expected ')' after parameter list");
482 if (fn_bc->
name) free((
void *)fn_bc->
name);
483 fn_bc->
name = strdup(
"<fn>");
490 size_t look_body = *pos;
491 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > 0) {
508 if (*pos < len && src[*pos] ==
'(') {
511 parser_fail(*pos,
"Expected expression after '('");
521 if (*pos < len && src[*pos] ==
'[') {
528 if (*pos < len && src[*pos] ==
':') {
531 size_t savep4 = *pos;
566 if (*pos < len && src[*pos] ==
'[') {
573 if (*pos < len && src[*pos] ==
':') {
608 if (*pos < len && src[*pos] ==
'[') {
612 if (*pos < len && src[*pos] !=
']') {
615 parser_fail(*pos,
"Expected expression in array literal");
620 if (*pos < len && src[*pos] ==
',') {
629 parser_fail(*pos,
"Expected ']' to close array literal");
636 if (*pos < len && src[*pos] ==
'[') {
643 if (*pos < len && src[*pos] ==
':') {
646 size_t savep3 = *pos;
674 if (*pos < len && src[*pos] ==
'{') {
678 if (*pos < len && src[*pos] !=
'}') {
683 parser_fail(*pos,
"Expected string key in map literal");
695 parser_fail(*pos,
"Expected value expression in map literal");
700 if (*pos < len && src[*pos] ==
',') {
709 parser_fail(*pos,
"Expected '}' to close map literal");
727 if (*pos < len && src[*pos] ==
'[') {
734 if (*pos < len && src[*pos] ==
':') {
737 size_t savep2 = *pos;
771 if (*pos < len && src[*pos] ==
'[') {
778 if (*pos < len && src[*pos] ==
':') {
782 size_t savep2 = *pos;
813 if (strcmp(name,
"true") == 0 || strcmp(name,
"false") == 0) {
823 int is_call = (*pos < len && src[*pos] ==
'(');
827 if (strcmp(name,
"len") == 0) {
843 if (strcmp(name,
"push") == 0) {
850 if (*pos < len && src[*pos] ==
',') {
872 if (strcmp(name,
"pop") == 0) {
888 if (strcmp(name,
"set") == 0) {
895 if (*pos < len && src[*pos] ==
',') {
908 if (*pos < len && src[*pos] ==
',') {
930 if (strcmp(name,
"insert") == 0) {
937 if (*pos < len && src[*pos] ==
',') {
950 if (*pos < len && src[*pos] ==
',') {
964 parser_fail(*pos,
"Expected ')' after insert args");
972 if (strcmp(name,
"remove") == 0) {
979 if (*pos < len && src[*pos] ==
',') {
993 parser_fail(*pos,
"Expected ')' after remove args");
1001 if (strcmp(name,
"to_number") == 0) {
1004 parser_fail(*pos,
"to_number expects 1 argument");
1009 parser_fail(*pos,
"Expected ')' after to_number arg");
1017 if (strcmp(name,
"to_string") == 0) {
1020 parser_fail(*pos,
"to_string expects 1 argument");
1025 parser_fail(*pos,
"Expected ')' after to_string arg");
1033 if (strcmp(name,
"cast") == 0) {
1037 parser_fail(*pos,
"cast expects (value, typeName)");
1042 parser_fail(*pos,
"cast expects (value, typeName)");
1050 if (strcmp(name,
"typeof") == 0) {
1058 if (peek < len && src[peek] ==
')') {
1065 if (gi >= 0) meta =
G.types[gi];
1070 int abs_bits = meta < 0 ? -meta : meta;
1071 const char *tname = (meta < 0)
1072 ? (abs_bits == 64 ?
"Sint64" : (abs_bits == 32 ?
"Sint32" : (abs_bits == 16 ?
"Sint16" :
"Sint8")))
1073 : (abs_bits == 64 ?
"Uint64" : (abs_bits == 32 ?
"Uint32" : (abs_bits == 16 ?
"Uint16" :
"Uint8")));
1095 parser_fail(*pos,
"Expected ')' after typeof arg");
1151 if (strcmp(name,
"keys") == 0) {
1162 if (strcmp(name,
"values") == 0) {
1173 if (strcmp(name,
"has") == 0) {
1189 if (strcmp(name,
"read_file") == 0) {
1200 if (strcmp(name,
"write_file") == 0) {
1216 if (strcmp(name,
"input") == 0) {
1220 if (*pos < len && src[*pos] !=
')') {
1222 parser_fail(*pos,
"input expects 0 or 1 argument");
1229 parser_fail(*pos,
"Expected ')' after input arg(s)");
1237 if (strcmp(name,
"input_hidden") == 0) {
1241 if (*pos < len && src[*pos] !=
')') {
1243 parser_fail(*pos,
"input_hidden expects 0 or 1 argument");
1250 parser_fail(*pos,
"Expected ')' after input_hidden arg(s)");
1259 if (strcmp(name,
"proc_run") == 0) {
1262 parser_fail(*pos,
"proc_run expects 1 argument (command string)");
1267 parser_fail(*pos,
"Expected ')' after proc_run arg");
1275 if (strcmp(name,
"system") == 0) {
1278 parser_fail(*pos,
"system expects 1 argument (command string)");
1283 parser_fail(*pos,
"Expected ')' after system arg");
1291 if (strcmp(name,
"time_now_ms") == 0) {
1302 if (strcmp(name,
"clock_mono_ms") == 0) {
1313 if (strcmp(name,
"date_format") == 0) {
1316 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1326 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1331 parser_fail(*pos,
"Expected ')' after date_format args");
1339 if (strcmp(name,
"env") == 0) {
1355 if (strcmp(name,
"env_all") == 0) {
1366 if (strcmp(name,
"fun_version") == 0) {
1378 if (strcmp(name,
"kcgi_parse") == 0) {
1389 if (strcmp(name,
"kcgi_reply_start") == 0) {
1392 parser_fail(*pos,
"kcgi_reply_start expects (code:int, content_type:string)");
1397 parser_fail(*pos,
"kcgi_reply_start expects 2 args");
1402 parser_fail(*pos,
"kcgi_reply_start expects (code:int, content_type:string)");
1407 parser_fail(*pos,
"Expected ')' after kcgi_reply_start args");
1415 if (strcmp(name,
"kcgi_write") == 0) {
1418 parser_fail(*pos,
"kcgi_write expects (chunk:string)");
1423 parser_fail(*pos,
"Expected ')' after kcgi_write arg");
1431 if (strcmp(name,
"kcgi_end") == 0) {
1442 if (strcmp(name,
"rust_hello") == 0) {
1453 if (strcmp(name,
"rust_hello_args") == 0) {
1456 parser_fail(*pos,
"rust_hello_args expects (message:string)");
1461 parser_fail(*pos,
"Expected ')' after rust_hello_args arg");
1469 if (strcmp(name,
"rust_hello_args_return") == 0) {
1472 parser_fail(*pos,
"rust_hello_args_return expects (message:string)");
1477 parser_fail(*pos,
"Expected ')' after rust_hello_args_return arg");
1485 if (strcmp(name,
"rust_get_sp") == 0) {
1496 if (strcmp(name,
"rust_set_exit") == 0) {
1499 parser_fail(*pos,
"rust_set_exit expects (code:int)");
1504 parser_fail(*pos,
"Expected ')' after rust_set_exit arg");
1512 if (strcmp(name,
"cpp_add") == 0) {
1515 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1520 parser_fail(*pos,
"cpp_add expects two arguments");
1525 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1530 parser_fail(*pos,
"Expected ')' after cpp_add args");
1538 if (strcmp(name,
"os_list_dir") == 0) {
1546 parser_fail(*pos,
"Expected ')' after os_list_dir arg");
1555 if (strcmp(name,
"json_parse") == 0) {
1563 parser_fail(*pos,
"Expected ')' after json_parse arg");
1572 if (strcmp(name,
"xml_parse") == 0) {
1580 parser_fail(*pos,
"Expected ')' after xml_parse arg");
1588 if (strcmp(name,
"xml_root") == 0) {
1591 parser_fail(*pos,
"xml_root expects (doc_handle)");
1596 parser_fail(*pos,
"Expected ')' after xml_root arg");
1604 if (strcmp(name,
"xml_name") == 0) {
1607 parser_fail(*pos,
"xml_name expects (node_handle)");
1612 parser_fail(*pos,
"Expected ')' after xml_name arg");
1620 if (strcmp(name,
"xml_text") == 0) {
1623 parser_fail(*pos,
"xml_text expects (node_handle)");
1628 parser_fail(*pos,
"Expected ')' after xml_text arg");
1636 if (strcmp(name,
"json_stringify") == 0) {
1639 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1644 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1649 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1654 parser_fail(*pos,
"Expected ')' after json_stringify args");
1662 if (strcmp(name,
"json_from_file") == 0) {
1665 parser_fail(*pos,
"json_from_file expects (path)");
1670 parser_fail(*pos,
"Expected ')' after json_from_file arg");
1678 if (strcmp(name,
"json_to_file") == 0) {
1681 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1686 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1691 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1696 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1701 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1706 parser_fail(*pos,
"Expected ')' after json_to_file args");
1715 if (strcmp(name,
"ini_load") == 0) {
1723 parser_fail(*pos,
"Expected ')' after ini_load arg");
1731 if (strcmp(name,
"ini_free") == 0) {
1739 parser_fail(*pos,
"Expected ')' after ini_free arg");
1747 if (strcmp(name,
"ini_get_string") == 0) {
1750 parser_fail(*pos,
"ini_get_string expects (handle, section, key, default)");
1755 parser_fail(*pos,
"ini_get_string expects 4 args");
1760 parser_fail(*pos,
"ini_get_string expects 4 args");
1765 parser_fail(*pos,
"ini_get_string expects 4 args");
1770 parser_fail(*pos,
"ini_get_string expects 4 args");
1775 parser_fail(*pos,
"ini_get_string expects 4 args");
1780 parser_fail(*pos,
"ini_get_string expects 4 args");
1785 parser_fail(*pos,
"Expected ')' after ini_get_string args");
1793 if (strcmp(name,
"ini_get_int") == 0) {
1796 parser_fail(*pos,
"ini_get_int expects (handle, section, key, default)");
1831 parser_fail(*pos,
"Expected ')' after ini_get_int args");
1839 if (strcmp(name,
"ini_get_double") == 0) {
1842 parser_fail(*pos,
"ini_get_double expects (handle, section, key, default)");
1847 parser_fail(*pos,
"ini_get_double expects 4 args");
1852 parser_fail(*pos,
"ini_get_double expects 4 args");
1857 parser_fail(*pos,
"ini_get_double expects 4 args");
1862 parser_fail(*pos,
"ini_get_double expects 4 args");
1867 parser_fail(*pos,
"ini_get_double expects 4 args");
1872 parser_fail(*pos,
"ini_get_double expects 4 args");
1877 parser_fail(*pos,
"Expected ')' after ini_get_double args");
1885 if (strcmp(name,
"ini_get_bool") == 0) {
1888 parser_fail(*pos,
"ini_get_bool expects (handle, section, key, default)");
1923 parser_fail(*pos,
"Expected ')' after ini_get_bool args");
1931 if (strcmp(name,
"ini_set") == 0) {
1934 parser_fail(*pos,
"ini_set expects (handle, section, key, value)");
1969 parser_fail(*pos,
"Expected ')' after ini_set args");
1977 if (strcmp(name,
"ini_unset") == 0) {
1980 parser_fail(*pos,
"ini_unset expects (handle, section, key)");
2005 parser_fail(*pos,
"Expected ')' after ini_unset args");
2013 if (strcmp(name,
"ini_save") == 0) {
2016 parser_fail(*pos,
"ini_save expects (handle, path)");
2031 parser_fail(*pos,
"Expected ')' after ini_save args");
2040 if (strcmp(name,
"curl_get") == 0) {
2048 parser_fail(*pos,
"Expected ')' after curl_get arg");
2057 if (strcmp(name,
"sqlite_open") == 0) {
2065 parser_fail(*pos,
"Expected ')' after sqlite_open arg");
2074 if (strcmp(name,
"redis_connect") == 0) {
2077 parser_fail(*pos,
"redis_connect expects (host, port)");
2082 parser_fail(*pos,
"redis_connect expects (host, port)");
2087 parser_fail(*pos,
"redis_connect expects (host, port)");
2092 parser_fail(*pos,
"Expected ')' after redis_connect args");
2100 if (strcmp(name,
"redis_cmd") == 0) {
2103 parser_fail(*pos,
"redis_cmd expects (handle, cmd)");
2108 parser_fail(*pos,
"redis_cmd expects (handle, cmd)");
2113 parser_fail(*pos,
"redis_cmd expects (handle, cmd)");
2118 parser_fail(*pos,
"Expected ')' after redis_cmd args");
2126 if (strcmp(name,
"redis_close") == 0) {
2129 parser_fail(*pos,
"redis_close expects (handle)");
2134 parser_fail(*pos,
"Expected ')' after redis_close arg");
2142 if (strcmp(name,
"sqlite_close") == 0) {
2145 parser_fail(*pos,
"sqlite_close expects (handle)");
2150 parser_fail(*pos,
"Expected ')' after sqlite_close arg");
2158 if (strcmp(name,
"sqlite_exec") == 0) {
2161 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2166 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2171 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2176 parser_fail(*pos,
"Expected ')' after sqlite_exec args");
2184 if (strcmp(name,
"sqlite_query") == 0) {
2187 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2192 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2197 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2202 parser_fail(*pos,
"Expected ')' after sqlite_query args");
2210 if (strcmp(name,
"curl_post") == 0) {
2213 parser_fail(*pos,
"curl_post expects (url, body)");
2218 parser_fail(*pos,
"curl_post expects (url, body)");
2223 parser_fail(*pos,
"curl_post expects (url, body)");
2228 parser_fail(*pos,
"Expected ')' after curl_post args");
2236 if (strcmp(name,
"curl_download") == 0) {
2239 parser_fail(*pos,
"curl_download expects (url, path)");
2244 parser_fail(*pos,
"curl_download expects (url, path)");
2249 parser_fail(*pos,
"curl_download expects (url, path)");
2254 parser_fail(*pos,
"Expected ')' after curl_download args");
2263 if (strcmp(name,
"openssl_md5") == 0) {
2271 parser_fail(*pos,
"Expected ')' after openssl_md5 arg");
2279 if (strcmp(name,
"openssl_sha256") == 0) {
2282 parser_fail(*pos,
"openssl_sha256 expects (data)");
2287 parser_fail(*pos,
"Expected ')' after openssl_sha256 arg");
2295 if (strcmp(name,
"openssl_sha512") == 0) {
2298 parser_fail(*pos,
"openssl_sha512 expects (data)");
2303 parser_fail(*pos,
"Expected ')' after openssl_sha512 arg");
2311 if (strcmp(name,
"openssl_ripemd160") == 0) {
2314 parser_fail(*pos,
"openssl_ripemd160 expects (data)");
2319 parser_fail(*pos,
"Expected ')' after openssl_ripemd160 arg");
2329 if (strcmp(name,
"pcsc_establish") == 0) {
2342 if (strcmp(name,
"pcre2_test") == 0) {
2346 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2351 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2356 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2361 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2366 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2371 parser_fail(*pos,
"Expected ')' after pcre2_test args");
2379 if (strcmp(name,
"pcre2_match") == 0) {
2382 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2387 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2392 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2397 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2402 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2407 parser_fail(*pos,
"Expected ')' after pcre2_match args");
2415 if (strcmp(name,
"pcre2_findall") == 0) {
2418 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2423 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2428 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2433 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2438 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2443 parser_fail(*pos,
"Expected ')' after pcre2_findall args");
2452 if (strcmp(name,
"pcsc_release") == 0) {
2455 parser_fail(*pos,
"pcsc_release expects 1 argument (ctx)");
2460 parser_fail(*pos,
"Expected ')' after pcsc_release arg");
2468 if (strcmp(name,
"pcsc_list_readers") == 0) {
2471 parser_fail(*pos,
"pcsc_list_readers expects 1 argument (ctx)");
2476 parser_fail(*pos,
"Expected ')' after pcsc_list_readers arg");
2484 if (strcmp(name,
"pcsc_connect") == 0) {
2488 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2493 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2498 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2503 parser_fail(*pos,
"Expected ')' after pcsc_connect args");
2511 if (strcmp(name,
"pcsc_disconnect") == 0) {
2514 parser_fail(*pos,
"pcsc_disconnect expects 1 argument (handle)");
2519 parser_fail(*pos,
"Expected ')' after pcsc_disconnect arg");
2527 if (strcmp(name,
"pcsc_transmit") == 0) {
2531 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2536 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2541 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2546 parser_fail(*pos,
"Expected ')' after pcsc_transmit args");
2555 if (strcmp(name,
"tcp_listen") == 0) {
2558 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2563 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2568 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2573 parser_fail(*pos,
"Expected ')' after tcp_listen args");
2581 if (strcmp(name,
"tcp_accept") == 0) {
2584 parser_fail(*pos,
"tcp_accept expects (listen_fd)");
2589 parser_fail(*pos,
"Expected ')' after tcp_accept arg");
2597 if (strcmp(name,
"tcp_connect") == 0) {
2600 parser_fail(*pos,
"tcp_connect expects (host, port)");
2605 parser_fail(*pos,
"tcp_connect expects (host, port)");
2610 parser_fail(*pos,
"tcp_connect expects (host, port)");
2615 parser_fail(*pos,
"Expected ')' after tcp_connect args");
2623 if (strcmp(name,
"sock_send") == 0) {
2626 parser_fail(*pos,
"sock_send expects (fd, data)");
2631 parser_fail(*pos,
"sock_send expects (fd, data)");
2636 parser_fail(*pos,
"sock_send expects (fd, data)");
2641 parser_fail(*pos,
"Expected ')' after sock_send args");
2649 if (strcmp(name,
"sock_recv") == 0) {
2652 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2657 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2662 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2667 parser_fail(*pos,
"Expected ')' after sock_recv args");
2675 if (strcmp(name,
"sock_close") == 0) {
2683 parser_fail(*pos,
"Expected ')' after sock_close arg");
2691 if (strcmp(name,
"unix_listen") == 0) {
2694 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2699 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2704 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2709 parser_fail(*pos,
"Expected ')' after unix_listen args");
2717 if (strcmp(name,
"unix_connect") == 0) {
2725 parser_fail(*pos,
"Expected ')' after unix_connect arg");
2734 if (strcmp(name,
"fd_set_nonblock") == 0) {
2738 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2743 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2748 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2753 parser_fail(*pos,
"Expected ')' after fd_set_nonblock args");
2761 if (strcmp(name,
"fd_poll_read") == 0) {
2765 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2770 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2775 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2780 parser_fail(*pos,
"Expected ')' after fd_poll_read args");
2788 if (strcmp(name,
"fd_poll_write") == 0) {
2792 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2797 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2802 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2807 parser_fail(*pos,
"Expected ')' after fd_poll_write args");
2816 if (strcmp(name,
"serial_open") == 0) {
2819 parser_fail(*pos,
"serial_open expects (path, baud)");
2824 parser_fail(*pos,
"serial_open expects (path, baud)");
2829 parser_fail(*pos,
"serial_open expects (path, baud)");
2834 parser_fail(*pos,
"Expected ')' after serial_open args");
2842 if (strcmp(name,
"serial_config") == 0) {
2845 for (
int i = 0; i < 5; ++i) {
2847 parser_fail(*pos,
"serial_config expects 5 arguments");
2853 parser_fail(*pos,
"serial_config expects 5 arguments");
2860 parser_fail(*pos,
"Expected ')' after serial_config args");
2868 if (strcmp(name,
"serial_send") == 0) {
2871 parser_fail(*pos,
"serial_send expects (fd, data)");
2876 parser_fail(*pos,
"serial_send expects (fd, data)");
2881 parser_fail(*pos,
"serial_send expects (fd, data)");
2886 parser_fail(*pos,
"Expected ')' after serial_send args");
2894 if (strcmp(name,
"serial_recv") == 0) {
2897 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2902 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2907 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2912 parser_fail(*pos,
"Expected ')' after serial_recv args");
2920 if (strcmp(name,
"serial_close") == 0) {
2928 parser_fail(*pos,
"Expected ')' after serial_close arg");
2937 if (strcmp(name,
"split") == 0) {
2944 if (*pos < len && src[*pos] ==
',') {
2958 parser_fail(*pos,
"Expected ')' after split args");
2966 if (strcmp(name,
"join") == 0) {
2973 if (*pos < len && src[*pos] ==
',') {
2987 parser_fail(*pos,
"Expected ')' after join args");
2995 if (strcmp(name,
"substr") == 0) {
3002 if (*pos < len && src[*pos] ==
',') {
3015 if (*pos < len && src[*pos] ==
',') {
3029 parser_fail(*pos,
"Expected ')' after substr args");
3037 if (strcmp(name,
"find") == 0) {
3044 if (*pos < len && src[*pos] ==
',') {
3058 parser_fail(*pos,
"Expected ')' after find args");
3067 if (strcmp(name,
"regex_match") == 0) {
3074 if (*pos < len && src[*pos] ==
',') {
3088 parser_fail(*pos,
"Expected ')' after regex_match args");
3096 if (strcmp(name,
"regex_search") == 0) {
3103 if (*pos < len && src[*pos] ==
',') {
3112 parser_fail(*pos,
"regex_search expects pattern");
3117 parser_fail(*pos,
"Expected ')' after regex_search args");
3125 if (strcmp(name,
"regex_replace") == 0) {
3132 if (*pos < len && src[*pos] ==
',') {
3136 parser_fail(*pos,
"regex_replace expects 3 args");
3141 parser_fail(*pos,
"regex_replace expects pattern");
3145 if (*pos < len && src[*pos] ==
',') {
3149 parser_fail(*pos,
"regex_replace expects 3 args");
3154 parser_fail(*pos,
"regex_replace expects replacement");
3159 parser_fail(*pos,
"Expected ')' after regex_replace args");
3168 if (strcmp(name,
"contains") == 0) {
3175 if (*pos < len && src[*pos] ==
',') {
3189 parser_fail(*pos,
"Expected ')' after contains args");
3197 if (strcmp(name,
"indexOf") == 0) {
3204 if (*pos < len && src[*pos] ==
',') {
3218 parser_fail(*pos,
"Expected ')' after indexOf args");
3226 if (strcmp(name,
"clear") == 0) {
3234 parser_fail(*pos,
"Expected ')' after clear arg");
3243 if (strcmp(name,
"enumerate") == 0) {
3251 parser_fail(*pos,
"Expected ')' after enumerate arg");
3259 if (strcmp(name,
"map") == 0) {
3263 parser_fail(*pos,
"map expects (array, function)");
3270 int larr = -1, garr = -1;
3280 parser_fail(*pos,
"map expects (array, function)");
3286 int lfn = -1, gfn = -1;
3298 int lres = -1, gres = -1;
3311 int li = -1, gi = -1;
3354 int lv = -1, gv = -1;
3414 if (strcmp(name,
"filter") == 0) {
3417 parser_fail(*pos,
"filter expects (array, function)");
3423 int larr = -1, garr = -1;
3432 parser_fail(*pos,
"filter expects (array, function)");
3438 int lfn = -1, gfn = -1;
3449 int lres = -1, gres = -1;
3461 int li = -1, gi = -1;
3510 int lvf = -1, gvf = -1;
3571 if (strcmp(name,
"reduce") == 0) {
3574 parser_fail(*pos,
"reduce expects (array, init, function)");
3580 int larr = -1, garr = -1;
3589 parser_fail(*pos,
"reduce expects (array, init, function)");
3595 int lacc = -1, gacc = -1;
3604 parser_fail(*pos,
"reduce expects (array, init, function)");
3610 int lfn = -1, gfn = -1;
3623 int li = -1, gi = -1;
3654 snprintf(telem,
sizeof(telem),
"__red_elem_%d",
g_temp_counter++);
3655 int lelem = -1, gelem = -1;
3716 if (strcmp(name,
"zip") == 0) {
3723 if (*pos < len && src[*pos] ==
',') {
3746 if (strcmp(name,
"min") == 0) {
3762 if (strcmp(name,
"max") == 0) {
3778 if (strcmp(name,
"fmin") == 0) {
3794 if (strcmp(name,
"fmax") == 0) {
3810 if (strcmp(name,
"clamp") == 0) {
3831 if (strcmp(name,
"abs") == 0) {
3842 if (strcmp(name,
"floor") == 0) {
3853 if (strcmp(name,
"ceil") == 0) {
3864 if (strcmp(name,
"trunc") == 0) {
3875 if (strcmp(name,
"round") == 0) {
3886 if (strcmp(name,
"sin") == 0) {
3897 if (strcmp(name,
"cos") == 0) {
3908 if (strcmp(name,
"tan") == 0) {
3919 if (strcmp(name,
"exp") == 0) {
3930 if (strcmp(name,
"log") == 0) {
3941 if (strcmp(name,
"log10") == 0) {
3952 if (strcmp(name,
"sqrt") == 0) {
3963 if (strcmp(name,
"gcd") == 0) {
3979 if (strcmp(name,
"lcm") == 0) {
3995 if (strcmp(name,
"isqrt") == 0) {
4006 if (strcmp(name,
"sign") == 0) {
4017 if (strcmp(name,
"pow") == 0) {
4034 if (strcmp(name,
"random_seed") == 0) {
4045 if (strcmp(name,
"random_int") == 0) {
4062 if (strcmp(name,
"random_number") == 0) {
4066 parser_fail(*pos,
"random_number expects 1 arg (length)");
4071 parser_fail(*pos,
"Expected ')' after random_number arg");
4081 if (strcmp(name,
"thread_spawn") == 0) {
4085 parser_fail(*pos,
"thread_spawn expects function as first arg");
4091 if (*pos < len && src[*pos] ==
',') {
4095 parser_fail(*pos,
"thread_spawn second arg must be array or value");
4102 parser_fail(*pos,
"Expected ')' after thread_spawn args");
4110 if (strcmp(name,
"thread_join") == 0) {
4113 parser_fail(*pos,
"thread_join expects 1 arg (thread id)");
4121 if (strcmp(name,
"sleep") == 0) {
4124 parser_fail(*pos,
"sleep expects 1 arg (milliseconds)");
4134 if (strcmp(name,
"band") == 0) {
4150 if (strcmp(name,
"bor") == 0) {
4166 if (strcmp(name,
"bxor") == 0) {
4182 if (strcmp(name,
"bnot") == 0) {
4198 if (strcmp(name,
"shl") == 0) {
4214 if (strcmp(name,
"shr") == 0) {
4230 if (strcmp(name,
"rol") == 0) {
4246 if (strcmp(name,
"ror") == 0) {
4265 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4266 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname, name);
4270 if (local_idx >= 0) {
4282 if (*pos < len && src[*pos] !=
')') {
4285 parser_fail(*pos,
"Expected expression as function argument");
4291 }
while (*pos < len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src, len, pos), 1));
4294 parser_fail(*pos,
"Expected ')' after arguments");
4301 printf(
"compile: CALL %s with %d arg(s)\n", name, argc);
4310 if (*pos < len && src[*pos] ==
'[') {
4318 if (*pos < len && src[*pos] ==
':') {
4346 if (*pos < len && src[*pos] ==
'.') {
4351 parser_fail(*pos,
"Expected identifier after '.'");
4355 int is_private = (mname && mname[0] ==
'_');
4359 size_t callp = *pos;
4361 if (callp < len && src[callp] ==
'(') {
4365 snprintf(msg,
sizeof(msg),
"AccessError: private method '%s' is not accessible here", mname);
4388 if (*pos < len && src[*pos] !=
')') {
4391 parser_fail(*pos,
"Expected expression as method argument");
4398 }
while (*pos < len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src, len, pos), 1));
4401 parser_fail(*pos,
"Expected ')' after arguments");
4426 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4427 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname, name);
4431 if (local_idx >= 0) {
4444 if (*pos < len && src[*pos] ==
'[') {
4452 if (*pos < len && src[*pos] ==
':') {
4480 if (*pos < len && src[*pos] ==
'.') {
4485 parser_fail(*pos,
"Expected identifier after '.'");
4489 int is_private = (mname && mname[0] ==
'_');
4493 size_t callp = *pos;
4495 if (callp < len && src[callp] ==
'(') {
4497 if (is_private && !(strcmp(name,
"this") == 0)) {
4499 snprintf(msg,
sizeof(msg),
"AccessError: private method '%s' is not accessible", mname);
4509 int is_ns = __ns_ctx;
4526 if (*pos < len && src[*pos] !=
')') {
4529 parser_fail(*pos,
"Expected expression as method argument");
4536 }
while (*pos < len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src, len, pos), 1));
4539 parser_fail(*pos,
"Expected ')' after arguments");
4584 if (*pos < len && src[*pos] ==
'!') {
4587 parser_fail(*pos,
"Expected expression after '!'");
4593 if (*pos < len && src[*pos] ==
'-') {
4599 parser_fail(*pos,
"Expected expression after unary '-'");
4620 if (!
emit_unary(bc, src, len, pos))
return 0;
4625 if (*pos + 1 < len && src[*pos] ==
'/' && src[*pos + 1] ==
'/') {
4629 if (*pos + 1 < len && src[*pos] ==
'/' && src[*pos + 1] ==
'*') {
4630 size_t p = *pos + 2;
4631 while (p + 1 < len && !(src[p] ==
'*' && src[p + 1] ==
'/')) {
4634 if (p + 1 < len) p += 2;
4639 if (*pos < len && src[*pos] ==
'*') {
4642 parser_fail(*pos,
"Expected expression after '*'");
4648 if (*pos < len && src[*pos] ==
'/') {
4651 parser_fail(*pos,
"Expected expression after '/'");
4657 if (*pos < len && src[*pos] ==
'%') {
4660 parser_fail(*pos,
"Expected expression after '%'");
4686 if (*pos < len && src[*pos] ==
'+') {
4689 parser_fail(*pos,
"Expected expression after '+'");
4695 if (*pos < len && src[*pos] ==
'-') {
4698 parser_fail(*pos,
"Expected expression after '-'");
4724 if (*pos + 1 < len && src[*pos] ==
'<' && src[*pos + 1] ==
'=') {
4727 parser_fail(*pos,
"Expected expression after '<='");
4733 if (*pos + 1 < len && src[*pos] ==
'>' && src[*pos + 1] ==
'=') {
4736 parser_fail(*pos,
"Expected expression after '>='");
4742 if (*pos < len && src[*pos] ==
'<') {
4745 parser_fail(*pos,
"Expected expression after '<'");
4751 if (*pos < len && src[*pos] ==
'>') {
4754 parser_fail(*pos,
"Expected expression after '>'");
4780 if (*pos + 1 < len && src[*pos] ==
'=' && src[*pos + 1] ==
'=') {
4783 parser_fail(*pos,
"Expected expression after '=='");
4789 if (*pos + 1 < len && src[*pos] ==
'!' && src[*pos + 1] ==
'=') {
4792 parser_fail(*pos,
"Expected expression after '!='");
4825 if (!(*pos + 1 < len && src[*pos] ==
'&' && src[*pos + 1] ==
'&'))
break;
4830 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4833 parser_fail(*pos,
"Too many operands in '&&' chain");
4839 parser_fail(*pos,
"Expected expression after '&&'");
4846 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4849 parser_fail(*pos,
"Too many operands in '&&' chain");
4860 for (
int i = 0; i < jf_count; ++i) {
4896 if (!(*pos + 1 < len && src[*pos] ==
'|' && src[*pos + 1] ==
'|'))
break;
4906 if (tj_count < (
int)(
sizeof(true_jumps) /
sizeof(true_jumps[0]))) {
4909 parser_fail(*pos,
"Too many operands in '||' chain");
4918 parser_fail(*pos,
"Expected expression after '||'");
4938 for (
int i = 0; i < tj_count; ++i) {
4963 if (!(*pos < len && src[*pos] ==
'?'))
break;
4972 parser_fail(*pos,
"Expected expression after '?'");
4984 if (!(*pos < len && src[*pos] ==
':')) {
4985 parser_fail(*pos,
"Expected ':' in conditional expression");
4993 parser_fail(*pos,
"Expected expression after ':'");
5047 while (p < len && src[p] ==
' ')
5055 if (src[p] ==
'\r') {
5057 if (p < len && src[p] ==
'\n') p++;
5061 if (src[p] ==
'\n') {
5067 if (p + 1 < len && src[p] ==
'/' && src[p + 1] ==
'/') {
5070 while (p < len && src[p] !=
'\n' && src[p] !=
'\r')
5072 if (p < len && src[p] ==
'\r') {
5074 if (p < len && src[p] ==
'\n') p++;
5075 }
else if (p < len && src[p] ==
'\n') {
5082 if (p + 1 < len && src[p] ==
'/' && src[p + 1] ==
'*') {
5085 while (p + 1 < len && !(src[p] ==
'*' && src[p + 1] ==
'/')) {
5092 parser_fail(p,
"Unterminated block comment at end of file");
5099 parser_fail(p,
"Unexpected trailing characters at end of line");
5130 while (*pos < len) {
5133 while (p < len && src[p] ==
' ') {
5137 if (p < len && src[p] ==
'\t') {
5138 parser_fail(p,
"Tabs are forbidden for indentation");
5147 if (src[p] ==
'\r') {
5149 if (p < len && src[p] ==
'\n') p++;
5153 if (src[p] ==
'\n') {
5160 if (p + 1 < len && src[p] ==
'/' && src[p + 1] ==
'/') {
5163 while (p < len && src[p] !=
'\n' && src[p] !=
'\r')
5165 if (p < len && src[p] ==
'\r') {
5167 if (p < len && src[p] ==
'\n') p++;
5168 }
else if (p < len && src[p] ==
'\n') {
5176 if (p + 1 < len && src[p] ==
'/' && src[p + 1] ==
'*') {
5179 while (p + 1 < len && !(src[p] ==
'*' && src[p + 1] ==
'/')) {
5182 if (p + 1 < len) p += 2;
5184 while (p < len && src[p] !=
'\n' && src[p] !=
'\r')
5186 if (p < len && src[p] ==
'\r') {
5188 if (p < len && src[p] ==
'\n') p++;
5189 }
else if (p < len && src[p] ==
'\n') {
5196 if (spaces % 2 != 0) {
5197 parser_fail(p,
"Indentation must be multiples of two spaces");
5200 *out_indent = spaces / 2;
5208static void parse_block(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos,
int current_indent);
5223 size_t local_pos = *pos;
5228 if (strcmp(name,
"sint8") == 0) {
5230 name = strdup(
"int8");
5231 }
else if (strcmp(name,
"sint16") == 0) {
5233 name = strdup(
"int16");
5234 }
else if (strcmp(name,
"sint32") == 0) {
5236 name = strdup(
"int32");
5237 }
else if (strcmp(name,
"sint64") == 0) {
5239 name = strdup(
"int64");
5243 if (strcmp(name,
"return") == 0) {
5247 size_t save_pos = local_pos;
5252 local_pos = save_pos;
5263 if (strcmp(name,
"exit") == 0) {
5266 size_t save_pos = local_pos;
5271 local_pos = save_pos;
5282 if (strcmp(name,
"break") == 0) {
5285 parser_fail(local_pos,
"break used outside of loop");
5292 parser_fail(local_pos,
"Too many 'break' in one loop");
5299 if (strcmp(name,
"continue") == 0) {
5302 parser_fail(local_pos,
"continue used outside of loop");
5309 parser_fail(local_pos,
"Too many 'continue' in one loop");
5321 if (strcmp(name,
"number") == 0 || strcmp(name,
"string") == 0 || strcmp(name,
"boolean") == 0 || strcmp(name,
"nil") == 0 || strcmp(name,
"class") == 0 || strcmp(name,
"float") == 0 || strcmp(name,
"array") == 0 || strcmp(name,
"byte") == 0 || strcmp(name,
"uint8") == 0 || strcmp(name,
"uint16") == 0 || strcmp(name,
"uint32") == 0 || strcmp(name,
"uint64") == 0 || strcmp(name,
"int8") == 0 || strcmp(name,
"int16") == 0 || strcmp(name,
"int32") == 0 || strcmp(name,
"int64") == 0) {
5322 int is_number = (strcmp(name,
"number") == 0);
5323 int is_string = (strcmp(name,
"string") == 0);
5324 int is_boolean = (strcmp(name,
"boolean") == 0);
5325 int is_nil = (strcmp(name,
"nil") == 0);
5326 int is_class = (strcmp(name,
"class") == 0);
5327 int is_float = (strcmp(name,
"float") == 0);
5328 int is_array = (strcmp(name,
"array") == 0);
5329 int is_byte = (strcmp(name,
"byte") == 0);
5330 int is_u8 = (strcmp(name,
"uint8") == 0) || is_byte;
5331 int is_u16 = (strcmp(name,
"uint16") == 0);
5332 int is_u32 = (strcmp(name,
"uint32") == 0);
5333 int is_u64 = (strcmp(name,
"uint64") == 0);
5334 int is_s8 = (strcmp(name,
"int8") == 0);
5335 int is_s16 = (strcmp(name,
"int16") == 0);
5336 int is_s32 = (strcmp(name,
"int32") == 0);
5337 int is_s64 = (strcmp(name,
"int64") == 0) || is_number;
5338 int decl_bits = is_u8 ? 8 : is_u16 ? 16
5346 int decl_signed = (is_s8 || is_s16 || is_s32 || is_s64) ? 1 : 0;
5348 if (decl_signed) decl_bits = -decl_bits;
5351 int decl_meta = decl_bits;
5354 }
else if (is_boolean) {
5356 }
else if (is_nil) {
5360 }
else if (is_float) {
5362 }
else if (is_array) {
5369 char *varname = NULL;
5372 parser_fail(local_pos,
"Expected identifier after type declaration");
5391 G.types[gi] = decl_meta;
5397 if (local_pos < len && src[local_pos] ==
'=') {
5400 parser_fail(local_pos,
"Expected initializer expression after '='");
5541 int abs_bits = decl_bits < 0 ? -decl_bits : decl_bits;
5576 }
else if (is_nil) {
5581 }
else if (is_boolean) {
5584 }
else if (is_number || (decl_bits != 0)) {
5590 int abs_bits2 = decl_bits < 0 ? -decl_bits : decl_bits;
5591 if (abs_bits2 > 0) {
5606 if (strcmp(name,
"print") == 0) {
5621 if (strcmp(name,
"echo") == 0) {
5638 int gi = (lidx < 0) ?
sym_find(name) : -1;
5639 if (lidx < 0 && gi < 0 &&
g_locals) {
5643 if (lidx < 0 && gi < 0) {
5657 if (local_pos < len && src[local_pos] ==
'.') {
5658 size_t stmt_start = *pos;
5659 size_t look = local_pos + 1;
5663 parser_fail(look,
"Expected field name after '.'");
5668 if (look < len && src[look] ==
'[') {
5683 if (!(look < len && src[look] ==
'['))
break;
5686 parser_fail(look,
"Expected index expression after '['");
5696 if (look < len && src[look] ==
'[') {
5704 if (look >= len || src[look] !=
'=') {
5707 size_t expr_pos = stmt_start;
5717 parser_fail(look,
"Expected expression after '='");
5726 }
else if (look < len && src[look] ==
'=') {
5735 local_pos = look + 1;
5737 parser_fail(local_pos,
"Expected expression after '='");
5743 int tmp_local =
local_add(
"__assign_tmp");
5769 size_t expr_pos = stmt_start;
5780 if (local_pos < len && src[local_pos] ==
'[') {
5789 parser_fail(local_pos,
"Expected index expression after '['");
5794 parser_fail(local_pos,
"Expected ']' after index");
5801 if (local_pos < len && src[local_pos] ==
'[') {
5807 parser_fail(local_pos,
"Expected nested index expression after '['");
5812 parser_fail(local_pos,
"Expected ']' after nested index");
5817 if (local_pos >= len || src[local_pos] !=
'=') {
5818 parser_fail(local_pos,
"Expected '=' after nested array index");
5824 parser_fail(local_pos,
"Expected expression after '='");
5837 if (local_pos >= len || src[local_pos] !=
'=') {
5838 parser_fail(local_pos,
"Expected '=' after array index");
5844 parser_fail(local_pos,
"Expected expression after '='");
5857 if (local_pos < len && src[local_pos] ==
'=') {
5864 }
else if (gi >= 0) {
5987 }
else if (meta != 0) {
5989 int abs_bits = meta < 0 ? -meta : meta;
6034 parser_fail(local_pos,
"Expected assignment '=' or call '(...)' after identifier");
6070 parser_fail(*pos,
"Unknown token at start of statement");
6088 while (*pos < len) {
6090 size_t line_start = *pos;
6096 if (indent < current_indent) {
6101 if (indent > current_indent) {
6112 int stmt_line = 1, stmt_col = 1;
6118 if (
starts_with(src, len, *pos,
"class") && (*pos + 5 < len) && (src[*pos + 5] ==
' ' || src[*pos + 5] ==
'\t')) {
6124 parser_fail(*pos,
"Expected class name after 'class'");
6130 char *parent_name = NULL;
6133 char *param_names[64];
6136 memset(param_names, 0,
sizeof(param_names));
6137 memset(param_kind, 0,
sizeof(param_kind));
6141#define MAP_TYPE_KIND(t) ( \
6142 ((t) && strcmp((t), "string") == 0) ? 2 : ((t) && strcmp((t), "nil") == 0) ? 3 \
6143 : ((t) && (strcmp((t), "boolean") == 0 || strcmp((t), "number") == 0 || strcmp((t), "byte") == 0 || strncmp((t), "uint", 4) == 0 || strncmp((t), "sint", 4) == 0 || strncmp((t), "int", 3) == 0)) ? 1 \
6147 if (*pos < len && src[*pos] ==
'(') {
6150 if (*pos < len && src[*pos] !=
')') {
6155 parser_fail(*pos,
"Expected type in class parameter list");
6163 parser_fail(*pos,
"Expected parameter name after type");
6168 if (pcount >= (
int)(
sizeof(param_names) /
sizeof(param_names[0]))) {
6175 param_names[pcount] = pname;
6181 if (*pos < len && src[*pos] ==
',') {
6190 parser_fail(*pos,
"Expected ')' after class parameter list");
6191 for (
int i = 0; i < pcount; ++i)
6192 free(param_names[i]);
6204 parser_fail(*pos,
"Expected parent class name after 'extends'");
6205 for (
int i = 0; i < pcount; ++i)
6206 free(param_names[i]);
6219 if (ctor_bc->
name) free((
void *)ctor_bc->
name);
6220 ctor_bc->
name = strdup(cname);
6226 memset(&ctor_env, 0,
sizeof(ctor_env));
6231 int ctor_present = 0;
6234 for (
int i = 0; i < pcount; ++i) {
6242 for (
int i = 0; i < pcount; ++i) {
6253 snprintf(msg,
sizeof(msg),
"TypeError: missing argument '%s' in %s()", param_names[i], cname);
6263 int kind = param_kind[i];
6264 if (kind == 1 || kind == 2 || kind == 3) {
6268 const char *exp = (kind == 1) ?
"Number" : (kind == 2) ?
"String"
6282 snprintf(msg2,
sizeof(msg2),
"TypeError: %s() expects %s for '%s'", cname, exp, param_names[i]);
6308 snprintf(msg3,
sizeof(msg3),
"TypeError: %s() received too many arguments", cname);
6337 for (
int i = 0; i < pcount; ++i) {
6341 int l_parent =
local_add(
"__parent_inst");
6347 int l_keys =
local_add(
"__parent_keys");
6405 int body_indent = 0;
6406 size_t look_body = *pos;
6407 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
6410 size_t member_line_start = *pos;
6411 int member_indent = 0;
6416 if (member_indent < body_indent) {
6418 *pos = member_line_start;
6421 if (member_indent > body_indent) {
6423 parse_block(ctor_bc, src, len, pos, member_indent);
6434 parser_fail(*pos,
"Expected method name after 'fun' in class");
6439 int is_ctor_method = (strcmp(mname,
"_construct") == 0);
6443 parser_fail(*pos,
"Expected '(' after method name");
6453 if (m_bc->
name) free((
void *)m_bc->
name);
6455 size_t qlen = strlen(cname) + 1 + strlen(mname) + 1;
6456 char *q = (
char *)malloc(qlen);
6458 snprintf(q, qlen,
"%s.%s", cname, mname);
6465 memset(&m_env, 0,
sizeof(m_env));
6471 int param_count = 0;
6473 if (*pos < len && src[*pos] !=
')') {
6484 if (param_count == 0 && strcmp(pname,
"this") != 0) {
6486 if (is_ctor_method) {
6487 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6489 parser_fail(*pos,
"First parameter of a method must be 'this'");
6502 if (*pos < len && src[*pos] ==
',') {
6511 if (is_ctor_method) {
6512 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6514 parser_fail(*pos,
"Method must declare at least 'this' parameter");
6524 parser_fail(*pos,
"Expected ')' after method parameter list");
6535 int m_body_indent = 0;
6536 size_t look_m = *pos;
6537 if (
read_line_start(src, len, &look_m, &m_body_indent) && m_body_indent > body_indent) {
6557 if (strcmp(mname,
"_construct") == 0) {
6569 parser_fail(*pos,
"Expected field or 'fun' in class body");
6576 if (tmp >= len || src[tmp] !=
'=') {
6578 parser_fail(tmp,
"Expected '=' in field initializer");
6591 parser_fail(*pos,
"Expected expression in field initializer");
6605 for (
int i = 0; i < pcount; ++i) {
6626 for (
int i = 0; i < pcount; ++i) {
6647 G.is_class[cgi] = 1;
6649 for (
int i = 0; i < pcount; ++i)
6650 free(param_names[i]);
6651 if (parent_name) free(parent_name);
6656 if (
starts_with(src, len, *pos,
"fun") && (*pos + 3 < len) && (src[*pos + 3] ==
' ' || src[*pos + 3] ==
'\t')) {
6662 parser_fail(*pos,
"Expected function name after 'fun'");
6668 parser_fail(*pos,
"Expected '(' after function name");
6679 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
6688 if (*pos < len && src[*pos] !=
')') {
6698 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
6707 if (*pos < len && src[*pos] ==
',') {
6716 parser_fail(*pos,
"Expected ')' after parameter list");
6727 if (fn_bc->
name) free((
void *)fn_bc->
name);
6728 fn_bc->
name = strdup(fname);
6734 int body_indent = 0;
6735 size_t look_body = *pos;
6736 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
6748 printf(
"=== compiled function %s (%d params) ===\n", fname, env.
count);
6750 printf(
"=== end function %s ===\n", fname);
6812 if (*pos < len && src[*pos] ==
'(') {
6817 parser_fail(*pos,
"Expected identifier after '(' in for tuple");
6822 parser_fail(*pos,
"Expected ',' between key and value in for tuple");
6828 parser_fail(*pos,
"Expected value identifier after ',' in for tuple");
6834 parser_fail(*pos,
"Expected ')' to close for tuple");
6843 parser_fail(*pos,
"Expected loop variable after 'for'");
6850 parser_fail(*pos,
"Expected 'in' after loop variable");
6868 parser_fail(*pos,
"Expected start expression in range");
6890 if (*pos >= len || src[*pos] !=
',') {
6891 parser_fail(*pos,
"Expected ',' between range start and end");
6900 parser_fail(*pos,
"Expected end expression in range");
6906 snprintf(tmpname,
sizeof(tmpname),
"__for_end_%d",
g_temp_counter++);
6908 int lend = -1, gend = -1;
6918 parser_fail(*pos,
"Expected ')' after range arguments");
6948 int body_indent = 0;
6949 size_t look_body = *pos;
6950 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
6981 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
6991 }
else if (!tuple_mode) {
6995 parser_fail(*pos,
"Expected iterable expression after 'in'");
7000 snprintf(arrname,
sizeof(arrname),
"__for_arr_%d",
g_temp_counter++);
7001 int larr = -1, garr = -1;
7018 snprintf(lenname,
sizeof(lenname),
"__for_len_%d",
g_temp_counter++);
7019 int llen = -1, glen = -1;
7033 int li = -1, gi = -1;
7095 int body_indent = 0;
7096 size_t look_body = *pos;
7097 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
7128 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
7142 parser_fail(*pos,
"Expected map expression after 'in'");
7148 snprintf(mapname,
sizeof(mapname),
"__for_map_%d",
g_temp_counter++);
7149 int lmap = -1, gmap = -1;
7166 snprintf(keysname,
sizeof(keysname),
"__for_keys_%d",
g_temp_counter++);
7167 int lkeys = -1, gkeys = -1;
7184 snprintf(lenname,
sizeof(lenname),
"__for_klen_%d",
g_temp_counter++);
7185 int llen = -1, glen = -1;
7199 int li = -1, gi = -1;
7289 int body_indent = 0;
7290 size_t look_body = *pos;
7291 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
7320 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
7355 size_t ppeek = *pos;
7357 while (ppeek < len && src[ppeek] ==
' ')
7359 int inline_stmt = 0;
7361 if (src[ppeek] ==
'\r' || src[ppeek] ==
'\n') {
7363 }
else if (ppeek + 1 < len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'/') {
7365 }
else if (ppeek + 1 < len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'*') {
7390 int next_indent = 0;
7391 size_t look_next = *pos;
7393 if (next_indent > current_indent) {
7405 if (end_count < (
int)(
sizeof(end_jumps) /
sizeof(end_jumps[0]))) {
7406 end_jumps[end_count++] = jmp_end;
7408 parser_fail(*pos,
"Too many chained else/if clauses");
7417 int look_indent = 0;
7422 if (look_indent != current_indent) {
7438 int else_indent = 0;
7439 size_t look_else = *pos;
7440 if (
read_line_start(src, len, &look_else, &else_indent) && else_indent > current_indent) {
7456 for (
int i = 0; i < end_count; ++i) {
7485 int body_indent = 0;
7486 size_t look_body = *pos;
7487 if (
read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) {
7494 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
7522 int try_body_indent = 0;
7523 size_t look_try = *pos;
7524 if (
read_line_start(src, len, &look_try, &try_body_indent) && try_body_indent > current_indent) {
7538 int seen_finally = 0;
7539 int catch_label = -1;
7542 int look_indent = 0;
7544 if (look_indent != current_indent)
break;
7546 if (!seen_catch &&
starts_with(src, len, look,
"catch")) {
7551 char *ex_name = NULL;
7567 int lidx = -1, gi = -1;
7586 if (ex_name) free(ex_name);
7589 int catch_indent = 0;
7590 size_t look_catch = *pos;
7591 if (
read_line_start(src, len, &look_catch, &catch_indent) && catch_indent > current_indent) {
7600 if (!seen_finally &&
starts_with(src, len, look,
"finally")) {
7607 int finally_indent = 0;
7608 size_t look_fin = *pos;
7609 if (
read_line_start(src, len, &look_fin, &finally_indent) && finally_indent > current_indent) {
7687 fprintf(stderr,
"Error: cannot read file: %s\n", path);
7693 const char *compile_src = prep ? prep : src;
7694 size_t compile_len = strlen(compile_src);
7718 bc->
source_file = path ? strdup(path) : strdup(
"<input>");
7719 if (bc->
name) free((
void *)bc->
name);
7721 const char *bn = path ? strrchr(path,
'/') : NULL;
7722 const char *base = bn ? bn + 1 : (path ? path :
"<input>");
7723 bc->
name = strdup(base);
7733 int line = 1, col = 1;
7743 const char *marker0 =
"// __include_begin__: ";
7744 size_t m0 = strlen(marker0);
7748 if (compile_len >= 2 && compile_src[0] ==
'#' && compile_src[1] ==
'!') {
7750 while (start < compile_len && compile_src[start] !=
'\n' && compile_src[start] !=
'\r') start++;
7751 if (start < compile_len && compile_src[start] ==
'\r') {
7753 if (start < compile_len && compile_src[start] ==
'\n') start++;
7754 }
else if (start < compile_len && compile_src[start] ==
'\n') {
7762 while (eol0 < compile_len && compile_src[eol0] !=
'\n') eol0++;
7764 if (ls + m0 <= compile_len && strncmp(compile_src + ls, marker0, m0) == 0) {
7767 if (line > 1) line -= 1;
7776 const char *marker =
"// __include_begin__: ";
7777 size_t mlen = strlen(marker);
7778 int inner_line = -1;
7787 while (ls > 0 && compile_src[ls - 1] !=
'\n')
7790 if (ls + mlen <= compile_len && strncmp(compile_src + ls, marker, mlen) == 0) {
7792 size_t p = ls + mlen;
7794 while (eol < compile_len && compile_src[eol] !=
'\n') eol++;
7796 size_t pos_as = eol, pos_line = eol;
7797 for (
size_t t = p; t + 3 < eol; ++t) {
7798 if (compile_src[t] ==
' ' && strncmp(compile_src + t,
" as ", 4) == 0) { pos_as = t;
break; }
7800 for (
size_t t = p; t + 6 < eol; ++t) {
7801 if (compile_src[t] ==
' ' && strncmp(compile_src + t,
" @line ", 7) == 0) { pos_line = t;
break; }
7803 size_t path_end = pos_as < pos_line ? pos_as : pos_line;
7804 if (path_end < p) path_end = eol;
7805 size_t copy = (path_end - p) <
sizeof(inc_path) - 1 ? (path_end - p) :
sizeof(inc_path) - 1;
7806 memcpy(inc_path, compile_src + p, copy);
7807 inc_path[copy] =
'\0';
7811 if (pos_line < eol) {
7812 size_t num_start = pos_line + 7;
7813 while (num_start < eol && compile_src[num_start] ==
' ') num_start++;
7815 while (num_start < eol && compile_src[num_start] >=
'0' && compile_src[num_start] <=
'9') {
7816 v = v * 10 + (compile_src[num_start] -
'0');
7819 if (v > 0) base_line = v;
7824 size_t q = (eol < compile_len && compile_src[eol] ==
'\n') ? (eol + 1) : eol;
7826 if (compile_src[q] ==
'\n')
count++;
7837 if (inner_line > 0 && inc_path[0] !=
'\0') {
7839 int shebang_adjust = 0;
7840 FILE *sf = fopen(inc_path,
"rb");
7844 if (c1 ==
'#' && c2 ==
'!') shebang_adjust = 1;
7847 int mapped_inner = inner_line + (base_line - 1) + shebang_adjust;
7849 if (path && strcmp(path, inc_path) == 0) {
7850 fprintf(stderr,
"Parse error %s:%d:%d: %s\n",
7853 fprintf(stderr,
"Parse error %s:%d:%d: %s (in %s:%d)\n",
7854 path ? path :
"<input>", line, col,
g_err_msg, inc_path, mapped_inner);
7857 fprintf(stderr,
"Parse error %s:%d:%d: %s\n", path ? path :
"<input>", line, col,
g_err_msg);
7861 if (prep) free(prep);
7866 if (prep) free(prep);
7882 fprintf(stderr,
"Error: null source provided\n");
7888 const char *compile_src = prep ? prep : source;
7889 size_t len = strlen(compile_src);
7913 if (bc->
name) free((
void *)bc->
name);
7914 bc->
name = strdup(
"<input>");
7923 int line = 1, col = 1;
7928 if (prep) free(prep);
7931 if (prep) free(prep);
7950 if (msgBuf && msgCap > 0) {
7951 snprintf(msgBuf, msgCap,
"%s",
g_err_msg);
Bytecode * bytecode_new(void)
Allocate and initialize an empty Bytecode object.
int bytecode_add_instruction(Bytecode *bc, OpCode op, int32_t operand)
Append a single instruction to the instruction stream.
void bytecode_free(Bytecode *bc)
Free a Bytecode and all memory it owns.
void bytecode_dump(const Bytecode *bc)
Print a human-readable dump of constants and instructions to stdout.
void bytecode_set_operand(Bytecode *bc, int idx, int32_t operand)
Patch the operand of a previously emitted instruction.
int bytecode_add_constant(Bytecode *bc, Value v)
Append a constant to a Bytecode's constant table with de-duplication.
@ OP_RUST_HELLO_ARGS_RETURN
int is_class[MAX_GLOBALS]
static void parser_fail(size_t pos, const char *fmt,...)
Record a parser/compiler error at a given source position.
#define TYPE_META_NIL
Type metadata tag indicating explicit nil type.
static LocalEnv * g_func_env_stack[64]
static int local_find(const char *name)
Find the index of a local variable in the current function.
static int fun_debug_enabled(void)
Determine whether parser/compiler debug tracing is enabled.
static int emit_and_expr(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit logical AND (&&) with short-circuiting.
static int g_temp_counter
char * names[MAX_GLOBALS]
static int emit_relational(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit relational expressions.
static int local_add(const char *name)
Add a new local variable to the current function environment.
#define TYPE_META_BOOLEAN
Type metadata tag used for boolean enforcement in declared types.
static int env_truthy(const char *name)
Interpret an environment variable as a boolean flag.
static struct @204206037126360267375134217342340021000343236145 G
static void calc_line_col(const char *src, size_t len, size_t pos, int *out_line, int *out_col)
Compute one-based line and column from a byte position.
static int emit_or_expr(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit logical OR (||) with short-circuiting.
static const char * g_active_src
static int is_ns_alias(const char *name)
Check whether an identifier is a registered namespace alias.
static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit bytecode for primary expressions.
#define TYPE_META_ARRAY
Type metadata tag marking array values.
static int sym_find(const char *name)
Find a global symbol index by name.
#define TYPE_META_FLOAT
Type metadata tag marking floating point numbers.
static int g_last_err_line
Bytecode * parse_string_to_bytecode(const char *source)
Parse a source string and return compiled bytecode.
static int emit_equality(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit equality/inequality expressions.
static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos, int current_indent)
Parse a block of statements at a given indentation level.
int parser_last_error(char *msgBuf, unsigned long msgCap, int *outLine, int *outCol)
Retrieve the last parser/compiler error information, if any.
static int emit_additive(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit additive expressions.
#define TYPE_META_CLASS
Type metadata tag marking class/instance values.
static int emit_conditional(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit the ternary conditional operator.
static void ns_aliases_reset(void)
Reset and free all tracked namespace aliases.
static int g_line_err_count
static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse a single statement on the current line and emit bytecode.
static int emit_multiplicative(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit multiplicative expressions.
#define TYPE_META_STRING
Type metadata tag used for string enforcement in declared types.
static char * g_ns_aliases[64]
static int read_line_start(const char *src, size_t len, size_t *pos, int *out_indent)
Read the start of a logical line and compute indentation.
static Bytecode * compile_minimal(const char *src, size_t len)
Compile a full source buffer into bytecode.
static char g_err_msg[256]
static LocalEnv * g_locals
static void ns_aliases_scan(const char *src, size_t len)
Scan preprocessed source for namespace alias markers.
static int emit_unary(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit unary expressions.
static int sym_index(const char *name)
Get or create a global symbol index for a name.
static int emit_expression(Bytecode *bc, const char *src, size_t len, size_t *pos)
Parse and emit a full expression using precedence climbing.
static const int G_ERRS_PER_LINE_CAP
static int g_ns_alias_count
static const char * g_current_source_path
char * preprocess_includes_with_path(const char *src, const char *current_path)
Preprocess includes with a known file path to improve span markers.
static int g_func_env_depth
static LoopCtx * g_loop_ctx
static void skip_to_eol(const char *src, size_t len, size_t *pos)
Advance position to the end of the current line, validating tail.
static size_t g_active_len
static int name_in_outer_envs(const char *name)
Check whether a local name exists in any outer function environment.
Bytecode * parse_file_to_bytecode(const char *path)
Parse a .fun source file and return compiled bytecode.
Public API for parsing Fun source into bytecode.
Low-level parsing helpers and include preprocessor for the Fun parser.
static double parse_float_literal_value(const char *src, size_t len, size_t *pos, int *ok)
Parse a floating-point literal (supports . and scientific notation).
static int read_identifier_into(const char *src, size_t len, size_t *pos, char **out_name)
Read an identifier starting at pos and allocate its name.
static void skip_ws(const char *src, size_t len, size_t *pos)
Skip spaces, tabs, carriage returns and newlines.
static uint64_t parse_int_literal_value(const char *src, size_t len, size_t *pos, int *ok)
Parse an integer literal (decimal or 0x-hex) with optional sign.
static int consume_char(const char *src, size_t len, size_t *pos, char expected)
Consume expected character after skipping whitespace.
static void skip_comments(const char *src, size_t len, size_t *pos)
Skip whitespace, then line and block comments. Continues until the next non-comment,...
static void skip_spaces(const char *src, size_t len, size_t *pos)
Skip only spaces, tabs and carriage returns (not newlines).
static void skip_shebang_if_present(const char *src, size_t len, size_t *pos)
Skip a top-of-file shebang line that starts with "#!" if present.
static char * read_file_all(const char *path, size_t *out_len)
Read entire file into a newly allocated buffer.
static int starts_with(const char *src, size_t len, size_t pos, const char *kw)
Check if src starting at pos begins with kw and fits in len.
static char * parse_string_literal_any_quote(const char *src, size_t len, size_t *pos)
Parse a single-quoted or double-quoted string literal.
char * preprocess_includes(const char *src)
Public wrapper to preprocess includes without a current path.
int types[MAX_FRAME_LOCALS]
char * names[MAX_FRAME_LOCALS]
Value make_bool(int v)
Construct a boolean Value.
Value make_nil(void)
Construct a nil Value.
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Value make_function(struct Bytecode *fn)
Construct a function Value referencing bytecode.
Value make_float(double v)
Construct a Value representing a double-precision float.
Value make_int(int64_t v)
Construct a Value representing a 64-bit integer.
Defines the Value type and associated functions for the Fun VM.
Core virtual machine data structures and public VM API.