566 lines
19 KiB
C
566 lines
19 KiB
C
|
|
#define _POSIX_C_SOURCE 200809L
|
||
|
|
#include "repl_executor.h"
|
||
|
|
#include "repl_input.h"
|
||
|
|
#include "repl_output.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <ctype.h>
|
||
|
|
#include <time.h>
|
||
|
|
|
||
|
|
RavaREPLExecutor_t* rava_repl_executor_create(RavaREPLSession_t *session) {
|
||
|
|
RavaREPLExecutor_t *executor = calloc(1, sizeof(RavaREPLExecutor_t));
|
||
|
|
if (!executor) return NULL;
|
||
|
|
executor->session = session;
|
||
|
|
executor->timeout_ms = RAVA_REPL_TIMEOUT_MS;
|
||
|
|
executor->interrupted = false;
|
||
|
|
executor->show_timing = false;
|
||
|
|
return executor;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_repl_executor_destroy(RavaREPLExecutor_t *executor) {
|
||
|
|
free(executor);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_class_name(const char *code) {
|
||
|
|
const char *p = code;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
if (strncmp(p, "public", 6) == 0) { p += 6; while (*p && isspace(*p)) p++; }
|
||
|
|
if (strncmp(p, "class", 5) == 0) p += 5;
|
||
|
|
else if (strncmp(p, "interface", 9) == 0) p += 9;
|
||
|
|
else if (strncmp(p, "enum", 4) == 0) p += 4;
|
||
|
|
else return NULL;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
const char *start = p;
|
||
|
|
while (*p && (isalnum(*p) || *p == '_')) p++;
|
||
|
|
if (p == start) return NULL;
|
||
|
|
return strndup(start, p - start);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_method_name(const char *code) {
|
||
|
|
const char *paren = strchr(code, '(');
|
||
|
|
if (!paren) return NULL;
|
||
|
|
const char *end = paren - 1;
|
||
|
|
while (end > code && isspace(*end)) end--;
|
||
|
|
const char *start = end;
|
||
|
|
while (start > code && (isalnum(*(start-1)) || *(start-1) == '_')) start--;
|
||
|
|
if (start > end) return NULL;
|
||
|
|
return strndup(start, end - start + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_method_return_type(const char *code) {
|
||
|
|
const char *p = code;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
if (strncmp(p, "public", 6) == 0) { p += 6; while (*p && isspace(*p)) p++; }
|
||
|
|
if (strncmp(p, "private", 7) == 0) { p += 7; while (*p && isspace(*p)) p++; }
|
||
|
|
if (strncmp(p, "static", 6) == 0) { p += 6; while (*p && isspace(*p)) p++; }
|
||
|
|
const char *start = p;
|
||
|
|
while (*p && (isalnum(*p) || *p == '_' || *p == '[' || *p == ']')) p++;
|
||
|
|
if (p == start) return NULL;
|
||
|
|
return strndup(start, p - start);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_var_name(const char *code) {
|
||
|
|
const char *p = code;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
while (*p && (isalnum(*p) || *p == '_' || *p == '[' || *p == ']')) p++;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
const char *start = p;
|
||
|
|
while (*p && (isalnum(*p) || *p == '_')) p++;
|
||
|
|
if (p == start) return NULL;
|
||
|
|
return strndup(start, p - start);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_var_type(const char *code) {
|
||
|
|
const char *p = code;
|
||
|
|
while (*p && isspace(*p)) p++;
|
||
|
|
const char *start = p;
|
||
|
|
while (*p && (isalnum(*p) || *p == '_' || *p == '[' || *p == ']')) p++;
|
||
|
|
if (p == start) return NULL;
|
||
|
|
return strndup(start, p - start);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* extract_var_initializer(const char *code) {
|
||
|
|
const char *eq = strchr(code, '=');
|
||
|
|
if (!eq) return NULL;
|
||
|
|
eq++;
|
||
|
|
while (*eq && isspace(*eq)) eq++;
|
||
|
|
const char *end = eq;
|
||
|
|
while (*end && *end != ';') end++;
|
||
|
|
if (end == eq) return NULL;
|
||
|
|
while (end > eq && isspace(*(end-1))) end--;
|
||
|
|
return strndup(eq, end - eq);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* generate_full_source(RavaREPLSession_t *session, const char *eval_code) {
|
||
|
|
size_t capacity = 16384;
|
||
|
|
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; } \
|
||
|
|
while ((size_t)needed >= capacity - len) { \
|
||
|
|
capacity *= 2; \
|
||
|
|
char *tmp = realloc(source, capacity); \
|
||
|
|
if (!tmp) { free(source); return NULL; } \
|
||
|
|
source = tmp; \
|
||
|
|
needed = 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_ {\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", type, var->name);
|
||
|
|
if (var->is_initialized) {
|
||
|
|
if (var->type == RAVA_VAL_OBJECT && var->initializer) {
|
||
|
|
APPEND(" = %s", var->initializer);
|
||
|
|
} else {
|
||
|
|
switch (var->type) {
|
||
|
|
case RAVA_VAL_INT:
|
||
|
|
case RAVA_VAL_LONG:
|
||
|
|
APPEND(" = %ld", var->value.data.int_val);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_DOUBLE:
|
||
|
|
APPEND(" = %g", var->value.data.double_val);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_BOOLEAN:
|
||
|
|
APPEND(" = %s", var->value.data.bool_val ? "true" : "false");
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_STRING:
|
||
|
|
if (var->value.data.string_val) {
|
||
|
|
APPEND(" = \"%s\"", var->value.data.string_val);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
if (var->initializer) {
|
||
|
|
APPEND(" = %s", var->initializer);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
APPEND(";\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = 0; i < session->method_count; i++) {
|
||
|
|
if (session->methods[i].source) {
|
||
|
|
APPEND("\n public static %s\n", session->methods[i].source);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
APPEND("\n public static int _eval_() {\n");
|
||
|
|
if (eval_code && strlen(eval_code) > 0) {
|
||
|
|
APPEND(" %s\n", eval_code);
|
||
|
|
}
|
||
|
|
APPEND(" return 0;\n");
|
||
|
|
APPEND(" }\n");
|
||
|
|
APPEND("}\n");
|
||
|
|
|
||
|
|
#undef APPEND
|
||
|
|
|
||
|
|
return source;
|
||
|
|
}
|
||
|
|
|
||
|
|
static char* generate_expression_source(RavaREPLSession_t *session, const char *expr) {
|
||
|
|
size_t capacity = 16384;
|
||
|
|
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; } \
|
||
|
|
while ((size_t)needed >= capacity - len) { \
|
||
|
|
capacity *= 2; \
|
||
|
|
char *tmp = realloc(source, capacity); \
|
||
|
|
if (!tmp) { free(source); return NULL; } \
|
||
|
|
source = tmp; \
|
||
|
|
needed = 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_ {\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", type, var->name);
|
||
|
|
if (var->is_initialized) {
|
||
|
|
if (var->type == RAVA_VAL_OBJECT && var->initializer) {
|
||
|
|
APPEND(" = %s", var->initializer);
|
||
|
|
} else {
|
||
|
|
switch (var->type) {
|
||
|
|
case RAVA_VAL_INT:
|
||
|
|
case RAVA_VAL_LONG:
|
||
|
|
APPEND(" = %ld", var->value.data.int_val);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_DOUBLE:
|
||
|
|
APPEND(" = %g", var->value.data.double_val);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_BOOLEAN:
|
||
|
|
APPEND(" = %s", var->value.data.bool_val ? "true" : "false");
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_STRING:
|
||
|
|
if (var->value.data.string_val) {
|
||
|
|
APPEND(" = \"%s\"", var->value.data.string_val);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
if (var->initializer) {
|
||
|
|
APPEND(" = %s", var->initializer);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
APPEND(";\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = 0; i < session->method_count; i++) {
|
||
|
|
if (session->methods[i].source) {
|
||
|
|
APPEND("\n public static %s\n", session->methods[i].source);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t expr_len = strlen(expr);
|
||
|
|
while (expr_len > 0 && (expr[expr_len-1] == ';' || isspace(expr[expr_len-1]))) expr_len--;
|
||
|
|
char *clean_expr = strndup(expr, expr_len);
|
||
|
|
|
||
|
|
char *qualified_expr = malloc(strlen(clean_expr) * 10 + 1024);
|
||
|
|
if (!qualified_expr) {
|
||
|
|
free(clean_expr);
|
||
|
|
free(source);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
strcpy(qualified_expr, clean_expr);
|
||
|
|
|
||
|
|
for (size_t i = 0; i < session->variable_count; i++) {
|
||
|
|
const char *var_name = session->variables[i].name;
|
||
|
|
size_t var_len = strlen(var_name);
|
||
|
|
char *qualified = malloc(var_len + 8);
|
||
|
|
snprintf(qualified, var_len + 8, "_REPL_.%s", var_name);
|
||
|
|
|
||
|
|
char *new_expr = malloc(strlen(qualified_expr) * 10 + 1024);
|
||
|
|
char *dst = new_expr;
|
||
|
|
char *src = qualified_expr;
|
||
|
|
|
||
|
|
while (*src) {
|
||
|
|
if (strncmp(src, var_name, var_len) == 0) {
|
||
|
|
char before = (src == qualified_expr) ? ' ' : *(src - 1);
|
||
|
|
char after = *(src + var_len);
|
||
|
|
if (!isalnum(before) && before != '_' && before != '.' &&
|
||
|
|
!isalnum(after) && after != '_') {
|
||
|
|
strcpy(dst, qualified);
|
||
|
|
dst += strlen(qualified);
|
||
|
|
src += var_len;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
*dst++ = *src++;
|
||
|
|
}
|
||
|
|
*dst = '\0';
|
||
|
|
free(qualified_expr);
|
||
|
|
qualified_expr = new_expr;
|
||
|
|
free(qualified);
|
||
|
|
}
|
||
|
|
|
||
|
|
APPEND("\n public static int _eval_() {\n");
|
||
|
|
APPEND(" System.out.println(%s);\n", qualified_expr);
|
||
|
|
APPEND(" return 0;\n");
|
||
|
|
APPEND(" }\n");
|
||
|
|
APPEND("}\n");
|
||
|
|
|
||
|
|
free(clean_expr);
|
||
|
|
free(qualified_expr);
|
||
|
|
|
||
|
|
#undef APPEND
|
||
|
|
|
||
|
|
return source;
|
||
|
|
}
|
||
|
|
|
||
|
|
static RavaREPLExecResult_e compile_and_run(RavaREPLExecutor_t *executor, const char *source) {
|
||
|
|
RavaREPLSession_t *session = executor->session;
|
||
|
|
|
||
|
|
if (session->debug_mode) {
|
||
|
|
fprintf(stderr, "[DEBUG] Compiling:\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_output_error("Parse error", parser->error_message);
|
||
|
|
rava_parser_destroy(parser);
|
||
|
|
rava_lexer_destroy(lexer);
|
||
|
|
return RAVA_REPL_EXEC_PARSE_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
|
||
|
|
if (!rava_semantic_analyze(analyzer, ast)) {
|
||
|
|
rava_repl_output_error("Semantic error", analyzer->error_message);
|
||
|
|
rava_ast_node_destroy(ast);
|
||
|
|
rava_parser_destroy(parser);
|
||
|
|
rava_lexer_destroy(lexer);
|
||
|
|
rava_semantic_analyzer_destroy(analyzer);
|
||
|
|
return RAVA_REPL_EXEC_SEMANTIC_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
|
||
|
|
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
|
||
|
|
|
||
|
|
if (!program) {
|
||
|
|
rava_repl_output_error("IR error", "Failed to generate bytecode");
|
||
|
|
rava_ast_node_destroy(ast);
|
||
|
|
rava_parser_destroy(parser);
|
||
|
|
rava_lexer_destroy(lexer);
|
||
|
|
rava_semantic_analyzer_destroy(analyzer);
|
||
|
|
rava_ir_generator_destroy(ir_gen);
|
||
|
|
return RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaVM_t *vm = rava_vm_create(program);
|
||
|
|
|
||
|
|
struct timespec start_time, end_time;
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||
|
|
|
||
|
|
bool success = rava_vm_execute(vm, "_REPL_", "_eval_");
|
||
|
|
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &end_time);
|
||
|
|
double elapsed_ms = (end_time.tv_sec - start_time.tv_sec) * 1000.0 +
|
||
|
|
(end_time.tv_nsec - start_time.tv_nsec) / 1000000.0;
|
||
|
|
|
||
|
|
if (!success && vm->error_message) {
|
||
|
|
rava_repl_output_error("Runtime error", vm->error_message);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (executor->show_timing || elapsed_ms >= 100.0) {
|
||
|
|
rava_repl_output_timing(elapsed_ms);
|
||
|
|
}
|
||
|
|
|
||
|
|
rava_vm_destroy(vm);
|
||
|
|
rava_program_destroy(program);
|
||
|
|
rava_ast_node_destroy(ast);
|
||
|
|
rava_parser_destroy(parser);
|
||
|
|
rava_lexer_destroy(lexer);
|
||
|
|
rava_semantic_analyzer_destroy(analyzer);
|
||
|
|
rava_ir_generator_destroy(ir_gen);
|
||
|
|
|
||
|
|
return success ? RAVA_REPL_EXEC_SUCCESS : RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
static RavaValueType_e type_from_string(const char *type_name) {
|
||
|
|
if (!type_name) return RAVA_VAL_NULL;
|
||
|
|
if (strcmp(type_name, "int") == 0) return RAVA_VAL_INT;
|
||
|
|
if (strcmp(type_name, "long") == 0) return RAVA_VAL_LONG;
|
||
|
|
if (strcmp(type_name, "double") == 0) return RAVA_VAL_DOUBLE;
|
||
|
|
if (strcmp(type_name, "float") == 0) return RAVA_VAL_FLOAT;
|
||
|
|
if (strcmp(type_name, "boolean") == 0) return RAVA_VAL_BOOLEAN;
|
||
|
|
if (strcmp(type_name, "char") == 0) return RAVA_VAL_CHAR;
|
||
|
|
if (strcmp(type_name, "String") == 0) return RAVA_VAL_STRING;
|
||
|
|
return RAVA_VAL_OBJECT;
|
||
|
|
}
|
||
|
|
|
||
|
|
static RavaValue_t parse_literal_value(const char *init, RavaValueType_e type) {
|
||
|
|
RavaValue_t value = rava_value_null();
|
||
|
|
if (!init) return value;
|
||
|
|
|
||
|
|
while (*init && isspace(*init)) init++;
|
||
|
|
|
||
|
|
switch (type) {
|
||
|
|
case RAVA_VAL_INT:
|
||
|
|
case RAVA_VAL_LONG:
|
||
|
|
value.type = type;
|
||
|
|
value.data.int_val = strtol(init, NULL, 10);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_DOUBLE:
|
||
|
|
case RAVA_VAL_FLOAT:
|
||
|
|
value.type = type;
|
||
|
|
value.data.double_val = strtod(init, NULL);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_BOOLEAN:
|
||
|
|
value.type = RAVA_VAL_BOOLEAN;
|
||
|
|
value.data.bool_val = (strncmp(init, "true", 4) == 0);
|
||
|
|
break;
|
||
|
|
case RAVA_VAL_STRING:
|
||
|
|
value.type = RAVA_VAL_STRING;
|
||
|
|
if (init[0] == '"') {
|
||
|
|
const char *start = init + 1;
|
||
|
|
const char *end = strchr(start, '"');
|
||
|
|
if (end) {
|
||
|
|
value.data.string_val = strndup(start, end - start);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute_expression(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
char *source = generate_expression_source(executor->session, code);
|
||
|
|
if (!source) return RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
|
||
|
|
RavaREPLExecResult_e result = compile_and_run(executor, source);
|
||
|
|
free(source);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute_statement(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
char *source = generate_full_source(executor->session, code);
|
||
|
|
if (!source) return RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
|
||
|
|
RavaREPLExecResult_e result = compile_and_run(executor, source);
|
||
|
|
free(source);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute_var_decl(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
char *var_name = extract_var_name(code);
|
||
|
|
char *var_type = extract_var_type(code);
|
||
|
|
char *var_init = extract_var_initializer(code);
|
||
|
|
|
||
|
|
if (!var_name || !var_type) {
|
||
|
|
free(var_name);
|
||
|
|
free(var_type);
|
||
|
|
free(var_init);
|
||
|
|
return rava_repl_executor_execute_statement(executor, code);
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValueType_e type = type_from_string(var_type);
|
||
|
|
RavaValue_t value = rava_value_null();
|
||
|
|
|
||
|
|
if (var_init && type != RAVA_VAL_OBJECT) {
|
||
|
|
value = parse_literal_value(var_init, type);
|
||
|
|
value.type = type;
|
||
|
|
} else {
|
||
|
|
value.type = type;
|
||
|
|
value.data.int_val = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
rava_repl_session_add_variable(executor->session, var_name, var_type, var_init, type, value);
|
||
|
|
|
||
|
|
char *source = generate_full_source(executor->session, NULL);
|
||
|
|
if (source) {
|
||
|
|
RavaREPLExecResult_e result = compile_and_run(executor, source);
|
||
|
|
free(source);
|
||
|
|
if (result != RAVA_REPL_EXEC_SUCCESS) {
|
||
|
|
free(var_name);
|
||
|
|
free(var_type);
|
||
|
|
free(var_init);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
free(var_name);
|
||
|
|
free(var_type);
|
||
|
|
free(var_init);
|
||
|
|
return RAVA_REPL_EXEC_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute_method_decl(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
char *method_name = extract_method_name(code);
|
||
|
|
char *return_type = extract_method_return_type(code);
|
||
|
|
|
||
|
|
if (!method_name) {
|
||
|
|
rava_repl_output_error("Parse error", "Could not extract method name");
|
||
|
|
free(return_type);
|
||
|
|
return RAVA_REPL_EXEC_PARSE_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
rava_repl_session_add_method(executor->session, method_name, return_type ? return_type : "void", code);
|
||
|
|
|
||
|
|
char *source = generate_full_source(executor->session, NULL);
|
||
|
|
if (!source) {
|
||
|
|
free(method_name);
|
||
|
|
free(return_type);
|
||
|
|
return RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e result = compile_and_run(executor, source);
|
||
|
|
free(source);
|
||
|
|
|
||
|
|
if (result == RAVA_REPL_EXEC_SUCCESS) {
|
||
|
|
printf("Method '%s' defined.\n", method_name);
|
||
|
|
}
|
||
|
|
|
||
|
|
free(method_name);
|
||
|
|
free(return_type);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute_class_decl(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
char *class_name = extract_class_name(code);
|
||
|
|
if (!class_name) {
|
||
|
|
rava_repl_output_error("Parse error", "Could not extract class name");
|
||
|
|
return RAVA_REPL_EXEC_PARSE_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
rava_repl_session_add_class(executor->session, class_name, code);
|
||
|
|
|
||
|
|
char *source = generate_full_source(executor->session, NULL);
|
||
|
|
if (!source) {
|
||
|
|
free(class_name);
|
||
|
|
return RAVA_REPL_EXEC_RUNTIME_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e result = compile_and_run(executor, source);
|
||
|
|
free(source);
|
||
|
|
|
||
|
|
if (result == RAVA_REPL_EXEC_SUCCESS) {
|
||
|
|
printf("Class '%s' defined.\n", class_name);
|
||
|
|
}
|
||
|
|
|
||
|
|
free(class_name);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaREPLExecResult_e rava_repl_executor_execute(RavaREPLExecutor_t *executor, const char *code) {
|
||
|
|
RavaREPLCodeType_e type = rava_repl_input_detect_type(code);
|
||
|
|
|
||
|
|
switch (type) {
|
||
|
|
case RAVA_REPL_CODE_EXPRESSION:
|
||
|
|
return rava_repl_executor_execute_expression(executor, code);
|
||
|
|
case RAVA_REPL_CODE_STATEMENT:
|
||
|
|
return rava_repl_executor_execute_statement(executor, code);
|
||
|
|
case RAVA_REPL_CODE_VAR_DECL:
|
||
|
|
return rava_repl_executor_execute_var_decl(executor, code);
|
||
|
|
case RAVA_REPL_CODE_METHOD_DECL:
|
||
|
|
return rava_repl_executor_execute_method_decl(executor, code);
|
||
|
|
case RAVA_REPL_CODE_CLASS_DECL:
|
||
|
|
return rava_repl_executor_execute_class_decl(executor, code);
|
||
|
|
default:
|
||
|
|
return rava_repl_executor_execute_expression(executor, code);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaValue_t rava_repl_executor_get_result(RavaREPLExecutor_t *executor) {
|
||
|
|
return executor->last_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_repl_executor_interrupt(RavaREPLExecutor_t *executor) {
|
||
|
|
executor->interrupted = true;
|
||
|
|
}
|