|
#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);
|
|
}
|
|
}
|