59static void skip_to_eol(
const char *src,
size_t len,
size_t *pos);
60static int read_line_start(
const char *src,
size_t len,
size_t *pos,
int *out_indent);
61static void parse_block(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos,
int current_indent);
64static const char *g_current_source_path = NULL;
65static int g_has_error = 0;
66static size_t g_err_pos = 0;
67static char g_err_msg[256];
68static int g_err_line = 0;
69static int g_err_col = 0;
72static int g_temp_counter = 0;
84static int env_truthy(
const char *
name) {
85 const char *
v = getenv(
name);
87 if (strcmp(
v,
"1") == 0)
return 1;
88 if (strcmp(
v,
"true") == 0)
return 1;
89 if (strcmp(
v,
"TRUE") == 0)
return 1;
90 if (strcmp(
v,
"yes") == 0)
return 1;
91 if (strcmp(
v,
"YES") == 0)
return 1;
92 if (strcmp(
v,
"on") == 0)
return 1;
93 if (strcmp(
v,
"ON") == 0)
return 1;
105static int fun_debug_enabled(
void) {
109 if (env_truthy(
"FUN_TRACE"))
return 1;
110 if (env_truthy(
"FUN_DEBUG"))
return 1;
120#define TYPE_META_STRING 10001 122#define TYPE_META_BOOLEAN 10002 124#define TYPE_META_NIL 10003 126#define TYPE_META_CLASS 10004 128#define TYPE_META_FLOAT 10005 130#define TYPE_META_ARRAY 10006 142static void parser_fail(
size_t pos,
const char *fmt, ...) {
147 vsnprintf(g_err_msg,
sizeof(g_err_msg), fmt, ap);
163static void calc_line_col(
const char *src,
size_t len,
size_t pos,
int *out_line,
int *out_col) {
164 int line = 1, col = 1;
165 size_t limit = pos <
len ? pos :
len;
166 for (
size_t i = 0; i < limit; ++i) {
167 if (src[i] ==
'\n') {
174 if (out_line) *out_line = line;
175 if (out_col) *out_col = col;
183static char *g_ns_aliases[64];
184static int g_ns_alias_count = 0;
189static void ns_aliases_reset(
void) {
190 for (
int i = 0; i < g_ns_alias_count; ++i) {
191 free(g_ns_aliases[i]);
192 g_ns_aliases[i] = NULL;
194 g_ns_alias_count = 0;
207static void ns_aliases_scan(
const char *src,
size_t len) {
208 const char *marker =
"// __ns_alias__: ";
209 size_t mlen = strlen(marker);
215 while (i <
len && src[i] !=
'\n')
219 if (i <
len && src[i] ==
'\n') i++;
221 if (le - ls >= mlen && strncmp(src + ls, marker, mlen) == 0) {
222 size_t p = ls + mlen;
225 while (
p < le && (src[
p] ==
' ' || src[
p] ==
'\t'))
227 if (
p < le && (isalpha((
unsigned char)src[
p]) || src[
p] ==
'_')) {
229 while (q < le && (isalnum((
unsigned char)src[q]) || src[q] ==
'_'))
232 if (
n > 0 && g_ns_alias_count < (
int)(
sizeof(g_ns_aliases) /
sizeof(g_ns_aliases[0]))) {
233 char *
name = (
char *)malloc(
n + 1);
237 g_ns_aliases[g_ns_alias_count++] =
name;
251static int is_ns_alias(
const char *
name) {
253 for (
int i = 0; i < g_ns_alias_count; ++i) {
254 if (strcmp(g_ns_aliases[i],
name) == 0)
return 1;
267} G = {{0}, {0}, {0}, 0};
275static int sym_find(
const char *
name) {
276 for (
int i = 0; i < G.count; ++i) {
277 if (strcmp(G.names[i],
name) == 0)
return i;
292static int sym_index(
const char *
name) {
293 int existing = sym_find(
name);
294 if (existing >= 0)
return existing;
296 parser_fail(0,
"Too many globals (max %d)",
MAX_GLOBALS);
299 G.names[G.count] = strdup(
name);
300 G.types[G.count] = 0;
301 G.is_class[G.count] = 0;
315static LocalEnv *g_func_env_stack[64];
316static int g_func_env_depth = 0;
326static int name_in_outer_envs(
const char *
name) {
327 if (g_func_env_depth <= 0)
return 0;
328 for (
int d = g_func_env_depth - 1; d >= 0; --d) {
331 for (
int i = 0; i < e->
count; ++i) {
347static LoopCtx *g_loop_ctx = NULL;
355static int local_find(
const char *
name) {
356 if (!g_locals)
return -1;
357 for (
int i = 0; i < g_locals->count; ++i) {
358 if (strcmp(g_locals->names[i],
name) == 0)
return i;
369static int local_add(
const char *
name) {
370 if (!g_locals)
return -1;
372 parser_fail(0,
"Too many local variables/parameters (max %d)",
MAX_FRAME_LOCALS);
375 int idx = g_locals->count++;
376 g_locals->names[
idx] = strdup(
name);
381static int emit_expression(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos);
396static int emit_primary(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
397 skip_spaces(src,
len, pos);
400 if (*pos + 2 <
len && starts_with(src,
len, *pos,
"fn") && (src[*pos + 2] ==
'(' || src[*pos + 2] ==
' ' || src[*pos + 2] ==
'\t')) {
402 skip_spaces(src,
len, pos);
403 if (!consume_char(src,
len, pos,
'(')) {
404 parser_fail(*pos,
"Expected '(' after 'fn'");
411 int saved_depth = g_func_env_depth;
414 if (g_func_env_depth >= (
int)(
sizeof(g_func_env_stack) /
sizeof(g_func_env_stack[0]))) {
415 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
418 g_func_env_stack[g_func_env_depth++] =
prev;
422 skip_spaces(src,
len, pos);
423 if (*pos <
len && src[*pos] !=
')') {
426 if (!read_identifier_into(src,
len, pos, &pname)) {
427 parser_fail(*pos,
"Expected parameter name");
429 g_func_env_depth = saved_depth;
432 if (local_find(pname) >= 0) {
433 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
436 g_func_env_depth = saved_depth;
441 skip_spaces(src,
len, pos);
442 if (*pos <
len && src[*pos] ==
',') {
444 skip_spaces(src,
len, pos);
450 if (!consume_char(src,
len, pos,
')')) {
451 parser_fail(*pos,
"Expected ')' after parameter list");
453 g_func_env_depth = saved_depth;
457 skip_to_eol(src,
len, pos);
463 fn_bc->
name = strdup(
"<fn>");
465 if (g_current_source_path) fn_bc->
source_file = strdup(g_current_source_path);
470 size_t look_body = *pos;
471 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > 0) {
472 parse_block(fn_bc, src,
len, pos, body_indent);
480 g_func_env_depth = saved_depth;
488 if (*pos <
len && src[*pos] ==
'(') {
490 if (!emit_expression(bc, src,
len, pos)) {
491 parser_fail(*pos,
"Expected expression after '('");
494 if (!consume_char(src,
len, pos,
')')) {
495 parser_fail(*pos,
"Expected ')'");
500 skip_spaces(src,
len, pos);
501 if (*pos <
len && src[*pos] ==
'[') {
503 if (!emit_expression(bc, src,
len, pos)) {
504 parser_fail(*pos,
"Expected start expression");
507 skip_spaces(src,
len, pos);
508 if (*pos <
len && src[*pos] ==
':') {
510 skip_spaces(src,
len, pos);
511 size_t savep4 = *pos;
512 if (!emit_expression(bc, src,
len, pos)) {
517 if (!consume_char(src,
len, pos,
']')) {
518 parser_fail(*pos,
"Expected ']' after slice");
524 if (!consume_char(src,
len, pos,
']')) {
525 parser_fail(*pos,
"Expected ']' after index");
538 char *
s = parse_string_literal_any_quote(src,
len, pos);
545 skip_spaces(src,
len, pos);
546 if (*pos <
len && src[*pos] ==
'[') {
548 if (!emit_expression(bc, src,
len, pos)) {
549 parser_fail(*pos,
"Expected start expression");
552 skip_spaces(src,
len, pos);
553 if (*pos <
len && src[*pos] ==
':') {
555 skip_spaces(src,
len, pos);
559 if (emit_expression(bc, src,
len, pos)) {
566 if (!consume_char(src,
len, pos,
']')) {
567 parser_fail(*pos,
"Expected ']' after slice");
573 if (!consume_char(src,
len, pos,
']')) {
574 parser_fail(*pos,
"Expected ']' after index");
587 skip_spaces(src,
len, pos);
588 if (*pos <
len && src[*pos] ==
'[') {
591 skip_spaces(src,
len, pos);
592 if (*pos <
len && src[*pos] !=
']') {
594 if (!emit_expression(bc, src,
len, pos)) {
595 parser_fail(*pos,
"Expected expression in array literal");
599 skip_spaces(src,
len, pos);
600 if (*pos <
len && src[*pos] ==
',') {
602 skip_spaces(src,
len, pos);
608 if (!consume_char(src,
len, pos,
']')) {
609 parser_fail(*pos,
"Expected ']' to close array literal");
615 skip_spaces(src,
len, pos);
616 if (*pos <
len && src[*pos] ==
'[') {
618 if (!emit_expression(bc, src,
len, pos)) {
619 parser_fail(*pos,
"Expected start expression");
622 skip_spaces(src,
len, pos);
623 if (*pos <
len && src[*pos] ==
':') {
625 skip_spaces(src,
len, pos);
626 size_t savep3 = *pos;
627 if (!emit_expression(bc, src,
len, pos)) {
632 if (!consume_char(src,
len, pos,
']')) {
633 parser_fail(*pos,
"Expected ']' after slice");
639 if (!consume_char(src,
len, pos,
']')) {
640 parser_fail(*pos,
"Expected ']' after index");
653 skip_spaces(src,
len, pos);
654 if (*pos <
len && src[*pos] ==
'{') {
657 skip_spaces(src,
len, pos);
658 if (*pos <
len && src[*pos] !=
'}') {
661 char *
k = parse_string_literal_any_quote(src,
len, pos);
663 parser_fail(*pos,
"Expected string key in map literal");
669 skip_spaces(src,
len, pos);
670 if (!consume_char(src,
len, pos,
':')) {
671 parser_fail(*pos,
"Expected ':' after map key");
674 if (!emit_expression(bc, src,
len, pos)) {
675 parser_fail(*pos,
"Expected value expression in map literal");
679 skip_spaces(src,
len, pos);
680 if (*pos <
len && src[*pos] ==
',') {
682 skip_spaces(src,
len, pos);
688 if (!consume_char(src,
len, pos,
'}')) {
689 parser_fail(*pos,
"Expected '}' to close map literal");
700 double fval = parse_float_literal_value(src,
len, pos, &
ok);
706 skip_spaces(src,
len, pos);
707 if (*pos <
len && src[*pos] ==
'[') {
709 if (!emit_expression(bc, src,
len, pos)) {
710 parser_fail(*pos,
"Expected start expression");
713 skip_spaces(src,
len, pos);
714 if (*pos <
len && src[*pos] ==
':') {
716 skip_spaces(src,
len, pos);
717 size_t savep2 = *pos;
718 if (!emit_expression(bc, src,
len, pos)) {
723 if (!consume_char(src,
len, pos,
']')) {
724 parser_fail(*pos,
"Expected ']' after slice");
730 if (!consume_char(src,
len, pos,
']')) {
731 parser_fail(*pos,
"Expected ']' after index");
744 int64_t ival = parse_int_literal_value(src,
len, pos, &
ok);
750 skip_spaces(src,
len, pos);
751 if (*pos <
len && src[*pos] ==
'[') {
753 if (!emit_expression(bc, src,
len, pos)) {
754 parser_fail(*pos,
"Expected start expression");
757 skip_spaces(src,
len, pos);
758 if (*pos <
len && src[*pos] ==
':') {
760 skip_spaces(src,
len, pos);
762 size_t savep2 = *pos;
763 if (emit_expression(bc, src,
len, pos)) {
770 if (!consume_char(src,
len, pos,
']')) {
771 parser_fail(*pos,
"Expected ']' after slice");
777 if (!consume_char(src,
len, pos,
']')) {
778 parser_fail(*pos,
"Expected ']' after index");
792 if (read_identifier_into(src,
len, pos, &
name)) {
793 if (strcmp(
name,
"true") == 0 || strcmp(
name,
"false") == 0) {
801 skip_spaces(src,
len, pos);
802 int local_idx = local_find(
name);
803 int is_call = (*pos <
len && src[*pos] ==
'(');
807 if (strcmp(
name,
"len") == 0) {
809 if (!emit_expression(bc, src,
len, pos)) {
810 parser_fail(*pos,
"len expects 1 argument");
814 if (!consume_char(src,
len, pos,
')')) {
815 parser_fail(*pos,
"Expected ')' after len arg");
823 if (strcmp(
name,
"push") == 0) {
825 if (!emit_expression(bc, src,
len, pos)) {
826 parser_fail(*pos,
"push expects array");
830 if (*pos <
len && src[*pos] ==
',') {
832 skip_spaces(src,
len, pos);
834 parser_fail(*pos,
"push expects 2 args");
838 if (!emit_expression(bc, src,
len, pos)) {
839 parser_fail(*pos,
"push expects value");
843 if (!consume_char(src,
len, pos,
')')) {
844 parser_fail(*pos,
"Expected ')' after push args");
852 if (strcmp(
name,
"pop") == 0) {
854 if (!emit_expression(bc, src,
len, pos)) {
855 parser_fail(*pos,
"pop expects array");
859 if (!consume_char(src,
len, pos,
')')) {
860 parser_fail(*pos,
"Expected ')' after pop arg");
868 if (strcmp(
name,
"set") == 0) {
870 if (!emit_expression(bc, src,
len, pos)) {
871 parser_fail(*pos,
"set expects array");
875 if (*pos <
len && src[*pos] ==
',') {
877 skip_spaces(src,
len, pos);
879 parser_fail(*pos,
"set expects 3 args");
883 if (!emit_expression(bc, src,
len, pos)) {
884 parser_fail(*pos,
"set expects index");
888 if (*pos <
len && src[*pos] ==
',') {
890 skip_spaces(src,
len, pos);
892 parser_fail(*pos,
"set expects 3 args");
896 if (!emit_expression(bc, src,
len, pos)) {
897 parser_fail(*pos,
"set expects value");
901 if (!consume_char(src,
len, pos,
')')) {
902 parser_fail(*pos,
"Expected ')' after set args");
910 if (strcmp(
name,
"insert") == 0) {
912 if (!emit_expression(bc, src,
len, pos)) {
913 parser_fail(*pos,
"insert expects array");
917 if (*pos <
len && src[*pos] ==
',') {
919 skip_spaces(src,
len, pos);
921 parser_fail(*pos,
"insert expects 3 args");
925 if (!emit_expression(bc, src,
len, pos)) {
926 parser_fail(*pos,
"insert expects index");
930 if (*pos <
len && src[*pos] ==
',') {
932 skip_spaces(src,
len, pos);
934 parser_fail(*pos,
"insert expects 3 args");
938 if (!emit_expression(bc, src,
len, pos)) {
939 parser_fail(*pos,
"insert expects value");
943 if (!consume_char(src,
len, pos,
')')) {
944 parser_fail(*pos,
"Expected ')' after insert args");
952 if (strcmp(
name,
"remove") == 0) {
954 if (!emit_expression(bc, src,
len, pos)) {
955 parser_fail(*pos,
"remove expects array");
959 if (*pos <
len && src[*pos] ==
',') {
961 skip_spaces(src,
len, pos);
963 parser_fail(*pos,
"remove expects 2 args");
967 if (!emit_expression(bc, src,
len, pos)) {
968 parser_fail(*pos,
"remove expects index");
972 if (!consume_char(src,
len, pos,
')')) {
973 parser_fail(*pos,
"Expected ')' after remove args");
981 if (strcmp(
name,
"to_number") == 0) {
983 if (!emit_expression(bc, src,
len, pos)) {
984 parser_fail(*pos,
"to_number expects 1 argument");
988 if (!consume_char(src,
len, pos,
')')) {
989 parser_fail(*pos,
"Expected ')' after to_number arg");
997 if (strcmp(
name,
"to_string") == 0) {
999 if (!emit_expression(bc, src,
len, pos)) {
1000 parser_fail(*pos,
"to_string expects 1 argument");
1004 if (!consume_char(src,
len, pos,
')')) {
1005 parser_fail(*pos,
"Expected ')' after to_string arg");
1013 if (strcmp(
name,
"cast") == 0) {
1016 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
1017 parser_fail(*pos,
"cast expects (value, typeName)");
1021 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1022 parser_fail(*pos,
"cast expects (value, typeName)");
1030 if (strcmp(
name,
"typeof") == 0) {
1036 if (read_identifier_into(src,
len, &peek, &vname)) {
1037 skip_spaces(src,
len, &peek);
1038 if (peek <
len && src[peek] ==
')') {
1040 int lidx = local_find(vname);
1042 meta = g_locals->types[lidx];
1044 int gi = sym_index(vname);
1045 if (gi >= 0) meta = G.types[gi];
1050 int abs_bits = meta < 0 ? -meta : meta;
1051 const char *
tname = (meta < 0)
1052 ? (abs_bits == 64 ?
"Sint64" : (abs_bits == 32 ?
"Sint32" : (abs_bits == 16 ?
"Sint16" :
"Sint8")))
1053 : (abs_bits == 64 ?
"Uint64" : (abs_bits == 32 ?
"Uint32" : (abs_bits == 16 ?
"Uint16" :
"Uint8")));
1069 if (!emit_expression(bc, src,
len, pos)) {
1070 parser_fail(*pos,
"typeof expects 1 argument");
1074 if (!consume_char(src,
len, pos,
')')) {
1075 parser_fail(*pos,
"Expected ')' after typeof arg");
1131 if (strcmp(
name,
"keys") == 0) {
1133 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1134 parser_fail(*pos,
"keys expects 1 arg");
1142 if (strcmp(
name,
"values") == 0) {
1144 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1145 parser_fail(*pos,
"values expects 1 arg");
1153 if (strcmp(
name,
"has") == 0) {
1155 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
1156 parser_fail(*pos,
"has expects (map, key)");
1160 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1161 parser_fail(*pos,
"has expects (map, key)");
1169 if (strcmp(
name,
"read_file") == 0) {
1171 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1172 parser_fail(*pos,
"read_file expects 1 arg");
1180 if (strcmp(
name,
"write_file") == 0) {
1182 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
1183 parser_fail(*pos,
"write_file expects 2 args");
1187 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
1188 parser_fail(*pos,
"write_file expects 2 args");
1196 if (strcmp(
name,
"input") == 0) {
1199 skip_spaces(src,
len, pos);
1200 if (*pos <
len && src[*pos] !=
')') {
1201 if (!emit_expression(bc, src,
len, pos)) {
1202 parser_fail(*pos,
"input expects 0 or 1 argument");
1208 if (!consume_char(src,
len, pos,
')')) {
1209 parser_fail(*pos,
"Expected ')' after input arg(s)");
1217 if (strcmp(
name,
"input_hidden") == 0) {
1220 skip_spaces(src,
len, pos);
1221 if (*pos <
len && src[*pos] !=
')') {
1222 if (!emit_expression(bc, src,
len, pos)) {
1223 parser_fail(*pos,
"input_hidden expects 0 or 1 argument");
1229 if (!consume_char(src,
len, pos,
')')) {
1230 parser_fail(*pos,
"Expected ')' after input_hidden arg(s)");
1239 if (strcmp(
name,
"proc_run") == 0) {
1241 if (!emit_expression(bc, src,
len, pos)) {
1242 parser_fail(*pos,
"proc_run expects 1 argument (command string)");
1246 if (!consume_char(src,
len, pos,
')')) {
1247 parser_fail(*pos,
"Expected ')' after proc_run arg");
1255 if (strcmp(
name,
"system") == 0) {
1257 if (!emit_expression(bc, src,
len, pos)) {
1258 parser_fail(*pos,
"system expects 1 argument (command string)");
1262 if (!consume_char(src,
len, pos,
')')) {
1263 parser_fail(*pos,
"Expected ')' after system arg");
1271 if (strcmp(
name,
"time_now_ms") == 0) {
1273 if (!consume_char(src,
len, pos,
')')) {
1274 parser_fail(*pos,
"time_now_ms expects ()");
1282 if (strcmp(
name,
"clock_mono_ms") == 0) {
1284 if (!consume_char(src,
len, pos,
')')) {
1285 parser_fail(*pos,
"clock_mono_ms expects ()");
1293 if (strcmp(
name,
"date_format") == 0) {
1295 if (!emit_expression(bc, src,
len, pos)) {
1296 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1300 if (!consume_char(src,
len, pos,
',')) {
1301 parser_fail(*pos,
"date_format expects 2 args");
1305 if (!emit_expression(bc, src,
len, pos)) {
1306 parser_fail(*pos,
"date_format expects (ms:int, fmt:string)");
1310 if (!consume_char(src,
len, pos,
')')) {
1311 parser_fail(*pos,
"Expected ')' after date_format args");
1319 if (strcmp(
name,
"env") == 0) {
1321 if (!emit_expression(bc, src,
len, pos)) {
1322 parser_fail(*pos,
"env expects 1 argument");
1326 if (!consume_char(src,
len, pos,
')')) {
1327 parser_fail(*pos,
"Expected ')' after env arg");
1335 if (strcmp(
name,
"env_all") == 0) {
1337 if (!consume_char(src,
len, pos,
')')) {
1338 parser_fail(*pos,
"env_all expects ()");
1346 if (strcmp(
name,
"fun_version") == 0) {
1348 if (!consume_char(src,
len, pos,
')')) {
1349 parser_fail(*pos,
"fun_version expects ()");
1357 if (strcmp(
name,
"rust_hello") == 0) {
1359 if (!consume_char(src,
len, pos,
')')) {
1360 parser_fail(*pos,
"rust_hello expects ()");
1368 if (strcmp(
name,
"rust_hello_args") == 0) {
1370 if (!emit_expression(bc, src,
len, pos)) {
1371 parser_fail(*pos,
"rust_hello_args expects (message:string)");
1375 if (!consume_char(src,
len, pos,
')')) {
1376 parser_fail(*pos,
"Expected ')' after rust_hello_args arg");
1384 if (strcmp(
name,
"rust_hello_args_return") == 0) {
1386 if (!emit_expression(bc, src,
len, pos)) {
1387 parser_fail(*pos,
"rust_hello_args_return expects (message:string)");
1391 if (!consume_char(src,
len, pos,
')')) {
1392 parser_fail(*pos,
"Expected ')' after rust_hello_args_return arg");
1400 if (strcmp(
name,
"rust_get_sp") == 0) {
1402 if (!consume_char(src,
len, pos,
')')) {
1403 parser_fail(*pos,
"rust_get_sp expects ()");
1411 if (strcmp(
name,
"rust_set_exit") == 0) {
1413 if (!emit_expression(bc, src,
len, pos)) {
1414 parser_fail(*pos,
"rust_set_exit expects (code:int)");
1418 if (!consume_char(src,
len, pos,
')')) {
1419 parser_fail(*pos,
"Expected ')' after rust_set_exit arg");
1427 if (strcmp(
name,
"cpp_add") == 0) {
1429 if (!emit_expression(bc, src,
len, pos)) {
1430 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1434 if (!consume_char(src,
len, pos,
',')) {
1435 parser_fail(*pos,
"cpp_add expects two arguments");
1439 if (!emit_expression(bc, src,
len, pos)) {
1440 parser_fail(*pos,
"cpp_add expects (a:int, b:int)");
1444 if (!consume_char(src,
len, pos,
')')) {
1445 parser_fail(*pos,
"Expected ')' after cpp_add args");
1453 if (strcmp(
name,
"os_list_dir") == 0) {
1455 if (!emit_expression(bc, src,
len, pos)) {
1456 parser_fail(*pos,
"os_list_dir expects (path)");
1460 if (!consume_char(src,
len, pos,
')')) {
1461 parser_fail(*pos,
"Expected ')' after os_list_dir arg");
1470 if (strcmp(
name,
"json_parse") == 0) {
1472 if (!emit_expression(bc, src,
len, pos)) {
1473 parser_fail(*pos,
"json_parse expects (text)");
1477 if (!consume_char(src,
len, pos,
')')) {
1478 parser_fail(*pos,
"Expected ')' after json_parse arg");
1487 if (strcmp(
name,
"xml_parse") == 0) {
1489 if (!emit_expression(bc, src,
len, pos)) {
1490 parser_fail(*pos,
"xml_parse expects (text)");
1494 if (!consume_char(src,
len, pos,
')')) {
1495 parser_fail(*pos,
"Expected ')' after xml_parse arg");
1503 if (strcmp(
name,
"xml_root") == 0) {
1505 if (!emit_expression(bc, src,
len, pos)) {
1506 parser_fail(*pos,
"xml_root expects (doc_handle)");
1510 if (!consume_char(src,
len, pos,
')')) {
1511 parser_fail(*pos,
"Expected ')' after xml_root arg");
1519 if (strcmp(
name,
"xml_name") == 0) {
1521 if (!emit_expression(bc, src,
len, pos)) {
1522 parser_fail(*pos,
"xml_name expects (node_handle)");
1526 if (!consume_char(src,
len, pos,
')')) {
1527 parser_fail(*pos,
"Expected ')' after xml_name arg");
1535 if (strcmp(
name,
"xml_text") == 0) {
1537 if (!emit_expression(bc, src,
len, pos)) {
1538 parser_fail(*pos,
"xml_text expects (node_handle)");
1542 if (!consume_char(src,
len, pos,
')')) {
1543 parser_fail(*pos,
"Expected ')' after xml_text arg");
1551 if (strcmp(
name,
"json_stringify") == 0) {
1553 if (!emit_expression(bc, src,
len, pos)) {
1554 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1558 if (!consume_char(src,
len, pos,
',')) {
1559 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1563 if (!emit_expression(bc, src,
len, pos)) {
1564 parser_fail(*pos,
"json_stringify expects (value, pretty)");
1568 if (!consume_char(src,
len, pos,
')')) {
1569 parser_fail(*pos,
"Expected ')' after json_stringify args");
1577 if (strcmp(
name,
"json_from_file") == 0) {
1579 if (!emit_expression(bc, src,
len, pos)) {
1580 parser_fail(*pos,
"json_from_file expects (path)");
1584 if (!consume_char(src,
len, pos,
')')) {
1585 parser_fail(*pos,
"Expected ')' after json_from_file arg");
1593 if (strcmp(
name,
"json_to_file") == 0) {
1595 if (!emit_expression(bc, src,
len, pos)) {
1596 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1600 if (!consume_char(src,
len, pos,
',')) {
1601 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1605 if (!emit_expression(bc, src,
len, pos)) {
1606 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1610 if (!consume_char(src,
len, pos,
',')) {
1611 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1615 if (!emit_expression(bc, src,
len, pos)) {
1616 parser_fail(*pos,
"json_to_file expects (path, value, pretty)");
1620 if (!consume_char(src,
len, pos,
')')) {
1621 parser_fail(*pos,
"Expected ')' after json_to_file args");
1630 if (strcmp(
name,
"ini_load") == 0) {
1632 if (!emit_expression(bc, src,
len, pos)) {
1633 parser_fail(*pos,
"ini_load expects (path)");
1637 if (!consume_char(src,
len, pos,
')')) {
1638 parser_fail(*pos,
"Expected ')' after ini_load arg");
1646 if (strcmp(
name,
"ini_free") == 0) {
1648 if (!emit_expression(bc, src,
len, pos)) {
1649 parser_fail(*pos,
"ini_free expects (handle)");
1653 if (!consume_char(src,
len, pos,
')')) {
1654 parser_fail(*pos,
"Expected ')' after ini_free arg");
1662 if (strcmp(
name,
"ini_get_string") == 0) {
1664 if (!emit_expression(bc, src,
len, pos)) {
1665 parser_fail(*pos,
"ini_get_string expects (handle, section, key, default)");
1669 if (!consume_char(src,
len, pos,
',')) {
1670 parser_fail(*pos,
"ini_get_string expects 4 args");
1674 if (!emit_expression(bc, src,
len, pos)) {
1675 parser_fail(*pos,
"ini_get_string expects 4 args");
1679 if (!consume_char(src,
len, pos,
',')) {
1680 parser_fail(*pos,
"ini_get_string expects 4 args");
1684 if (!emit_expression(bc, src,
len, pos)) {
1685 parser_fail(*pos,
"ini_get_string expects 4 args");
1689 if (!consume_char(src,
len, pos,
',')) {
1690 parser_fail(*pos,
"ini_get_string expects 4 args");
1694 if (!emit_expression(bc, src,
len, pos)) {
1695 parser_fail(*pos,
"ini_get_string expects 4 args");
1699 if (!consume_char(src,
len, pos,
')')) {
1700 parser_fail(*pos,
"Expected ')' after ini_get_string args");
1708 if (strcmp(
name,
"ini_get_int") == 0) {
1710 if (!emit_expression(bc, src,
len, pos)) {
1711 parser_fail(*pos,
"ini_get_int expects (handle, section, key, default)");
1715 if (!consume_char(src,
len, pos,
',')) {
1716 parser_fail(*pos,
"ini_get_int expects 4 args");
1720 if (!emit_expression(bc, src,
len, pos)) {
1721 parser_fail(*pos,
"ini_get_int expects 4 args");
1725 if (!consume_char(src,
len, pos,
',')) {
1726 parser_fail(*pos,
"ini_get_int expects 4 args");
1730 if (!emit_expression(bc, src,
len, pos)) {
1731 parser_fail(*pos,
"ini_get_int expects 4 args");
1735 if (!consume_char(src,
len, pos,
',')) {
1736 parser_fail(*pos,
"ini_get_int expects 4 args");
1740 if (!emit_expression(bc, src,
len, pos)) {
1741 parser_fail(*pos,
"ini_get_int expects 4 args");
1745 if (!consume_char(src,
len, pos,
')')) {
1746 parser_fail(*pos,
"Expected ')' after ini_get_int args");
1754 if (strcmp(
name,
"ini_get_double") == 0) {
1756 if (!emit_expression(bc, src,
len, pos)) {
1757 parser_fail(*pos,
"ini_get_double expects (handle, section, key, default)");
1761 if (!consume_char(src,
len, pos,
',')) {
1762 parser_fail(*pos,
"ini_get_double expects 4 args");
1766 if (!emit_expression(bc, src,
len, pos)) {
1767 parser_fail(*pos,
"ini_get_double expects 4 args");
1771 if (!consume_char(src,
len, pos,
',')) {
1772 parser_fail(*pos,
"ini_get_double expects 4 args");
1776 if (!emit_expression(bc, src,
len, pos)) {
1777 parser_fail(*pos,
"ini_get_double expects 4 args");
1781 if (!consume_char(src,
len, pos,
',')) {
1782 parser_fail(*pos,
"ini_get_double expects 4 args");
1786 if (!emit_expression(bc, src,
len, pos)) {
1787 parser_fail(*pos,
"ini_get_double expects 4 args");
1791 if (!consume_char(src,
len, pos,
')')) {
1792 parser_fail(*pos,
"Expected ')' after ini_get_double args");
1800 if (strcmp(
name,
"ini_get_bool") == 0) {
1802 if (!emit_expression(bc, src,
len, pos)) {
1803 parser_fail(*pos,
"ini_get_bool expects (handle, section, key, default)");
1807 if (!consume_char(src,
len, pos,
',')) {
1808 parser_fail(*pos,
"ini_get_bool expects 4 args");
1812 if (!emit_expression(bc, src,
len, pos)) {
1813 parser_fail(*pos,
"ini_get_bool expects 4 args");
1817 if (!consume_char(src,
len, pos,
',')) {
1818 parser_fail(*pos,
"ini_get_bool expects 4 args");
1822 if (!emit_expression(bc, src,
len, pos)) {
1823 parser_fail(*pos,
"ini_get_bool expects 4 args");
1827 if (!consume_char(src,
len, pos,
',')) {
1828 parser_fail(*pos,
"ini_get_bool expects 4 args");
1832 if (!emit_expression(bc, src,
len, pos)) {
1833 parser_fail(*pos,
"ini_get_bool expects 4 args");
1837 if (!consume_char(src,
len, pos,
')')) {
1838 parser_fail(*pos,
"Expected ')' after ini_get_bool args");
1846 if (strcmp(
name,
"ini_set") == 0) {
1848 if (!emit_expression(bc, src,
len, pos)) {
1849 parser_fail(*pos,
"ini_set expects (handle, section, key, value)");
1853 if (!consume_char(src,
len, pos,
',')) {
1854 parser_fail(*pos,
"ini_set expects 4 args");
1858 if (!emit_expression(bc, src,
len, pos)) {
1859 parser_fail(*pos,
"ini_set expects 4 args");
1863 if (!consume_char(src,
len, pos,
',')) {
1864 parser_fail(*pos,
"ini_set expects 4 args");
1868 if (!emit_expression(bc, src,
len, pos)) {
1869 parser_fail(*pos,
"ini_set expects 4 args");
1873 if (!consume_char(src,
len, pos,
',')) {
1874 parser_fail(*pos,
"ini_set expects 4 args");
1878 if (!emit_expression(bc, src,
len, pos)) {
1879 parser_fail(*pos,
"ini_set expects 4 args");
1883 if (!consume_char(src,
len, pos,
')')) {
1884 parser_fail(*pos,
"Expected ')' after ini_set args");
1892 if (strcmp(
name,
"ini_unset") == 0) {
1894 if (!emit_expression(bc, src,
len, pos)) {
1895 parser_fail(*pos,
"ini_unset expects (handle, section, key)");
1899 if (!consume_char(src,
len, pos,
',')) {
1900 parser_fail(*pos,
"ini_unset expects 3 args");
1904 if (!emit_expression(bc, src,
len, pos)) {
1905 parser_fail(*pos,
"ini_unset expects 3 args");
1909 if (!consume_char(src,
len, pos,
',')) {
1910 parser_fail(*pos,
"ini_unset expects 3 args");
1914 if (!emit_expression(bc, src,
len, pos)) {
1915 parser_fail(*pos,
"ini_unset expects 3 args");
1919 if (!consume_char(src,
len, pos,
')')) {
1920 parser_fail(*pos,
"Expected ')' after ini_unset args");
1928 if (strcmp(
name,
"ini_save") == 0) {
1930 if (!emit_expression(bc, src,
len, pos)) {
1931 parser_fail(*pos,
"ini_save expects (handle, path)");
1935 if (!consume_char(src,
len, pos,
',')) {
1936 parser_fail(*pos,
"ini_save expects 2 args");
1940 if (!emit_expression(bc, src,
len, pos)) {
1941 parser_fail(*pos,
"ini_save expects 2 args");
1945 if (!consume_char(src,
len, pos,
')')) {
1946 parser_fail(*pos,
"Expected ')' after ini_save args");
1955 if (strcmp(
name,
"curl_get") == 0) {
1957 if (!emit_expression(bc, src,
len, pos)) {
1958 parser_fail(*pos,
"curl_get expects (url)");
1962 if (!consume_char(src,
len, pos,
')')) {
1963 parser_fail(*pos,
"Expected ')' after curl_get arg");
1972 if (strcmp(
name,
"sqlite_open") == 0) {
1974 if (!emit_expression(bc, src,
len, pos)) {
1975 parser_fail(*pos,
"sqlite_open expects (path)");
1979 if (!consume_char(src,
len, pos,
')')) {
1980 parser_fail(*pos,
"Expected ')' after sqlite_open arg");
1988 if (strcmp(
name,
"sqlite_close") == 0) {
1990 if (!emit_expression(bc, src,
len, pos)) {
1991 parser_fail(*pos,
"sqlite_close expects (handle)");
1995 if (!consume_char(src,
len, pos,
')')) {
1996 parser_fail(*pos,
"Expected ')' after sqlite_close arg");
2004 if (strcmp(
name,
"sqlite_exec") == 0) {
2006 if (!emit_expression(bc, src,
len, pos)) {
2007 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2011 if (!consume_char(src,
len, pos,
',')) {
2012 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2016 if (!emit_expression(bc, src,
len, pos)) {
2017 parser_fail(*pos,
"sqlite_exec expects (handle, sql)");
2021 if (!consume_char(src,
len, pos,
')')) {
2022 parser_fail(*pos,
"Expected ')' after sqlite_exec args");
2030 if (strcmp(
name,
"sqlite_query") == 0) {
2032 if (!emit_expression(bc, src,
len, pos)) {
2033 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2037 if (!consume_char(src,
len, pos,
',')) {
2038 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2042 if (!emit_expression(bc, src,
len, pos)) {
2043 parser_fail(*pos,
"sqlite_query expects (handle, sql)");
2047 if (!consume_char(src,
len, pos,
')')) {
2048 parser_fail(*pos,
"Expected ')' after sqlite_query args");
2056 if (strcmp(
name,
"curl_post") == 0) {
2058 if (!emit_expression(bc, src,
len, pos)) {
2059 parser_fail(*pos,
"curl_post expects (url, body)");
2063 if (!consume_char(src,
len, pos,
',')) {
2064 parser_fail(*pos,
"curl_post expects (url, body)");
2068 if (!emit_expression(bc, src,
len, pos)) {
2069 parser_fail(*pos,
"curl_post expects (url, body)");
2073 if (!consume_char(src,
len, pos,
')')) {
2074 parser_fail(*pos,
"Expected ')' after curl_post args");
2082 if (strcmp(
name,
"curl_download") == 0) {
2084 if (!emit_expression(bc, src,
len, pos)) {
2085 parser_fail(*pos,
"curl_download expects (url, path)");
2089 if (!consume_char(src,
len, pos,
',')) {
2090 parser_fail(*pos,
"curl_download expects (url, path)");
2094 if (!emit_expression(bc, src,
len, pos)) {
2095 parser_fail(*pos,
"curl_download expects (url, path)");
2099 if (!consume_char(src,
len, pos,
')')) {
2100 parser_fail(*pos,
"Expected ')' after curl_download args");
2109 if (strcmp(
name,
"openssl_md5") == 0) {
2111 if (!emit_expression(bc, src,
len, pos)) {
2112 parser_fail(*pos,
"openssl_md5 expects (data)");
2116 if (!consume_char(src,
len, pos,
')')) {
2117 parser_fail(*pos,
"Expected ')' after openssl_md5 arg");
2125 if (strcmp(
name,
"openssl_sha256") == 0) {
2127 if (!emit_expression(bc, src,
len, pos)) {
2128 parser_fail(*pos,
"openssl_sha256 expects (data)");
2132 if (!consume_char(src,
len, pos,
')')) {
2133 parser_fail(*pos,
"Expected ')' after openssl_sha256 arg");
2141 if (strcmp(
name,
"openssl_sha512") == 0) {
2143 if (!emit_expression(bc, src,
len, pos)) {
2144 parser_fail(*pos,
"openssl_sha512 expects (data)");
2148 if (!consume_char(src,
len, pos,
')')) {
2149 parser_fail(*pos,
"Expected ')' after openssl_sha512 arg");
2157 if (strcmp(
name,
"openssl_ripemd160") == 0) {
2159 if (!emit_expression(bc, src,
len, pos)) {
2160 parser_fail(*pos,
"openssl_ripemd160 expects (data)");
2164 if (!consume_char(src,
len, pos,
')')) {
2165 parser_fail(*pos,
"Expected ')' after openssl_ripemd160 arg");
2175 if (strcmp(
name,
"pcsc_establish") == 0) {
2178 if (!consume_char(src,
len, pos,
')')) {
2179 parser_fail(*pos,
"pcsc_establish expects ()");
2188 if (strcmp(
name,
"pcre2_test") == 0) {
2191 if (!emit_expression(bc, src,
len, pos)) {
2192 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2196 if (!consume_char(src,
len, pos,
',')) {
2197 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2201 if (!emit_expression(bc, src,
len, pos)) {
2202 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2206 if (!consume_char(src,
len, pos,
',')) {
2207 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2211 if (!emit_expression(bc, src,
len, pos)) {
2212 parser_fail(*pos,
"pcre2_test expects (pattern, text, flags)");
2216 if (!consume_char(src,
len, pos,
')')) {
2217 parser_fail(*pos,
"Expected ')' after pcre2_test args");
2225 if (strcmp(
name,
"pcre2_match") == 0) {
2227 if (!emit_expression(bc, src,
len, pos)) {
2228 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2232 if (!consume_char(src,
len, pos,
',')) {
2233 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2237 if (!emit_expression(bc, src,
len, pos)) {
2238 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2242 if (!consume_char(src,
len, pos,
',')) {
2243 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2247 if (!emit_expression(bc, src,
len, pos)) {
2248 parser_fail(*pos,
"pcre2_match expects (pattern, text, flags)");
2252 if (!consume_char(src,
len, pos,
')')) {
2253 parser_fail(*pos,
"Expected ')' after pcre2_match args");
2261 if (strcmp(
name,
"pcre2_findall") == 0) {
2263 if (!emit_expression(bc, src,
len, pos)) {
2264 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2268 if (!consume_char(src,
len, pos,
',')) {
2269 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2273 if (!emit_expression(bc, src,
len, pos)) {
2274 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2278 if (!consume_char(src,
len, pos,
',')) {
2279 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2283 if (!emit_expression(bc, src,
len, pos)) {
2284 parser_fail(*pos,
"pcre2_findall expects (pattern, text, flags)");
2288 if (!consume_char(src,
len, pos,
')')) {
2289 parser_fail(*pos,
"Expected ')' after pcre2_findall args");
2298 if (strcmp(
name,
"pcsc_release") == 0) {
2300 if (!emit_expression(bc, src,
len, pos)) {
2301 parser_fail(*pos,
"pcsc_release expects 1 argument (ctx)");
2305 if (!consume_char(src,
len, pos,
')')) {
2306 parser_fail(*pos,
"Expected ')' after pcsc_release arg");
2314 if (strcmp(
name,
"pcsc_list_readers") == 0) {
2316 if (!emit_expression(bc, src,
len, pos)) {
2317 parser_fail(*pos,
"pcsc_list_readers expects 1 argument (ctx)");
2321 if (!consume_char(src,
len, pos,
')')) {
2322 parser_fail(*pos,
"Expected ')' after pcsc_list_readers arg");
2330 if (strcmp(
name,
"pcsc_connect") == 0) {
2333 if (!emit_expression(bc, src,
len, pos)) {
2334 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2338 if (!consume_char(src,
len, pos,
',')) {
2339 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2343 if (!emit_expression(bc, src,
len, pos)) {
2344 parser_fail(*pos,
"pcsc_connect expects (ctx, reader)");
2348 if (!consume_char(src,
len, pos,
')')) {
2349 parser_fail(*pos,
"Expected ')' after pcsc_connect args");
2357 if (strcmp(
name,
"pcsc_disconnect") == 0) {
2359 if (!emit_expression(bc, src,
len, pos)) {
2360 parser_fail(*pos,
"pcsc_disconnect expects 1 argument (handle)");
2364 if (!consume_char(src,
len, pos,
')')) {
2365 parser_fail(*pos,
"Expected ')' after pcsc_disconnect arg");
2373 if (strcmp(
name,
"pcsc_transmit") == 0) {
2376 if (!emit_expression(bc, src,
len, pos)) {
2377 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2381 if (!consume_char(src,
len, pos,
',')) {
2382 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2386 if (!emit_expression(bc, src,
len, pos)) {
2387 parser_fail(*pos,
"pcsc_transmit expects (handle, bytes)");
2391 if (!consume_char(src,
len, pos,
')')) {
2392 parser_fail(*pos,
"Expected ')' after pcsc_transmit args");
2401 if (strcmp(
name,
"tcp_listen") == 0) {
2403 if (!emit_expression(bc, src,
len, pos)) {
2404 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2408 if (!consume_char(src,
len, pos,
',')) {
2409 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2413 if (!emit_expression(bc, src,
len, pos)) {
2414 parser_fail(*pos,
"tcp_listen expects (port, backlog)");
2418 if (!consume_char(src,
len, pos,
')')) {
2419 parser_fail(*pos,
"Expected ')' after tcp_listen args");
2427 if (strcmp(
name,
"tcp_accept") == 0) {
2429 if (!emit_expression(bc, src,
len, pos)) {
2430 parser_fail(*pos,
"tcp_accept expects (listen_fd)");
2434 if (!consume_char(src,
len, pos,
')')) {
2435 parser_fail(*pos,
"Expected ')' after tcp_accept arg");
2443 if (strcmp(
name,
"tcp_connect") == 0) {
2445 if (!emit_expression(bc, src,
len, pos)) {
2446 parser_fail(*pos,
"tcp_connect expects (host, port)");
2450 if (!consume_char(src,
len, pos,
',')) {
2451 parser_fail(*pos,
"tcp_connect expects (host, port)");
2455 if (!emit_expression(bc, src,
len, pos)) {
2456 parser_fail(*pos,
"tcp_connect expects (host, port)");
2460 if (!consume_char(src,
len, pos,
')')) {
2461 parser_fail(*pos,
"Expected ')' after tcp_connect args");
2469 if (strcmp(
name,
"sock_send") == 0) {
2471 if (!emit_expression(bc, src,
len, pos)) {
2472 parser_fail(*pos,
"sock_send expects (fd, data)");
2476 if (!consume_char(src,
len, pos,
',')) {
2477 parser_fail(*pos,
"sock_send expects (fd, data)");
2481 if (!emit_expression(bc, src,
len, pos)) {
2482 parser_fail(*pos,
"sock_send expects (fd, data)");
2486 if (!consume_char(src,
len, pos,
')')) {
2487 parser_fail(*pos,
"Expected ')' after sock_send args");
2495 if (strcmp(
name,
"sock_recv") == 0) {
2497 if (!emit_expression(bc, src,
len, pos)) {
2498 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2502 if (!consume_char(src,
len, pos,
',')) {
2503 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2507 if (!emit_expression(bc, src,
len, pos)) {
2508 parser_fail(*pos,
"sock_recv expects (fd, maxlen)");
2512 if (!consume_char(src,
len, pos,
')')) {
2513 parser_fail(*pos,
"Expected ')' after sock_recv args");
2521 if (strcmp(
name,
"sock_close") == 0) {
2523 if (!emit_expression(bc, src,
len, pos)) {
2524 parser_fail(*pos,
"sock_close expects (fd)");
2528 if (!consume_char(src,
len, pos,
')')) {
2529 parser_fail(*pos,
"Expected ')' after sock_close arg");
2537 if (strcmp(
name,
"unix_listen") == 0) {
2539 if (!emit_expression(bc, src,
len, pos)) {
2540 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2544 if (!consume_char(src,
len, pos,
',')) {
2545 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2549 if (!emit_expression(bc, src,
len, pos)) {
2550 parser_fail(*pos,
"unix_listen expects (path, backlog)");
2554 if (!consume_char(src,
len, pos,
')')) {
2555 parser_fail(*pos,
"Expected ')' after unix_listen args");
2563 if (strcmp(
name,
"unix_connect") == 0) {
2565 if (!emit_expression(bc, src,
len, pos)) {
2566 parser_fail(*pos,
"unix_connect expects (path)");
2570 if (!consume_char(src,
len, pos,
')')) {
2571 parser_fail(*pos,
"Expected ')' after unix_connect arg");
2580 if (strcmp(
name,
"fd_set_nonblock") == 0) {
2583 if (!emit_expression(bc, src,
len, pos)) {
2584 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2588 if (!consume_char(src,
len, pos,
',')) {
2589 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2593 if (!emit_expression(bc, src,
len, pos)) {
2594 parser_fail(*pos,
"fd_set_nonblock expects (fd, on)");
2598 if (!consume_char(src,
len, pos,
')')) {
2599 parser_fail(*pos,
"Expected ')' after fd_set_nonblock args");
2607 if (strcmp(
name,
"fd_poll_read") == 0) {
2610 if (!emit_expression(bc, src,
len, pos)) {
2611 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2615 if (!consume_char(src,
len, pos,
',')) {
2616 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2620 if (!emit_expression(bc, src,
len, pos)) {
2621 parser_fail(*pos,
"fd_poll_read expects (fd, timeout_ms)");
2625 if (!consume_char(src,
len, pos,
')')) {
2626 parser_fail(*pos,
"Expected ')' after fd_poll_read args");
2634 if (strcmp(
name,
"fd_poll_write") == 0) {
2637 if (!emit_expression(bc, src,
len, pos)) {
2638 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2642 if (!consume_char(src,
len, pos,
',')) {
2643 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2647 if (!emit_expression(bc, src,
len, pos)) {
2648 parser_fail(*pos,
"fd_poll_write expects (fd, timeout_ms)");
2652 if (!consume_char(src,
len, pos,
')')) {
2653 parser_fail(*pos,
"Expected ')' after fd_poll_write args");
2662 if (strcmp(
name,
"serial_open") == 0) {
2664 if (!emit_expression(bc, src,
len, pos)) {
2665 parser_fail(*pos,
"serial_open expects (path, baud)");
2669 if (!consume_char(src,
len, pos,
',')) {
2670 parser_fail(*pos,
"serial_open expects (path, baud)");
2674 if (!emit_expression(bc, src,
len, pos)) {
2675 parser_fail(*pos,
"serial_open expects (path, baud)");
2679 if (!consume_char(src,
len, pos,
')')) {
2680 parser_fail(*pos,
"Expected ')' after serial_open args");
2688 if (strcmp(
name,
"serial_config") == 0) {
2691 for (
int i = 0; i < 5; ++i) {
2692 if (!emit_expression(bc, src,
len, pos)) {
2693 parser_fail(*pos,
"serial_config expects 5 arguments");
2698 if (!consume_char(src,
len, pos,
',')) {
2699 parser_fail(*pos,
"serial_config expects 5 arguments");
2705 if (!consume_char(src,
len, pos,
')')) {
2706 parser_fail(*pos,
"Expected ')' after serial_config args");
2714 if (strcmp(
name,
"serial_send") == 0) {
2716 if (!emit_expression(bc, src,
len, pos)) {
2717 parser_fail(*pos,
"serial_send expects (fd, data)");
2721 if (!consume_char(src,
len, pos,
',')) {
2722 parser_fail(*pos,
"serial_send expects (fd, data)");
2726 if (!emit_expression(bc, src,
len, pos)) {
2727 parser_fail(*pos,
"serial_send expects (fd, data)");
2731 if (!consume_char(src,
len, pos,
')')) {
2732 parser_fail(*pos,
"Expected ')' after serial_send args");
2740 if (strcmp(
name,
"serial_recv") == 0) {
2742 if (!emit_expression(bc, src,
len, pos)) {
2743 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2747 if (!consume_char(src,
len, pos,
',')) {
2748 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2752 if (!emit_expression(bc, src,
len, pos)) {
2753 parser_fail(*pos,
"serial_recv expects (fd, maxlen)");
2757 if (!consume_char(src,
len, pos,
')')) {
2758 parser_fail(*pos,
"Expected ')' after serial_recv args");
2766 if (strcmp(
name,
"serial_close") == 0) {
2768 if (!emit_expression(bc, src,
len, pos)) {
2769 parser_fail(*pos,
"serial_close expects (fd)");
2773 if (!consume_char(src,
len, pos,
')')) {
2774 parser_fail(*pos,
"Expected ')' after serial_close arg");
2783 if (strcmp(
name,
"split") == 0) {
2785 if (!emit_expression(bc, src,
len, pos)) {
2786 parser_fail(*pos,
"split expects string");
2790 if (*pos <
len && src[*pos] ==
',') {
2792 skip_spaces(src,
len, pos);
2794 parser_fail(*pos,
"split expects 2 args");
2798 if (!emit_expression(bc, src,
len, pos)) {
2799 parser_fail(*pos,
"split expects separator");
2803 if (!consume_char(src,
len, pos,
')')) {
2804 parser_fail(*pos,
"Expected ')' after split args");
2812 if (strcmp(
name,
"join") == 0) {
2814 if (!emit_expression(bc, src,
len, pos)) {
2815 parser_fail(*pos,
"join expects array");
2819 if (*pos <
len && src[*pos] ==
',') {
2821 skip_spaces(src,
len, pos);
2823 parser_fail(*pos,
"join expects 2 args");
2827 if (!emit_expression(bc, src,
len, pos)) {
2828 parser_fail(*pos,
"join expects separator");
2832 if (!consume_char(src,
len, pos,
')')) {
2833 parser_fail(*pos,
"Expected ')' after join args");
2841 if (strcmp(
name,
"substr") == 0) {
2843 if (!emit_expression(bc, src,
len, pos)) {
2844 parser_fail(*pos,
"substr expects string");
2848 if (*pos <
len && src[*pos] ==
',') {
2850 skip_spaces(src,
len, pos);
2852 parser_fail(*pos,
"substr expects 3 args");
2856 if (!emit_expression(bc, src,
len, pos)) {
2857 parser_fail(*pos,
"substr expects start");
2861 if (*pos <
len && src[*pos] ==
',') {
2863 skip_spaces(src,
len, pos);
2865 parser_fail(*pos,
"substr expects 3 args");
2869 if (!emit_expression(bc, src,
len, pos)) {
2870 parser_fail(*pos,
"substr expects len");
2874 if (!consume_char(src,
len, pos,
')')) {
2875 parser_fail(*pos,
"Expected ')' after substr args");
2883 if (strcmp(
name,
"find") == 0) {
2885 if (!emit_expression(bc, src,
len, pos)) {
2886 parser_fail(*pos,
"find expects haystack");
2890 if (*pos <
len && src[*pos] ==
',') {
2892 skip_spaces(src,
len, pos);
2894 parser_fail(*pos,
"find expects 2 args");
2898 if (!emit_expression(bc, src,
len, pos)) {
2899 parser_fail(*pos,
"find expects needle");
2903 if (!consume_char(src,
len, pos,
')')) {
2904 parser_fail(*pos,
"Expected ')' after find args");
2913 if (strcmp(
name,
"regex_match") == 0) {
2915 if (!emit_expression(bc, src,
len, pos)) {
2916 parser_fail(*pos,
"regex_match expects text");
2920 if (*pos <
len && src[*pos] ==
',') {
2922 skip_spaces(src,
len, pos);
2924 parser_fail(*pos,
"regex_match expects 2 args");
2928 if (!emit_expression(bc, src,
len, pos)) {
2929 parser_fail(*pos,
"regex_match expects pattern");
2933 if (!consume_char(src,
len, pos,
')')) {
2934 parser_fail(*pos,
"Expected ')' after regex_match args");
2942 if (strcmp(
name,
"regex_search") == 0) {
2944 if (!emit_expression(bc, src,
len, pos)) {
2945 parser_fail(*pos,
"regex_search expects text");
2949 if (*pos <
len && src[*pos] ==
',') {
2951 skip_spaces(src,
len, pos);
2953 parser_fail(*pos,
"regex_search expects 2 args");
2957 if (!emit_expression(bc, src,
len, pos)) {
2958 parser_fail(*pos,
"regex_search expects pattern");
2962 if (!consume_char(src,
len, pos,
')')) {
2963 parser_fail(*pos,
"Expected ')' after regex_search args");
2971 if (strcmp(
name,
"regex_replace") == 0) {
2973 if (!emit_expression(bc, src,
len, pos)) {
2974 parser_fail(*pos,
"regex_replace expects text");
2978 if (*pos <
len && src[*pos] ==
',') {
2980 skip_spaces(src,
len, pos);
2982 parser_fail(*pos,
"regex_replace expects 3 args");
2986 if (!emit_expression(bc, src,
len, pos)) {
2987 parser_fail(*pos,
"regex_replace expects pattern");
2991 if (*pos <
len && src[*pos] ==
',') {
2993 skip_spaces(src,
len, pos);
2995 parser_fail(*pos,
"regex_replace expects 3 args");
2999 if (!emit_expression(bc, src,
len, pos)) {
3000 parser_fail(*pos,
"regex_replace expects replacement");
3004 if (!consume_char(src,
len, pos,
')')) {
3005 parser_fail(*pos,
"Expected ')' after regex_replace args");
3014 if (strcmp(
name,
"contains") == 0) {
3016 if (!emit_expression(bc, src,
len, pos)) {
3017 parser_fail(*pos,
"contains expects array");
3021 if (*pos <
len && src[*pos] ==
',') {
3023 skip_spaces(src,
len, pos);
3025 parser_fail(*pos,
"contains expects 2 args");
3029 if (!emit_expression(bc, src,
len, pos)) {
3030 parser_fail(*pos,
"contains expects value");
3034 if (!consume_char(src,
len, pos,
')')) {
3035 parser_fail(*pos,
"Expected ')' after contains args");
3043 if (strcmp(
name,
"indexOf") == 0) {
3045 if (!emit_expression(bc, src,
len, pos)) {
3046 parser_fail(*pos,
"indexOf expects array");
3050 if (*pos <
len && src[*pos] ==
',') {
3052 skip_spaces(src,
len, pos);
3054 parser_fail(*pos,
"indexOf expects 2 args");
3058 if (!emit_expression(bc, src,
len, pos)) {
3059 parser_fail(*pos,
"indexOf expects value");
3063 if (!consume_char(src,
len, pos,
')')) {
3064 parser_fail(*pos,
"Expected ')' after indexOf args");
3072 if (strcmp(
name,
"clear") == 0) {
3074 if (!emit_expression(bc, src,
len, pos)) {
3075 parser_fail(*pos,
"clear expects array");
3079 if (!consume_char(src,
len, pos,
')')) {
3080 parser_fail(*pos,
"Expected ')' after clear arg");
3089 if (strcmp(
name,
"enumerate") == 0) {
3091 if (!emit_expression(bc, src,
len, pos)) {
3092 parser_fail(*pos,
"enumerate expects array");
3096 if (!consume_char(src,
len, pos,
')')) {
3097 parser_fail(*pos,
"Expected ')' after enumerate arg");
3105 if (strcmp(
name,
"map") == 0) {
3108 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3109 parser_fail(*pos,
"map expects (array, function)");
3115 snprintf(tarr,
sizeof(tarr),
"__map_arr_%d", g_temp_counter++);
3116 int larr = -1, garr = -1;
3118 larr = local_add(tarr);
3121 garr = sym_index(tarr);
3125 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3126 parser_fail(*pos,
"map expects (array, function)");
3131 snprintf(tfn,
sizeof(tfn),
"__map_fn_%d", g_temp_counter++);
3132 int lfn = -1, gfn = -1;
3134 lfn = local_add(tfn);
3137 gfn = sym_index(tfn);
3143 snprintf(tres,
sizeof(tres),
"__map_res_%d", g_temp_counter++);
3144 int lres = -1, gres = -1;
3146 lres = local_add(tres);
3149 gres = sym_index(tres);
3156 snprintf(ti,
sizeof(ti),
"__map_i_%d", g_temp_counter++);
3157 int li = -1, gi = -1;
3199 snprintf(tv,
sizeof(tv),
"__map_v_%d", g_temp_counter++);
3200 int lv = -1, gv = -1;
3260 if (strcmp(
name,
"filter") == 0) {
3262 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3263 parser_fail(*pos,
"filter expects (array, function)");
3268 snprintf(tarr,
sizeof(tarr),
"__flt_arr_%d", g_temp_counter++);
3269 int larr = -1, garr = -1;
3271 larr = local_add(tarr);
3274 garr = sym_index(tarr);
3277 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3278 parser_fail(*pos,
"filter expects (array, function)");
3283 snprintf(tfn,
sizeof(tfn),
"__flt_fn_%d", g_temp_counter++);
3284 int lfn = -1, gfn = -1;
3286 lfn = local_add(tfn);
3289 gfn = sym_index(tfn);
3294 snprintf(tres,
sizeof(tres),
"__flt_res_%d", g_temp_counter++);
3295 int lres = -1, gres = -1;
3297 lres = local_add(tres);
3300 gres = sym_index(tres);
3306 snprintf(ti,
sizeof(ti),
"__flt_i_%d", g_temp_counter++);
3307 int li = -1, gi = -1;
3355 snprintf(tvf,
sizeof(tvf),
"__flt_v_%d", g_temp_counter++);
3356 int lvf = -1, gvf = -1;
3358 lvf = local_add(tvf);
3361 gvf = sym_index(tvf);
3417 if (strcmp(
name,
"reduce") == 0) {
3419 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3420 parser_fail(*pos,
"reduce expects (array, init, function)");
3425 snprintf(tarr,
sizeof(tarr),
"__red_arr_%d", g_temp_counter++);
3426 int larr = -1, garr = -1;
3428 larr = local_add(tarr);
3431 garr = sym_index(tarr);
3434 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3435 parser_fail(*pos,
"reduce expects (array, init, function)");
3440 snprintf(tacc,
sizeof(tacc),
"__red_acc_%d", g_temp_counter++);
3441 int lacc = -1, gacc = -1;
3443 lacc = local_add(tacc);
3446 gacc = sym_index(tacc);
3449 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3450 parser_fail(*pos,
"reduce expects (array, init, function)");
3455 snprintf(tfn,
sizeof(tfn),
"__red_fn_%d", g_temp_counter++);
3456 int lfn = -1, gfn = -1;
3458 lfn = local_add(tfn);
3461 gfn = sym_index(tfn);
3468 snprintf(ti,
sizeof(ti),
"__red_i_%d", g_temp_counter++);
3469 int li = -1, gi = -1;
3500 snprintf(telem,
sizeof(telem),
"__red_elem_%d", g_temp_counter++);
3501 int lelem = -1, gelem = -1;
3503 lelem = local_add(telem);
3506 gelem = sym_index(telem);
3562 if (strcmp(
name,
"zip") == 0) {
3564 if (!emit_expression(bc, src,
len, pos)) {
3565 parser_fail(*pos,
"zip expects first array");
3569 if (*pos <
len && src[*pos] ==
',') {
3571 skip_spaces(src,
len, pos);
3573 parser_fail(*pos,
"zip expects 2 args");
3577 if (!emit_expression(bc, src,
len, pos)) {
3578 parser_fail(*pos,
"zip expects second array");
3582 if (!consume_char(src,
len, pos,
')')) {
3583 parser_fail(*pos,
"Expected ')' after zip args");
3592 if (strcmp(
name,
"min") == 0) {
3594 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3595 parser_fail(*pos,
"min expects 2 args");
3599 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3600 parser_fail(*pos,
"min expects 2 args");
3608 if (strcmp(
name,
"max") == 0) {
3610 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3611 parser_fail(*pos,
"max expects 2 args");
3615 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3616 parser_fail(*pos,
"max expects 2 args");
3624 if (strcmp(
name,
"fmin") == 0) {
3626 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3627 parser_fail(*pos,
"fmin expects 2 args");
3631 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3632 parser_fail(*pos,
"fmin expects 2 args");
3640 if (strcmp(
name,
"fmax") == 0) {
3642 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3643 parser_fail(*pos,
"fmax expects 2 args");
3647 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3648 parser_fail(*pos,
"fmax expects 2 args");
3656 if (strcmp(
name,
"clamp") == 0) {
3658 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3659 parser_fail(*pos,
"clamp expects 3 args");
3663 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3664 parser_fail(*pos,
"clamp expects 3 args");
3668 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3669 parser_fail(*pos,
"clamp expects 3 args");
3677 if (strcmp(
name,
"abs") == 0) {
3679 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3680 parser_fail(*pos,
"abs expects 1 arg");
3688 if (strcmp(
name,
"floor") == 0) {
3690 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3691 parser_fail(*pos,
"floor expects 1 arg");
3699 if (strcmp(
name,
"ceil") == 0) {
3701 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3702 parser_fail(*pos,
"ceil expects 1 arg");
3710 if (strcmp(
name,
"trunc") == 0) {
3712 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3713 parser_fail(*pos,
"trunc expects 1 arg");
3721 if (strcmp(
name,
"round") == 0) {
3723 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3724 parser_fail(*pos,
"round expects 1 arg");
3732 if (strcmp(
name,
"sin") == 0) {
3734 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3735 parser_fail(*pos,
"sin expects 1 arg");
3743 if (strcmp(
name,
"cos") == 0) {
3745 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3746 parser_fail(*pos,
"cos expects 1 arg");
3754 if (strcmp(
name,
"tan") == 0) {
3756 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3757 parser_fail(*pos,
"tan expects 1 arg");
3765 if (strcmp(
name,
"exp") == 0) {
3767 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3768 parser_fail(*pos,
"exp expects 1 arg");
3776 if (strcmp(
name,
"log") == 0) {
3778 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3779 parser_fail(*pos,
"log expects 1 arg");
3787 if (strcmp(
name,
"log10") == 0) {
3789 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3790 parser_fail(*pos,
"log10 expects 1 arg");
3798 if (strcmp(
name,
"sqrt") == 0) {
3800 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3801 parser_fail(*pos,
"sqrt expects 1 arg");
3809 if (strcmp(
name,
"gcd") == 0) {
3811 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3812 parser_fail(*pos,
"gcd expects 2 args");
3816 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3817 parser_fail(*pos,
"gcd expects 2 args");
3825 if (strcmp(
name,
"lcm") == 0) {
3827 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3828 parser_fail(*pos,
"lcm expects 2 args");
3832 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3833 parser_fail(*pos,
"lcm expects 2 args");
3841 if (strcmp(
name,
"isqrt") == 0) {
3843 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3844 parser_fail(*pos,
"isqrt expects 1 arg");
3852 if (strcmp(
name,
"sign") == 0) {
3854 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3855 parser_fail(*pos,
"sign expects 1 arg");
3863 if (strcmp(
name,
"pow") == 0) {
3865 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3866 parser_fail(*pos,
"pow expects 2 args");
3870 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3871 parser_fail(*pos,
"pow expects 2 args");
3880 if (strcmp(
name,
"random_seed") == 0) {
3882 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3883 parser_fail(*pos,
"random_seed expects 1 arg");
3891 if (strcmp(
name,
"random_int") == 0) {
3893 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3894 parser_fail(*pos,
"random_int expects 2 args");
3898 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3899 parser_fail(*pos,
"random_int expects 2 args");
3908 if (strcmp(
name,
"random_number") == 0) {
3911 if (!emit_expression(bc, src,
len, pos)) {
3912 parser_fail(*pos,
"random_number expects 1 arg (length)");
3916 if (!consume_char(src,
len, pos,
')')) {
3917 parser_fail(*pos,
"Expected ')' after random_number arg");
3927 if (strcmp(
name,
"thread_spawn") == 0) {
3930 if (!emit_expression(bc, src,
len, pos)) {
3931 parser_fail(*pos,
"thread_spawn expects function as first arg");
3936 skip_spaces(src,
len, pos);
3937 if (*pos <
len && src[*pos] ==
',') {
3939 skip_spaces(src,
len, pos);
3940 if (!emit_expression(bc, src,
len, pos)) {
3941 parser_fail(*pos,
"thread_spawn second arg must be array or value");
3947 if (!consume_char(src,
len, pos,
')')) {
3948 parser_fail(*pos,
"Expected ')' after thread_spawn args");
3956 if (strcmp(
name,
"thread_join") == 0) {
3958 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3959 parser_fail(*pos,
"thread_join expects 1 arg (thread id)");
3967 if (strcmp(
name,
"sleep") == 0) {
3969 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3970 parser_fail(*pos,
"sleep expects 1 arg (milliseconds)");
3980 if (strcmp(
name,
"band") == 0) {
3982 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3983 parser_fail(*pos,
"band expects 2 args");
3987 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
3988 parser_fail(*pos,
"band expects 2 args");
3996 if (strcmp(
name,
"bor") == 0) {
3998 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
3999 parser_fail(*pos,
"bor expects 2 args");
4003 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4004 parser_fail(*pos,
"bor expects 2 args");
4012 if (strcmp(
name,
"bxor") == 0) {
4014 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
4015 parser_fail(*pos,
"bxor expects 2 args");
4019 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4020 parser_fail(*pos,
"bxor expects 2 args");
4028 if (strcmp(
name,
"bnot") == 0) {
4030 if (!emit_expression(bc, src,
len, pos)) {
4031 parser_fail(*pos,
"bnot expects 1 arg");
4035 if (!consume_char(src,
len, pos,
')')) {
4036 parser_fail(*pos,
"bnot expects 1 arg");
4044 if (strcmp(
name,
"shl") == 0) {
4046 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
4047 parser_fail(*pos,
"shl expects 2 args");
4051 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4052 parser_fail(*pos,
"shl expects 2 args");
4060 if (strcmp(
name,
"shr") == 0) {
4062 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
4063 parser_fail(*pos,
"shr expects 2 args");
4067 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4068 parser_fail(*pos,
"shr expects 2 args");
4076 if (strcmp(
name,
"rol") == 0) {
4078 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
4079 parser_fail(*pos,
"rol expects 2 args");
4083 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4084 parser_fail(*pos,
"rol expects 2 args");
4092 if (strcmp(
name,
"ror") == 0) {
4094 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
',')) {
4095 parser_fail(*pos,
"ror expects 2 args");
4099 if (!emit_expression(bc, src,
len, pos) || !consume_char(src,
len, pos,
')')) {
4100 parser_fail(*pos,
"ror expects 2 args");
4110 if (local_idx < 0 && name_in_outer_envs(
name)) {
4111 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4112 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname,
name);
4116 if (local_idx >= 0) {
4119 int gi = sym_index(
name);
4123 int __ns_ctx = is_ns_alias(
name);
4127 skip_spaces(src,
len, pos);
4128 if (*pos <
len && src[*pos] !=
')') {
4130 if (!emit_expression(bc, src,
len, pos)) {
4131 parser_fail(*pos,
"Expected expression as function argument");
4136 skip_spaces(src,
len, pos);
4137 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos), skip_spaces(src,
len, pos), 1));
4139 if (!consume_char(src,
len, pos,
')')) {
4140 parser_fail(*pos,
"Expected ')' after arguments");
4146 if (fun_debug_enabled()) {
4147 printf(
"compile: CALL %s with %d arg(s)\n",
name, argc);
4153 skip_spaces(src,
len, pos);
4156 if (*pos <
len && src[*pos] ==
'[') {
4158 if (!emit_expression(bc, src,
len, pos)) {
4159 parser_fail(*pos,
"Expected start expression");
4163 skip_spaces(src,
len, pos);
4164 if (*pos <
len && src[*pos] ==
':') {
4166 skip_spaces(src,
len, pos);
4168 if (!emit_expression(bc, src,
len, pos)) {
4173 if (!consume_char(src,
len, pos,
']')) {
4174 parser_fail(*pos,
"Expected ']' after slice");
4181 if (!consume_char(src,
len, pos,
']')) {
4182 parser_fail(*pos,
"Expected ']' after index");
4192 if (*pos <
len && src[*pos] ==
'.') {
4194 skip_spaces(src,
len, pos);
4196 if (!read_identifier_into(src,
len, pos, &mname)) {
4197 parser_fail(*pos,
"Expected identifier after '.'");
4201 int is_private = (mname && mname[0] ==
'_');
4205 size_t callp = *pos;
4206 skip_spaces(src,
len, &callp);
4207 if (callp <
len && src[callp] ==
'(') {
4211 snprintf(msg,
sizeof(msg),
"AccessError: private method '%s' is not accessible here", mname);
4233 skip_spaces(src,
len, pos);
4234 if (*pos <
len && src[*pos] !=
')') {
4236 if (!emit_expression(bc, src,
len, pos)) {
4237 parser_fail(*pos,
"Expected expression as method argument");
4243 skip_spaces(src,
len, pos);
4244 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos), skip_spaces(src,
len, pos), 1));
4246 if (!consume_char(src,
len, pos,
')')) {
4247 parser_fail(*pos,
"Expected ')' after arguments");
4271 if (local_idx < 0 && name_in_outer_envs(
name)) {
4272 const char *fname = (bc && bc->
name) ? bc->
name :
"<function>";
4273 parser_fail(*pos,
"Nested function '%s' cannot access outer local '%s'. Pass it as a parameter instead.", fname,
name);
4277 if (local_idx >= 0) {
4280 int gi = sym_index(
name);
4284 int __ns_ctx = is_ns_alias(
name);
4287 skip_spaces(src,
len, pos);
4290 if (*pos <
len && src[*pos] ==
'[') {
4292 if (!emit_expression(bc, src,
len, pos)) {
4293 parser_fail(*pos,
"Expected start expression");
4297 skip_spaces(src,
len, pos);
4298 if (*pos <
len && src[*pos] ==
':') {
4300 skip_spaces(src,
len, pos);
4302 if (!emit_expression(bc, src,
len, pos)) {
4307 if (!consume_char(src,
len, pos,
']')) {
4308 parser_fail(*pos,
"Expected ']' after slice");
4315 if (!consume_char(src,
len, pos,
']')) {
4316 parser_fail(*pos,
"Expected ']' after index");
4326 if (*pos <
len && src[*pos] ==
'.') {
4328 skip_spaces(src,
len, pos);
4330 if (!read_identifier_into(src,
len, pos, &mname)) {
4331 parser_fail(*pos,
"Expected identifier after '.'");
4335 int is_private = (mname && mname[0] ==
'_');
4339 size_t callp = *pos;
4340 skip_spaces(src,
len, &callp);
4341 if (callp <
len && src[callp] ==
'(') {
4343 if (is_private && !(strcmp(
name,
"this") == 0)) {
4345 snprintf(msg,
sizeof(msg),
"AccessError: private method '%s' is not accessible", mname);
4355 int is_ns = __ns_ctx;
4371 skip_spaces(src,
len, pos);
4372 if (*pos <
len && src[*pos] !=
')') {
4374 if (!emit_expression(bc, src,
len, pos)) {
4375 parser_fail(*pos,
"Expected expression as method argument");
4381 skip_spaces(src,
len, pos);
4382 }
while (*pos <
len && src[*pos] ==
',' && (++(*pos), skip_spaces(src,
len, pos), 1));
4384 if (!consume_char(src,
len, pos,
')')) {
4385 parser_fail(*pos,
"Expected ')' after arguments");
4428static int emit_unary(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4429 skip_spaces(src,
len, pos);
4430 if (*pos <
len && src[*pos] ==
'!') {
4432 if (!emit_unary(bc, src,
len, pos)) {
4433 parser_fail(*pos,
"Expected expression after '!'");
4439 if (*pos <
len && src[*pos] ==
'-') {
4444 if (!emit_unary(bc, src,
len, pos)) {
4445 parser_fail(*pos,
"Expected expression after unary '-'");
4451 return emit_primary(bc, src,
len, pos);
4465static int emit_multiplicative(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4466 if (!emit_unary(bc, src,
len, pos))
return 0;
4468 skip_spaces(src,
len, pos);
4471 if (*pos + 1 <
len && src[*pos] ==
'/' && src[*pos + 1] ==
'/') {
4475 if (*pos + 1 <
len && src[*pos] ==
'/' && src[*pos + 1] ==
'*') {
4476 size_t p = *pos + 2;
4477 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
4480 if (
p + 1 <
len)
p += 2;
4485 if (*pos <
len && src[*pos] ==
'*') {
4487 if (!emit_unary(bc, src,
len, pos)) {
4488 parser_fail(*pos,
"Expected expression after '*'");
4494 if (*pos <
len && src[*pos] ==
'/') {
4496 if (!emit_unary(bc, src,
len, pos)) {
4497 parser_fail(*pos,
"Expected expression after '/'");
4503 if (*pos <
len && src[*pos] ==
'%') {
4505 if (!emit_unary(bc, src,
len, pos)) {
4506 parser_fail(*pos,
"Expected expression after '%'");
4528static int emit_additive(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4529 if (!emit_multiplicative(bc, src,
len, pos))
return 0;
4531 skip_spaces(src,
len, pos);
4532 if (*pos <
len && src[*pos] ==
'+') {
4534 if (!emit_multiplicative(bc, src,
len, pos)) {
4535 parser_fail(*pos,
"Expected expression after '+'");
4541 if (*pos <
len && src[*pos] ==
'-') {
4543 if (!emit_multiplicative(bc, src,
len, pos)) {
4544 parser_fail(*pos,
"Expected expression after '-'");
4566static int emit_relational(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4567 if (!emit_additive(bc, src,
len, pos))
return 0;
4569 skip_spaces(src,
len, pos);
4570 if (*pos + 1 <
len && src[*pos] ==
'<' && src[*pos + 1] ==
'=') {
4572 if (!emit_additive(bc, src,
len, pos)) {
4573 parser_fail(*pos,
"Expected expression after '<='");
4579 if (*pos + 1 <
len && src[*pos] ==
'>' && src[*pos + 1] ==
'=') {
4581 if (!emit_additive(bc, src,
len, pos)) {
4582 parser_fail(*pos,
"Expected expression after '>='");
4588 if (*pos <
len && src[*pos] ==
'<') {
4590 if (!emit_additive(bc, src,
len, pos)) {
4591 parser_fail(*pos,
"Expected expression after '<'");
4597 if (*pos <
len && src[*pos] ==
'>') {
4599 if (!emit_additive(bc, src,
len, pos)) {
4600 parser_fail(*pos,
"Expected expression after '>'");
4622static int emit_equality(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4623 if (!emit_relational(bc, src,
len, pos))
return 0;
4625 skip_spaces(src,
len, pos);
4626 if (*pos + 1 <
len && src[*pos] ==
'=' && src[*pos + 1] ==
'=') {
4628 if (!emit_relational(bc, src,
len, pos)) {
4629 parser_fail(*pos,
"Expected expression after '=='");
4635 if (*pos + 1 <
len && src[*pos] ==
'!' && src[*pos + 1] ==
'=') {
4637 if (!emit_relational(bc, src,
len, pos)) {
4638 parser_fail(*pos,
"Expected expression after '!='");
4661static int emit_and_expr(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4667 if (!emit_equality(bc, src,
len, pos))
return 0;
4670 skip_spaces(src,
len, pos);
4671 if (!(*pos + 1 <
len && src[*pos] ==
'&' && src[*pos + 1] ==
'&'))
break;
4676 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4679 parser_fail(*pos,
"Too many operands in '&&' chain");
4684 if (!emit_equality(bc, src,
len, pos)) {
4685 parser_fail(*pos,
"Expected expression after '&&'");
4692 if (jf_count < (
int)(
sizeof(jf_idxs) /
sizeof(jf_idxs[0]))) {
4695 parser_fail(*pos,
"Too many operands in '&&' chain");
4706 for (
int i = 0; i < jf_count; ++i) {
4732static int emit_or_expr(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4738 if (!emit_and_expr(bc, src,
len, pos))
return 0;
4741 skip_spaces(src,
len, pos);
4742 if (!(*pos + 1 <
len && src[*pos] ==
'|' && src[*pos + 1] ==
'|'))
break;
4752 if (tj_count < (
int)(
sizeof(true_jumps) /
sizeof(true_jumps[0]))) {
4755 parser_fail(*pos,
"Too many operands in '||' chain");
4763 if (!emit_and_expr(bc, src,
len, pos)) {
4764 parser_fail(*pos,
"Expected expression after '||'");
4784 for (
int i = 0; i < tj_count; ++i) {
4803static int emit_conditional(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4805 if (!emit_or_expr(bc, src,
len, pos))
return 0;
4808 skip_spaces(src,
len, pos);
4809 if (!(*pos <
len && src[*pos] ==
'?'))
break;
4816 skip_spaces(src,
len, pos);
4817 if (!emit_conditional(bc, src,
len, pos)) {
4818 parser_fail(*pos,
"Expected expression after '?'");
4829 skip_spaces(src,
len, pos);
4830 if (!(*pos <
len && src[*pos] ==
':')) {
4831 parser_fail(*pos,
"Expected ':' in conditional expression");
4837 skip_spaces(src,
len, pos);
4838 if (!emit_conditional(bc, src,
len, pos)) {
4839 parser_fail(*pos,
"Expected expression after ':'");
4864static int emit_expression(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
4865 return emit_conditional(bc, src,
len, pos);
4887static void skip_to_eol(
const char *src,
size_t len,
size_t *pos) {
4893 while (
p <
len && src[
p] ==
' ')
4901 if (src[
p] ==
'\r') {
4903 if (
p <
len && src[
p] ==
'\n')
p++;
4907 if (src[
p] ==
'\n') {
4913 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'/') {
4916 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
4918 if (
p <
len && src[
p] ==
'\r') {
4920 if (
p <
len && src[
p] ==
'\n')
p++;
4921 }
else if (
p <
len && src[
p] ==
'\n') {
4928 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'*') {
4931 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
4938 parser_fail(
p,
"Unterminated block comment at end of file");
4945 parser_fail(
p,
"Unexpected trailing characters at end of line");
4975static int read_line_start(
const char *src,
size_t len,
size_t *pos,
int *out_indent) {
4976 while (*pos <
len) {
4979 while (
p <
len && src[
p] ==
' ') {
4983 if (
p <
len && src[
p] ==
'\t') {
4984 parser_fail(
p,
"Tabs are forbidden for indentation");
4993 if (src[
p] ==
'\r') {
4995 if (
p <
len && src[
p] ==
'\n')
p++;
4999 if (src[
p] ==
'\n') {
5006 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'/') {
5009 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
5011 if (
p <
len && src[
p] ==
'\r') {
5013 if (
p <
len && src[
p] ==
'\n')
p++;
5014 }
else if (
p <
len && src[
p] ==
'\n') {
5022 if (
p + 1 <
len && src[
p] ==
'/' && src[
p + 1] ==
'*') {
5025 while (
p + 1 <
len && !(src[
p] ==
'*' && src[
p + 1] ==
'/')) {
5028 if (
p + 1 <
len)
p += 2;
5030 while (
p <
len && src[
p] !=
'\n' && src[
p] !=
'\r')
5032 if (
p <
len && src[
p] ==
'\r') {
5034 if (
p <
len && src[
p] ==
'\n')
p++;
5035 }
else if (
p <
len && src[
p] ==
'\n') {
5042 if (spaces % 2 != 0) {
5043 parser_fail(
p,
"Indentation must be multiples of two spaces");
5046 *out_indent = spaces / 2;
5054static void parse_block(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos,
int current_indent);
5068static void parse_simple_statement(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos) {
5069 size_t local_pos = *pos;
5071 if (read_identifier_into(src,
len, &local_pos, &
name)) {
5074 if (strcmp(
name,
"sint8") == 0) {
5076 name = strdup(
"int8");
5077 }
else if (strcmp(
name,
"sint16") == 0) {
5079 name = strdup(
"int16");
5080 }
else if (strcmp(
name,
"sint32") == 0) {
5082 name = strdup(
"int32");
5083 }
else if (strcmp(
name,
"sint64") == 0) {
5085 name = strdup(
"int64");
5089 if (strcmp(
name,
"return") == 0) {
5091 skip_spaces(src,
len, &local_pos);
5093 size_t save_pos = local_pos;
5094 if (emit_expression(bc, src,
len, &local_pos)) {
5098 local_pos = save_pos;
5104 skip_to_eol(src,
len, pos);
5109 if (strcmp(
name,
"exit") == 0) {
5111 skip_spaces(src,
len, &local_pos);
5112 size_t save_pos = local_pos;
5113 if (emit_expression(bc, src,
len, &local_pos)) {
5117 local_pos = save_pos;
5123 skip_to_eol(src,
len, pos);
5128 if (strcmp(
name,
"break") == 0) {
5131 parser_fail(local_pos,
"break used outside of loop");
5135 if (g_loop_ctx->break_count < (
int)(
sizeof(g_loop_ctx->break_jumps) /
sizeof(g_loop_ctx->break_jumps[0]))) {
5136 g_loop_ctx->break_jumps[g_loop_ctx->break_count++] = j;
5138 parser_fail(local_pos,
"Too many 'break' in one loop");
5142 skip_to_eol(src,
len, pos);
5145 if (strcmp(
name,
"continue") == 0) {
5148 parser_fail(local_pos,
"continue used outside of loop");
5152 if (g_loop_ctx->cont_count < (
int)(
sizeof(g_loop_ctx->continue_jumps) /
sizeof(g_loop_ctx->continue_jumps[0]))) {
5153 g_loop_ctx->continue_jumps[g_loop_ctx->cont_count++] = j;
5155 parser_fail(local_pos,
"Too many 'continue' in one loop");
5159 skip_to_eol(src,
len, pos);
5167 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) {
5168 int is_number = (strcmp(
name,
"number") == 0);
5169 int is_string = (strcmp(
name,
"string") == 0);
5170 int is_boolean = (strcmp(
name,
"boolean") == 0);
5171 int is_nil = (strcmp(
name,
"nil") == 0);
5173 int is_float = (strcmp(
name,
"float") == 0);
5174 int is_array = (strcmp(
name,
"array") == 0);
5175 int is_byte = (strcmp(
name,
"byte") == 0);
5176 int is_u8 = (strcmp(
name,
"uint8") == 0) || is_byte;
5177 int is_u16 = (strcmp(
name,
"uint16") == 0);
5178 int is_u32 = (strcmp(
name,
"uint32") == 0);
5179 int is_u64 = (strcmp(
name,
"uint64") == 0);
5180 int is_s8 = (strcmp(
name,
"int8") == 0);
5181 int is_s16 = (strcmp(
name,
"int16") == 0);
5182 int is_s32 = (strcmp(
name,
"int32") == 0);
5183 int is_s64 = (strcmp(
name,
"int64") == 0) || is_number;
5184 int decl_bits = is_u8 ? 8 : is_u16 ? 16
5192 int decl_signed = (is_s8 || is_s16 || is_s32 || is_s64) ? 1 : 0;
5194 if (decl_signed) decl_bits = -decl_bits;
5197 int decl_meta = decl_bits;
5200 }
else if (is_boolean) {
5202 }
else if (is_nil) {
5206 }
else if (is_float) {
5208 }
else if (is_array) {
5215 char *varname = NULL;
5216 skip_spaces(src,
len, &local_pos);
5217 if (!read_identifier_into(src,
len, &local_pos, &varname)) {
5218 parser_fail(local_pos,
"Expected identifier after type declaration");
5226 int existing = local_find(varname);
5230 lidx = local_add(varname);
5232 g_locals->types[lidx] = decl_meta;
5235 gi = sym_index(varname);
5237 G.types[gi] = decl_meta;
5242 skip_spaces(src,
len, &local_pos);
5243 if (local_pos <
len && src[local_pos] ==
'=') {
5245 if (!emit_expression(bc, src,
len, &local_pos)) {
5246 parser_fail(local_pos,
"Expected initializer expression after '='");
5387 int abs_bits = decl_bits < 0 ? -decl_bits : decl_bits;
5422 }
else if (is_nil) {
5427 }
else if (is_boolean) {
5430 }
else if (is_number || (decl_bits != 0)) {
5436 int abs_bits2 = decl_bits < 0 ? -decl_bits : decl_bits;
5437 if (abs_bits2 > 0) {
5448 skip_to_eol(src,
len, pos);
5452 if (strcmp(
name,
"print") == 0) {
5454 skip_spaces(src,
len, &local_pos);
5455 (void)consume_char(src,
len, &local_pos,
'(');
5456 if (emit_expression(bc, src,
len, &local_pos)) {
5457 (void)consume_char(src,
len, &local_pos,
')');
5460 (void)consume_char(src,
len, &local_pos,
')');
5463 skip_to_eol(src,
len, pos);
5467 if (strcmp(
name,
"echo") == 0) {
5469 skip_spaces(src,
len, &local_pos);
5470 (void)consume_char(src,
len, &local_pos,
'(');
5471 if (emit_expression(bc, src,
len, &local_pos)) {
5472 (void)consume_char(src,
len, &local_pos,
')');
5475 (void)consume_char(src,
len, &local_pos,
')');
5478 skip_to_eol(src,
len, pos);
5483 int lidx = local_find(
name);
5484 int gi = (lidx < 0) ? sym_find(
name) : -1;
5485 if (lidx < 0 && gi < 0 && g_locals) {
5487 lidx = local_add(
name);
5489 if (lidx < 0 && gi < 0) {
5493 gi = sym_index(
name);
5495 skip_spaces(src,
len, &local_pos);
5503 if (local_pos <
len && src[local_pos] ==
'.') {
5504 size_t stmt_start = *pos;
5505 size_t look = local_pos + 1;
5506 skip_spaces(src,
len, &look);
5508 if (!read_identifier_into(src,
len, &look, &fname)) {
5509 parser_fail(look,
"Expected field name after '.'");
5513 skip_spaces(src,
len, &look);
5514 if (look <
len && src[look] ==
'[') {
5529 if (!(look <
len && src[look] ==
'['))
break;
5531 if (!emit_expression(bc, src,
len, &look)) {
5532 parser_fail(look,
"Expected index expression after '['");
5536 if (!consume_char(src,
len, &look,
']')) {
5537 parser_fail(look,
"Expected ']' after index");
5541 skip_spaces(src,
len, &look);
5542 if (look <
len && src[look] ==
'[') {
5550 if (look >=
len || src[look] !=
'=') {
5553 size_t expr_pos = stmt_start;
5554 if (emit_expression(bc, src,
len, &expr_pos)) {
5558 skip_to_eol(src,
len, pos);
5562 if (!emit_expression(bc, src,
len, &look)) {
5563 parser_fail(look,
"Expected expression after '='");
5570 skip_to_eol(src,
len, pos);
5572 }
else if (look <
len && src[look] ==
'=') {
5581 local_pos = look + 1;
5582 if (!emit_expression(bc, src,
len, &local_pos)) {
5583 parser_fail(local_pos,
"Expected expression after '='");
5589 int tmp_local = local_add(
"__assign_tmp");
5609 skip_to_eol(src,
len, pos);
5615 size_t expr_pos = stmt_start;
5616 if (emit_expression(bc, src,
len, &expr_pos)) {
5620 skip_to_eol(src,
len, pos);
5626 if (local_pos <
len && src[local_pos] ==
'[') {
5634 if (!emit_expression(bc, src,
len, &local_pos)) {
5635 parser_fail(local_pos,
"Expected index expression after '['");
5639 if (!consume_char(src,
len, &local_pos,
']')) {
5640 parser_fail(local_pos,
"Expected ']' after index");
5644 skip_spaces(src,
len, &local_pos);
5647 if (local_pos <
len && src[local_pos] ==
'[') {
5652 if (!emit_expression(bc, src,
len, &local_pos)) {
5653 parser_fail(local_pos,
"Expected nested index expression after '['");
5657 if (!consume_char(src,
len, &local_pos,
']')) {
5658 parser_fail(local_pos,
"Expected ']' after nested index");
5662 skip_spaces(src,
len, &local_pos);
5663 if (local_pos >=
len || src[local_pos] !=
'=') {
5664 parser_fail(local_pos,
"Expected '=' after nested array index");
5669 if (!emit_expression(bc, src,
len, &local_pos)) {
5670 parser_fail(local_pos,
"Expected expression after '='");
5678 skip_to_eol(src,
len, pos);
5683 if (local_pos >=
len || src[local_pos] !=
'=') {
5684 parser_fail(local_pos,
"Expected '=' after array index");
5689 if (!emit_expression(bc, src,
len, &local_pos)) {
5690 parser_fail(local_pos,
"Expected expression after '='");
5698 skip_to_eol(src,
len, pos);
5703 if (local_pos <
len && src[local_pos] ==
'=') {
5705 if (emit_expression(bc, src,
len, &local_pos)) {
5708 if (lidx >= 0 && g_locals) {
5709 meta = g_locals->types[lidx];
5710 }
else if (gi >= 0) {
5833 }
else if (meta != 0) {
5835 int abs_bits = meta < 0 ? -meta : meta;
5866 skip_to_eol(src,
len, pos);
5873 if (emit_expression(bc, src,
len, &local_pos)) {
5876 skip_to_eol(src,
len, pos);
5880 parser_fail(local_pos,
"Expected assignment '=' or call '(...)' after identifier");
5886 if (starts_with(src,
len, *pos,
"print")) {
5888 skip_spaces(src,
len, pos);
5889 (void)consume_char(src,
len, pos,
'(');
5890 if (emit_expression(bc, src,
len, pos)) {
5891 (void)consume_char(src,
len, pos,
')');
5894 (void)consume_char(src,
len, pos,
')');
5896 skip_to_eol(src,
len, pos);
5901 if (starts_with(src,
len, *pos,
"echo")) {
5903 skip_spaces(src,
len, pos);
5904 (void)consume_char(src,
len, pos,
'(');
5905 if (emit_expression(bc, src,
len, pos)) {
5906 (void)consume_char(src,
len, pos,
')');
5909 (void)consume_char(src,
len, pos,
')');
5911 skip_to_eol(src,
len, pos);
5916 parser_fail(*pos,
"Unknown token at start of statement");
5933static void parse_block(
Bytecode *bc,
const char *src,
size_t len,
size_t *pos,
int current_indent) {
5934 while (*pos <
len) {
5935 if (g_has_error)
return;
5936 size_t line_start = *pos;
5938 if (!read_line_start(src,
len, pos, &indent)) {
5942 if (indent < current_indent) {
5947 if (indent > current_indent) {
5949 parse_block(bc, src,
len, pos, indent);
5958 int stmt_line = 1, stmt_col = 1;
5959 calc_line_col(src,
len, *pos, &stmt_line, &stmt_col);
5964 if (starts_with(src,
len, *pos,
"class") && (*pos + 5 <
len) && (src[*pos + 5] ==
' ' || src[*pos + 5] ==
'\t')) {
5966 skip_spaces(src,
len, pos);
5969 if (!read_identifier_into(src,
len, pos, &cname)) {
5970 parser_fail(*pos,
"Expected class name after 'class'");
5973 int cgi = sym_index(cname);
5976 char *parent_name = NULL;
5979 char *param_names[64];
5982 memset(param_names, 0,
sizeof(param_names));
5983 memset(param_kind, 0,
sizeof(param_kind));
5987#define MAP_TYPE_KIND(t) ( \ 5988 ((t) && strcmp((t), "string") == 0) ? 2 : ((t) && strcmp((t), "nil") == 0) ? 3 \ 5989 : ((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 \ 5992 skip_spaces(src,
len, pos);
5993 if (*pos <
len && src[*pos] ==
'(') {
5995 skip_spaces(src,
len, pos);
5996 if (*pos <
len && src[*pos] !=
')') {
6000 if (!read_identifier_into(src,
len, pos, &
tname)) {
6001 parser_fail(*pos,
"Expected type in class parameter list");
6006 skip_spaces(src,
len, pos);
6008 if (!read_identifier_into(src,
len, pos, &pname)) {
6009 parser_fail(*pos,
"Expected parameter name after type");
6014 if (pcount >= (
int)(
sizeof(param_names) /
sizeof(param_names[0]))) {
6015 parser_fail(*pos,
"Too many class parameters");
6021 param_names[pcount] = pname;
6026 skip_spaces(src,
len, pos);
6027 if (*pos <
len && src[*pos] ==
',') {
6029 skip_spaces(src,
len, pos);
6035 if (!consume_char(src,
len, pos,
')')) {
6036 parser_fail(*pos,
"Expected ')' after class parameter list");
6037 for (
int i = 0; i < pcount; ++i)
6038 free(param_names[i]);
6045 skip_spaces(src,
len, pos);
6046 if (starts_with(src,
len, *pos,
"extends")) {
6048 skip_spaces(src,
len, pos);
6049 if (!read_identifier_into(src,
len, pos, &parent_name)) {
6050 parser_fail(*pos,
"Expected parent class name after 'extends'");
6051 for (
int i = 0; i < pcount; ++i)
6052 free(param_names[i]);
6059 skip_to_eol(src,
len, pos);
6066 ctor_bc->
name = strdup(cname);
6068 if (g_current_source_path) ctor_bc->
source_file = strdup(g_current_source_path);
6072 memset(&ctor_env, 0,
sizeof(ctor_env));
6074 g_locals = &ctor_env;
6077 int ctor_present = 0;
6080 for (
int i = 0; i < pcount; ++i) {
6081 local_add(param_names[i]);
6085 int l_extra = local_add(
"__extra");
6088 for (
int i = 0; i < pcount; ++i) {
6099 snprintf(msg,
sizeof(msg),
"TypeError: missing argument '%s' in %s()", param_names[i], cname);
6109 int kind = param_kind[i];
6110 if (kind == 1 || kind == 2 || kind == 3) {
6114 const char *
exp = (kind == 1) ?
"Number" : (kind == 2) ?
"String" 6128 snprintf(msg2,
sizeof(msg2),
"TypeError: %s() expects %s for '%s'", cname,
exp, param_names[i]);
6154 snprintf(msg3,
sizeof(msg3),
"TypeError: %s() received too many arguments", cname);
6164 int l_this = local_add(
"__this");
6181 int parent_gi = sym_index(parent_name);
6183 for (
int i = 0; i < pcount; ++i) {
6187 int l_parent = local_add(
"__parent_inst");
6193 int l_keys = local_add(
"__parent_keys");
6199 int l_i = local_add(
"__inh_i");
6214 int l_k = local_add(
"__inh_k");
6251 int body_indent = 0;
6252 size_t look_body = *pos;
6253 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6256 size_t member_line_start = *pos;
6257 int member_indent = 0;
6258 if (!read_line_start(src,
len, pos, &member_indent)) {
6262 if (member_indent < body_indent) {
6264 *pos = member_line_start;
6267 if (member_indent > body_indent) {
6269 parse_block(ctor_bc, src,
len, pos, member_indent);
6274 if (starts_with(src,
len, *pos,
"fun")) {
6277 skip_spaces(src,
len, pos);
6279 if (!read_identifier_into(src,
len, pos, &mname)) {
6280 parser_fail(*pos,
"Expected method name after 'fun' in class");
6281 g_locals = prev_env;
6285 int is_ctor_method = (strcmp(mname,
"_construct") == 0);
6287 skip_spaces(src,
len, pos);
6288 if (!consume_char(src,
len, pos,
'(')) {
6289 parser_fail(*pos,
"Expected '(' after method name");
6291 g_locals = prev_env;
6301 size_t qlen = strlen(cname) + 1 + strlen(mname) + 1;
6302 char *q = (
char *)malloc(qlen);
6304 snprintf(q, qlen,
"%s.%s", cname, mname);
6308 if (g_current_source_path) m_bc->
source_file = strdup(g_current_source_path);
6311 memset(&m_env, 0,
sizeof(m_env));
6317 int param_count = 0;
6318 skip_spaces(src,
len, pos);
6319 if (*pos <
len && src[*pos] !=
')') {
6322 if (!read_identifier_into(src,
len, pos, &pname)) {
6323 parser_fail(*pos,
"Expected parameter name");
6326 g_locals = prev_env;
6330 if (param_count == 0 && strcmp(pname,
"this") != 0) {
6332 if (is_ctor_method) {
6333 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6335 parser_fail(*pos,
"First parameter of a method must be 'this'");
6340 g_locals = prev_env;
6347 skip_spaces(src,
len, pos);
6348 if (*pos <
len && src[*pos] ==
',') {
6350 skip_spaces(src,
len, pos);
6357 if (is_ctor_method) {
6358 parser_fail(*pos,
"Constructor '_construct' must declare 'this' as its first parameter");
6360 parser_fail(*pos,
"Method must declare at least 'this' parameter");
6364 g_locals = prev_env;
6369 if (!consume_char(src,
len, pos,
')')) {
6370 parser_fail(*pos,
"Expected ')' after method parameter list");
6373 g_locals = prev_env;
6378 skip_to_eol(src,
len, pos);
6381 int m_body_indent = 0;
6382 size_t look_m = *pos;
6383 if (read_line_start(src,
len, &look_m, &m_body_indent) && m_body_indent > body_indent) {
6384 parse_block(m_bc, src,
len, pos, m_body_indent);
6403 if (strcmp(mname,
"_construct") == 0) {
6414 if (!read_identifier_into(src,
len, &lp, &fname)) {
6415 parser_fail(*pos,
"Expected field or 'fun' in class body");
6416 g_locals = prev_env;
6421 skip_spaces(src,
len, &tmp);
6422 if (tmp >=
len || src[tmp] !=
'=') {
6424 parser_fail(tmp,
"Expected '=' in field initializer");
6425 g_locals = prev_env;
6436 if (!emit_expression(ctor_bc, src,
len, pos)) {
6437 parser_fail(*pos,
"Expected expression in field initializer");
6438 g_locals = prev_env;
6444 skip_to_eol(src,
len, pos);
6451 for (
int i = 0; i < pcount; ++i) {
6472 for (
int i = 0; i < pcount; ++i) {
6486 g_locals = prev_env;
6493 G.is_class[cgi] = 1;
6495 for (
int i = 0; i < pcount; ++i)
6496 free(param_names[i]);
6497 if (parent_name)
free(parent_name);
6502 if (starts_with(src,
len, *pos,
"fun") && (*pos + 3 <
len) && (src[*pos + 3] ==
' ' || src[*pos + 3] ==
'\t')) {
6505 skip_spaces(src,
len, pos);
6507 if (!read_identifier_into(src,
len, pos, &fname)) {
6508 parser_fail(*pos,
"Expected function name after 'fun'");
6511 int fgi = sym_index(fname);
6512 skip_spaces(src,
len, pos);
6513 if (!consume_char(src,
len, pos,
'(')) {
6514 parser_fail(*pos,
"Expected '(' after function name");
6522 int saved_depth = g_func_env_depth;
6524 if (g_func_env_depth >= (
int)(
sizeof(g_func_env_stack) /
sizeof(g_func_env_stack[0]))) {
6525 parser_fail(*pos,
"Too many nested functions (env stack overflow)");
6529 g_func_env_stack[g_func_env_depth++] =
prev;
6533 skip_spaces(src,
len, pos);
6534 if (*pos <
len && src[*pos] !=
')') {
6537 if (!read_identifier_into(src,
len, pos, &pname)) {
6538 parser_fail(*pos,
"Expected parameter name");
6543 if (local_find(pname) >= 0) {
6544 parser_fail(*pos,
"Duplicate parameter name '%s'", pname);
6552 skip_spaces(src,
len, pos);
6553 if (*pos <
len && src[*pos] ==
',') {
6555 skip_spaces(src,
len, pos);
6561 if (!consume_char(src,
len, pos,
')')) {
6562 parser_fail(*pos,
"Expected ')' after parameter list");
6568 skip_to_eol(src,
len, pos);
6574 fn_bc->
name = strdup(fname);
6576 if (g_current_source_path) fn_bc->
source_file = strdup(g_current_source_path);
6580 int body_indent = 0;
6581 size_t look_body = *pos;
6582 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6584 parse_block(fn_bc, src,
len, pos, body_indent);
6593 if (fun_debug_enabled()) {
6594 printf(
"=== compiled function %s (%d params) ===\n", fname, env.
count);
6596 printf(
"=== end function %s ===\n", fname);
6610 int lidx = local_find(fname);
6612 lidx = local_add(fname);
6616 g_locals = save_env;
6629 int gsym = sym_index(fname);
6632 g_locals = save_env;
6639 g_func_env_depth = saved_depth;
6649 if (starts_with(src,
len, *pos,
"for")) {
6651 skip_spaces(src,
len, pos);
6658 if (*pos <
len && src[*pos] ==
'(') {
6661 skip_spaces(src,
len, pos);
6662 if (!read_identifier_into(src,
len, pos, &ivar)) {
6663 parser_fail(*pos,
"Expected identifier after '(' in for tuple");
6666 skip_spaces(src,
len, pos);
6667 if (!consume_char(src,
len, pos,
',')) {
6668 parser_fail(*pos,
"Expected ',' between key and value in for tuple");
6672 skip_spaces(src,
len, pos);
6673 if (!read_identifier_into(src,
len, pos, &vvar)) {
6674 parser_fail(*pos,
"Expected value identifier after ',' in for tuple");
6678 skip_spaces(src,
len, pos);
6679 if (!consume_char(src,
len, pos,
')')) {
6680 parser_fail(*pos,
"Expected ')' to close for tuple");
6688 if (!read_identifier_into(src,
len, pos, &ivar)) {
6689 parser_fail(*pos,
"Expected loop variable after 'for'");
6694 skip_spaces(src,
len, pos);
6695 if (!starts_with(src,
len, *pos,
"in")) {
6696 parser_fail(*pos,
"Expected 'in' after loop variable");
6701 skip_spaces(src,
len, pos);
6703 if (starts_with(src,
len, *pos,
"range")) {
6706 if (!consume_char(src,
len, pos,
'(')) {
6707 parser_fail(*pos,
"Expected '(' after range");
6713 if (!emit_expression(bc, src,
len, pos)) {
6714 parser_fail(*pos,
"Expected start expression in range");
6720 int lidx = local_find(ivar);
6724 lidx = local_add(ivar);
6726 gi = sym_index(ivar);
6735 skip_spaces(src,
len, pos);
6736 if (*pos >=
len || src[*pos] !=
',') {
6737 parser_fail(*pos,
"Expected ',' between range start and end");
6742 skip_spaces(src,
len, pos);
6745 if (!emit_expression(bc, src,
len, pos)) {
6746 parser_fail(*pos,
"Expected end expression in range");
6752 snprintf(tmpname,
sizeof(tmpname),
"__for_end_%d", g_temp_counter++);
6754 int lend = -1, gend = -1;
6756 lend = local_add(tmpname);
6759 gend = sym_index(tmpname);
6763 if (!consume_char(src,
len, pos,
')')) {
6764 parser_fail(*pos,
"Expected ')' after range arguments");
6770 skip_to_eol(src,
len, pos);
6790 LoopCtx ctx = {{0}, 0, {0}, 0, g_loop_ctx};
6794 int body_indent = 0;
6795 size_t look_body = *pos;
6796 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6797 parse_block(bc, src,
len, pos, body_indent);
6827 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
6833 g_loop_ctx = ctx.
prev;
6837 }
else if (!tuple_mode) {
6840 if (!emit_expression(bc, src,
len, pos)) {
6841 parser_fail(*pos,
"Expected iterable expression after 'in'");
6846 snprintf(arrname,
sizeof(arrname),
"__for_arr_%d", g_temp_counter++);
6847 int larr = -1, garr = -1;
6849 larr = local_add(arrname);
6852 garr = sym_index(arrname);
6864 snprintf(lenname,
sizeof(lenname),
"__for_len_%d", g_temp_counter++);
6865 int llen = -1, glen = -1;
6867 llen = local_add(lenname);
6870 glen = sym_index(lenname);
6878 snprintf(iname,
sizeof(iname),
"__for_i_%d", g_temp_counter++);
6879 int li = -1, gi = -1;
6881 li = local_add(iname);
6884 gi = sym_index(iname);
6889 skip_to_eol(src,
len, pos);
6922 int ldst = local_find(ivar);
6926 ldst = local_add(ivar);
6928 gdst = sym_index(ivar);
6937 LoopCtx ctx = {{0}, 0, {0}, 0, g_loop_ctx};
6941 int body_indent = 0;
6942 size_t look_body = *pos;
6943 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
6944 parse_block(bc, src,
len, pos, body_indent);
6974 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
6980 g_loop_ctx = ctx.
prev;
6987 if (!emit_expression(bc, src,
len, pos)) {
6988 parser_fail(*pos,
"Expected map expression after 'in'");
6994 snprintf(mapname,
sizeof(mapname),
"__for_map_%d", g_temp_counter++);
6995 int lmap = -1, gmap = -1;
6997 lmap = local_add(mapname);
7000 gmap = sym_index(mapname);
7012 snprintf(keysname,
sizeof(keysname),
"__for_keys_%d", g_temp_counter++);
7013 int lkeys = -1, gkeys = -1;
7015 lkeys = local_add(keysname);
7018 gkeys = sym_index(keysname);
7030 snprintf(lenname,
sizeof(lenname),
"__for_klen_%d", g_temp_counter++);
7031 int llen = -1, glen = -1;
7033 llen = local_add(lenname);
7036 glen = sym_index(lenname);
7044 snprintf(iname,
sizeof(iname),
"__for_ki_%d", g_temp_counter++);
7045 int li = -1, gi = -1;
7047 li = local_add(iname);
7050 gi = sym_index(iname);
7055 skip_to_eol(src,
len, pos);
7087 int lk = local_find(ivar);
7091 lk = local_add(ivar);
7093 gk = sym_index(ivar);
7116 int lv = local_find(vvar);
7120 lv = local_add(vvar);
7122 gv = sym_index(vvar);
7131 LoopCtx ctx = {{0}, 0, {0}, 0, g_loop_ctx};
7135 int body_indent = 0;
7136 size_t look_body = *pos;
7137 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
7138 parse_block(bc, src,
len, pos, body_indent);
7166 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
7172 g_loop_ctx = ctx.
prev;
7180 if (starts_with(src,
len, *pos,
"if")) {
7186 if (starts_with(src,
len, *pos,
"if")) {
7193 skip_spaces(src,
len, pos);
7194 if (!emit_expression(bc, src,
len, pos)) {
7201 size_t ppeek = *pos;
7203 while (ppeek <
len && src[ppeek] ==
' ')
7205 int inline_stmt = 0;
7207 if (src[ppeek] ==
'\r' || src[ppeek] ==
'\n') {
7209 }
else if (ppeek + 1 <
len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'/') {
7211 }
else if (ppeek + 1 <
len && src[ppeek] ==
'/' && src[ppeek + 1] ==
'*') {
7225 parse_simple_statement(bc, src,
len, pos);
7233 skip_to_eol(src,
len, pos);
7236 int next_indent = 0;
7237 size_t look_next = *pos;
7238 if (read_line_start(src,
len, &look_next, &next_indent)) {
7239 if (next_indent > current_indent) {
7241 parse_block(bc, src,
len, pos, next_indent);
7251 if (end_count < (
int)(
sizeof(end_jumps) /
sizeof(end_jumps[0]))) {
7252 end_jumps[end_count++] = jmp_end;
7254 parser_fail(*pos,
"Too many chained else/if clauses");
7263 int look_indent = 0;
7264 if (!read_line_start(src,
len, &look, &look_indent)) {
7268 if (look_indent != current_indent) {
7272 if (starts_with(src,
len, look,
"else")) {
7275 skip_spaces(src,
len, pos);
7277 if (starts_with(src,
len, *pos,
"if")) {
7283 skip_to_eol(src,
len, pos);
7284 int else_indent = 0;
7285 size_t look_else = *pos;
7286 if (read_line_start(src,
len, &look_else, &else_indent) && else_indent > current_indent) {
7288 parse_block(bc, src,
len, pos, else_indent);
7302 for (
int i = 0; i < end_count; ++i) {
7309 if (starts_with(src,
len, *pos,
"while")) {
7311 skip_spaces(src,
len, pos);
7316 if (!emit_expression(bc, src,
len, pos)) {
7321 skip_to_eol(src,
len, pos);
7327 LoopCtx ctx = {{0}, 0, {0}, 0, g_loop_ctx};
7331 int body_indent = 0;
7332 size_t look_body = *pos;
7333 if (read_line_start(src,
len, &look_body, &body_indent) && body_indent > current_indent) {
7334 parse_block(bc, src,
len, pos, body_indent);
7340 for (
int bi = 0; bi < ctx.
cont_count; ++bi) {
7353 g_loop_ctx = ctx.
prev;
7358 if (starts_with(src,
len, *pos,
"try")) {
7362 skip_to_eol(src,
len, pos);
7368 int try_body_indent = 0;
7369 size_t look_try = *pos;
7370 if (read_line_start(src,
len, &look_try, &try_body_indent) && try_body_indent > current_indent) {
7371 parse_block(bc, src,
len, pos, try_body_indent);
7384 int seen_finally = 0;
7385 int catch_label = -1;
7388 int look_indent = 0;
7389 if (!read_line_start(src,
len, &look, &look_indent))
break;
7390 if (look_indent != current_indent)
break;
7392 if (!seen_catch && starts_with(src,
len, look,
"catch")) {
7396 skip_spaces(src,
len, pos);
7397 char *ex_name = NULL;
7400 if (read_identifier_into(src,
len, &tmp, &ex_name)) {
7405 skip_to_eol(src,
len, pos);
7413 int lidx = -1, gi = -1;
7415 int existing = local_find(ex_name);
7419 lidx = local_add(ex_name);
7421 gi = sym_index(ex_name);
7432 if (ex_name)
free(ex_name);
7435 int catch_indent = 0;
7436 size_t look_catch = *pos;
7437 if (read_line_start(src,
len, &look_catch, &catch_indent) && catch_indent > current_indent) {
7438 parse_block(bc, src,
len, pos, catch_indent);
7446 if (!seen_finally && starts_with(src,
len, look,
"finally")) {
7450 skip_to_eol(src,
len, pos);
7453 int finally_indent = 0;
7454 size_t look_fin = *pos;
7455 if (read_line_start(src,
len, &look_fin, &finally_indent) && finally_indent > current_indent) {
7456 parse_block(bc, src,
len, pos, finally_indent);
7483 parse_simple_statement(bc, src,
len, pos);
7498static Bytecode *compile_minimal(
const char *src,
size_t len) {
7504 ns_aliases_scan(src,
len);
7506 skip_shebang_if_present(src,
len, &pos);
7509 skip_comments(src,
len, &pos);
7510 skip_ws(src,
len, &pos);
7513 parse_block(bc, src,
len, &pos, 0);
7531 char *src = read_file_all(
path, &
len);
7533 fprintf(stderr,
"Error: cannot read file: %s\n",
path);
7539 const char *compile_src = prep ? prep : src;
7540 size_t compile_len = strlen(compile_src);
7545 g_err_msg[0] =
'\0';
7550 const char *prev_source = g_current_source_path;
7551 g_current_source_path =
path;
7552 Bytecode *bc = compile_minimal(compile_src, compile_len);
7559 const char *bn =
path ? strrchr(
path,
'/') : NULL;
7560 const char *
base = bn ? bn + 1 : (
path ?
path :
"<input>");
7564 g_current_source_path = prev_source;
7567 int line = 1, col = 1;
7568 calc_line_col(compile_src, compile_len, g_err_pos, &line, &col);
7577 const char *marker0 =
"// __include_begin__: ";
7578 size_t m0 = strlen(marker0);
7582 if (compile_len >= 2 && compile_src[0] ==
'#' && compile_src[1] ==
'!') {
7584 while (
start < compile_len && compile_src[
start] !=
'\n' && compile_src[
start] !=
'\r')
start++;
7585 if (
start < compile_len && compile_src[
start] ==
'\r') {
7588 }
else if (
start < compile_len && compile_src[
start] ==
'\n') {
7596 while (eol0 < compile_len && compile_src[eol0] !=
'\n') eol0++;
7598 if (ls + m0 <= compile_len && strncmp(compile_src + ls, marker0, m0) == 0) {
7600 if (g_err_pos > eol0) {
7601 if (line > 1) line -= 1;
7610 const char *marker =
"// __include_begin__: ";
7611 size_t mlen = strlen(marker);
7612 int inner_line = -1;
7617 size_t scan = g_err_pos;
7621 while (ls > 0 && compile_src[ls - 1] !=
'\n')
7624 if (ls + mlen <= compile_len && strncmp(compile_src + ls, marker, mlen) == 0) {
7626 size_t p = ls + mlen;
7628 while (eol < compile_len && compile_src[eol] !=
'\n') eol++;
7630 size_t pos_as = eol, pos_line = eol;
7631 for (
size_t t =
p;
t + 3 < eol; ++
t) {
7632 if (compile_src[
t] ==
' ' && strncmp(compile_src +
t,
" as ", 4) == 0) { pos_as =
t;
break; }
7634 for (
size_t t =
p;
t + 6 < eol; ++
t) {
7635 if (compile_src[
t] ==
' ' && strncmp(compile_src +
t,
" @line ", 7) == 0) { pos_line =
t;
break; }
7637 size_t path_end = pos_as < pos_line ? pos_as : pos_line;
7638 if (path_end <
p) path_end = eol;
7639 size_t copy = (path_end -
p) <
sizeof(inc_path) - 1 ? (path_end -
p) :
sizeof(inc_path) - 1;
7640 memcpy(inc_path, compile_src +
p, copy);
7641 inc_path[copy] =
'\0';
7645 if (pos_line < eol) {
7646 size_t num_start = pos_line + 7;
7647 while (num_start < eol && compile_src[num_start] ==
' ') num_start++;
7649 while (num_start < eol && compile_src[num_start] >=
'0' && compile_src[num_start] <=
'9') {
7650 v =
v * 10 + (compile_src[num_start] -
'0');
7653 if (
v > 0) base_line =
v;
7658 size_t q = (eol < compile_len && compile_src[eol] ==
'\n') ? (eol + 1) : eol;
7659 while (q < g_err_pos) {
7660 if (compile_src[q] ==
'\n')
count++;
7671 if (inner_line > 0 && inc_path[0] !=
'\0') {
7673 int shebang_adjust = 0;
7674 FILE *sf = fopen(inc_path,
"rb");
7678 if (c1 ==
'#' && c2 ==
'!') shebang_adjust = 1;
7681 int mapped_inner = inner_line + (base_line - 1) + shebang_adjust;
7683 if (
path && strcmp(
path, inc_path) == 0) {
7684 fprintf(stderr,
"Parse error %s:%d:%d: %s\n",
7685 path, line, col, g_err_msg);
7687 fprintf(stderr,
"Parse error %s:%d:%d: %s (in %s:%d)\n",
7688 path ?
path :
"<input>", line, col, g_err_msg, inc_path, mapped_inner);
7691 fprintf(stderr,
"Parse error %s:%d:%d: %s\n",
path ?
path :
"<input>", line, col, g_err_msg);
7695 if (prep)
free(prep);
7700 if (prep)
free(prep);
7716 fprintf(stderr,
"Error: null source provided\n");
7722 const char *compile_src = prep ? prep : source;
7723 size_t len = strlen(compile_src);
7728 g_err_msg[0] =
'\0';
7733 const char *prev_src = g_current_source_path;
7734 g_current_source_path = NULL;
7740 bc->
name = strdup(
"<input>");
7742 g_current_source_path = prev_src;
7745 int line = 1, col = 1;
7746 calc_line_col(compile_src,
len, g_err_pos, &line, &col);
7750 if (prep)
free(prep);
7753 if (prep)
free(prep);
7771 if (!g_has_error)
return 0;
7772 if (msgBuf && msgCap > 0) {
7773 snprintf(msgBuf, msgCap,
"%s", g_err_msg);
7775 if (outLine) *outLine = g_err_line;
7776 if (outCol) *outCol = g_err_col;
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]
#define TYPE_META_NIL
Type metadata tag indicating explicit nil type.
char * names[MAX_GLOBALS]
#define TYPE_META_BOOLEAN
Type metadata tag used for boolean enforcement in declared types.
#define TYPE_META_ARRAY
Type metadata tag marking array values.
#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.
int parser_last_error(char *msgBuf, unsigned long msgCap, int *outLine, int *outCol)
Retrieve the last parser/compiler error information, if any.
#define TYPE_META_CLASS
Type metadata tag marking class/instance values.
#define TYPE_META_STRING
Type metadata tag used for string enforcement in declared types.
char * preprocess_includes_with_path(const char *src, const char *current_path)
Preprocess includes with a known file path to improve span markers.
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.
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.