# HG changeset patch # User Michael Pavone # Date 1699601420 28800 # Node ID 1fe5afe263f3385c749abe9c41030effdecc2560 # Parent 48cc69b4c3582b7c292e72138304ec224e10a93f Initial stab at user-defined functions in debugger language diff -r 48cc69b4c358 -r 1fe5afe263f3 debug.c --- a/debug.c Thu Nov 09 19:22:07 2023 -0800 +++ b/debug.c Thu Nov 09 23:30:20 2023 -0800 @@ -52,6 +52,21 @@ }; } +static debug_val new_user_func(command_block *block, char **args, int num_args) +{ + debug_func *f = alloc_func(); + f->impl.block = *block; + f->arg_names = args; + f->max_args = f->min_args = num_args; + f->is_native = 0; + return (debug_val) { + .v = { + .u32 = f - funcs + }, + .type = DBG_VAL_FUNC + }; +} + debug_val user_var_get(debug_var *var) { return var->val; @@ -1116,6 +1131,7 @@ } } +static uint8_t execute_block(debug_root *root, command_block * block); uint8_t eval_expr(debug_root *root, expr *e, debug_val *out) { debug_val right; @@ -1332,15 +1348,31 @@ for (int i = 0; i < num_args; i++) { if (!eval_expr(root, e->right + i, args + i)) { + free(args); return 0; } } if (func->is_native) { *out = func->impl.native(args, num_args); + free(args); + return 1; } else { //TODO: Implement me + debug_root *func_root = calloc(1, sizeof(debug_root)); + for (int i = 0; i < num_args; i++) + { + new_user_variable(func_root, func->arg_names[i], args[i]); + } + free(args); + func_root->other_roots = tern_insert_ptr(func_root->other_roots, "parent", root); + execute_block(func_root, &func->impl.block); + *out = func_root->retval; + //FIXME: properly free root + tern_free(func_root->variables); + tern_free(func_root->other_roots); + free(func_root); + return 1; } - return 1; default: return 0; } @@ -2568,9 +2600,9 @@ static uint8_t execute_block(debug_root *root, command_block * block) { uint8_t debugging = 1; - for (int i = 0; i < block->num_commands; i++) + for (int i = 0; i < block->num_commands && debugging; i++) { - debugging = run_command(root, block->commands + i) && debugging; + debugging = run_command(root, block->commands + i); } return debugging; } @@ -2605,6 +2637,53 @@ "EXPR_MEM" }; +static uint8_t cmd_function(debug_root *root, parsed_command *cmd) +{ + debug_root *set_root = root; + expr *set_expr = cmd->args[0].parsed; + while (set_expr->type == EXPR_NAMESPACE) + { + set_root = tern_find_ptr(set_root->other_roots, set_expr->op.v.str); + if (!set_root) { + fprintf(stderr, "%s is not a valid namespace\n", set_expr->op.v.str); + return 1; + } + set_expr = set_expr->left; + } + if (set_expr->type != EXPR_SCALAR || set_expr->op.type != TOKEN_NAME) { + fprintf(stderr, "Arguments to function must be names, bug argument 0 is %s\n", expr_type_names[set_expr->type]); + return 1; + } + debug_var *var = tern_find_ptr(set_root->variables, set_expr->op.v.str); + if (var) { + fprintf(stderr, "%s is already defined\n", set_expr->op.v.str); + return 1; + } + for (uint32_t i = 1; i < cmd->num_args; i++) + { + if (cmd->args[i].parsed->type != EXPR_SCALAR || cmd->args[i].parsed->op.type != TOKEN_NAME) { + fprintf(stderr, "Arguments to function must be names, bug argument %d is %s\n", i, expr_type_names[cmd->args[i].parsed->type]); + return 1; + } + } + char **args = calloc(cmd->num_args - 1, sizeof(char *)); + for (uint32_t i = 1; i < cmd->num_args; i++) + { + args[i - 1] = cmd->args[i].parsed->op.v.str; + cmd->args[i].parsed->op.v.str = NULL; + } + new_readonly_variable(set_root, set_expr->op.v.str, new_user_func(&cmd->block, args, cmd->num_args - 1)); + cmd->block.commands = NULL; + cmd->block.num_commands = 0; + return 1; +} + +static uint8_t cmd_return(debug_root *root, parsed_command *cmd) +{ + root->retval = cmd->args[0].value; + return 0; +} + static uint8_t cmd_set(debug_root *root, parsed_command *cmd) { char *name = NULL; @@ -3425,6 +3504,28 @@ }, { .names = (const char *[]){ + "function", NULL + }, + .usage = "function NAME [ARGS...]", + .desc = "Creates a user-defined function named NAME with arguments ARGS", + .impl = cmd_function, + .min_args = 1, + .max_args = -1, + .has_block = 1, + .skip_eval = 1 + }, + { + .names = (const char *[]){ + "return", NULL + }, + .usage = "return VALUE", + .desc = "Return from a user defined function with the result VALUE", + .impl = cmd_return, + .min_args = 1, + .max_args = 1 + }, + { + .names = (const char *[]){ "set", NULL }, .usage = "set MEM|NAME VALUE", diff -r 48cc69b4c358 -r 1fe5afe263f3 debug.h --- a/debug.h Thu Nov 09 19:22:07 2023 -0800 +++ b/debug.h Thu Nov 09 23:30:20 2023 -0800 @@ -155,9 +155,9 @@ typedef struct { union { debug_native_func native; - parsed_command *commands; + command_block block; } impl; - uint32_t num_commands; + char **arg_names; int max_args; int min_args; uint8_t is_native; @@ -190,6 +190,7 @@ reader read_mem; writer write_mem; parsed_command last_cmd; + debug_val retval; uint32_t bp_index; uint32_t disp_index; uint32_t branch_t;