82 const char *
v = getenv(
name);
84 if (strcmp(
v,
"1") == 0)
return 1;
85 if (strcmp(
v,
"true") == 0)
return 1;
86 if (strcmp(
v,
"TRUE") == 0)
return 1;
87 if (strcmp(
v,
"yes") == 0)
return 1;
88 if (strcmp(
v,
"YES") == 0)
return 1;
89 if (strcmp(
v,
"on") == 0)
return 1;
90 if (strcmp(
v,
"ON") == 0)
return 1;
117#define TYPE_META_STRING 10001
119#define TYPE_META_BOOLEAN 10002
121#define TYPE_META_NIL 10003
123#define TYPE_META_CLASS 10004
125#define TYPE_META_FLOAT 10005
127#define TYPE_META_ARRAY 10006
160static void calc_line_col(
const char *src,
size_t len,
size_t pos,
int *out_line,
int *out_col) {
161 int line = 1, col = 1;
162 size_t limit = pos <
len ? pos :
len;
163 for (
size_t i = 0; i < limit; ++i) {
164 if (src[i] ==
'\n') {
171 if (out_line) *out_line = line;
172 if (out_col) *out_col = col;
205 const char *marker =
"// __ns_alias__: ";
206 size_t mlen = strlen(marker);
212 while (i <
len && src[i] !=
'\n')
216 if (i <
len && src[i] ==
'\n') i++;
218 if (le - ls >= mlen && strncmp(src + ls, marker, mlen) == 0) {
219 size_t p = ls + mlen;
222 while (
p < le && (src[
p] ==
' ' || src[
p] ==
'\t'))
224 if (
p < le && (isalpha((
unsigned char)src[
p]) || src[
p] ==
'_')) {
226 while (q < le && (isalnum((
unsigned char)src[q]) || src[q] ==
'_'))
230 char *
name = (
char *)malloc(
n + 1);
264}
G = {{0}, {0}, {0}, 0};
273 for (
int i = 0; i <
G.count; ++i) {
274 if (strcmp(
G.names[i],
name) == 0)
return i;
291 if (existing >= 0)
return existing;
296 G.names[
G.count] = strdup(
name);
297 G.types[
G.count] = 0;
298 G.is_class[
G.count] = 0;
328 for (
int i = 0; i <
e->count; ++i) {
329 if (
e->names[i] && strcmp(
e->names[i],
name) == 0)
return 1;
354 for (
int i = 0; i <
g_locals->count; ++i) {
397 if (*pos + 2 <
len &&
starts_with(src,
len, *pos,
"fn") && (src[*pos + 2] ==
'(' || src[*pos + 2] ==
' ' || src[*pos + 2] ==
'\t')) {
412 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
420 if (*pos <
len && src[*pos] !=
')') {
430 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
439 if (*pos <
len && src[*pos] ==
',') {
448 parser_fail(*pos,
"Expected ')' after parameter list");
460 fn_bc->
name = strdup(
"<fn>");
467 size_t look_body = *pos;
485 if (*pos <
len && src[*pos] ==
'(') {
488 parser_fail(*pos,
"Expected expression after '('");
498 if (*pos <
len && src[*pos] ==
'[') {
505 if (*pos <
len && src[*pos] ==
':') {
508 size_t savep4 = *pos;
543 if (*pos <
len && src[*pos] ==
'[') {
550 if (*pos <
len && src[*pos] ==
':') {
585 if (*pos <
len && src[*pos] ==
'[') {
589 if (*pos <
len && src[*pos] !=
']') {
592 parser_fail(*pos,
"Expected expression in array literal");
597 if (*pos <
len && src[*pos] ==
',') {
606 parser_fail(*pos,
"Expected ']' to close array literal");
613 if (*pos <
len && src[*pos] ==
'[') {
620 if (*pos <
len && src[*pos] ==
':') {
623 size_t savep3 = *pos;
651 if (*pos <
len && src[*pos] ==
'{') {
655 if (*pos <
len && src[*pos] !=
'}') {
660 parser_fail(*pos,
"Expected string key in map literal");
672 parser_fail(*pos,
"Expected value expression in map literal");
677 if (*pos <
len && src[*pos] ==
',') {
686 parser_fail(*pos,
"Expected '}' to close map literal");
704 if (*pos <
len && src[*pos] ==
'[') {
711 if (*pos <
len && src[*pos] ==
':') {
714 size_t savep2 = *pos;
748 if (*pos <
len && src[*pos] ==
'[') {
755 if (*pos <
len && src[*pos] ==
':') {
759 size_t savep2 = *pos;
790 if (strcmp(
name,
"true") == 0 || strcmp(
name,
"false") == 0) {
800 int is_call = (*pos <
len && src[*pos] ==
'(');
804 if (strcmp(
name,
"len") == 0) {
820 if (strcmp(
name,
"push") == 0) {
827 if (*pos <
len && src[*pos] ==
',') {
849 if (strcmp(
name,
"pop") == 0) {
865 if (strcmp(
name,
"set") == 0) {
872 if (*pos <
len && src[*pos] ==
',') {
885 if (*pos <
len && src[*pos] ==
',') {
907 if (strcmp(
name,
"insert") == 0) {
914 if (*pos <
len && src[*pos] ==
',') {
927 if (*pos <
len && src[*pos] ==
',') {
941 parser_fail(*pos,
"Expected ')' after insert args");
949 if (strcmp(
name,
"remove") == 0) {
956 if (*pos <
len && src[*pos] ==
',') {
970 parser_fail(*pos,
"Expected ')' after remove args");
978 if (strcmp(
name,
"to_number") == 0) {
986 parser_fail(*pos,
"Expected ')' after to_number arg");
994 if (strcmp(
name,
"to_string") == 0) {
1002 parser_fail(*pos,
"Expected ')' after to_string arg");
1010 if (strcmp(
name,
"cast") == 0) {
1014 parser_fail(*pos,
"cast expects (value, typeName)");
1019 parser_fail(*pos,
"cast expects (value, typeName)");
1027 if (strcmp(
name,
"typeof") == 0) {
1035 if (peek <
len && src[peek] ==
')') {
1042 if (gi >= 0) meta =
G.types[gi];
1047 int abs_bits = meta < 0 ? -meta : meta;
1048 const char *
tname = (meta < 0)
1049 ? (abs_bits == 64 ?
"Sint64" : (abs_bits == 32 ?
"Sint32" : (abs_bits == 16 ?
"Sint16" :
"Sint8")))
1050 : (abs_bits == 64 ?
"Uint64" : (abs_bits == 32 ?
"Uint32" : (abs_bits == 16 ?
"Uint16" :
"Uint8")));
1072 parser_fail(*pos,
"Expected ')' after typeof arg");
1128 if (strcmp(
name,
"keys") == 0) {
1139 if (strcmp(
name,
"values") == 0) {
1150 if (strcmp(
name,
"has") == 0) {
1166 if (strcmp(
name,
"read_file") == 0) {
1177 if (strcmp(
name,
"write_file") == 0) {
1193 if (strcmp(
name,
"input") == 0) {
1197 if (*pos <
len && src[*pos] !=
')') {
1199 parser_fail(*pos,
"input expects 0 or 1 argument");
1206 parser_fail(*pos,
"Expected ')' after input arg(s)");
1214 if (strcmp(
name,
"input_hidden") == 0) {
1218 if (*pos <
len && src[*pos] !=
')') {
1220 parser_fail(*pos,
"input_hidden expects 0 or 1 argument");
1227 parser_fail(*pos,
"Expected ')' after input_hidden arg(s)");
1236 if (strcmp(
name,
"proc_run") == 0) {
1239 parser_fail(*pos,
"proc_run expects 1 argument (command string)");
1244 parser_fail(*pos,
"Expected ')' after proc_run arg");
1252 if (strcmp(
name,
"system") == 0) {
1255 parser_fail(*pos,
"system expects 1 argument (command string)");
1260 parser_fail(*pos,
"Expected ')' after system arg");
1268 if (strcmp(
name,
"time_now_ms") == 0) {
1279 if (strcmp(
name,
"clock_mono_ms") == 0) {
1290 if (strcmp(
name,
"date_format") == 0) {
1293 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1303 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1308 parser_fail(*pos,
"Expected ')' after date_format args");
1316 if (strcmp(
name,
"env") == 0) {
1332 if (strcmp(
name,
"env_all") == 0) {
1343 if (strcmp(
name,
"fun_version") == 0) {
1354 if (strcmp(
name,
"rust_hello") == 0) {
1365 if (strcmp(
name,
"rust_hello_args") == 0) {
1368 parser_fail(*pos,
"rust_hello_args expects (message:string)");
1373 parser_fail(*pos,
"Expected ')' after rust_hello_args arg");
1381 if (strcmp(
name,
"rust_hello_args_return") == 0) {
1384 parser_fail(*pos,
"rust_hello_args_return expects (message:string)");
1389 parser_fail(*pos,
"Expected ')' after rust_hello_args_return arg");
1397 if (strcmp(
name,
"rust_get_sp") == 0) {
1408 if (strcmp(
name,
"rust_set_exit") == 0) {
1411 parser_fail(*pos,
"rust_set_exit expects (code:int)");
1416 parser_fail(*pos,
"Expected ')' after rust_set_exit arg");
1424 if (strcmp(
name,
"cpp_add") == 0) {
1427 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1432 parser_fail(*pos,
"cpp_add expects two arguments");
1437 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1442 parser_fail(*pos,
"Expected ')' after cpp_add args");
1450 if (strcmp(
name,
"os_list_dir") == 0) {
1458 parser_fail(*pos,
"Expected ')' after os_list_dir arg");
1467 if (strcmp(
name,
"json_parse") == 0) {
1475 parser_fail(*pos,
"Expected ')' after json_parse arg");
1484 if (strcmp(
name,
"xml_parse") == 0) {
1492 parser_fail(*pos,
"Expected ')' after xml_parse arg");
1500 if (strcmp(
name,
"xml_root") == 0) {
1503 parser_fail(*pos,
"xml_root expects (doc_handle)");
1508 parser_fail(*pos,
"Expected ')' after xml_root arg");
1516 if (strcmp(
name,
"xml_name") == 0) {
1519 parser_fail(*pos,
"xml_name expects (node_handle)");
1524 parser_fail(*pos,
"Expected ')' after xml_name arg");
1532 if (strcmp(
name,
"xml_text") == 0) {
1535 parser_fail(*pos,
"xml_text expects (node_handle)");
1540 parser_fail(*pos,
"Expected ')' after xml_text arg");
1548 if (strcmp(
name,
"json_stringify") == 0) {
1551 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1556 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1561 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1566 parser_fail(*pos,
"Expected ')' after json_stringify args");
1574 if (strcmp(
name,
"json_from_file") == 0) {
1577 parser_fail(*pos,
"json_from_file expects (path)");
1582 parser_fail(*pos,
"Expected ')' after json_from_file arg");
1590 if (strcmp(
name,
"json_to_file") == 0) {
1593 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1598 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1603 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1608 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1613 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1618 parser_fail(*pos,
"Expected ')' after json_to_file args");
1627 if (strcmp(
name,
"ini_load") == 0) {
1635 parser_fail(*pos,
"Expected ')' after ini_load arg");
1643 if (strcmp(
name,
"ini_free") == 0) {
1651 parser_fail(*pos,
"Expected ')' after ini_free arg");
1659 if (strcmp(
name,
"ini_get_string") == 0) {
1662 parser_fail(*pos,
"ini_get_string expects (handle, section, key, default)");
1667 parser_fail(*pos,
"ini_get_string expects 4 args");
1672 parser_fail(*pos,
"ini_get_string expects 4 args");
1677 parser_fail(*pos,
"ini_get_string expects 4 args");
1682 parser_fail(*pos,
"ini_get_string expects 4 args");
1687 parser_fail(*pos,
"ini_get_string expects 4 args");
1692 parser_fail(*pos,
"ini_get_string expects 4 args");
1697 parser_fail(*pos,
"Expected ')' after ini_get_string args");
1705 if (strcmp(
name,
"ini_get_int") == 0) {
1708 parser_fail(*pos,
"ini_get_int expects (handle, section, key, default)");
1743 parser_fail(*pos,
"Expected ')' after ini_get_int args");
1751 if (strcmp(
name,
"ini_get_double") == 0) {
1754 parser_fail(*pos,
"ini_get_double expects (handle, section, key, default)");
1759 parser_fail(*pos,
"ini_get_double expects 4 args");
1764 parser_fail(*pos,
"ini_get_double expects 4 args");
1769 parser_fail(*pos,
"ini_get_double expects 4 args");
1774 parser_fail(*pos,
"ini_get_double expects 4 args");
1779 parser_fail(*pos,
"ini_get_double expects 4 args");
1784 parser_fail(*pos,
"ini_get_double expects 4 args");
1789 parser_fail(*pos,
"Expected ')' after ini_get_double args");
1797 if (strcmp(
name,
"ini_get_bool") == 0) {
1800 parser_fail(*pos,
"ini_get_bool expects (handle, section, key, default)");
1835 parser_fail(*pos,
"Expected ')' after ini_get_bool args");
1843 if (strcmp(
name,
"ini_set") == 0) {
1846 parser_fail(*pos,
"ini_set expects (handle, section, key, value)");
1881 parser_fail(*pos,
"Expected ')' after ini_set args");
1889 if (strcmp(
name,
"ini_unset") == 0) {
1892 parser_fail(*pos,
"ini_unset expects (handle, section, key)");
1917 parser_fail(*pos,
"Expected ')' after ini_unset args");
1925 if (strcmp(
name,
"ini_save") == 0) {
1928 parser_fail(*pos,
"ini_save expects (handle, path)");
1943 parser_fail(*pos,
"Expected ')' after ini_save args");
1952 if (strcmp(
name,
"curl_get") == 0) {
1960 parser_fail(*pos,
"Expected ')' after curl_get arg");
1969 if (strcmp(
name,
"sqlite_open") == 0) {
1977 parser_fail(*pos,
"Expected ')' after sqlite_open arg");
1985 if (strcmp(
name,
"sqlite_close") == 0) {
1988 parser_fail(*pos,
"sqlite_close expects (handle)");
1993 parser_fail(*pos,
"Expected ')' after sqlite_close arg");
2001 if (strcmp(
name,
"sqlite_exec") == 0) {
2004 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2009 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2014 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2019 parser_fail(*pos,
"Expected ')' after sqlite_exec args");
2027 if (strcmp(
name,
"sqlite_query") == 0) {
2030 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2035 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2040 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2045 parser_fail(*pos,
"Expected ')' after sqlite_query args");
2053 if (strcmp(
name,
"curl_post") == 0) {
2056 parser_fail(*pos,
"curl_post expects (url, body)");
2061 parser_fail(*pos,
"curl_post expects (url, body)");
2066 parser_fail(*pos,
"curl_post expects (url, body)");
2071 parser_fail(*pos,
"Expected ')' after curl_post args");
2079 if (strcmp(
name,
"curl_download") == 0) {
2082 parser_fail(*pos,
"curl_download expects (url, path)");
2087 parser_fail(*pos,
"curl_download expects (url, path)");
2092 parser_fail(*pos,
"curl_download expects (url, path)");
2097 parser_fail(*pos,
"Expected ')' after curl_download args");
2106 if (strcmp(
name,
"openssl_md5") == 0) {
2114 parser_fail(*pos,
"Expected ')' after openssl_md5 arg");
2122 if (strcmp(
name,
"openssl_sha256") == 0) {
2125 parser_fail(*pos,
"openssl_sha256 expects (data)");
2130 parser_fail(*pos,
"Expected ')' after openssl_sha256 arg");
2138 if (strcmp(
name,
"openssl_sha512") == 0) {
2141 parser_fail(*pos,
"openssl_sha512 expects (data)");
2146 parser_fail(*pos,
"Expected ')' after openssl_sha512 arg");
2154 if (strcmp(
name,
"openssl_ripemd160") == 0) {
2157 parser_fail(*pos,
"openssl_ripemd160 expects (data)");
2162 parser_fail(*pos,
"Expected ')' after openssl_ripemd160 arg");
2172 if (strcmp(
name,
"pcsc_establish") == 0) {
2185 if (strcmp(
name,
"pcre2_test") == 0) {
2189 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2194 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2199 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2204 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2209 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2214 parser_fail(*pos,
"Expected ')' after pcre2_test args");
2222 if (strcmp(
name,
"pcre2_match") == 0) {
2225 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2230 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2235 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2240 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2245 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2250 parser_fail(*pos,
"Expected ')' after pcre2_match args");
2258 if (strcmp(
name,
"pcre2_findall") == 0) {
2261 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2266 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2271 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2276 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2281 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2286 parser_fail(*pos,
"Expected ')' after pcre2_findall args");
2295 if (strcmp(
name,
"pcsc_release") == 0) {
2298 parser_fail(*pos,
"pcsc_release expects 1 argument (ctx)");
2303 parser_fail(*pos,
"Expected ')' after pcsc_release arg");
2311 if (strcmp(
name,
"pcsc_list_readers") == 0) {
2314 parser_fail(*pos,
"pcsc_list_readers expects 1 argument (ctx)");
2319 parser_fail(*pos,
"Expected ')' after pcsc_list_readers arg");
2327 if (strcmp(
name,
"pcsc_connect") == 0) {
2331 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2336 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2341 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2346 parser_fail(*pos,
"Expected ')' after pcsc_connect args");
2354 if (strcmp(
name,
"pcsc_disconnect") == 0) {
2357 parser_fail(*pos,
"pcsc_disconnect expects 1 argument (handle)");
2362 parser_fail(*pos,
"Expected ')' after pcsc_disconnect arg");
2370 if (strcmp(
name,
"pcsc_transmit") == 0) {
2374 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2379 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2384 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2389 parser_fail(*pos,
"Expected ')' after pcsc_transmit args");
2398 if (strcmp(
name,
"tcp_listen") == 0) {
2401 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2406 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2411 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2416 parser_fail(*pos,
"Expected ')' after tcp_listen args");
2424 if (strcmp(
name,
"tcp_accept") == 0) {
2427 parser_fail(*pos,
"tcp_accept expects (listen_fd)");
2432 parser_fail(*pos,
"Expected ')' after tcp_accept arg");
2440 if (strcmp(
name,
"tcp_connect") == 0) {
2443 parser_fail(*pos,
"tcp_connect expects (host, port)");
2448 parser_fail(*pos,
"tcp_connect expects (host, port)");
2453 parser_fail(*pos,
"tcp_connect expects (host, port)");
2458 parser_fail(*pos,
"Expected ')' after tcp_connect args");
2466 if (strcmp(
name,
"sock_send") == 0) {
2469 parser_fail(*pos,
"sock_send expects (fd, data)");
2474 parser_fail(*pos,
"sock_send expects (fd, data)");
2479 parser_fail(*pos,
"sock_send expects (fd, data)");
2484 parser_fail(*pos,
"Expected ')' after sock_send args");
2492 if (strcmp(
name,
"sock_recv") == 0) {
2495 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2500 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2505 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2510 parser_fail(*pos,
"Expected ')' after sock_recv args");
2518 if (strcmp(
name,
"sock_close") == 0) {
2526 parser_fail(*pos,
"Expected ')' after sock_close arg");
2534 if (strcmp(
name,
"unix_listen") == 0) {
2537 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2542 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2547 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2552 parser_fail(*pos,
"Expected ')' after unix_listen args");
2560 if (strcmp(
name,
"unix_connect") == 0) {
2568 parser_fail(*pos,
"Expected ')' after unix_connect arg");
2577 if (strcmp(
name,
"fd_set_nonblock") == 0) {
2581 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2586 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2591 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2596 parser_fail(*pos,
"Expected ')' after fd_set_nonblock args");
2604 if (strcmp(
name,
"fd_poll_read") == 0) {
2608 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2613 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2618 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2623 parser_fail(*pos,
"Expected ')' after fd_poll_read args");
2631 if (strcmp(
name,
"fd_poll_write") == 0) {
2635 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2640 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2645 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2650 parser_fail(*pos,
"Expected ')' after fd_poll_write args");
2659 if (strcmp(
name,
"serial_open") == 0) {
2662 parser_fail(*pos,
"serial_open expects (path, baud)");
2667 parser_fail(*pos,
"serial_open expects (path, baud)");
2672 parser_fail(*pos,
"serial_open expects (path, baud)");
2677 parser_fail(*pos,
"Expected ')' after serial_open args");
2685 if (strcmp(
name,
"serial_config") == 0) {
2688 for (
int i = 0; i < 5; ++i) {
2690 parser_fail(*pos,
"serial_config expects 5 arguments");
2696 parser_fail(*pos,
"serial_config expects 5 arguments");
2703 parser_fail(*pos,
"Expected ')' after serial_config args");
2711 if (strcmp(
name,
"serial_send") == 0) {
2714 parser_fail(*pos,
"serial_send expects (fd, data)");
2719 parser_fail(*pos,
"serial_send expects (fd, data)");
2724 parser_fail(*pos,
"serial_send expects (fd, data)");
2729 parser_fail(*pos,
"Expected ')' after serial_send args");
2737 if (strcmp(
name,
"serial_recv") == 0) {
2740 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2745 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2750 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2755 parser_fail(*pos,
"Expected ')' after serial_recv args");
2763 if (strcmp(
name,
"serial_close") == 0) {
2771 parser_fail(*pos,
"Expected ')' after serial_close arg");
2780 if (strcmp(
name,
"split") == 0) {
2787 if (*pos <
len && src[*pos] ==
',') {
2801 parser_fail(*pos,
"Expected ')' after split args");
2809 if (strcmp(
name,
"join") == 0) {
2816 if (*pos <
len && src[*pos] ==
',') {
2830 parser_fail(*pos,
"Expected ')' after join args");
2838 if (strcmp(
name,
"substr") == 0) {
2845 if (*pos <
len && src[*pos] ==
',') {
2858 if (*pos <
len && src[*pos] ==
',') {
2872 parser_fail(*pos,
"Expected ')' after substr args");
2880 if (strcmp(
name,
"find") == 0) {
2887 if (*pos <
len && src[*pos] ==
',') {
2901 parser_fail(*pos,
"Expected ')' after find args");
2910 if (strcmp(
name,
"regex_match") == 0) {
2917 if (*pos <
len && src[*pos] ==
',') {
2931 parser_fail(*pos,
"Expected ')' after regex_match args");
2939 if (strcmp(
name,
"regex_search") == 0) {
2946 if (*pos <
len && src[*pos] ==
',') {
2955 parser_fail(*pos,
"regex_search expects pattern");
2960 parser_fail(*pos,
"Expected ')' after regex_search args");
2968 if (strcmp(
name,
"regex_replace") == 0) {
2975 if (*pos <
len && src[*pos] ==
',') {
2979 parser_fail(*pos,
"regex_replace expects 3 args");
2984 parser_fail(*pos,
"regex_replace expects pattern");
2988 if (*pos <
len && src[*pos] ==
',') {
2992 parser_fail(*pos,
"regex_replace expects 3 args");
2997 parser_fail(*pos,
"regex_replace expects replacement");
3002 parser_fail(*pos,
"Expected ')' after regex_replace args");
3011 if (strcmp(
name,
"contains") == 0) {
3018 if (*pos <
len && src[*pos] ==
',') {
3032 parser_fail(*pos,
"Expected ')' after contains args");
3040 if (strcmp(
name,
"indexOf") == 0) {
3047 if (*pos <
len && src[*pos] ==
',') {
3061 parser_fail(*pos,
"Expected ')' after indexOf args");
3069 if (strcmp(
name,
"clear") == 0) {
3077 parser_fail(*pos,
"Expected ')' after clear arg");
3086 if (strcmp(
name,
"enumerate") == 0) {
3094 parser_fail(*pos,
"Expected ')' after enumerate arg");
3102 if (strcmp(
name,
"map") == 0) {
3106 parser_fail(*pos,
"map expects (array, function)");
3113 int larr = -1, garr = -1;
3123 parser_fail(*pos,
"map expects (array, function)");
3129 int lfn = -1, gfn = -1;
3141 int lres = -1, gres = -1;
3154 int li = -1, gi = -1;
3197 int lv = -1, gv = -1;
3257 if (strcmp(
name,
"filter") == 0) {
3260 parser_fail(*pos,
"filter expects (array, function)");
3266 int larr = -1, garr = -1;
3275 parser_fail(*pos,
"filter expects (array, function)");
3281 int lfn = -1, gfn = -1;
3292 int lres = -1, gres = -1;
3304 int li = -1, gi = -1;
3353 int lvf = -1, gvf = -1;
3414 if (strcmp(
name,
"reduce") == 0) {
3417 parser_fail(*pos,
"reduce expects (array, init, function)");
3423 int larr = -1, garr = -1;
3432 parser_fail(*pos,
"reduce expects (array, init, function)");
3438 int lacc = -1, gacc = -1;
3447 parser_fail(*pos,
"reduce expects (array, init, function)");
3453 int lfn = -1, gfn = -1;
3466 int li = -1, gi = -1;
3497 snprintf(telem,
sizeof(telem),
"__red_elem_%d",
g_temp_counter++);
3498 int lelem = -1, gelem = -1;
3559 if (strcmp(
name,
"zip") == 0) {
3566 if (*pos <
len && src[*pos] ==
',') {
3589 if (strcmp(
name,
"min") == 0) {
3605 if (strcmp(
name,
"max") == 0) {
3621 if (strcmp(
name,
"fmin") == 0) {
3637 if (strcmp(
name,
"fmax") == 0) {
3653 if (strcmp(
name,
"clamp") == 0) {
3674 if (strcmp(
name,
"abs") == 0) {
3685 if (strcmp(
name,
"floor") == 0) {
3696 if (strcmp(
name,
"ceil") == 0) {
3707 if (strcmp(
name,
"trunc") == 0) {
3718 if (strcmp(
name,
"round") == 0) {
3729 if (strcmp(
name,
"sin") == 0) {
3740 if (strcmp(
name,
"cos") == 0) {
3751 if (strcmp(
name,
"tan") == 0) {
3762 if (strcmp(
name,
"exp") == 0) {
3773 if (strcmp(
name,
"log") == 0) {
3784 if (strcmp(
name,
"log10") == 0) {
3795 if (strcmp(
name,
"sqrt") == 0) {
3806 if (strcmp(
name,
"gcd") == 0) {
3822 if (strcmp(
name,
"lcm") == 0) {
3838 if (strcmp(
name,
"isqrt") == 0) {
3849 if (strcmp(
name,
"sign") == 0) {
3860 if (strcmp(
name,
"pow") == 0) {
3877 if (strcmp(
name,
"random_seed") == 0) {
3888 if (strcmp(
name,
"random_int") == 0) {
3905 if (strcmp(
name,
"random_number") == 0) {
3909 parser_fail(*pos,
"random_number expects 1 arg (length)");
3914 parser_fail(*pos,
"Expected ')' after random_number arg");
3924 if (strcmp(
name,
"thread_spawn") == 0) {
3928 parser_fail(*pos,
"thread_spawn expects function as first arg");
3934 if (*pos <
len && src[*pos] ==
',') {
3938 parser_fail(*pos,
"thread_spawn second arg must be array or value");
3945 parser_fail(*pos,
"Expected ')' after thread_spawn args");
3953 if (strcmp(
name,
"thread_join") == 0) {
3956 parser_fail(*pos,
"thread_join expects 1 arg (thread id)");
3964 if (strcmp(
name,
"sleep") == 0) {
3967 parser_fail(*pos,
"sleep expects 1 arg (milliseconds)");
3977 if (strcmp(
name,
"band") == 0) {
3993 if (strcmp(
name,
"bor") == 0) {
4009 if (strcmp(
name,
"bxor") == 0) {
4025 if (strcmp(
name,
"bnot") == 0) {
4041 if (strcmp(
name,
"shl") == 0) {
4057 if (strcmp(
name,
"shr") == 0) {
4073 if (strcmp(
name,
"rol") == 0) {
4089 if (strcmp(
name,
"ror") == 0) {
4108 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4109 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname,
name);
4113 if (local_idx >= 0) {
4125 if (*pos <
len && src[*pos] !=
')') {
4128 parser_fail(*pos,
"Expected expression as function argument");
4134 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src,
len, pos), 1));
4137 parser_fail(*pos,
"Expected ')' after arguments");
4144 printf(
"compile: CALL %s with %d arg(s)\n",
name, argc);
4153 if (*pos <
len && src[*pos] ==
'[') {
4161 if (*pos <
len && src[*pos] ==
':') {
4189 if (*pos <
len && src[*pos] ==
'.') {
4194 parser_fail(*pos,
"Expected identifier after '.'");
4198 int is_private = (mname && mname[0] ==
'_');
4202 size_t callp = *pos;
4204 if (callp <
len && src[callp] ==
'(') {
4208 snprintf(
msg,
sizeof(
msg),
"AccessError: private method '%s' is not accessible here", mname);
4231 if (*pos <
len && src[*pos] !=
')') {
4234 parser_fail(*pos,
"Expected expression as method argument");
4241 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src,
len, pos), 1));
4244 parser_fail(*pos,
"Expected ')' after arguments");
4269 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4270 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname,
name);
4274 if (local_idx >= 0) {
4287 if (*pos <
len && src[*pos] ==
'[') {
4295 if (*pos <
len && src[*pos] ==
':') {
4323 if (*pos <
len && src[*pos] ==
'.') {
4328 parser_fail(*pos,
"Expected identifier after '.'");
4332 int is_private = (mname && mname[0] ==
'_');
4336 size_t callp = *pos;
4338 if (callp <
len && src[callp] ==
'(') {
4340 if (is_private && !(strcmp(
name,
"this") == 0)) {
4342 snprintf(
msg,
sizeof(
msg),
"AccessError: private method '%s' is not accessible", mname);
4352 int is_ns = __ns_ctx;
4369 if (*pos <
len && src[*pos] !=
')') {
4372 parser_fail(*pos,
"Expected expression as method argument");
4379 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos),
skip_spaces(src,
len, pos), 1));
4382 parser_fail(*pos,
"Expected ')' after arguments");
4427 if (*pos <
len && src[*pos] ==
'!') {
4430 parser_fail(*pos,
"Expected expression after '!'");
4436 if (*pos <
len && src[*pos] ==
'-') {
4442 parser_fail(*pos,
"Expected expression after unary '-'");
4468 if (*pos + 1 <
len && src[*pos] ==
'/' && src[*pos + 1] ==
'/') {
4472 if (*pos + 1 <
len && src[*pos] ==
'/' && src[*pos + 1] ==
'*') {
4473 size_t p = *pos + 2;
4474 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
4477 if (
p + 1 <
len)
p += 2;
4482 if (*pos <
len && src[*pos] ==
'*') {
4485 parser_fail(*pos,
"Expected expression after '*'");
4491 if (*pos <
len && src[*pos] ==
'/') {
4494 parser_fail(*pos,
"Expected expression after '/'");
4500 if (*pos <
len && src[*pos] ==
'%') {
4503 parser_fail(*pos,
"Expected expression after '%'");
4529 if (*pos <
len && src[*pos] ==
'+') {
4532 parser_fail(*pos,
"Expected expression after '+'");
4538 if (*pos <
len && src[*pos] ==
'-') {
4541 parser_fail(*pos,
"Expected expression after '-'");
4567 if (*pos + 1 <
len && src[*pos] ==
'<' && src[*pos + 1] ==
'=') {
4570 parser_fail(*pos,
"Expected expression after '<='");
4576 if (*pos + 1 <
len && src[*pos] ==
'>' && src[*pos + 1] ==
'=') {
4579 parser_fail(*pos,
"Expected expression after '>='");
4585 if (*pos <
len && src[*pos] ==
'<') {
4588 parser_fail(*pos,
"Expected expression after '<'");
4594 if (*pos <
len && src[*pos] ==
'>') {
4597 parser_fail(*pos,
"Expected expression after '>'");
4623 if (*pos + 1 <
len && src[*pos] ==
'=' && src[*pos + 1] ==
'=') {
4626 parser_fail(*pos,
"Expected expression after '=='");
4632 if (*pos + 1 <
len && src[*pos] ==
'!' && src[*pos + 1] ==
'=') {
4635 parser_fail(*pos,
"Expected expression after '!='");
4668 if (!(*pos + 1 <
len && src[*pos] ==
'&' && src[*pos + 1] ==
'&'))
break;
4673 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4676 parser_fail(*pos,
"Too many operands in '&&' chain");
4682 parser_fail(*pos,
"Expected expression after '&&'");
4689 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4692 parser_fail(*pos,
"Too many operands in '&&' chain");
4703 for (
int i = 0; i < jf_count; ++i) {
4739 if (!(*pos + 1 <
len && src[*pos] ==
'|' && src[*pos + 1] ==
'|'))
break;
4749 if (tj_count < (
int)(
sizeof(true_jumps) /
sizeof(true_jumps[0]))) {
4752 parser_fail(*pos,
"Too many operands in '||' chain");
4761 parser_fail(*pos,
"Expected expression after '||'");
4781 for (
int i = 0; i < tj_count; ++i) {
4806 if (!(*pos <
len && src[*pos] ==
'?'))
break;
4815 parser_fail(*pos,
"Expected expression after '?'");
4827 if (!(*pos <
len && src[*pos] ==
':')) {
4828 parser_fail(*pos,
"Expected ':' in conditional expression");
4836 parser_fail(*pos,
"Expected expression after ':'");
4890 while (
p <
len && src[
p] ==
' ')
4898 if (src[
p] ==
'\r') {
4900 if (
p <
len && src[
p] ==
'\n')
p++;
4904 if (src[
p] ==
'\n') {
4910 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'/') {
4913 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
4915 if (
p <
len && src[
p] ==
'\r') {
4917 if (
p <
len && src[
p] ==
'\n')
p++;
4918 }
else if (
p <
len && src[
p] ==
'\n') {
4925 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'*') {
4928 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
4935 parser_fail(
p,
"Unterminated block comment at end of file");
4942 parser_fail(
p,
"Unexpected trailing characters at end of line");
4973 while (*pos <
len) {
4976 while (
p <
len && src[
p] ==
' ') {
4980 if (
p <
len && src[
p] ==
'\t') {
4990 if (src[
p] ==
'\r') {
4992 if (
p <
len && src[
p] ==
'\n')
p++;
4996 if (src[
p] ==
'\n') {
5003 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'/') {
5006 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
5008 if (
p <
len && src[
p] ==
'\r') {
5010 if (
p <
len && src[
p] ==
'\n')
p++;
5011 }
else if (
p <
len && src[
p] ==
'\n') {
5019 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'*') {
5022 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
5025 if (
p + 1 <
len)
p += 2;
5027 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
5029 if (
p <
len && src[
p] ==
'\r') {
5031 if (
p <
len && src[
p] ==
'\n')
p++;
5032 }
else if (
p <
len && src[
p] ==
'\n') {
5039 if (spaces % 2 != 0) {
5040 parser_fail(
p,
"Indentation must be multiples of two spaces");
5043 *out_indent = spaces / 2;
5066 size_t local_pos = *pos;
5071 if (strcmp(
name,
"sint8") == 0) {
5073 name = strdup(
"int8");
5074 }
else if (strcmp(
name,
"sint16") == 0) {
5076 name = strdup(
"int16");
5077 }
else if (strcmp(
name,
"sint32") == 0) {
5079 name = strdup(
"int32");
5080 }
else if (strcmp(
name,
"sint64") == 0) {
5082 name = strdup(
"int64");
5086 if (strcmp(
name,
"return") == 0) {
5090 size_t save_pos = local_pos;
5095 local_pos = save_pos;
5106 if (strcmp(
name,
"exit") == 0) {
5109 size_t save_pos = local_pos;
5114 local_pos = save_pos;
5125 if (strcmp(
name,
"break") == 0) {
5128 parser_fail(local_pos,
"break used outside of loop");
5135 parser_fail(local_pos,
"Too many 'break' in one loop");
5142 if (strcmp(
name,
"continue") == 0) {
5145 parser_fail(local_pos,
"continue used outside of loop");
5152 parser_fail(local_pos,
"Too many 'continue' in one loop");
5164 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) {
5165 int is_number = (strcmp(
name,
"number") == 0);
5166 int is_string = (strcmp(
name,
"string") == 0);
5167 int is_boolean = (strcmp(
name,
"boolean") == 0);
5168 int is_nil = (strcmp(
name,
"nil") == 0);
5170 int is_float = (strcmp(
name,
"float") == 0);
5171 int is_array = (strcmp(
name,
"array") == 0);
5172 int is_byte = (strcmp(
name,
"byte") == 0);
5173 int is_u8 = (strcmp(
name,
"uint8") == 0) || is_byte;
5174 int is_u16 = (strcmp(
name,
"uint16") == 0);
5175 int is_u32 = (strcmp(
name,
"uint32") == 0);
5176 int is_u64 = (strcmp(
name,
"uint64") == 0);
5177 int is_s8 = (strcmp(
name,
"int8") == 0);
5178 int is_s16 = (strcmp(
name,
"int16") == 0);
5179 int is_s32 = (strcmp(
name,
"int32") == 0);
5180 int is_s64 = (strcmp(
name,
"int64") == 0) || is_number;
5181 int decl_bits = is_u8 ? 8 : is_u16 ? 16
5189 int decl_signed = (is_s8 || is_s16 || is_s32 || is_s64) ? 1 : 0;
5191 if (decl_signed) decl_bits = -decl_bits;
5194 int decl_meta = decl_bits;
5197 }
else if (is_boolean) {
5199 }
else if (is_nil) {
5203 }
else if (is_float) {
5205 }
else if (is_array) {
5212 char *varname = NULL;
5215 parser_fail(local_pos,
"Expected identifier after type declaration");
5234 G.types[gi] = decl_meta;
5240 if (local_pos <
len && src[local_pos] ==
'=') {
5243 parser_fail(local_pos,
"Expected initializer expression after '='");
5384 int abs_bits = decl_bits < 0 ? -decl_bits : decl_bits;
5419 }
else if (is_nil) {
5424 }
else if (is_boolean) {
5427 }
else if (is_number || (decl_bits != 0)) {
5433 int abs_bits2 = decl_bits < 0 ? -decl_bits : decl_bits;
5434 if (abs_bits2 > 0) {
5449 if (strcmp(
name,
"print") == 0) {
5464 if (strcmp(
name,
"echo") == 0) {
5482 if (lidx < 0 && gi < 0 &&
g_locals) {
5486 if (lidx < 0 && gi < 0) {
5500 if (local_pos <
len && src[local_pos] ==
'.') {
5501 size_t stmt_start = *pos;
5502 size_t look = local_pos + 1;
5506 parser_fail(look,
"Expected field name after '.'");
5511 if (look <
len && src[look] ==
'[') {
5526 if (!(look <
len && src[look] ==
'['))
break;
5529 parser_fail(look,
"Expected index expression after '['");
5539 if (look <
len && src[look] ==
'[') {
5547 if (look >=
len || src[look] !=
'=') {
5550 size_t expr_pos = stmt_start;
5560 parser_fail(look,
"Expected expression after '='");
5569 }
else if (look <
len && src[look] ==
'=') {
5578 local_pos = look + 1;
5580 parser_fail(local_pos,
"Expected expression after '='");
5586 int tmp_local =
local_add(
"__assign_tmp");
5612 size_t expr_pos = stmt_start;
5623 if (local_pos <
len && src[local_pos] ==
'[') {
5632 parser_fail(local_pos,
"Expected index expression after '['");
5637 parser_fail(local_pos,
"Expected ']' after index");
5644 if (local_pos <
len && src[local_pos] ==
'[') {
5650 parser_fail(local_pos,
"Expected nested index expression after '['");
5655 parser_fail(local_pos,
"Expected ']' after nested index");
5660 if (local_pos >=
len || src[local_pos] !=
'=') {
5661 parser_fail(local_pos,
"Expected '=' after nested array index");
5667 parser_fail(local_pos,
"Expected expression after '='");
5680 if (local_pos >=
len || src[local_pos] !=
'=') {
5681 parser_fail(local_pos,
"Expected '=' after array index");
5687 parser_fail(local_pos,
"Expected expression after '='");
5700 if (local_pos <
len && src[local_pos] ==
'=') {
5707 }
else if (gi >= 0) {
5830 }
else if (meta != 0) {
5832 int abs_bits = meta < 0 ? -meta : meta;
5877 parser_fail(local_pos,
"Expected assignment '=' or call '(...)' after identifier");
5913 parser_fail(*pos,
"Unknown token at start of statement");
5931 while (*pos <
len) {
5933 size_t line_start = *pos;
5939 if (indent < current_indent) {
5944 if (indent > current_indent) {
5955 int stmt_line = 1, stmt_col = 1;
5961 if (
starts_with(src,
len, *pos,
"class") && (*pos + 5 <
len) && (src[*pos + 5] ==
' ' || src[*pos + 5] ==
'\t')) {
5967 parser_fail(*pos,
"Expected class name after 'class'");
5973 char *parent_name = NULL;
5976 char *param_names[64];
5979 memset(param_names, 0,
sizeof(param_names));
5980 memset(param_kind, 0,
sizeof(param_kind));
5984#define MAP_TYPE_KIND(t) ( \
5985 ((t) && strcmp((t), "string") == 0) ? 2 : ((t) && strcmp((t), "nil") == 0) ? 3 \
5986 : ((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 \
5990 if (*pos <
len && src[*pos] ==
'(') {
5993 if (*pos <
len && src[*pos] !=
')') {
5998 parser_fail(*pos,
"Expected type in class parameter list");
6006 parser_fail(*pos,
"Expected parameter name after type");
6011 if (pcount >= (
int)(
sizeof(param_names) /
sizeof(param_names[0]))) {
6018 param_names[pcount] = pname;
6024 if (*pos <
len && src[*pos] ==
',') {
6033 parser_fail(*pos,
"Expected ')' after class parameter list");
6034 for (
int i = 0; i < pcount; ++i)
6035 free(param_names[i]);
6047 parser_fail(*pos,
"Expected parent class name after 'extends'");
6048 for (
int i = 0; i < pcount; ++i)
6049 free(param_names[i]);
6063 ctor_bc->
name = strdup(cname);
6069 memset(&ctor_env, 0,
sizeof(ctor_env));
6074 int ctor_present = 0;
6077 for (
int i = 0; i < pcount; ++i) {
6085 for (
int i = 0; i < pcount; ++i) {
6096 snprintf(
msg,
sizeof(
msg),
"TypeError: missing argument '%s' in %s()", param_names[i], cname);
6106 int kind = param_kind[i];
6107 if (kind == 1 || kind == 2 || kind == 3) {
6111 const char *
exp = (kind == 1) ?
"Number" : (kind == 2) ?
"String"
6125 snprintf(msg2,
sizeof(msg2),
"TypeError: %s() expects %s for '%s'", cname,
exp, param_names[i]);
6151 snprintf(msg3,
sizeof(msg3),
"TypeError: %s() received too many arguments", cname);
6180 for (
int i = 0; i < pcount; ++i) {
6184 int l_parent =
local_add(
"__parent_inst");
6190 int l_keys =
local_add(
"__parent_keys");
6248 int body_indent = 0;
6249 size_t look_body = *pos;
6250 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6253 size_t member_line_start = *pos;
6254 int member_indent = 0;
6259 if (member_indent < body_indent) {
6261 *pos = member_line_start;
6264 if (member_indent > body_indent) {
6277 parser_fail(*pos,
"Expected method name after 'fun' in class");
6282 int is_ctor_method = (strcmp(mname,
"_construct") == 0);
6286 parser_fail(*pos,
"Expected '(' after method name");
6298 size_t qlen = strlen(cname) + 1 + strlen(mname) + 1;
6299 char *q = (
char *)malloc(qlen);
6301 snprintf(q, qlen,
"%s.%s", cname, mname);
6308 memset(&m_env, 0,
sizeof(m_env));
6314 int param_count = 0;
6316 if (*pos <
len && src[*pos] !=
')') {
6327 if (param_count == 0 && strcmp(pname,
"this") != 0) {
6329 if (is_ctor_method) {
6330 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6332 parser_fail(*pos,
"First parameter of a method must be 'this'");
6345 if (*pos <
len && src[*pos] ==
',') {
6354 if (is_ctor_method) {
6355 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6357 parser_fail(*pos,
"Method must declare at least 'this' parameter");
6367 parser_fail(*pos,
"Expected ')' after method parameter list");
6378 int m_body_indent = 0;
6379 size_t look_m = *pos;
6380 if (
read_line_start(src,
len, &look_m, &m_body_indent) && m_body_indent > body_indent) {
6400 if (strcmp(mname,
"_construct") == 0) {
6412 parser_fail(*pos,
"Expected field or 'fun' in class body");
6419 if (tmp >=
len || src[tmp] !=
'=') {
6421 parser_fail(tmp,
"Expected '=' in field initializer");
6434 parser_fail(*pos,
"Expected expression in field initializer");
6448 for (
int i = 0; i < pcount; ++i) {
6469 for (
int i = 0; i < pcount; ++i) {
6490 G.is_class[cgi] = 1;
6492 for (
int i = 0; i < pcount; ++i)
6493 free(param_names[i]);
6494 if (parent_name)
free(parent_name);
6499 if (
starts_with(src,
len, *pos,
"fun") && (*pos + 3 <
len) && (src[*pos + 3] ==
' ' || src[*pos + 3] ==
'\t')) {
6505 parser_fail(*pos,
"Expected function name after 'fun'");
6511 parser_fail(*pos,
"Expected '(' after function name");
6522 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
6531 if (*pos <
len && src[*pos] !=
')') {
6541 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
6550 if (*pos <
len && src[*pos] ==
',') {
6559 parser_fail(*pos,
"Expected ')' after parameter list");
6571 fn_bc->
name = strdup(fname);
6577 int body_indent = 0;
6578 size_t look_body = *pos;
6579 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6591 printf(
"=== compiled function %s (%d params) ===\n", fname, env.
count);
6593 printf(
"=== end function %s ===\n", fname);
6655 if (*pos <
len && src[*pos] ==
'(') {
6660 parser_fail(*pos,
"Expected identifier after '(' in for tuple");
6665 parser_fail(*pos,
"Expected ',' between key and value in for tuple");
6671 parser_fail(*pos,
"Expected value identifier after ',' in for tuple");
6677 parser_fail(*pos,
"Expected ')' to close for tuple");
6686 parser_fail(*pos,
"Expected loop variable after 'for'");
6693 parser_fail(*pos,
"Expected 'in' after loop variable");
6711 parser_fail(*pos,
"Expected start expression in range");
6733 if (*pos >=
len || src[*pos] !=
',') {
6734 parser_fail(*pos,
"Expected ',' between range start and end");
6743 parser_fail(*pos,
"Expected end expression in range");
6749 snprintf(tmpname,
sizeof(tmpname),
"__for_end_%d",
g_temp_counter++);
6751 int lend = -1, gend = -1;
6761 parser_fail(*pos,
"Expected ')' after range arguments");
6791 int body_indent = 0;
6792 size_t look_body = *pos;
6793 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6824 for (
int bi = 0; bi <
ctx.cont_count; ++bi) {
6827 for (
int bi = 0; bi <
ctx.break_count; ++bi) {
6834 }
else if (!tuple_mode) {
6838 parser_fail(*pos,
"Expected iterable expression after 'in'");
6843 snprintf(arrname,
sizeof(arrname),
"__for_arr_%d",
g_temp_counter++);
6844 int larr = -1, garr = -1;
6861 snprintf(lenname,
sizeof(lenname),
"__for_len_%d",
g_temp_counter++);
6862 int llen = -1, glen = -1;
6876 int li = -1, gi = -1;
6938 int body_indent = 0;
6939 size_t look_body = *pos;
6940 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6971 for (
int bi = 0; bi <
ctx.cont_count; ++bi) {
6974 for (
int bi = 0; bi <
ctx.break_count; ++bi) {
6985 parser_fail(*pos,
"Expected map expression after 'in'");
6991 snprintf(mapname,
sizeof(mapname),
"__for_map_%d",
g_temp_counter++);
6992 int lmap = -1, gmap = -1;
7009 snprintf(keysname,
sizeof(keysname),
"__for_keys_%d",
g_temp_counter++);
7010 int lkeys = -1, gkeys = -1;
7027 snprintf(lenname,
sizeof(lenname),
"__for_klen_%d",
g_temp_counter++);
7028 int llen = -1, glen = -1;
7042 int li = -1, gi = -1;
7132 int body_indent = 0;
7133 size_t look_body = *pos;
7134 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
7163 for (
int bi = 0; bi <
ctx.cont_count; ++bi) {
7166 for (
int bi = 0; bi <
ctx.break_count; ++bi) {
7198 size_t ppeek = *pos;
7200 while (ppeek <
len && src[ppeek] ==
' ')
7202 int inline_stmt = 0;
7204 if (src[ppeek] ==
'\r' || src[ppeek] ==
'\n') {
7206 }
else if (ppeek + 1 <
len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'/') {
7208 }
else if (ppeek + 1 <
len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'*') {
7233 int next_indent = 0;
7234 size_t look_next = *pos;
7236 if (next_indent > current_indent) {
7248 if (end_count < (
int)(
sizeof(end_jumps) /
sizeof(end_jumps[0]))) {
7249 end_jumps[end_count++] = jmp_end;
7251 parser_fail(*pos,
"Too many chained else/if clauses");
7260 int look_indent = 0;
7265 if (look_indent != current_indent) {
7281 int else_indent = 0;
7282 size_t look_else = *pos;
7283 if (
read_line_start(src,
len, &look_else, &else_indent) && else_indent > current_indent) {
7299 for (
int i = 0; i < end_count; ++i) {
7328 int body_indent = 0;
7329 size_t look_body = *pos;
7330 if (
read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
7337 for (
int bi = 0; bi <
ctx.cont_count; ++bi) {
7347 for (
int bi = 0; bi <
ctx.break_count; ++bi) {
7365 int try_body_indent = 0;
7366 size_t look_try = *pos;
7367 if (
read_line_start(src,
len, &look_try, &try_body_indent) && try_body_indent > current_indent) {
7381 int seen_finally = 0;
7382 int catch_label = -1;
7385 int look_indent = 0;
7387 if (look_indent != current_indent)
break;
7394 char *ex_name = NULL;
7410 int lidx = -1, gi = -1;
7429 if (ex_name)
free(ex_name);
7432 int catch_indent = 0;
7433 size_t look_catch = *pos;
7434 if (
read_line_start(src,
len, &look_catch, &catch_indent) && catch_indent > current_indent) {
7450 int finally_indent = 0;
7451 size_t look_fin = *pos;
7452 if (
read_line_start(src,
len, &look_fin, &finally_indent) && finally_indent > current_indent) {
7530 fprintf(stderr,
"Error: cannot read file: %s\n",
path);
7536 const char *compile_src = prep ? prep : src;
7537 size_t compile_len = strlen(compile_src);
7556 const char *bn =
path ? strrchr(
path,
'/') : NULL;
7557 const char *
base = bn ? bn + 1 : (
path ?
path :
"<input>");
7564 int line = 1, col = 1;
7574 const char *marker0 =
"// __include_begin__: ";
7575 size_t m0 = strlen(marker0);
7579 if (compile_len >= 2 && compile_src[0] ==
'#' && compile_src[1] ==
'!') {
7581 while (
start < compile_len && compile_src[
start] !=
'\n' && compile_src[
start] !=
'\r')
start++;
7582 if (
start < compile_len && compile_src[
start] ==
'\r') {
7585 }
else if (
start < compile_len && compile_src[
start] ==
'\n') {
7593 while (eol0 < compile_len && compile_src[eol0] !=
'\n') eol0++;
7595 if (ls + m0 <= compile_len && strncmp(compile_src + ls, marker0, m0) == 0) {
7598 if (line > 1) line -= 1;
7607 const char *marker =
"// __include_begin__: ";
7608 size_t mlen = strlen(marker);
7609 int inner_line = -1;
7618 while (ls > 0 && compile_src[ls - 1] !=
'\n')
7621 if (ls + mlen <= compile_len && strncmp(compile_src + ls, marker, mlen) == 0) {
7623 size_t p = ls + mlen;
7625 while (eol < compile_len && compile_src[eol] !=
'\n') eol++;
7627 size_t pos_as = eol, pos_line = eol;
7628 for (
size_t t =
p;
t + 3 < eol; ++
t) {
7629 if (compile_src[
t] ==
' ' && strncmp(compile_src +
t,
" as ", 4) == 0) { pos_as =
t;
break; }
7631 for (
size_t t =
p;
t + 6 < eol; ++
t) {
7632 if (compile_src[
t] ==
' ' && strncmp(compile_src +
t,
" @line ", 7) == 0) { pos_line =
t;
break; }
7634 size_t path_end = pos_as < pos_line ? pos_as : pos_line;
7635 if (path_end <
p) path_end = eol;
7636 size_t copy = (path_end -
p) <
sizeof(inc_path) - 1 ? (path_end -
p) :
sizeof(inc_path) - 1;
7637 memcpy(inc_path, compile_src +
p, copy);
7638 inc_path[copy] =
'\0';
7642 if (pos_line < eol) {
7643 size_t num_start = pos_line + 7;
7644 while (num_start < eol && compile_src[num_start] ==
' ') num_start++;
7646 while (num_start < eol && compile_src[num_start] >=
'0' && compile_src[num_start] <=
'9') {
7647 v =
v * 10 + (compile_src[num_start] -
'0');
7650 if (
v > 0) base_line =
v;
7655 size_t q = (eol < compile_len && compile_src[eol] ==
'\n') ? (eol + 1) : eol;
7657 if (compile_src[q] ==
'\n')
count++;
7668 if (inner_line > 0 && inc_path[0] !=
'\0') {
7670 int shebang_adjust = 0;
7671 FILE *sf = fopen(inc_path,
"rb");
7675 if (c1 ==
'#' && c2 ==
'!') shebang_adjust = 1;
7678 int mapped_inner = inner_line + (base_line - 1) + shebang_adjust;
7680 if (
path && strcmp(
path, inc_path) == 0) {
7681 fprintf(stderr,
"Parse error %s:%d:%d: %s\n",
7684 fprintf(stderr,
"Parse error %s:%d:%d: %s (in %s:%d)\n",
7692 if (prep)
free(prep);
7697 if (prep)
free(prep);
7713 fprintf(stderr,
"Error: null source provided\n");
7719 const char *compile_src = prep ? prep : source;
7720 size_t len = strlen(compile_src);
7737 bc->
name = strdup(
"<input>");
7742 int line = 1, col = 1;
7747 if (prep)
free(prep);
7750 if (prep)
free(prep);
7769 if (msgBuf && msgCap > 0) {
7770 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.
@ 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 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.
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 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 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 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.