#define _POSIX_C_SOURCE 200809L
#include "repl_session.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
RavaREPLSession_t* rava_repl_session_create(void) {
RavaREPLSession_t *session = calloc(1, sizeof(RavaREPLSession_t));
if (!session) return NULL;
session->variable_capacity = RAVA_REPL_MAX_VARIABLES;
session->variables = calloc(session->variable_capacity, sizeof(RavaREPLVariable_t));
if (!session->variables) {
free(session);
return NULL;
}
session->method_capacity = RAVA_REPL_MAX_METHODS;
session->methods = calloc(session->method_capacity, sizeof(RavaREPLMethod_t));
if (!session->methods) {
free(session->variables);
free(session);
return NULL;
}
session->class_capacity = RAVA_REPL_MAX_CLASSES;
session->classes = calloc(session->class_capacity, sizeof(RavaREPLClass_t));
if (!session->classes) {
free(session->methods);
free(session->variables);
free(session);
return NULL;
}
session->history = rava_repl_history_create(RAVA_REPL_MAX_HISTORY);
session->start_time = time(NULL);
session->debug_mode = false;
session->execution_count = 0;
session->program = NULL;
session->session_class = NULL;
session->vm = NULL;
session->last_error = NULL;
return session;
}
void rava_repl_session_destroy(RavaREPLSession_t *session) {
if (!session) return;
for (size_t i = 0; i < session->variable_count; i++) {
free(session->variables[i].name);
free(session->variables[i].type_name);
free(session->variables[i].initializer);
}
free(session->variables);
for (size_t i = 0; i < session->method_count; i++) {
free(session->methods[i].name);
free(session->methods[i].return_type);
free(session->methods[i].source);
for (size_t j = 0; j < session->methods[i].param_count; j++) {
free(session->methods[i].param_names[j]);
free(session->methods[i].param_types[j]);
}
free(session->methods[i].param_names);
free(session->methods[i].param_types);
}
free(session->methods);
for (size_t i = 0; i < session->class_count; i++) {
free(session->classes[i].name);
free(session->classes[i].source);
for (size_t j = 0; j < session->classes[i].field_count; j++) {
free(session->classes[i].field_names[j]);
free(session->classes[i].field_types[j]);
}
free(session->classes[i].field_names);
free(session->classes[i].field_types);
for (size_t j = 0; j < session->classes[i].method_count; j++) {
free(session->classes[i].method_names[j]);
}
free(session->classes[i].method_names);
}
free(session->classes);
rava_repl_history_destroy(session->history);
if (session->vm) {
rava_vm_destroy(session->vm);
}
if (session->program) {
rava_program_destroy(session->program);
}
free(session->last_error);
free(session);
}
bool rava_repl_session_add_variable(RavaREPLSession_t *session, const char *name,
const char *type_name, const char *initializer,
RavaValueType_e type, RavaValue_t value) {
if (!session || !name) return false;
RavaREPLVariable_t *existing = rava_repl_session_get_variable(session, name);
if (existing) {
free(existing->type_name);
free(existing->initializer);
existing->type_name = type_name ? strdup(type_name) : NULL;
existing->initializer = initializer ? strdup(initializer) : NULL;
existing->type = type;
existing->value = value;
existing->is_initialized = true;
return true;
}
if (session->variable_count >= session->variable_capacity) {
return false;
}
RavaREPLVariable_t *var = &session->variables[session->variable_count++];
var->name = strdup(name);
var->type_name = type_name ? strdup(type_name) : NULL;
var->initializer = initializer ? strdup(initializer) : NULL;
var->type = type;
var->value = value;
var->is_initialized = true;
return true;
}
RavaREPLVariable_t* rava_repl_session_get_variable(RavaREPLSession_t *session, const char *name) {
if (!session || !name) return NULL;
for (size_t i = 0; i < session->variable_count; i++) {
if (strcmp(session->variables[i].name, name) == 0) {
return &session->variables[i];
}
}
return NULL;
}
bool rava_repl_session_set_variable(RavaREPLSession_t *session, const char *name, RavaValue_t value) {
RavaREPLVariable_t *var = rava_repl_session_get_variable(session, name);
if (!var) return false;
var->value = value;
var->type = value.type;
return true;
}
void rava_repl_session_clear_variables(RavaREPLSession_t *session) {
if (!session) return;
for (size_t i = 0; i < session->variable_count; i++) {
free(session->variables[i].name);
free(session->variables[i].type_name);
free(session->variables[i].initializer);
}
session->variable_count = 0;
}
bool rava_repl_session_add_method(RavaREPLSession_t *session, const char *name,
const char *return_type, const char *source) {
if (!session || !name) return false;
RavaREPLMethod_t *existing = rava_repl_session_get_method(session, name);
if (existing) {
free(existing->return_type);
free(existing->source);
existing->return_type = return_type ? strdup(return_type) : NULL;
existing->source = source ? strdup(source) : NULL;
existing->compiled = NULL;
return true;
}
if (session->method_count >= session->method_capacity) {
return false;
}
RavaREPLMethod_t *method = &session->methods[session->method_count++];
method->name = strdup(name);
method->return_type = return_type ? strdup(return_type) : NULL;
method->source = source ? strdup(source) : NULL;
method->param_names = NULL;
method->param_types = NULL;
method->param_count = 0;
method->compiled = NULL;
return true;
}
RavaREPLMethod_t* rava_repl_session_get_method(RavaREPLSession_t *session, const char *name) {
if (!session || !name) return NULL;
for (size_t i = 0; i < session->method_count; i++) {
if (strcmp(session->methods[i].name, name) == 0) {
return &session->methods[i];
}
}
return NULL;
}
bool rava_repl_session_add_class(RavaREPLSession_t *session, const char *name, const char *source) {
if (!session || !name) return false;
RavaREPLClass_t *existing = rava_repl_session_get_class(session, name);
if (existing) {
free(existing->source);
existing->source = source ? strdup(source) : NULL;
existing->compiled = NULL;
return true;
}
if (session->class_count >= session->class_capacity) {
return false;
}
RavaREPLClass_t *cls = &session->classes[session->class_count++];
cls->name = strdup(name);
cls->source = source ? strdup(source) : NULL;
cls->field_names = NULL;
cls->field_types = NULL;
cls->field_count = 0;
cls->method_names = NULL;
cls->method_count = 0;
cls->compiled = NULL;
return true;
}
RavaREPLClass_t* rava_repl_session_get_class(RavaREPLSession_t *session, const char *name) {
if (!session || !name) return NULL;
for (size_t i = 0; i < session->class_count; i++) {
if (strcmp(session->classes[i].name, name) == 0) {
return &session->classes[i];
}
}
return NULL;
}
char* rava_repl_session_generate_source(RavaREPLSession_t *session) {
if (!session) return NULL;
size_t capacity = 4096;
char *source = malloc(capacity);
if (!source) return NULL;
size_t len = 0;
source[0] = '\0';
#define APPEND(...) do { \
int needed = snprintf(source + len, capacity - len, __VA_ARGS__); \
if (needed < 0) { free(source); return NULL; } \
if ((size_t)needed >= capacity - len) { \
capacity = capacity * 2 + needed; \
char *tmp = realloc(source, capacity); \
if (!tmp) { free(source); return NULL; } \
source = tmp; \
snprintf(source + len, capacity - len, __VA_ARGS__); \
} \
len += needed; \
} while(0)
for (size_t i = 0; i < session->class_count; i++) {
if (session->classes[i].source) {
APPEND("%s\n\n", session->classes[i].source);
}
}
APPEND("public class _REPL_Session_ {\n");
for (size_t i = 0; i < session->variable_count; i++) {
RavaREPLVariable_t *var = &session->variables[i];
const char *type = var->type_name ? var->type_name : "int";
APPEND(" public static %s %s;\n", type, var->name);
}
if (session->variable_count > 0) {
APPEND("\n");
}
for (size_t i = 0; i < session->method_count; i++) {
if (session->methods[i].source) {
APPEND(" %s\n\n", session->methods[i].source);
}
}
APPEND("}\n");
#undef APPEND
return source;
}
bool rava_repl_session_recompile(RavaREPLSession_t *session) {
if (!session) return false;
char *source = rava_repl_session_generate_source(session);
if (!source) {
rava_repl_session_set_error(session, "Failed to generate session source");
return false;
}
if (session->debug_mode) {
fprintf(stderr, "[DEBUG] Session source:\n%s\n", source);
}
RavaLexer_t *lexer = rava_lexer_create(source);
RavaParser_t *parser = rava_parser_create(lexer);
RavaASTNode_t *ast = rava_parser_parse(parser);
if (!ast || parser->had_error) {
rava_repl_session_set_error(session, parser->error_message ? parser->error_message : "Parse error");
rava_parser_destroy(parser);
rava_lexer_destroy(lexer);
free(source);
return false;
}
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
if (!rava_semantic_analyze(analyzer, ast)) {
rava_repl_session_set_error(session, analyzer->error_message ? analyzer->error_message : "Semantic error");
rava_ast_node_destroy(ast);
rava_parser_destroy(parser);
rava_lexer_destroy(lexer);
rava_semantic_analyzer_destroy(analyzer);
free(source);
return false;
}
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
if (!program) {
rava_repl_session_set_error(session, "IR generation failed");
rava_ast_node_destroy(ast);
rava_parser_destroy(parser);
rava_lexer_destroy(lexer);
rava_semantic_analyzer_destroy(analyzer);
rava_ir_generator_destroy(ir_gen);
free(source);
return false;
}
if (session->vm) {
rava_vm_destroy(session->vm);
}
if (session->program) {
rava_program_destroy(session->program);
}
session->program = program;
session->vm = rava_vm_create(program);
session->session_class = NULL;
rava_ast_node_destroy(ast);
rava_parser_destroy(parser);
rava_lexer_destroy(lexer);
rava_semantic_analyzer_destroy(analyzer);
rava_ir_generator_destroy(ir_gen);
free(source);
return true;
}
void rava_repl_session_set_error(RavaREPLSession_t *session, const char *error) {
if (!session) return;
free(session->last_error);
session->last_error = error ? strdup(error) : NULL;
}
const char* rava_repl_session_get_error(RavaREPLSession_t *session) {
if (!session) return NULL;
return session->last_error;
}