230 lines
8.2 KiB
C
Raw Normal View History

2025-12-05 12:32:09 +01:00
#define _POSIX_C_SOURCE 200809L
#include "repl_commands.h"
#include "repl_output.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
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 <filename>\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 <variable>\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 <classname>\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 <filename>\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 <command> 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);
}
}