#define _POSIX_C_SOURCE 200809L #include "repl_commands.h" #include "repl_output.h" #include #include #include #include static RavaREPLCommandDef_t commands[] = { {"%help", NULL, "Show help for commands", RAVA_CMD_HELP}, {"%whos", NULL, "List all variables with types", RAVA_CMD_WHOS}, {"%who", NULL, "List all variable names", RAVA_CMD_WHO}, {"%reset", NULL, "Clear all session state", RAVA_CMD_RESET}, {"%clear", NULL, "Clear screen", RAVA_CMD_CLEAR}, {"%quit", "%exit", "Exit REPL", RAVA_CMD_QUIT}, {"%history", NULL, "Show input history", RAVA_CMD_HISTORY}, {"%run", NULL, "Run a Java file", RAVA_CMD_RUN}, {"%load", NULL, "Load file contents", RAVA_CMD_LOAD}, {"%save", NULL, "Save session to file", RAVA_CMD_SAVE}, {"%debug", NULL, "Toggle debug mode", RAVA_CMD_DEBUG}, {"%time", NULL, "Time single execution", RAVA_CMD_TIME}, {"%timeit", NULL, "Time repeated executions", RAVA_CMD_TIMEIT}, {"%memory", NULL, "Show memory usage", RAVA_CMD_MEMORY}, {"%dir", NULL, "List object fields/methods", RAVA_CMD_DIR}, {"%type", NULL, "Show variable type info", RAVA_CMD_TYPE}, {"%source", NULL, "Show class source", RAVA_CMD_SOURCE}, {"%methods", NULL, "List session methods", RAVA_CMD_METHODS}, {"%classes", NULL, "List session classes", RAVA_CMD_CLASSES}, {NULL, NULL, NULL, RAVA_CMD_UNKNOWN} }; bool rava_repl_command_is_command(const char *input) { if (!input) return false; while (*input && isspace(*input)) input++; return *input == '%'; } RavaREPLCommand_e rava_repl_command_parse(const char *input, char **arg) { if (!input) return RAVA_CMD_UNKNOWN; while (*input && isspace(*input)) input++; if (*input != '%') return RAVA_CMD_UNKNOWN; const char *end = input; while (*end && !isspace(*end)) end++; size_t cmd_len = end - input; while (*end && isspace(*end)) end++; if (arg) { *arg = (*end) ? strdup(end) : NULL; } for (int i = 0; commands[i].name; i++) { if (strlen(commands[i].name) == cmd_len && strncmp(commands[i].name, input, cmd_len) == 0) { return commands[i].command; } if (commands[i].alias && strlen(commands[i].alias) == cmd_len && strncmp(commands[i].alias, input, cmd_len) == 0) { return commands[i].command; } } return RAVA_CMD_UNKNOWN; } bool rava_repl_command_execute(RavaREPLSession_t *session, RavaREPLCommand_e cmd, const char *arg) { switch (cmd) { case RAVA_CMD_HELP: rava_repl_command_help(arg); return true; case RAVA_CMD_WHOS: rava_repl_output_variables(session); return true; case RAVA_CMD_WHO: if (session->variable_count == 0) { printf("No variables defined.\n"); } else { for (size_t i = 0; i < session->variable_count; i++) { printf("%s\n", session->variables[i].name); } } return true; case RAVA_CMD_RESET: rava_repl_session_clear_variables(session); printf("Session reset. All variables cleared.\n"); return true; case RAVA_CMD_CLEAR: printf("\033[2J\033[H"); return true; case RAVA_CMD_QUIT: return false; case RAVA_CMD_HISTORY: { int count = 20; if (arg) { count = atoi(arg); if (count <= 0) count = 20; } size_t start = 0; if (session->history->count > (size_t)count) { start = session->history->count - count; } for (size_t i = start; i < session->history->count; i++) { printf("[%zu] %s\n", i + 1, session->history->entries[i]); } return true; } case RAVA_CMD_RUN: if (!arg || strlen(arg) == 0) { printf("Usage: %%run \n"); } else { printf("Loading %s...\n", arg); FILE *f = fopen(arg, "r"); if (!f) { printf("Error: Cannot open file '%s'\n", arg); } else { fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, 0, SEEK_SET); char *content = malloc(size + 1); if (content) { size_t read_size = fread(content, 1, size, f); content[read_size] = '\0'; printf("Loaded %ld bytes.\n", size); free(content); } fclose(f); } } return true; case RAVA_CMD_DEBUG: session->debug_mode = !session->debug_mode; printf("Debug mode: %s\n", session->debug_mode ? "ON" : "OFF"); return true; case RAVA_CMD_MEMORY: printf("Memory usage information not available.\n"); return true; case RAVA_CMD_METHODS: rava_repl_output_methods(session); return true; case RAVA_CMD_CLASSES: rava_repl_output_classes(session); return true; case RAVA_CMD_TYPE: if (!arg || strlen(arg) == 0) { printf("Usage: %%type \n"); } else { RavaREPLVariable_t *var = rava_repl_session_get_variable(session, arg); if (var) { printf("%s: %s\n", var->name, var->type_name ? var->type_name : "unknown"); } else { printf("Variable '%s' not found.\n", arg); } } return true; case RAVA_CMD_SOURCE: if (!arg || strlen(arg) == 0) { printf("Usage: %%source \n"); } else { RavaREPLClass_t *cls = rava_repl_session_get_class(session, arg); if (cls && cls->source) { printf("%s\n", cls->source); } else { printf("Class '%s' not found.\n", arg); } } return true; case RAVA_CMD_SAVE: if (!arg || strlen(arg) == 0) { printf("Usage: %%save \n"); } else { char *source = rava_repl_session_generate_source(session); if (source) { FILE *f = fopen(arg, "w"); if (f) { fprintf(f, "%s", source); fclose(f); printf("Session saved to %s\n", arg); } else { printf("Error: Cannot write to '%s'\n", arg); } free(source); } } return true; default: printf("Unknown command.\n"); return true; } } void rava_repl_command_help(const char *topic) { if (!topic || strlen(topic) == 0) { printf("Available commands:\n\n"); for (int i = 0; commands[i].name; i++) { printf(" %-12s %s\n", commands[i].name, commands[i].description); } printf("\nType %%help for detailed help.\n"); } else { for (int i = 0; commands[i].name; i++) { if (strcmp(commands[i].name + 1, topic) == 0 || strcmp(commands[i].name, topic) == 0) { printf("%s - %s\n", commands[i].name, commands[i].description); return; } } printf("Unknown command: %s\n", topic); } } void rava_repl_command_list_all(void) { for (int i = 0; commands[i].name; i++) { printf("%s\n", commands[i].name); } }