From 235ceb6686d1163a34f426ac338ae6b0230f37ba Mon Sep 17 00:00:00 2001 From: Lev Babiev Date: Tue, 24 Dec 2024 17:18:35 +0000 Subject: [PATCH] vm: implement conditionals in user defined functions --- src/config/toplevel.c | 17 +++++++++++++---- src/vm/parser.c | 44 +++++++++++++++++++++++++++---------------- src/vm/vm.h | 2 +- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/config/toplevel.c b/src/config/toplevel.c index 2042e76..0a41c07 100644 --- a/src/config/toplevel.c +++ b/src/config/toplevel.c @@ -12,7 +12,13 @@ gboolean config_action ( GScanner *scanner, GBytes **action_dst ) { - *action_dst = parser_closure_parse(scanner); + GByteArray *code; + + code = g_byte_array_new(); + if(parser_block_parse(scanner, code)) + *action_dst = g_byte_array_free_to_bytes(code); + else + g_byte_array_unref(code); return !!*action_dst; } @@ -151,7 +157,7 @@ void config_menu_clear ( GScanner *scanner ) void config_function ( GScanner *scanner ) { gchar *name; - GBytes *action; + GByteArray *code; config_parse_sequence(scanner, SEQ_REQ, '(', NULL, NULL, "missing '(' after 'function'", @@ -161,8 +167,11 @@ void config_function ( GScanner *scanner ) if(!scanner->max_parse_errors) { - action = parser_closure_parse(scanner); - vm_func_add_user(name, action); + code = g_byte_array_new(); + if(parser_block_parse(scanner, code)) + vm_func_add_user(name, g_byte_array_free_to_bytes(code)); + else + g_byte_array_unref(code); } g_free(name); diff --git a/src/vm/parser.c b/src/vm/parser.c index 682fcc3..3c38d6d 100644 --- a/src/vm/parser.c +++ b/src/vm/parser.c @@ -47,7 +47,7 @@ static void parser_emit_na ( GByteArray *code ) static void parser_jump_backpatch ( GByteArray *code, gint olen, gint clen ) { - gint data = clen - olen; + gint data = clen - olen - sizeof(gint); memcpy(code->data + olen, &data, sizeof(gint)); } @@ -105,13 +105,13 @@ static gboolean parser_if ( GScanner *scanner, GByteArray *code ) return FALSE; /* JZ over len change + JMP instruction (1 + sizeof(gint)) */ - parser_jump_backpatch(code, alen, code->len + 1); + parser_jump_backpatch(code, alen, code->len + sizeof(gint) + 1); alen = parser_emit_jump(code, EXPR_OP_JMP); if(!parser_expr_parse(scanner, code)) return FALSE; /* JMP over len change */ - parser_jump_backpatch(code, alen, code->len - sizeof(gint)); + parser_jump_backpatch(code, alen, code->len); if(g_scanner_get_next_token(scanner)!=')') return FALSE; @@ -394,40 +394,52 @@ gboolean parser_action_parse ( GScanner *scanner, GByteArray *code ) if(cond) { - parser_jump_backpatch(code, alen, code->len + 1); + parser_jump_backpatch(code, alen, code->len + sizeof(gint) + 1); alen = parser_emit_jump(code, EXPR_OP_JMP); parser_emit_na(code); - parser_jump_backpatch(code, alen, code->len - sizeof(gint)); + parser_jump_backpatch(code, alen, code->len); } return TRUE; } -GBytes *parser_closure_parse ( GScanner *scanner ) +gboolean parser_block_parse ( GScanner *scanner, GByteArray *code ) { - GByteArray *code; + gint alen; static guint8 discard = EXPR_OP_DISCARD; - code = g_byte_array_new(); if(!config_check_and_consume(scanner, '{')) { if(!parser_action_parse(scanner, code)) - { - g_byte_array_free(code, TRUE); - return NULL; - } + return FALSE; } else { while(!config_check_and_consume(scanner, '}')) - if(!parser_action_parse(scanner, code)) + if(g_scanner_peek_next_token(scanner) == G_TOKEN_IDENTIFIER && + !g_ascii_strcasecmp(scanner->next_value.v_identifier, "if")) { - g_byte_array_free(code, TRUE); - return NULL; + g_scanner_get_next_token(scanner); + parser_expr_parse(scanner, code); + alen = parser_emit_jump(code, EXPR_OP_JZ); + parser_block_parse(scanner, code); + if(g_scanner_peek_next_token(scanner) == G_TOKEN_IDENTIFIER && + !g_ascii_strcasecmp(scanner->next_value.v_identifier, "else")) + { + g_scanner_get_next_token(scanner); + parser_jump_backpatch(code, alen, code->len + sizeof(gint) + 1); + alen = parser_emit_jump(code, EXPR_OP_JMP); + parser_block_parse(scanner, code); + parser_jump_backpatch(code, alen, code->len); + } + else + parser_jump_backpatch(code, alen, code->len); } + else if(!parser_action_parse(scanner, code)) + return FALSE; else g_byte_array_append(code, &discard, 1); } - return g_byte_array_free_to_bytes(code); + return TRUE; } diff --git a/src/vm/vm.h b/src/vm/vm.h index fcc8d22..32c5b61 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -53,7 +53,7 @@ typedef struct { #define vm_param_check_numeric(vm, p, n, fname) { if(!value_like_numeric(p[n])) { return value_na; } } GBytes *parser_expr_compile ( gchar *expr ); -GBytes *parser_closure_parse ( GScanner *scanner ); +gboolean parser_block_parse ( GScanner *scanner, GByteArray *code ); gboolean parser_expr_parse ( GScanner *scanner, GByteArray *code ); gboolean parser_macro_add ( GScanner *scanner ); const gchar *parser_identifier_lookup ( gchar *identifier );