Mercurial > repos > blastem
comparison debug.c @ 2665:54ac5fe14cf9
Allow calling functions directly as if they were commands
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 07 Mar 2025 21:45:53 -0800 |
parents | b0f314b19964 |
children | 7e86ec94c899 |
comparison
equal
deleted
inserted
replaced
2664:36ae207af490 | 2665:54ac5fe14cf9 |
---|---|
1487 if (func->is_native) { | 1487 if (func->is_native) { |
1488 *out = func->impl.native(args, num_args); | 1488 *out = func->impl.native(args, num_args); |
1489 free(args); | 1489 free(args); |
1490 return 1; | 1490 return 1; |
1491 } else { | 1491 } else { |
1492 //TODO: Implement me | |
1493 debug_root *func_root = calloc(1, sizeof(debug_root)); | 1492 debug_root *func_root = calloc(1, sizeof(debug_root)); |
1494 for (int i = 0; i < num_args; i++) | 1493 for (int i = 0; i < num_args; i++) |
1495 { | 1494 { |
1496 new_user_variable(func_root, func->arg_names[i], args[i]); | 1495 new_user_variable(func_root, func->arg_names[i], args[i]); |
1497 } | 1496 } |
2096 } | 2095 } |
2097 | 2096 |
2098 uint8_t parse_command(debug_root *root, char *text, parsed_command *out) | 2097 uint8_t parse_command(debug_root *root, char *text, parsed_command *out) |
2099 { | 2098 { |
2100 char *cur = text; | 2099 char *cur = text; |
2100 uint8_t is_func = 0; | |
2101 while (*cur && *cur != '/' && !isspace(*cur)) | 2101 while (*cur && *cur != '/' && !isspace(*cur)) |
2102 { | 2102 { |
2103 if (*cur == '(') { | |
2104 is_func = 1; | |
2105 break; | |
2106 } | |
2103 ++cur; | 2107 ++cur; |
2104 } | 2108 } |
2105 char *name = malloc(cur - text + 1); | 2109 char *name = malloc(cur - text + 1); |
2106 memcpy(name, text, cur - text); | 2110 memcpy(name, text, cur - text); |
2107 name[cur-text] = 0; | 2111 name[cur-text] = 0; |
2108 uint8_t ret = 0; | 2112 uint8_t ret = 0; |
2109 tern_node *prefix_res = tern_find_prefix(root->commands, name); | 2113 char *format = NULL; |
2110 command_def *def = tern_find_ptr(prefix_res, ""); | 2114 debug_func *func = NULL; |
2111 if (!def) { | 2115 command_def *def = NULL; |
2112 tern_node *node = prefix_res; | 2116 if (is_func) { |
2113 while (node) | 2117 char *start = name; |
2118 for (char *ncur = name; *ncur; ncur++) | |
2114 { | 2119 { |
2115 if (node->left || node->right) { | 2120 if (*ncur == ':') { |
2116 break; | 2121 char *nspace = malloc(ncur - start + 1); |
2117 } | 2122 memcpy(nspace, start, ncur - start); |
2118 if (node->el) { | 2123 nspace[ncur - start] = 0; |
2119 node = node->straight.next; | 2124 root = tern_find_ptr(root->other_roots, nspace); |
2120 } else { | 2125 if (!root) { |
2121 def = node->straight.value.ptrval; | 2126 fprintf(stderr, "%s is not a valid namespace\n", nspace); |
2122 break; | 2127 free(nspace); |
2123 } | 2128 goto cleanup_name; |
2124 } | 2129 } |
2125 if (!def && prefix_res) { | 2130 start = ncur + 1; |
2126 fprintf(stderr, "%s is ambiguous. Matching commands:\n", name); | 2131 } |
2127 tern_foreach(prefix_res, ambiguous_iter, name); | 2132 } |
2133 debug_var *var = tern_find_ptr(root->variables, start); | |
2134 if (!var) { | |
2135 fprintf(stderr, "%s is not defined\n", name); | |
2128 goto cleanup_name; | 2136 goto cleanup_name; |
2129 } | 2137 } |
2130 } | 2138 debug_val val = var->get(var); |
2131 if (!def) { | 2139 if (val.type != DBG_VAL_FUNC) { |
2132 fprintf(stderr, "%s is not a recognized command\n", name); | 2140 fprintf(stderr, "%s is not a function\n", name); |
2133 goto cleanup_name; | 2141 goto cleanup_name; |
2134 } | 2142 } |
2135 char *format = NULL; | 2143 func = funcs + val.v.u32; |
2136 if (*cur == '/') { | 2144 } else { |
2137 ++cur; | 2145 tern_node *prefix_res = tern_find_prefix(root->commands, name); |
2138 text = cur; | 2146 def = tern_find_ptr(prefix_res, ""); |
2139 while (*cur && !isspace(*cur)) | 2147 if (!def) { |
2140 { | 2148 tern_node *node = prefix_res; |
2149 while (node) | |
2150 { | |
2151 if (node->left || node->right) { | |
2152 break; | |
2153 } | |
2154 if (node->el) { | |
2155 node = node->straight.next; | |
2156 } else { | |
2157 def = node->straight.value.ptrval; | |
2158 break; | |
2159 } | |
2160 } | |
2161 if (!def && prefix_res) { | |
2162 fprintf(stderr, "%s is ambiguous. Matching commands:\n", name); | |
2163 tern_foreach(prefix_res, ambiguous_iter, name); | |
2164 goto cleanup_name; | |
2165 } | |
2166 } | |
2167 if (!def) { | |
2168 fprintf(stderr, "%s is not a recognized command\n", name); | |
2169 goto cleanup_name; | |
2170 } | |
2171 if (*cur == '/') { | |
2141 ++cur; | 2172 ++cur; |
2142 } | 2173 text = cur; |
2143 format = malloc(cur - text + 1); | 2174 while (*cur && !isspace(*cur)) |
2144 memcpy(format, text, cur - text); | 2175 { |
2145 format[cur - text] = 0; | 2176 ++cur; |
2146 } | 2177 } |
2178 format = malloc(cur - text + 1); | |
2179 memcpy(format, text, cur - text); | |
2180 format[cur - text] = 0; | |
2181 } | |
2182 } | |
2183 | |
2147 int num_args = 0; | 2184 int num_args = 0; |
2148 command_arg *args = NULL; | 2185 command_arg *args = NULL; |
2149 if (*cur && *cur != '\n') { | 2186 if (*cur && *cur != '\n') { |
2150 ++cur; | 2187 ++cur; |
2151 } | 2188 } |
2152 text = cur; | 2189 text = cur; |
2153 if (def->raw_args) { | 2190 if (def && def->raw_args) { |
2154 while (*cur && *cur != '\n') | 2191 while (*cur && *cur != '\n') |
2155 { | 2192 { |
2156 ++cur; | 2193 ++cur; |
2157 } | 2194 } |
2158 char *raw_param = NULL; | 2195 char *raw_param = NULL; |
2164 out->raw = raw_param; | 2201 out->raw = raw_param; |
2165 out->args = NULL; | 2202 out->args = NULL; |
2166 out->num_args = 0; | 2203 out->num_args = 0; |
2167 } else { | 2204 } else { |
2168 int arg_storage = 0; | 2205 int arg_storage = 0; |
2169 if (def->max_args > 0) { | 2206 int32_t max_args = def ? def->max_args : func->max_args; |
2170 arg_storage = def->max_args; | 2207 int32_t min_args = def ? def->min_args : func->min_args; |
2171 } else if (def->max_args) { | 2208 if (max_args > 0) { |
2172 arg_storage = def->min_args > 0 ? 2 * def->min_args : 2; | 2209 arg_storage = max_args; |
2210 } else if (max_args) { | |
2211 arg_storage = min_args > 0 ? 2 * min_args : 2; | |
2173 } | 2212 } |
2174 if (arg_storage) { | 2213 if (arg_storage) { |
2175 args = calloc(arg_storage, sizeof(command_arg)); | 2214 args = calloc(arg_storage, sizeof(command_arg)); |
2176 } | 2215 } |
2177 while (*text && *text != '\n') | 2216 while (*text && *text != '\n' && (!is_func || *text != ')')) |
2178 { | 2217 { |
2179 char *after; | 2218 char *after; |
2180 expr *e = parse_expression(text, &after); | 2219 expr *e = parse_expression(text, &after); |
2181 if (e) { | 2220 if (e) { |
2182 if (num_args == arg_storage) { | 2221 if (num_args == arg_storage) { |
2183 if (def->max_args >= 0) { | 2222 if (max_args >= 0) { |
2184 free_expr(e); | 2223 free_expr(e); |
2185 fprintf(stderr, "Command %s takes a max of %d arguments, but at least %d provided\n", name, def->max_args, def->max_args+1); | 2224 fprintf(stderr, "Command %s takes a max of %d arguments, but at least %d provided\n", name, max_args, max_args+1); |
2186 goto cleanup_args; | 2225 goto cleanup_args; |
2187 } else { | 2226 } else { |
2188 arg_storage *= 2; | 2227 arg_storage *= 2; |
2189 args = realloc(args, arg_storage * sizeof(command_arg)); | 2228 args = realloc(args, arg_storage * sizeof(command_arg)); |
2190 } | 2229 } |
2196 text = after; | 2235 text = after; |
2197 } else { | 2236 } else { |
2198 goto cleanup_args; | 2237 goto cleanup_args; |
2199 } | 2238 } |
2200 } | 2239 } |
2201 if (num_args < def->min_args) { | 2240 if (num_args < min_args) { |
2202 fprintf(stderr, "Command %s requires at least %d arguments, but only %d provided\n", name, def->min_args, num_args); | 2241 fprintf(stderr, "Command %s requires at least %d arguments, but only %d provided\n", name, min_args, num_args); |
2203 goto cleanup_args; | 2242 goto cleanup_args; |
2204 } | 2243 } |
2205 out->raw = NULL; | 2244 out->raw = NULL; |
2206 out->args = args; | 2245 out->args = args; |
2207 out->num_args = num_args; | 2246 out->num_args = num_args; |
2208 } | 2247 } |
2209 out->def = def; | 2248 out->def = def; |
2249 out->func = func ? func - funcs : 0; | |
2210 out->format = format; | 2250 out->format = format; |
2211 | 2251 |
2212 ret = 1; | 2252 ret = 1; |
2213 cleanup_args: | 2253 cleanup_args: |
2214 if (!ret) { | 2254 if (!ret) { |
2304 if (!strcmp(stripped, "end")) { | 2344 if (!strcmp(stripped, "end")) { |
2305 return END; | 2345 return END; |
2306 } | 2346 } |
2307 } | 2347 } |
2308 if (parse_command(root, input_buf, out)) { | 2348 if (parse_command(root, input_buf, out)) { |
2309 if (!out->def->has_block) { | 2349 if (!out->def || !out->def->has_block) { |
2310 return NORMAL; | 2350 return NORMAL; |
2311 } | 2351 } |
2312 int command_storage = 4; | 2352 int command_storage = 4; |
2313 command_block *block = &out->block; | 2353 command_block *block = &out->block; |
2314 block->commands = calloc(command_storage, sizeof(parsed_command)); | 2354 block->commands = calloc(command_storage, sizeof(parsed_command)); |
2347 return READ_FAILED; | 2387 return READ_FAILED; |
2348 } | 2388 } |
2349 | 2389 |
2350 static uint8_t run_command(debug_root *root, parsed_command *cmd) | 2390 static uint8_t run_command(debug_root *root, parsed_command *cmd) |
2351 { | 2391 { |
2352 if (!cmd->def->raw_args && !cmd->def->skip_eval) { | 2392 if (!cmd->def || (!cmd->def->raw_args && !cmd->def->skip_eval)) { |
2353 for (int i = 0; i < cmd->num_args; i++) | 2393 for (int i = 0; i < cmd->num_args; i++) |
2354 { | 2394 { |
2355 if (!eval_expr(root, cmd->args[i].parsed, &cmd->args[i].value)) { | 2395 if (!eval_expr(root, cmd->args[i].parsed, &cmd->args[i].value)) { |
2356 fprintf(stderr, "Failed to eval %s\n", cmd->args[i].raw); | 2396 fprintf(stderr, "Failed to eval %s\n", cmd->args[i].raw); |
2357 return 1; | 2397 return 1; |
2358 } | 2398 } |
2359 } | 2399 } |
2360 } | 2400 } |
2361 return cmd->def->impl(root, cmd); | 2401 if (cmd->def) { |
2402 return cmd->def->impl(root, cmd); | |
2403 } else { | |
2404 debug_func *func = funcs + cmd->func; | |
2405 if (func->is_native) { | |
2406 debug_val *args = calloc(cmd->num_args, sizeof(debug_val)); | |
2407 for (int i = 0; i < cmd->num_args; i++) | |
2408 { | |
2409 args[i] = cmd->args[i].value; | |
2410 } | |
2411 func->impl.native(args, cmd->num_args); | |
2412 free(args); | |
2413 } else { | |
2414 debug_root *func_root = calloc(1, sizeof(debug_root)); | |
2415 for (int i = 0; i < cmd->num_args; i++) | |
2416 { | |
2417 new_user_variable(func_root, func->arg_names[i], cmd->args[i].value); | |
2418 } | |
2419 func_root->other_roots = tern_insert_ptr(func_root->other_roots, "parent", root); | |
2420 execute_block(func_root, &func->impl.block); | |
2421 //FIXME: properly free root | |
2422 tern_free(func_root->variables); | |
2423 tern_free(func_root->other_roots); | |
2424 free(func_root); | |
2425 } | |
2426 return 1; | |
2427 } | |
2362 } | 2428 } |
2363 | 2429 |
2364 static void debugger_repl(debug_root *root) | 2430 static void debugger_repl(debug_root *root) |
2365 { | 2431 { |
2366 | 2432 |