Compare commits
No commits in common. "a92ed68948acdbf706a239edd84519ce09c6f859" and "fca0ade5733b1f34532172f8dacfd5810a45a7cb" have entirely different histories.
a92ed68948
...
fca0ade573
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,4 +5,3 @@ merge.py
|
||||
/test_*
|
||||
*.o
|
||||
run_examples
|
||||
rava
|
||||
|
||||
34
Makefile
34
Makefile
@ -26,9 +26,6 @@ RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
|
||||
LOADER_SOURCES = loader/loader.c
|
||||
LOADER_OBJECTS = $(LOADER_SOURCES:.c=.o)
|
||||
|
||||
REPL_SOURCES = repl/repl.c repl/repl_session.c repl/repl_input.c repl/repl_executor.c repl/repl_output.c repl/repl_commands.c repl/repl_history.c
|
||||
REPL_OBJECTS = $(REPL_SOURCES:.c=.o)
|
||||
|
||||
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
|
||||
PHASE0_OBJECTS = $(PHASE0_SOURCES:.c=.o)
|
||||
|
||||
@ -158,7 +155,7 @@ UNITTEST_OBJECTS = $(UNITTEST_SOURCES:.c=.o)
|
||||
TEST_UNITTEST_DEMO_SOURCES = tests/test_unittest_demo.c
|
||||
TEST_UNITTEST_DEMO_OBJECTS = $(TEST_UNITTEST_DEMO_SOURCES:.c=.o)
|
||||
|
||||
all: test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_super test_inheritance test_break test_elseif test_forloop test_println test_loader test_object_methods test_autobox test_sockets test_method_ref test_gc
|
||||
all: test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_super test_inheritance test_break test_elseif test_forloop test_println test_loader test_object_methods test_autobox test_gc
|
||||
|
||||
test_lexer: $(LEXER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_LEXER_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
@ -305,18 +302,6 @@ benchmark: test_benchmark
|
||||
@python3 examples/benchmark.py
|
||||
@echo ""
|
||||
|
||||
rava: rava.o $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(REPL_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lreadline
|
||||
|
||||
examples: rava
|
||||
@echo "=== Running All Examples ==="
|
||||
@for f in examples/*.java; do \
|
||||
echo "--- $$f ---"; \
|
||||
./rava "$$f" || true; \
|
||||
echo ""; \
|
||||
done
|
||||
@echo "=== Examples Complete ==="
|
||||
|
||||
test_nanbox: tests/test_nanbox.c runtime/nanbox.h $(UNITTEST_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ tests/test_nanbox.c $(UNITTEST_OBJECTS) $(LDFLAGS)
|
||||
|
||||
@ -356,15 +341,15 @@ pgo: test_benchmark_pgo
|
||||
./test_benchmark_pgo
|
||||
|
||||
clean:
|
||||
rm -f $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(REPL_OBJECTS) \
|
||||
rm -f $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) \
|
||||
$(PHASE0_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS) \
|
||||
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
|
||||
$(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \
|
||||
$(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) $(TEST_NEGATIVE_OBJECTS) $(TEST_ENUMS_OBJECTS) $(TEST_COLLECTIONS_OBJECTS) $(TEST_SUPER_OBJECTS) $(TEST_INHERITANCE_OBJECTS) $(TEST_BREAK_OBJECTS) $(TEST_ELSEIF_OBJECTS) $(TEST_FORLOOP_OBJECTS) $(TEST_PRINTLN_OBJECTS) $(TEST_LOADER_OBJECTS) $(TEST_OBJECT_METHODS_OBJECTS) $(TEST_AUTOBOX_OBJECTS) $(TEST_SOCKETS_OBJECTS) $(TEST_METHOD_REF_OBJECTS) $(TEST_GC_OBJECTS) $(TEST_BENCHMARK_OBJECTS) \
|
||||
test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_super test_inheritance test_break test_elseif test_forloop test_println test_loader test_object_methods test_autobox test_sockets test_method_ref test_gc test_benchmark \
|
||||
test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo test_unittest_demo rava rava.o *.gcda */*.gcda
|
||||
$(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) $(TEST_NEGATIVE_OBJECTS) $(TEST_ENUMS_OBJECTS) $(TEST_COLLECTIONS_OBJECTS) $(TEST_SUPER_OBJECTS) $(TEST_INHERITANCE_OBJECTS) $(TEST_BREAK_OBJECTS) $(TEST_ELSEIF_OBJECTS) $(TEST_FORLOOP_OBJECTS) $(TEST_PRINTLN_OBJECTS) $(TEST_LOADER_OBJECTS) $(TEST_OBJECT_METHODS_OBJECTS) $(TEST_AUTOBOX_OBJECTS) $(TEST_SOCKETS_OBJECTS) $(TEST_BENCHMARK_OBJECTS) \
|
||||
test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_super test_inheritance test_break test_elseif test_forloop test_println test_loader test_object_methods test_autobox test_sockets test_benchmark \
|
||||
test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo test_unittest_demo *.gcda */*.gcda
|
||||
|
||||
.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test test_repl examples
|
||||
.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test
|
||||
|
||||
test: all
|
||||
@echo "=== Running All Tests ==="
|
||||
@ -376,10 +361,5 @@ test: all
|
||||
./test_shortcircuit && ./test_multidim_arrays && ./test_static_init && ./test_negative && \
|
||||
./test_enums && ./test_collections && ./test_super && ./test_inheritance && ./test_break && \
|
||||
./test_elseif && ./test_forloop && ./test_println && ./test_loader && ./test_object_methods && \
|
||||
./test_autobox && ./test_sockets && ./test_method_ref && ./test_gc && \
|
||||
./repl/run_tests.sh && \
|
||||
./test_autobox && ./test_sockets && \
|
||||
echo "" && echo "=== All Tests Passed ==="
|
||||
|
||||
test_repl: rava
|
||||
@echo "=== Running REPL Tests ==="
|
||||
@./repl/run_tests.sh
|
||||
|
||||
@ -3,26 +3,26 @@ public class TowerOfHanoiStatic {
|
||||
|
||||
public static int hanoi(int n, int from, int to, int aux) {
|
||||
if (n == 1) {
|
||||
TowerOfHanoiStatic.moveCount = TowerOfHanoiStatic.moveCount + 1;
|
||||
return TowerOfHanoiStatic.moveCount;
|
||||
moveCount = moveCount + 1;
|
||||
return moveCount;
|
||||
}
|
||||
hanoi(n - 1, from, aux, to);
|
||||
TowerOfHanoiStatic.moveCount = TowerOfHanoiStatic.moveCount + 1;
|
||||
moveCount = moveCount + 1;
|
||||
hanoi(n - 1, aux, to, from);
|
||||
return TowerOfHanoiStatic.moveCount;
|
||||
return moveCount;
|
||||
}
|
||||
|
||||
public static int main() {
|
||||
TowerOfHanoiStatic.moveCount = 0;
|
||||
moveCount = 0;
|
||||
System.out.println(hanoi(1, 1, 3, 2));
|
||||
|
||||
TowerOfHanoiStatic.moveCount = 0;
|
||||
moveCount = 0;
|
||||
System.out.println(hanoi(2, 1, 3, 2));
|
||||
|
||||
TowerOfHanoiStatic.moveCount = 0;
|
||||
moveCount = 0;
|
||||
System.out.println(hanoi(3, 1, 3, 2));
|
||||
|
||||
TowerOfHanoiStatic.moveCount = 0;
|
||||
moveCount = 0;
|
||||
System.out.println(hanoi(4, 1, 3, 2));
|
||||
|
||||
return 0;
|
||||
|
||||
@ -33,10 +33,8 @@ static RavaASTNode_t* _rava_parser_parse_method_declaration(RavaParser_t *parser
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after method name");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
|
||||
if (!param_type) break;
|
||||
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
@ -126,8 +124,7 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after class name");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
|
||||
RavaModifier_e *member_modifiers = NULL;
|
||||
size_t member_modifiers_count = 0;
|
||||
@ -146,10 +143,8 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after constructor name");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
|
||||
if (!param_type) break;
|
||||
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
@ -180,7 +175,6 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
|
||||
}
|
||||
|
||||
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
|
||||
if (!member_type) break;
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
char *name = strdup(parser->current_token->lexeme);
|
||||
@ -210,9 +204,6 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
|
||||
rava_ast_node_add_child(class_decl, field);
|
||||
member_modifiers = NULL;
|
||||
}
|
||||
} else {
|
||||
free(member_modifiers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,8 +235,7 @@ static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *par
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after interface name");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
|
||||
RavaModifier_e *member_modifiers = NULL;
|
||||
size_t member_modifiers_count = 0;
|
||||
@ -253,10 +243,6 @@ static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *par
|
||||
_rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count);
|
||||
|
||||
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
|
||||
if (!member_type) {
|
||||
free(member_modifiers);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
char *name = strdup(parser->current_token->lexeme);
|
||||
@ -275,7 +261,6 @@ static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *par
|
||||
}
|
||||
} else {
|
||||
free(member_modifiers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,8 +302,7 @@ static RavaASTNode_t* _rava_parser_parse_enum_declaration(RavaParser_t *parser)
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
if (enum_decl->data.enum_decl.constants_count >= capacity) {
|
||||
@ -335,8 +319,6 @@ static RavaASTNode_t* _rava_parser_parse_enum_declaration(RavaParser_t *parser)
|
||||
enum_decl->data.enum_decl.constants[enum_decl->data.enum_decl.constants_count++] =
|
||||
strdup(parser->current_token->lexeme);
|
||||
_rava_parser_advance(parser);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
|
||||
@ -346,8 +328,7 @@ static RavaASTNode_t* _rava_parser_parse_enum_declaration(RavaParser_t *parser)
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_SEMICOLON)) {
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
|
||||
RavaModifier_e *member_modifiers = NULL;
|
||||
size_t member_modifiers_count = 0;
|
||||
@ -355,10 +336,6 @@ static RavaASTNode_t* _rava_parser_parse_enum_declaration(RavaParser_t *parser)
|
||||
_rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count);
|
||||
|
||||
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
|
||||
if (!member_type) {
|
||||
free(member_modifiers);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
char *name = strdup(parser->current_token->lexeme);
|
||||
@ -389,7 +366,6 @@ static RavaASTNode_t* _rava_parser_parse_enum_declaration(RavaParser_t *parser)
|
||||
}
|
||||
} else {
|
||||
free(member_modifiers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,14 +23,9 @@ RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser) {
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
if (parser->had_error) {
|
||||
break;
|
||||
}
|
||||
RavaASTNode_t *stmt = _rava_parser_parse_statement(parser);
|
||||
if (stmt) {
|
||||
rava_ast_node_add_child(block, stmt);
|
||||
} else if (parser->had_error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,8 +211,7 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) {
|
||||
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after switch");
|
||||
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_CASE)) {
|
||||
RavaASTNode_t *case_node = rava_ast_node_create(RAVA_AST_CASE_STMT,
|
||||
@ -230,13 +224,10 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) {
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CASE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DEFAULT) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
RavaASTNode_t *stmt = _rava_parser_parse_statement(parser);
|
||||
if (stmt) {
|
||||
rava_ast_node_add_child(case_node, stmt);
|
||||
} else if (parser->had_error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,13 +244,10 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) {
|
||||
while (!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CASE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DEFAULT) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF) &&
|
||||
!parser->had_error) {
|
||||
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
|
||||
RavaASTNode_t *stmt = _rava_parser_parse_statement(parser);
|
||||
if (stmt) {
|
||||
rava_ast_node_add_child(default_node, stmt);
|
||||
} else if (parser->had_error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
169
rava.c
169
rava.c
@ -1,169 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lexer/lexer.h"
|
||||
#include "parser/parser.h"
|
||||
#include "semantic/semantic.h"
|
||||
#include "ir/ir.h"
|
||||
#include "ir/ir_gen.h"
|
||||
#include "runtime/runtime.h"
|
||||
#include "repl/repl.h"
|
||||
|
||||
static char* read_file(const char *filename) {
|
||||
FILE *file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Error: Cannot open file '%s'\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
char *content = malloc(size + 1);
|
||||
if (!content) {
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
size_t read_bytes = fread(content, 1, size, file);
|
||||
content[read_bytes] = '\0';
|
||||
fclose(file);
|
||||
return content;
|
||||
}
|
||||
|
||||
static const char* find_main_class(const char *source) {
|
||||
static char class_name[256];
|
||||
const char *p = strstr(source, "public static");
|
||||
if (!p) p = strstr(source, "static public");
|
||||
if (!p) return "Main";
|
||||
|
||||
while (p > source) {
|
||||
p--;
|
||||
if (strncmp(p, "class ", 6) == 0) {
|
||||
p += 6;
|
||||
while (*p == ' ') p++;
|
||||
int i = 0;
|
||||
while (*p && *p != ' ' && *p != '{' && *p != '\n' && i < 255) {
|
||||
class_name[i++] = *p++;
|
||||
}
|
||||
class_name[i] = '\0';
|
||||
return class_name;
|
||||
}
|
||||
}
|
||||
return "Main";
|
||||
}
|
||||
|
||||
static void print_usage(const char *prog) {
|
||||
fprintf(stderr, "Usage: %s [options] [file.java] [class] [method]\n", prog);
|
||||
fprintf(stderr, "\nOptions:\n");
|
||||
fprintf(stderr, " -i, --interactive Start interactive REPL\n");
|
||||
fprintf(stderr, " -h, --help Show this help message\n");
|
||||
fprintf(stderr, " -v, --version Show version\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, " %s Start REPL (interactive mode)\n", prog);
|
||||
fprintf(stderr, " %s file.java Run file.java\n", prog);
|
||||
fprintf(stderr, " %s file.java Main Run Main class from file.java\n", prog);
|
||||
fprintf(stderr, " %s -i Start REPL explicitly\n", prog);
|
||||
}
|
||||
|
||||
static void print_version(void) {
|
||||
printf("Rava %s - Java Interpreter\n", RAVA_REPL_VERSION);
|
||||
printf("A stack-based VM for Java source code\n");
|
||||
}
|
||||
|
||||
static int run_file(const char *filename, const char *class_name_arg, const char *method_name_arg) {
|
||||
char *source = read_file(filename);
|
||||
if (!source) return 1;
|
||||
|
||||
const char *class_name = class_name_arg ? class_name_arg : find_main_class(source);
|
||||
const char *method_name = method_name_arg ? method_name_arg : "main";
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "Parse error: %s\n", parser->error_message ? parser->error_message : "unknown");
|
||||
free(source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
|
||||
if (!rava_semantic_analyze(analyzer, ast)) {
|
||||
fprintf(stderr, "Semantic error: %s\n", analyzer->error_message ? analyzer->error_message : "unknown");
|
||||
free(source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
|
||||
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
|
||||
if (!program) {
|
||||
fprintf(stderr, "IR generation failed\n");
|
||||
free(source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
RavaVM_t *vm = rava_vm_create(program);
|
||||
if (!rava_vm_execute(vm, class_name, method_name)) {
|
||||
fprintf(stderr, "Runtime error: %s\n", vm->error_message ? vm->error_message : "unknown");
|
||||
free(source);
|
||||
return 1;
|
||||
}
|
||||
|
||||
RavaValue_t result = rava_vm_get_result(vm);
|
||||
int ret = 0;
|
||||
if (result.type == RAVA_VAL_INT) {
|
||||
ret = (int)result.data.int_val;
|
||||
}
|
||||
|
||||
rava_vm_destroy(vm);
|
||||
rava_program_destroy(program);
|
||||
rava_ir_generator_destroy(ir_gen);
|
||||
rava_semantic_analyzer_destroy(analyzer);
|
||||
rava_ast_node_destroy(ast);
|
||||
rava_parser_destroy(parser);
|
||||
rava_lexer_destroy(lexer);
|
||||
free(source);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
return rava_repl_run();
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
|
||||
print_version();
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--interactive") == 0) {
|
||||
return rava_repl_run();
|
||||
}
|
||||
}
|
||||
|
||||
const char *filename = NULL;
|
||||
const char *class_name = NULL;
|
||||
const char *method_name = NULL;
|
||||
int pos_arg = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') continue;
|
||||
switch (pos_arg) {
|
||||
case 0: filename = argv[i]; break;
|
||||
case 1: class_name = argv[i]; break;
|
||||
case 2: method_name = argv[i]; break;
|
||||
}
|
||||
pos_arg++;
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return run_file(filename, class_name, method_name);
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
class BankAccount {
|
||||
public String holder;
|
||||
public double balance;
|
||||
public BankAccount(String name, double initial) {
|
||||
this.holder = name;
|
||||
this.balance = initial;
|
||||
}
|
||||
public void deposit(double amount) {
|
||||
if (amount > 0) {
|
||||
this.balance = this.balance + amount;
|
||||
}
|
||||
}
|
||||
public boolean withdraw(double amount) {
|
||||
if (amount > 0 && amount <= this.balance) {
|
||||
this.balance = this.balance - amount;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public double getBalance() {
|
||||
return this.balance;
|
||||
}
|
||||
public String info() {
|
||||
return this.holder + ": $" + this.balance;
|
||||
}
|
||||
}
|
||||
|
||||
BankAccount acc = new BankAccount("Alice", 1000.0);
|
||||
acc.info()
|
||||
acc.getBalance()
|
||||
|
||||
acc.deposit(500.0)
|
||||
acc.getBalance()
|
||||
|
||||
acc.withdraw(200.0)
|
||||
acc.getBalance()
|
||||
|
||||
acc.withdraw(2000.0)
|
||||
acc.getBalance()
|
||||
|
||||
acc.info()
|
||||
|
||||
%classes
|
||||
%whos
|
||||
%quit
|
||||
@ -1,20 +0,0 @@
|
||||
int add(int a, int b) { return a + b; }
|
||||
int sub(int a, int b) { return a - b; }
|
||||
int mul(int a, int b) { return a * b; }
|
||||
int div(int a, int b) { return a / b; }
|
||||
int mod(int a, int b) { return a % b; }
|
||||
|
||||
add(100, 50)
|
||||
sub(100, 50)
|
||||
mul(100, 50)
|
||||
div(100, 50)
|
||||
mod(100, 7)
|
||||
|
||||
double sqrt(double x) { return Math.sqrt(x); }
|
||||
double pow(double base, double exp) { return Math.pow(base, exp); }
|
||||
|
||||
sqrt(144.0)
|
||||
pow(2.0, 8.0)
|
||||
|
||||
%methods
|
||||
%quit
|
||||
@ -1,28 +0,0 @@
|
||||
int fib_recursive(int n) {
|
||||
if (n <= 1) return n;
|
||||
return fib_recursive(n - 1) + fib_recursive(n - 2);
|
||||
}
|
||||
|
||||
fib_recursive(0)
|
||||
fib_recursive(1)
|
||||
fib_recursive(5)
|
||||
fib_recursive(10)
|
||||
fib_recursive(15)
|
||||
|
||||
int fib_iterative(int n) {
|
||||
if (n <= 1) return n;
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
int temp = a + b;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
fib_iterative(20)
|
||||
fib_iterative(30)
|
||||
|
||||
%methods
|
||||
%quit
|
||||
@ -1,63 +0,0 @@
|
||||
class Point {
|
||||
public double x;
|
||||
public double y;
|
||||
public Point(double px, double py) {
|
||||
this.x = px;
|
||||
this.y = py;
|
||||
}
|
||||
public double distanceTo(Point other) {
|
||||
double dx = this.x - other.x;
|
||||
double dy = this.y - other.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
}
|
||||
|
||||
class Circle {
|
||||
public Point center;
|
||||
public double radius;
|
||||
public Circle(Point c, double r) {
|
||||
this.center = c;
|
||||
this.radius = r;
|
||||
}
|
||||
public double area() {
|
||||
return 3.14159 * this.radius * this.radius;
|
||||
}
|
||||
public double circumference() {
|
||||
return 2.0 * 3.14159 * this.radius;
|
||||
}
|
||||
}
|
||||
|
||||
class Rectangle {
|
||||
public double width;
|
||||
public double height;
|
||||
public Rectangle(double w, double h) {
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
}
|
||||
public double area() {
|
||||
return this.width * this.height;
|
||||
}
|
||||
public double perimeter() {
|
||||
return 2.0 * (this.width + this.height);
|
||||
}
|
||||
public double diagonal() {
|
||||
return Math.sqrt(this.width * this.width + this.height * this.height);
|
||||
}
|
||||
}
|
||||
|
||||
Point p1 = new Point(0.0, 0.0);
|
||||
Point p2 = new Point(3.0, 4.0);
|
||||
p1.distanceTo(p2)
|
||||
|
||||
Circle c = new Circle(new Point(0.0, 0.0), 5.0);
|
||||
c.area()
|
||||
c.circumference()
|
||||
|
||||
Rectangle r = new Rectangle(3.0, 4.0);
|
||||
r.area()
|
||||
r.perimeter()
|
||||
r.diagonal()
|
||||
|
||||
%classes
|
||||
%whos
|
||||
%quit
|
||||
@ -1,34 +0,0 @@
|
||||
boolean isPrime(int n) {
|
||||
if (n < 2) return false;
|
||||
if (n == 2) return true;
|
||||
if (n % 2 == 0) return false;
|
||||
for (int i = 3; i * i <= n; i = i + 2) {
|
||||
if (n % i == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isPrime(2)
|
||||
isPrime(17)
|
||||
isPrime(100)
|
||||
isPrime(997)
|
||||
|
||||
for (int i = 2; i <= 50; i++) {
|
||||
if (isPrime(i)) {
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
|
||||
int countPrimes(int limit) {
|
||||
int count = 0;
|
||||
for (int i = 2; i <= limit; i++) {
|
||||
if (isPrime(i)) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
countPrimes(100)
|
||||
countPrimes(1000)
|
||||
|
||||
%methods
|
||||
%quit
|
||||
@ -1,48 +0,0 @@
|
||||
void printArray(int[] arr) {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
System.out.print(arr[i]);
|
||||
if (i < arr.length - 1) System.out.print(", ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
void bubbleSort(int[] arr) {
|
||||
int n = arr.length;
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
for (int j = 0; j < n - i - 1; j++) {
|
||||
if (arr[j] > arr[j + 1]) {
|
||||
int temp = arr[j];
|
||||
arr[j] = arr[j + 1];
|
||||
arr[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int[] arr1 = {64, 34, 25, 12, 22, 11, 90};
|
||||
printArray(arr1)
|
||||
bubbleSort(arr1)
|
||||
printArray(arr1)
|
||||
|
||||
int findMin(int[] arr) {
|
||||
int min = arr[0];
|
||||
for (int i = 1; i < arr.length; i++) {
|
||||
if (arr[i] < min) min = arr[i];
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
int findMax(int[] arr) {
|
||||
int max = arr[0];
|
||||
for (int i = 1; i < arr.length; i++) {
|
||||
if (arr[i] > max) max = arr[i];
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
int[] nums = {3, 1, 4, 1, 5, 9, 2, 6};
|
||||
findMin(nums)
|
||||
findMax(nums)
|
||||
|
||||
%methods
|
||||
%quit
|
||||
@ -1,53 +0,0 @@
|
||||
String reverse(String s) {
|
||||
String result = "";
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
result = result + s.charAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
reverse("hello")
|
||||
reverse("Rava")
|
||||
|
||||
boolean isPalindrome(String s) {
|
||||
String lower = s.toLowerCase();
|
||||
int left = 0;
|
||||
int right = lower.length() - 1;
|
||||
while (left < right) {
|
||||
if (lower.charAt(left) != lower.charAt(right)) {
|
||||
return false;
|
||||
}
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isPalindrome("radar")
|
||||
isPalindrome("hello")
|
||||
isPalindrome("Racecar")
|
||||
|
||||
int countChar(String s, char c) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) == c) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
countChar("mississippi", 's')
|
||||
countChar("hello world", 'l')
|
||||
|
||||
String repeat(String s, int n) {
|
||||
String result = "";
|
||||
for (int i = 0; i < n; i++) {
|
||||
result = result + s;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
repeat("ab", 5)
|
||||
repeat("*", 10)
|
||||
|
||||
%methods
|
||||
%quit
|
||||
192
repl/repl.c
192
repl/repl.c
@ -1,192 +0,0 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "repl.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
static volatile bool g_interrupted = false;
|
||||
|
||||
static void sigint_handler(int sig) {
|
||||
(void)sig;
|
||||
g_interrupted = true;
|
||||
}
|
||||
|
||||
RavaREPL_t* rava_repl_create(void) {
|
||||
RavaREPL_t *repl = calloc(1, sizeof(RavaREPL_t));
|
||||
if (!repl) return NULL;
|
||||
|
||||
repl->session = rava_repl_session_create();
|
||||
if (!repl->session) {
|
||||
free(repl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
repl->input = rava_repl_input_create();
|
||||
if (!repl->input) {
|
||||
rava_repl_session_destroy(repl->session);
|
||||
free(repl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
repl->executor = rava_repl_executor_create(repl->session);
|
||||
if (!repl->executor) {
|
||||
rava_repl_input_destroy(repl->input);
|
||||
rava_repl_session_destroy(repl->session);
|
||||
free(repl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
repl->running = true;
|
||||
repl->interactive = true;
|
||||
|
||||
return repl;
|
||||
}
|
||||
|
||||
void rava_repl_destroy(RavaREPL_t *repl) {
|
||||
if (!repl) return;
|
||||
rava_repl_executor_destroy(repl->executor);
|
||||
rava_repl_input_destroy(repl->input);
|
||||
rava_repl_session_destroy(repl->session);
|
||||
free(repl);
|
||||
}
|
||||
|
||||
void rava_repl_print_banner(void) {
|
||||
printf("Rava %s Interactive Interpreter\n", RAVA_REPL_VERSION);
|
||||
printf("Type \"%%help\" for commands, \"%%quit\" to exit\n\n");
|
||||
}
|
||||
|
||||
void rava_repl_print_prompt(RavaREPL_t *repl, bool continuation) {
|
||||
(void)repl;
|
||||
printf("%s", continuation ? "... " : ">>> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
bool rava_repl_process_line(RavaREPL_t *repl, const char *line) {
|
||||
if (!repl || !line) return true;
|
||||
|
||||
while (*line && isspace(*line)) line++;
|
||||
if (strlen(line) == 0) return true;
|
||||
|
||||
if (rava_repl_command_is_command(line)) {
|
||||
char *arg = NULL;
|
||||
RavaREPLCommand_e cmd = rava_repl_command_parse(line, &arg);
|
||||
|
||||
if (cmd == RAVA_CMD_QUIT) {
|
||||
free(arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
rava_repl_history_add(repl->session->history, line);
|
||||
bool result = rava_repl_command_execute(repl->session, cmd, arg);
|
||||
free(arg);
|
||||
return result;
|
||||
}
|
||||
|
||||
RavaREPLInputState_e state = rava_repl_input_append(repl->input, line);
|
||||
|
||||
if (state == RAVA_REPL_INPUT_COMPLETE) {
|
||||
const char *code = rava_repl_input_get(repl->input);
|
||||
rava_repl_history_add(repl->session->history, code);
|
||||
rava_repl_executor_execute(repl->executor, code);
|
||||
rava_repl_input_reset(repl->input);
|
||||
} else if (state == RAVA_REPL_INPUT_ERROR) {
|
||||
rava_repl_output_error("Input error", "Buffer overflow or invalid input");
|
||||
rava_repl_input_reset(repl->input);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char* read_line_stdin(const char *prompt) {
|
||||
printf("%s", prompt);
|
||||
fflush(stdout);
|
||||
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read = getline(&line, &len, stdin);
|
||||
|
||||
if (read == -1) {
|
||||
free(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (read > 0 && line[read - 1] == '\n') {
|
||||
line[read - 1] = '\0';
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
int rava_repl_run(void) {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sigint_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
RavaREPL_t *repl = rava_repl_create();
|
||||
if (!repl) {
|
||||
fprintf(stderr, "Failed to create REPL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool is_tty = isatty(fileno(stdin));
|
||||
|
||||
rava_repl_print_banner();
|
||||
|
||||
char history_file[256];
|
||||
const char *home = getenv("HOME");
|
||||
if (home && is_tty) {
|
||||
snprintf(history_file, sizeof(history_file), "%s/.rava_history", home);
|
||||
rava_repl_history_load(repl->session->history, history_file);
|
||||
read_history(history_file);
|
||||
}
|
||||
|
||||
if (is_tty) {
|
||||
rl_bind_key('\t', rl_complete);
|
||||
}
|
||||
|
||||
while (repl->running) {
|
||||
bool continuation = !rava_repl_input_is_empty(repl->input);
|
||||
const char *prompt = continuation ? "... " : ">>> ";
|
||||
|
||||
char *line;
|
||||
if (is_tty) {
|
||||
line = readline(prompt);
|
||||
} else {
|
||||
line = read_line_stdin(prompt);
|
||||
}
|
||||
|
||||
if (!line) {
|
||||
if (is_tty) printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen(line) == 0) {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_tty && strlen(line) > 0) {
|
||||
add_history(line);
|
||||
}
|
||||
|
||||
g_interrupted = false;
|
||||
repl->running = rava_repl_process_line(repl, line);
|
||||
|
||||
free(line);
|
||||
}
|
||||
|
||||
if (home && is_tty) {
|
||||
rava_repl_history_save(repl->session->history, history_file);
|
||||
write_history(history_file);
|
||||
}
|
||||
|
||||
rava_repl_destroy(repl);
|
||||
return 0;
|
||||
}
|
||||
29
repl/repl.h
29
repl/repl.h
@ -1,29 +0,0 @@
|
||||
#ifndef RAVA_REPL_H
|
||||
#define RAVA_REPL_H
|
||||
|
||||
#include "repl_types.h"
|
||||
#include "repl_session.h"
|
||||
#include "repl_input.h"
|
||||
#include "repl_executor.h"
|
||||
#include "repl_commands.h"
|
||||
#include "repl_output.h"
|
||||
#include "repl_history.h"
|
||||
|
||||
typedef struct {
|
||||
RavaREPLSession_t *session;
|
||||
RavaREPLInput_t *input;
|
||||
RavaREPLExecutor_t *executor;
|
||||
bool running;
|
||||
bool interactive;
|
||||
} RavaREPL_t;
|
||||
|
||||
RavaREPL_t* rava_repl_create(void);
|
||||
void rava_repl_destroy(RavaREPL_t *repl);
|
||||
|
||||
int rava_repl_run(void);
|
||||
bool rava_repl_process_line(RavaREPL_t *repl, const char *line);
|
||||
|
||||
void rava_repl_print_banner(void);
|
||||
void rava_repl_print_prompt(RavaREPL_t *repl, bool continuation);
|
||||
|
||||
#endif
|
||||
@ -1,229 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
#ifndef RAVA_REPL_COMMANDS_H
|
||||
#define RAVA_REPL_COMMANDS_H
|
||||
|
||||
#include "repl_types.h"
|
||||
#include "repl_session.h"
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *alias;
|
||||
const char *description;
|
||||
RavaREPLCommand_e command;
|
||||
} RavaREPLCommandDef_t;
|
||||
|
||||
bool rava_repl_command_is_command(const char *input);
|
||||
RavaREPLCommand_e rava_repl_command_parse(const char *input, char **arg);
|
||||
bool rava_repl_command_execute(RavaREPLSession_t *session, RavaREPLCommand_e cmd, const char *arg);
|
||||
void rava_repl_command_help(const char *topic);
|
||||
void rava_repl_command_list_all(void);
|
||||
|
||||
#endif
|
||||
@ -1,565 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
#ifndef RAVA_REPL_EXECUTOR_H
|
||||
#define RAVA_REPL_EXECUTOR_H
|
||||
|
||||
#include "repl_types.h"
|
||||
#include "repl_session.h"
|
||||
|
||||
typedef struct {
|
||||
RavaREPLSession_t *session;
|
||||
int timeout_ms;
|
||||
volatile bool interrupted;
|
||||
RavaValue_t last_result;
|
||||
bool show_timing;
|
||||
} RavaREPLExecutor_t;
|
||||
|
||||
RavaREPLExecutor_t* rava_repl_executor_create(RavaREPLSession_t *session);
|
||||
void rava_repl_executor_destroy(RavaREPLExecutor_t *executor);
|
||||
|
||||
RavaREPLExecResult_e rava_repl_executor_execute(RavaREPLExecutor_t *executor, const char *code);
|
||||
RavaREPLExecResult_e rava_repl_executor_execute_expression(RavaREPLExecutor_t *executor, const char *code);
|
||||
RavaREPLExecResult_e rava_repl_executor_execute_statement(RavaREPLExecutor_t *executor, const char *code);
|
||||
RavaREPLExecResult_e rava_repl_executor_execute_var_decl(RavaREPLExecutor_t *executor, const char *code);
|
||||
RavaREPLExecResult_e rava_repl_executor_execute_method_decl(RavaREPLExecutor_t *executor, const char *code);
|
||||
RavaREPLExecResult_e rava_repl_executor_execute_class_decl(RavaREPLExecutor_t *executor, const char *code);
|
||||
|
||||
RavaValue_t rava_repl_executor_get_result(RavaREPLExecutor_t *executor);
|
||||
void rava_repl_executor_interrupt(RavaREPLExecutor_t *executor);
|
||||
|
||||
#endif
|
||||
@ -1,102 +0,0 @@
|
||||
#include "repl_history.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
RavaREPLHistory_t* rava_repl_history_create(size_t max_size) {
|
||||
RavaREPLHistory_t *history = malloc(sizeof(RavaREPLHistory_t));
|
||||
if (!history) return NULL;
|
||||
history->capacity = max_size;
|
||||
history->entries = calloc(max_size, sizeof(char*));
|
||||
if (!history->entries) {
|
||||
free(history);
|
||||
return NULL;
|
||||
}
|
||||
history->count = 0;
|
||||
history->position = 0;
|
||||
return history;
|
||||
}
|
||||
|
||||
void rava_repl_history_destroy(RavaREPLHistory_t *history) {
|
||||
if (!history) return;
|
||||
for (size_t i = 0; i < history->count; i++) {
|
||||
free(history->entries[i]);
|
||||
}
|
||||
free(history->entries);
|
||||
free(history);
|
||||
}
|
||||
|
||||
void rava_repl_history_add(RavaREPLHistory_t *history, const char *entry) {
|
||||
if (!history || !entry || strlen(entry) == 0) return;
|
||||
if (history->count > 0) {
|
||||
if (strcmp(history->entries[history->count - 1], entry) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (history->count >= history->capacity) {
|
||||
free(history->entries[0]);
|
||||
memmove(history->entries, history->entries + 1, (history->capacity - 1) * sizeof(char*));
|
||||
history->count--;
|
||||
}
|
||||
history->entries[history->count++] = strdup(entry);
|
||||
history->position = history->count;
|
||||
add_history(entry);
|
||||
}
|
||||
|
||||
const char* rava_repl_history_get(RavaREPLHistory_t *history, size_t index) {
|
||||
if (!history || index >= history->count) return NULL;
|
||||
return history->entries[index];
|
||||
}
|
||||
|
||||
const char* rava_repl_history_prev(RavaREPLHistory_t *history) {
|
||||
if (!history || history->count == 0) return NULL;
|
||||
if (history->position > 0) {
|
||||
history->position--;
|
||||
}
|
||||
return history->entries[history->position];
|
||||
}
|
||||
|
||||
const char* rava_repl_history_next(RavaREPLHistory_t *history) {
|
||||
if (!history || history->count == 0) return NULL;
|
||||
if (history->position < history->count - 1) {
|
||||
history->position++;
|
||||
return history->entries[history->position];
|
||||
}
|
||||
history->position = history->count;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rava_repl_history_reset_position(RavaREPLHistory_t *history) {
|
||||
if (!history) return;
|
||||
history->position = history->count;
|
||||
}
|
||||
|
||||
bool rava_repl_history_save(RavaREPLHistory_t *history, const char *filename) {
|
||||
if (!history || !filename) return false;
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f) return false;
|
||||
for (size_t i = 0; i < history->count; i++) {
|
||||
fprintf(f, "%s\n", history->entries[i]);
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rava_repl_history_load(RavaREPLHistory_t *history, const char *filename) {
|
||||
if (!history || !filename) return false;
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (!f) return false;
|
||||
char line[RAVA_REPL_MAX_INPUT];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
size_t len = strlen(line);
|
||||
if (len > 0 && line[len - 1] == '\n') {
|
||||
line[len - 1] = '\0';
|
||||
}
|
||||
if (strlen(line) > 0) {
|
||||
rava_repl_history_add(history, line);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef RAVA_REPL_HISTORY_H
|
||||
#define RAVA_REPL_HISTORY_H
|
||||
|
||||
#include "repl_types.h"
|
||||
|
||||
typedef struct {
|
||||
char **entries;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
size_t position;
|
||||
} RavaREPLHistory_t;
|
||||
|
||||
RavaREPLHistory_t* rava_repl_history_create(size_t max_size);
|
||||
void rava_repl_history_destroy(RavaREPLHistory_t *history);
|
||||
void rava_repl_history_add(RavaREPLHistory_t *history, const char *entry);
|
||||
const char* rava_repl_history_get(RavaREPLHistory_t *history, size_t index);
|
||||
const char* rava_repl_history_prev(RavaREPLHistory_t *history);
|
||||
const char* rava_repl_history_next(RavaREPLHistory_t *history);
|
||||
void rava_repl_history_reset_position(RavaREPLHistory_t *history);
|
||||
bool rava_repl_history_save(RavaREPLHistory_t *history, const char *filename);
|
||||
bool rava_repl_history_load(RavaREPLHistory_t *history, const char *filename);
|
||||
|
||||
#endif
|
||||
@ -1,250 +0,0 @@
|
||||
#include "repl_input.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
RavaREPLInput_t* rava_repl_input_create(void) {
|
||||
RavaREPLInput_t *input = malloc(sizeof(RavaREPLInput_t));
|
||||
if (!input) return NULL;
|
||||
input->capacity = RAVA_REPL_MAX_INPUT;
|
||||
input->buffer = malloc(input->capacity);
|
||||
if (!input->buffer) {
|
||||
free(input);
|
||||
return NULL;
|
||||
}
|
||||
input->buffer[0] = '\0';
|
||||
input->size = 0;
|
||||
input->brace_depth = 0;
|
||||
input->bracket_depth = 0;
|
||||
input->paren_depth = 0;
|
||||
input->in_string = false;
|
||||
input->string_delimiter = 0;
|
||||
input->line_count = 0;
|
||||
return input;
|
||||
}
|
||||
|
||||
void rava_repl_input_destroy(RavaREPLInput_t *input) {
|
||||
if (!input) return;
|
||||
free(input->buffer);
|
||||
free(input);
|
||||
}
|
||||
|
||||
void rava_repl_input_reset(RavaREPLInput_t *input) {
|
||||
if (!input) return;
|
||||
input->buffer[0] = '\0';
|
||||
input->size = 0;
|
||||
input->brace_depth = 0;
|
||||
input->bracket_depth = 0;
|
||||
input->paren_depth = 0;
|
||||
input->in_string = false;
|
||||
input->string_delimiter = 0;
|
||||
input->line_count = 0;
|
||||
}
|
||||
|
||||
static void update_nesting(RavaREPLInput_t *input, const char *line) {
|
||||
for (const char *p = line; *p; p++) {
|
||||
if (input->in_string) {
|
||||
if (*p == '\\' && *(p + 1)) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (*p == input->string_delimiter) {
|
||||
input->in_string = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
switch (*p) {
|
||||
case '"':
|
||||
case '\'':
|
||||
input->in_string = true;
|
||||
input->string_delimiter = *p;
|
||||
break;
|
||||
case '{':
|
||||
input->brace_depth++;
|
||||
break;
|
||||
case '}':
|
||||
input->brace_depth--;
|
||||
break;
|
||||
case '[':
|
||||
input->bracket_depth++;
|
||||
break;
|
||||
case ']':
|
||||
input->bracket_depth--;
|
||||
break;
|
||||
case '(':
|
||||
input->paren_depth++;
|
||||
break;
|
||||
case ')':
|
||||
input->paren_depth--;
|
||||
break;
|
||||
case '/':
|
||||
if (*(p + 1) == '/') {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ends_with_operator(const char *line) {
|
||||
size_t len = strlen(line);
|
||||
while (len > 0 && isspace(line[len - 1])) len--;
|
||||
if (len == 0) return false;
|
||||
char last = line[len - 1];
|
||||
if (last == '+' || last == '-' || last == '*' || last == '/' || last == '%' ||
|
||||
last == '&' || last == '|' || last == '^' || last == '=' || last == '<' ||
|
||||
last == '>' || last == '!' || last == '?' || last == ':' || last == ',') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RavaREPLInputState_e rava_repl_input_append(RavaREPLInput_t *input, const char *line) {
|
||||
if (!input || !line) return RAVA_REPL_INPUT_ERROR;
|
||||
size_t line_len = strlen(line);
|
||||
if (input->size + line_len + 2 > input->capacity) {
|
||||
return RAVA_REPL_INPUT_ERROR;
|
||||
}
|
||||
if (input->size > 0) {
|
||||
input->buffer[input->size++] = '\n';
|
||||
}
|
||||
memcpy(input->buffer + input->size, line, line_len);
|
||||
input->size += line_len;
|
||||
input->buffer[input->size] = '\0';
|
||||
input->line_count++;
|
||||
update_nesting(input, line);
|
||||
if (input->in_string) return RAVA_REPL_INPUT_CONTINUE;
|
||||
if (input->brace_depth > 0) return RAVA_REPL_INPUT_CONTINUE;
|
||||
if (input->bracket_depth > 0) return RAVA_REPL_INPUT_CONTINUE;
|
||||
if (input->paren_depth > 0) return RAVA_REPL_INPUT_CONTINUE;
|
||||
if (ends_with_operator(input->buffer)) return RAVA_REPL_INPUT_CONTINUE;
|
||||
return RAVA_REPL_INPUT_COMPLETE;
|
||||
}
|
||||
|
||||
const char* rava_repl_input_get(RavaREPLInput_t *input) {
|
||||
if (!input) return NULL;
|
||||
return input->buffer;
|
||||
}
|
||||
|
||||
bool rava_repl_input_is_empty(RavaREPLInput_t *input) {
|
||||
if (!input) return true;
|
||||
return input->size == 0;
|
||||
}
|
||||
|
||||
static bool starts_with_keyword(const char *code, const char *keyword) {
|
||||
size_t len = strlen(keyword);
|
||||
if (strncmp(code, keyword, len) != 0) return false;
|
||||
char next = code[len];
|
||||
return next == ' ' || next == '\t' || next == '\n' || next == '(' || next == '{' || next == '[';
|
||||
}
|
||||
|
||||
RavaREPLCodeType_e rava_repl_input_detect_type(const char *code) {
|
||||
while (*code && isspace(*code)) code++;
|
||||
if (starts_with_keyword(code, "public") ||
|
||||
starts_with_keyword(code, "private") ||
|
||||
starts_with_keyword(code, "protected")) {
|
||||
const char *p = code;
|
||||
while (*p && !isspace(*p)) p++;
|
||||
while (*p && isspace(*p)) p++;
|
||||
if (starts_with_keyword(p, "class")) {
|
||||
return RAVA_REPL_CODE_CLASS_DECL;
|
||||
}
|
||||
if (starts_with_keyword(p, "static")) {
|
||||
p += 6;
|
||||
while (*p && isspace(*p)) p++;
|
||||
}
|
||||
bool has_paren = false;
|
||||
const char *scan = p;
|
||||
while (*scan && *scan != ';' && *scan != '{') {
|
||||
if (*scan == '(') {
|
||||
has_paren = true;
|
||||
break;
|
||||
}
|
||||
scan++;
|
||||
}
|
||||
if (has_paren) {
|
||||
return RAVA_REPL_CODE_METHOD_DECL;
|
||||
}
|
||||
return RAVA_REPL_CODE_VAR_DECL;
|
||||
}
|
||||
if (starts_with_keyword(code, "class")) {
|
||||
return RAVA_REPL_CODE_CLASS_DECL;
|
||||
}
|
||||
if (starts_with_keyword(code, "interface")) {
|
||||
return RAVA_REPL_CODE_CLASS_DECL;
|
||||
}
|
||||
if (starts_with_keyword(code, "enum")) {
|
||||
return RAVA_REPL_CODE_CLASS_DECL;
|
||||
}
|
||||
if (starts_with_keyword(code, "int") ||
|
||||
starts_with_keyword(code, "long") ||
|
||||
starts_with_keyword(code, "double") ||
|
||||
starts_with_keyword(code, "float") ||
|
||||
starts_with_keyword(code, "boolean") ||
|
||||
starts_with_keyword(code, "char") ||
|
||||
starts_with_keyword(code, "byte") ||
|
||||
starts_with_keyword(code, "short") ||
|
||||
starts_with_keyword(code, "String") ||
|
||||
starts_with_keyword(code, "void")) {
|
||||
const char *p = code;
|
||||
while (*p && !isspace(*p) && *p != '[') p++;
|
||||
if (*p == '[') {
|
||||
while (*p == '[' || *p == ']' || isspace(*p)) p++;
|
||||
}
|
||||
while (*p && isspace(*p)) p++;
|
||||
while (*p && (isalnum(*p) || *p == '_')) p++;
|
||||
while (*p && isspace(*p)) p++;
|
||||
if (*p == '[') {
|
||||
while (*p == '[' || *p == ']' || isspace(*p)) p++;
|
||||
}
|
||||
if (*p == '(') {
|
||||
return RAVA_REPL_CODE_METHOD_DECL;
|
||||
}
|
||||
if (*p == '=' || *p == ';' || *p == ',') {
|
||||
return RAVA_REPL_CODE_VAR_DECL;
|
||||
}
|
||||
}
|
||||
if (starts_with_keyword(code, "if") ||
|
||||
starts_with_keyword(code, "while") ||
|
||||
starts_with_keyword(code, "for") ||
|
||||
starts_with_keyword(code, "do") ||
|
||||
starts_with_keyword(code, "switch") ||
|
||||
starts_with_keyword(code, "try") ||
|
||||
starts_with_keyword(code, "return") ||
|
||||
starts_with_keyword(code, "break") ||
|
||||
starts_with_keyword(code, "continue") ||
|
||||
starts_with_keyword(code, "throw")) {
|
||||
return RAVA_REPL_CODE_STATEMENT;
|
||||
}
|
||||
const char *p = code;
|
||||
if (isupper(*p)) {
|
||||
while (*p && (isalnum(*p) || *p == '_')) p++;
|
||||
if (*p == '[') {
|
||||
while (*p == '[' || *p == ']' || isspace(*p)) p++;
|
||||
}
|
||||
while (*p && isspace(*p)) p++;
|
||||
if (islower(*p) || *p == '_') {
|
||||
const char *var_start = p;
|
||||
while (*p && (isalnum(*p) || *p == '_')) p++;
|
||||
if (p > var_start) {
|
||||
while (*p && isspace(*p)) p++;
|
||||
if (*p == '=' || *p == ';') {
|
||||
return RAVA_REPL_CODE_VAR_DECL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = code;
|
||||
bool has_semicolon = false;
|
||||
bool has_assign = false;
|
||||
while (*p) {
|
||||
if (*p == ';') has_semicolon = true;
|
||||
if (*p == '=' && *(p+1) != '=') has_assign = true;
|
||||
p++;
|
||||
}
|
||||
if (has_assign && has_semicolon) {
|
||||
return RAVA_REPL_CODE_STATEMENT;
|
||||
}
|
||||
return RAVA_REPL_CODE_EXPRESSION;
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
#ifndef RAVA_REPL_INPUT_H
|
||||
#define RAVA_REPL_INPUT_H
|
||||
|
||||
#include "repl_types.h"
|
||||
|
||||
typedef struct {
|
||||
char *buffer;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
int brace_depth;
|
||||
int bracket_depth;
|
||||
int paren_depth;
|
||||
bool in_string;
|
||||
char string_delimiter;
|
||||
int line_count;
|
||||
} RavaREPLInput_t;
|
||||
|
||||
RavaREPLInput_t* rava_repl_input_create(void);
|
||||
void rava_repl_input_destroy(RavaREPLInput_t *input);
|
||||
void rava_repl_input_reset(RavaREPLInput_t *input);
|
||||
RavaREPLInputState_e rava_repl_input_append(RavaREPLInput_t *input, const char *line);
|
||||
const char* rava_repl_input_get(RavaREPLInput_t *input);
|
||||
bool rava_repl_input_is_empty(RavaREPLInput_t *input);
|
||||
RavaREPLCodeType_e rava_repl_input_detect_type(const char *code);
|
||||
|
||||
#endif
|
||||
@ -1,196 +0,0 @@
|
||||
#include "repl_output.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char* type_name(RavaValueType_e type) {
|
||||
switch (type) {
|
||||
case RAVA_VAL_INT: return "int";
|
||||
case RAVA_VAL_LONG: return "long";
|
||||
case RAVA_VAL_FLOAT: return "float";
|
||||
case RAVA_VAL_DOUBLE: return "double";
|
||||
case RAVA_VAL_BOOLEAN: return "boolean";
|
||||
case RAVA_VAL_CHAR: return "char";
|
||||
case RAVA_VAL_NULL: return "null";
|
||||
case RAVA_VAL_OBJECT: return "Object";
|
||||
case RAVA_VAL_ARRAY: return "Array";
|
||||
case RAVA_VAL_STRING: return "String";
|
||||
case RAVA_VAL_ARRAYLIST: return "ArrayList";
|
||||
case RAVA_VAL_HASHMAP: return "HashMap";
|
||||
case RAVA_VAL_SOCKET: return "Socket";
|
||||
case RAVA_VAL_STREAM: return "Stream";
|
||||
case RAVA_VAL_METHOD_REF: return "MethodRef";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_value(RavaValue_t value, RavaVM_t *vm) {
|
||||
(void)vm;
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT:
|
||||
printf("%ld\n", value.data.int_val);
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
printf("%ldL\n", value.data.long_val);
|
||||
break;
|
||||
case RAVA_VAL_FLOAT:
|
||||
printf("%gf\n", value.data.float_val);
|
||||
break;
|
||||
case RAVA_VAL_DOUBLE:
|
||||
printf("%g\n", value.data.double_val);
|
||||
break;
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
printf("%s\n", value.data.bool_val ? "true" : "false");
|
||||
break;
|
||||
case RAVA_VAL_CHAR:
|
||||
printf("'%c'\n", value.data.char_val);
|
||||
break;
|
||||
case RAVA_VAL_STRING:
|
||||
if (value.data.string_val) {
|
||||
printf("\"%s\"\n", value.data.string_val);
|
||||
} else {
|
||||
printf("null\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_OBJECT:
|
||||
if (value.data.object_val) {
|
||||
RavaObject_t *obj = value.data.object_val;
|
||||
printf("%s@%p\n", obj->class_name ? obj->class_name : "Object", (void*)obj);
|
||||
} else {
|
||||
printf("null\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_ARRAY:
|
||||
if (value.data.array_val) {
|
||||
RavaArray_t *arr = value.data.array_val;
|
||||
printf("[%s array]: size=%zu\n", type_name(arr->element_type), arr->length);
|
||||
} else {
|
||||
printf("null\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
if (value.data.arraylist_val) {
|
||||
printf("[ArrayList]: size=%zu\n", rava_arraylist_size(value.data.arraylist_val));
|
||||
} else {
|
||||
printf("null\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_HASHMAP:
|
||||
if (value.data.hashmap_val) {
|
||||
printf("[HashMap]: size=%zu\n", rava_hashmap_size(value.data.hashmap_val));
|
||||
} else {
|
||||
printf("null\n");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_NULL:
|
||||
printf("null\n");
|
||||
break;
|
||||
default:
|
||||
printf("<%s>\n", type_name(value.type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_variable(RavaREPLVariable_t *var) {
|
||||
if (!var) return;
|
||||
printf("%-20s %-15s ", var->name, var->type_name ? var->type_name : "?");
|
||||
if (!var->is_initialized) {
|
||||
printf("<uninitialized>");
|
||||
} else {
|
||||
switch (var->type) {
|
||||
case RAVA_VAL_INT:
|
||||
printf("%ld", var->value.data.int_val);
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
printf("%ldL", var->value.data.long_val);
|
||||
break;
|
||||
case RAVA_VAL_FLOAT:
|
||||
printf("%gf", var->value.data.float_val);
|
||||
break;
|
||||
case RAVA_VAL_DOUBLE:
|
||||
printf("%g", var->value.data.double_val);
|
||||
break;
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
printf("%s", var->value.data.bool_val ? "true" : "false");
|
||||
break;
|
||||
case RAVA_VAL_STRING:
|
||||
if (var->value.data.string_val) {
|
||||
printf("\"%s\"", var->value.data.string_val);
|
||||
} else {
|
||||
printf("null");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_OBJECT:
|
||||
if (var->value.data.object_val) {
|
||||
printf("%s@%p", var->type_name ? var->type_name : "Object",
|
||||
(void*)var->value.data.object_val);
|
||||
} else {
|
||||
printf("null");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_ARRAY:
|
||||
if (var->value.data.array_val) {
|
||||
printf("[array]: size=%zu", var->value.data.array_val->length);
|
||||
} else {
|
||||
printf("null");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void rava_repl_output_variables(RavaREPLSession_t *session) {
|
||||
if (!session || session->variable_count == 0) {
|
||||
printf("No variables defined.\n");
|
||||
return;
|
||||
}
|
||||
printf("%-20s %-15s %s\n", "Variable", "Type", "Value");
|
||||
printf("%-20s %-15s %s\n", "--------", "----", "-----");
|
||||
for (size_t i = 0; i < session->variable_count; i++) {
|
||||
rava_repl_output_variable(&session->variables[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_methods(RavaREPLSession_t *session) {
|
||||
if (!session || session->method_count == 0) {
|
||||
printf("No methods defined.\n");
|
||||
return;
|
||||
}
|
||||
printf("%-20s %-15s\n", "Method", "Return Type");
|
||||
printf("%-20s %-15s\n", "------", "-----------");
|
||||
for (size_t i = 0; i < session->method_count; i++) {
|
||||
printf("%-20s %-15s\n",
|
||||
session->methods[i].name,
|
||||
session->methods[i].return_type ? session->methods[i].return_type : "void");
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_classes(RavaREPLSession_t *session) {
|
||||
if (!session || session->class_count == 0) {
|
||||
printf("No classes defined.\n");
|
||||
return;
|
||||
}
|
||||
printf("Defined classes:\n");
|
||||
for (size_t i = 0; i < session->class_count; i++) {
|
||||
printf(" %s\n", session->classes[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_error(const char *type, const char *message) {
|
||||
if (type) {
|
||||
printf("%s: %s\n", type, message ? message : "Unknown error");
|
||||
} else {
|
||||
printf("Error: %s\n", message ? message : "Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
void rava_repl_output_timing(double elapsed_ms) {
|
||||
if (elapsed_ms >= 1000.0) {
|
||||
printf("# Executed in %.2f s\n", elapsed_ms / 1000.0);
|
||||
} else {
|
||||
printf("# Executed in %.1f ms\n", elapsed_ms);
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
#ifndef RAVA_REPL_OUTPUT_H
|
||||
#define RAVA_REPL_OUTPUT_H
|
||||
|
||||
#include "repl_types.h"
|
||||
#include "repl_session.h"
|
||||
|
||||
void rava_repl_output_value(RavaValue_t value, RavaVM_t *vm);
|
||||
void rava_repl_output_variable(RavaREPLVariable_t *var);
|
||||
void rava_repl_output_variables(RavaREPLSession_t *session);
|
||||
void rava_repl_output_methods(RavaREPLSession_t *session);
|
||||
void rava_repl_output_classes(RavaREPLSession_t *session);
|
||||
void rava_repl_output_error(const char *type, const char *message);
|
||||
void rava_repl_output_timing(double elapsed_ms);
|
||||
|
||||
#endif
|
||||
@ -1,369 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
#ifndef RAVA_REPL_SESSION_H
|
||||
#define RAVA_REPL_SESSION_H
|
||||
|
||||
#include "repl_types.h"
|
||||
#include "repl_history.h"
|
||||
|
||||
typedef struct {
|
||||
RavaREPLVariable_t *variables;
|
||||
size_t variable_count;
|
||||
size_t variable_capacity;
|
||||
|
||||
RavaREPLMethod_t *methods;
|
||||
size_t method_count;
|
||||
size_t method_capacity;
|
||||
|
||||
RavaREPLClass_t *classes;
|
||||
size_t class_count;
|
||||
size_t class_capacity;
|
||||
|
||||
RavaProgram_t *program;
|
||||
RavaClass_t *session_class;
|
||||
RavaVM_t *vm;
|
||||
|
||||
RavaREPLHistory_t *history;
|
||||
time_t start_time;
|
||||
int execution_count;
|
||||
bool debug_mode;
|
||||
char *last_error;
|
||||
} RavaREPLSession_t;
|
||||
|
||||
RavaREPLSession_t* rava_repl_session_create(void);
|
||||
void rava_repl_session_destroy(RavaREPLSession_t *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);
|
||||
RavaREPLVariable_t* rava_repl_session_get_variable(RavaREPLSession_t *session, const char *name);
|
||||
bool rava_repl_session_set_variable(RavaREPLSession_t *session, const char *name, RavaValue_t value);
|
||||
void rava_repl_session_clear_variables(RavaREPLSession_t *session);
|
||||
|
||||
bool rava_repl_session_add_method(RavaREPLSession_t *session, const char *name,
|
||||
const char *return_type, const char *source);
|
||||
RavaREPLMethod_t* rava_repl_session_get_method(RavaREPLSession_t *session, const char *name);
|
||||
|
||||
bool rava_repl_session_add_class(RavaREPLSession_t *session, const char *name, const char *source);
|
||||
RavaREPLClass_t* rava_repl_session_get_class(RavaREPLSession_t *session, const char *name);
|
||||
|
||||
char* rava_repl_session_generate_source(RavaREPLSession_t *session);
|
||||
bool rava_repl_session_recompile(RavaREPLSession_t *session);
|
||||
|
||||
void rava_repl_session_set_error(RavaREPLSession_t *session, const char *error);
|
||||
const char* rava_repl_session_get_error(RavaREPLSession_t *session);
|
||||
|
||||
#endif
|
||||
@ -1,99 +0,0 @@
|
||||
#ifndef RAVA_REPL_TYPES_H
|
||||
#define RAVA_REPL_TYPES_H
|
||||
|
||||
#include "../runtime/runtime.h"
|
||||
#include "../lexer/lexer.h"
|
||||
#include "../parser/parser.h"
|
||||
#include "../semantic/semantic.h"
|
||||
#include "../ir/ir_gen.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#define RAVA_REPL_VERSION "1.0"
|
||||
#define RAVA_REPL_MAX_INPUT 65536
|
||||
#define RAVA_REPL_MAX_HISTORY 1000
|
||||
#define RAVA_REPL_MAX_VARIABLES 256
|
||||
#define RAVA_REPL_MAX_METHODS 128
|
||||
#define RAVA_REPL_MAX_CLASSES 64
|
||||
#define RAVA_REPL_TIMEOUT_MS 30000
|
||||
|
||||
typedef enum {
|
||||
RAVA_REPL_INPUT_CONTINUE,
|
||||
RAVA_REPL_INPUT_COMPLETE,
|
||||
RAVA_REPL_INPUT_ERROR,
|
||||
RAVA_REPL_INPUT_EOF
|
||||
} RavaREPLInputState_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_REPL_EXEC_SUCCESS,
|
||||
RAVA_REPL_EXEC_PARSE_ERROR,
|
||||
RAVA_REPL_EXEC_SEMANTIC_ERROR,
|
||||
RAVA_REPL_EXEC_RUNTIME_ERROR,
|
||||
RAVA_REPL_EXEC_INTERRUPTED
|
||||
} RavaREPLExecResult_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_REPL_CODE_EXPRESSION,
|
||||
RAVA_REPL_CODE_STATEMENT,
|
||||
RAVA_REPL_CODE_VAR_DECL,
|
||||
RAVA_REPL_CODE_METHOD_DECL,
|
||||
RAVA_REPL_CODE_CLASS_DECL,
|
||||
RAVA_REPL_CODE_UNKNOWN
|
||||
} RavaREPLCodeType_e;
|
||||
|
||||
typedef enum {
|
||||
RAVA_CMD_HELP,
|
||||
RAVA_CMD_WHOS,
|
||||
RAVA_CMD_WHO,
|
||||
RAVA_CMD_RESET,
|
||||
RAVA_CMD_CLEAR,
|
||||
RAVA_CMD_QUIT,
|
||||
RAVA_CMD_EXIT,
|
||||
RAVA_CMD_HISTORY,
|
||||
RAVA_CMD_RUN,
|
||||
RAVA_CMD_LOAD,
|
||||
RAVA_CMD_SAVE,
|
||||
RAVA_CMD_DEBUG,
|
||||
RAVA_CMD_TIME,
|
||||
RAVA_CMD_TIMEIT,
|
||||
RAVA_CMD_MEMORY,
|
||||
RAVA_CMD_DIR,
|
||||
RAVA_CMD_TYPE,
|
||||
RAVA_CMD_SOURCE,
|
||||
RAVA_CMD_METHODS,
|
||||
RAVA_CMD_CLASSES,
|
||||
RAVA_CMD_UNKNOWN
|
||||
} RavaREPLCommand_e;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *type_name;
|
||||
char *initializer;
|
||||
RavaValueType_e type;
|
||||
RavaValue_t value;
|
||||
bool is_initialized;
|
||||
} RavaREPLVariable_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *return_type;
|
||||
char **param_names;
|
||||
char **param_types;
|
||||
size_t param_count;
|
||||
char *source;
|
||||
RavaMethod_t *compiled;
|
||||
} RavaREPLMethod_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *source;
|
||||
char **field_names;
|
||||
char **field_types;
|
||||
size_t field_count;
|
||||
char **method_names;
|
||||
size_t method_count;
|
||||
RavaClass_t *compiled;
|
||||
} RavaREPLClass_t;
|
||||
|
||||
#endif
|
||||
@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RAVA="$SCRIPT_DIR/../rava"
|
||||
TESTS_DIR="$SCRIPT_DIR/tests"
|
||||
EXAMPLES_DIR="$SCRIPT_DIR/examples"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
passed=0
|
||||
failed=0
|
||||
|
||||
run_test() {
|
||||
local file="$1"
|
||||
local name=$(basename "$file" .txt)
|
||||
|
||||
echo -n " $name ... "
|
||||
|
||||
if timeout 30 "$RAVA" < "$file" > /tmp/repl_test_output.txt 2>&1; then
|
||||
echo -e "${GREEN}ok${NC}"
|
||||
((passed++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}"
|
||||
echo " Output:"
|
||||
head -20 /tmp/repl_test_output.txt | sed 's/^/ /'
|
||||
((failed++))
|
||||
fi
|
||||
}
|
||||
|
||||
echo "========================================"
|
||||
echo "REPL Test Suite"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
echo "Running tests..."
|
||||
for test_file in "$TESTS_DIR"/*.txt; do
|
||||
if [ -f "$test_file" ]; then
|
||||
run_test "$test_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Running examples..."
|
||||
for example_file in "$EXAMPLES_DIR"/*.txt; do
|
||||
if [ -f "$example_file" ]; then
|
||||
run_test "$example_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "Results: $passed passed, $failed failed"
|
||||
echo "========================================"
|
||||
|
||||
if [ $failed -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
@ -1,15 +0,0 @@
|
||||
int[] arr = new int[5];
|
||||
arr.length
|
||||
int[] nums = {1, 2, 3, 4, 5};
|
||||
nums.length
|
||||
nums[0]
|
||||
nums[4]
|
||||
String[] names = {"Alice", "Bob", "Charlie"};
|
||||
names.length
|
||||
names[0]
|
||||
names[1]
|
||||
double[] vals = {1.5, 2.5, 3.5};
|
||||
vals[0]
|
||||
vals[2]
|
||||
%whos
|
||||
%quit
|
||||
@ -1,16 +0,0 @@
|
||||
class Point { public int x; public int y; public Point(int px, int py) { this.x = px; this.y = py; } }
|
||||
Point p = new Point(3, 4);
|
||||
p.x
|
||||
p.y
|
||||
class Rectangle { public int width; public int height; public Rectangle(int w, int h) { this.width = w; this.height = h; } public int area() { return this.width * this.height; } public int perimeter() { return 2 * (this.width + this.height); } }
|
||||
Rectangle r = new Rectangle(5, 10);
|
||||
r.width
|
||||
r.height
|
||||
r.area()
|
||||
r.perimeter()
|
||||
class Counter { public int count; public Counter() { this.count = 0; } public void inc() { this.count++; } public void dec() { this.count--; } public int get() { return this.count; } }
|
||||
Counter c = new Counter();
|
||||
c.get()
|
||||
%classes
|
||||
%whos
|
||||
%quit
|
||||
@ -1,16 +0,0 @@
|
||||
%help
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
%whos
|
||||
%who
|
||||
int triple(int x) { return x * 3; }
|
||||
%methods
|
||||
class Foo { public int val; }
|
||||
%classes
|
||||
%reset
|
||||
%whos
|
||||
%who
|
||||
%methods
|
||||
%classes
|
||||
%quit
|
||||
@ -1,8 +0,0 @@
|
||||
for (int i = 0; i < 5; i++) { System.out.println(i); }
|
||||
int sum = 0; for (int i = 1; i <= 10; i++) { sum = sum + i; } System.out.println(sum);
|
||||
int x = 10; while (x > 0) { System.out.println(x); x = x - 2; }
|
||||
int n = 1; do { System.out.println(n); n = n * 2; } while (n < 100);
|
||||
int val = 2; switch (val) { case 1: System.out.println("one"); break; case 2: System.out.println("two"); break; default: System.out.println("other"); }
|
||||
if (5 > 3) { System.out.println("yes"); } else { System.out.println("no"); }
|
||||
for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { System.out.println(i * 3 + j); } }
|
||||
%quit
|
||||
@ -1,8 +0,0 @@
|
||||
undefined_variable
|
||||
1 + "string"
|
||||
int x = ;
|
||||
class { }
|
||||
1 / 0
|
||||
int y = 10;
|
||||
y
|
||||
%quit
|
||||
@ -1,24 +0,0 @@
|
||||
1 + 2
|
||||
3 * 4
|
||||
10 - 5
|
||||
20 / 4
|
||||
17 % 5
|
||||
-42
|
||||
1 + 2 * 3
|
||||
(1 + 2) * 3
|
||||
10 > 5
|
||||
10 < 5
|
||||
10 == 10
|
||||
10 != 5
|
||||
true && false
|
||||
true || false
|
||||
!true
|
||||
1 < 2 && 3 < 4
|
||||
5 > 3 ? 100 : 200
|
||||
1 | 2
|
||||
3 & 2
|
||||
4 ^ 1
|
||||
~0
|
||||
8 >> 2
|
||||
1 << 3
|
||||
%quit
|
||||
@ -1,16 +0,0 @@
|
||||
Math.abs(-42)
|
||||
Math.abs(42)
|
||||
Math.sqrt(16.0)
|
||||
Math.sqrt(2.0)
|
||||
Math.pow(2.0, 10.0)
|
||||
Math.min(5, 3)
|
||||
Math.max(5, 3)
|
||||
Math.floor(3.7)
|
||||
Math.ceil(3.2)
|
||||
Math.round(3.5)
|
||||
Math.sin(0.0)
|
||||
Math.cos(0.0)
|
||||
Math.tan(0.0)
|
||||
Math.log(2.718281828)
|
||||
Math.exp(1.0)
|
||||
%quit
|
||||
@ -1,21 +0,0 @@
|
||||
int add(int a, int b) { return a + b; }
|
||||
add(3, 4)
|
||||
add(10, 20)
|
||||
int square(int x) { return x * x; }
|
||||
square(5)
|
||||
square(12)
|
||||
int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); }
|
||||
factorial(5)
|
||||
factorial(10)
|
||||
int fib(int n) { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); }
|
||||
fib(10)
|
||||
fib(15)
|
||||
double avg(double a, double b) { return (a + b) / 2.0; }
|
||||
avg(10.0, 20.0)
|
||||
boolean isEven(int n) { return n % 2 == 0; }
|
||||
isEven(4)
|
||||
isEven(7)
|
||||
String greet(String name) { return "Hello, " + name + "!"; }
|
||||
greet("World")
|
||||
%methods
|
||||
%quit
|
||||
@ -1,22 +0,0 @@
|
||||
class Person {
|
||||
public String name;
|
||||
public int age;
|
||||
public Person(String n, int a) {
|
||||
this.name = n;
|
||||
this.age = a;
|
||||
}
|
||||
public String describe() {
|
||||
return this.name + " is " + this.age + " years old";
|
||||
}
|
||||
}
|
||||
Person p = new Person("Alice", 30);
|
||||
p.name
|
||||
p.age
|
||||
p.describe()
|
||||
int compute(int x,
|
||||
int y,
|
||||
int z) {
|
||||
return x + y + z;
|
||||
}
|
||||
compute(1, 2, 3)
|
||||
%quit
|
||||
@ -1,19 +0,0 @@
|
||||
String s = "hello world";
|
||||
s
|
||||
s.length()
|
||||
s.toUpperCase()
|
||||
s.toLowerCase()
|
||||
s.charAt(0)
|
||||
s.substring(0, 5)
|
||||
s.indexOf("world")
|
||||
s.contains("ell")
|
||||
s.startsWith("hello")
|
||||
s.endsWith("world")
|
||||
s.trim()
|
||||
String a = "foo";
|
||||
String b = "bar";
|
||||
a + b
|
||||
a.equals("foo")
|
||||
a.compareTo(b)
|
||||
%whos
|
||||
%quit
|
||||
@ -1,23 +0,0 @@
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
x
|
||||
y
|
||||
x + y
|
||||
x * y
|
||||
x - y
|
||||
x / y
|
||||
x % y
|
||||
long big = 1000000000;
|
||||
big
|
||||
double pi = 3.14159;
|
||||
pi
|
||||
float f = 2.5;
|
||||
f
|
||||
boolean flag = true;
|
||||
flag
|
||||
char c = 'A';
|
||||
c
|
||||
String name = "Rava";
|
||||
name
|
||||
%whos
|
||||
%quit
|
||||
@ -22,8 +22,8 @@ typedef uint64_t RavaNanboxValue_t;
|
||||
#define RAVA_TAG_STRING (RAVA_QNAN | 0x0006000000000000ULL)
|
||||
#define RAVA_TAG_ARRAY (RAVA_QNAN | 0x0007000000000000ULL)
|
||||
|
||||
static inline RavaNanboxValue_t rava_nanbox_int(int64_t v) {
|
||||
return RAVA_TAG_LONG | ((uint64_t)v & RAVA_PAYLOAD_MASK);
|
||||
static inline RavaNanboxValue_t rava_nanbox_int(int32_t v) {
|
||||
return RAVA_TAG_INT | (uint64_t)(uint32_t)v;
|
||||
}
|
||||
|
||||
static inline RavaNanboxValue_t rava_nanbox_long(int64_t v) {
|
||||
@ -56,7 +56,7 @@ static inline RavaNanboxValue_t rava_nanbox_array(void* ptr) {
|
||||
}
|
||||
|
||||
static inline bool rava_nanbox_is_int(RavaNanboxValue_t v) {
|
||||
return (v & RAVA_TAG_MASK) == RAVA_TAG_LONG;
|
||||
return (v & RAVA_TAG_MASK) == RAVA_TAG_INT;
|
||||
}
|
||||
|
||||
static inline bool rava_nanbox_is_long(RavaNanboxValue_t v) {
|
||||
@ -87,12 +87,8 @@ static inline bool rava_nanbox_is_double(RavaNanboxValue_t v) {
|
||||
return (v & RAVA_QNAN) != RAVA_QNAN;
|
||||
}
|
||||
|
||||
static inline int64_t rava_nanbox_as_int(RavaNanboxValue_t v) {
|
||||
int64_t payload = (int64_t)(v & RAVA_PAYLOAD_MASK);
|
||||
if (payload & 0x800000000000ULL) {
|
||||
payload |= (int64_t)0xFFFF000000000000ULL;
|
||||
}
|
||||
return payload;
|
||||
static inline int32_t rava_nanbox_as_int(RavaNanboxValue_t v) {
|
||||
return (int32_t)(v & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static inline int64_t rava_nanbox_as_long(RavaNanboxValue_t v) {
|
||||
@ -124,11 +120,11 @@ static inline void* rava_nanbox_as_array(RavaNanboxValue_t v) {
|
||||
return (void*)(uintptr_t)(v & RAVA_PAYLOAD_MASK);
|
||||
}
|
||||
|
||||
static inline int64_t rava_nanbox_to_int(RavaNanboxValue_t v) {
|
||||
static inline int32_t rava_nanbox_to_int(RavaNanboxValue_t v) {
|
||||
if (rava_nanbox_is_int(v)) return rava_nanbox_as_int(v);
|
||||
if (rava_nanbox_is_long(v)) return rava_nanbox_as_long(v);
|
||||
if (rava_nanbox_is_long(v)) return (int32_t)rava_nanbox_as_long(v);
|
||||
if (rava_nanbox_is_bool(v)) return rava_nanbox_as_bool(v) ? 1 : 0;
|
||||
if (rava_nanbox_is_double(v)) return (int64_t)rava_nanbox_as_double(v);
|
||||
if (rava_nanbox_is_double(v)) return (int32_t)rava_nanbox_as_double(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -205,12 +205,12 @@ static void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaV
|
||||
}
|
||||
|
||||
|
||||
int64_t rava_value_as_int(RavaValue_t value) {
|
||||
int32_t rava_value_as_int(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT: return value.data.int_val;
|
||||
case RAVA_VAL_LONG: return value.data.long_val;
|
||||
case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val;
|
||||
case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val;
|
||||
case RAVA_VAL_LONG: return (int32_t)value.data.long_val;
|
||||
case RAVA_VAL_FLOAT: return (int32_t)value.data.float_val;
|
||||
case RAVA_VAL_DOUBLE: return (int32_t)value.data.double_val;
|
||||
case RAVA_VAL_BOOLEAN: return value.data.bool_val ? 1 : 0;
|
||||
case RAVA_VAL_CHAR: return value.data.char_val;
|
||||
default: return 0;
|
||||
@ -687,7 +687,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
snprintf(buf_a, sizeof(buf_a), "%ld", (long)rava_value_as_long(a));
|
||||
str_a = buf_a;
|
||||
} else {
|
||||
snprintf(buf_a, sizeof(buf_a), "%ld", (long)rava_value_as_int(a));
|
||||
snprintf(buf_a, sizeof(buf_a), "%d", rava_value_as_int(a));
|
||||
str_a = buf_a;
|
||||
}
|
||||
if (b.type == RAVA_VAL_STRING) {
|
||||
@ -696,7 +696,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
snprintf(buf_b, sizeof(buf_b), "%ld", (long)rava_value_as_long(b));
|
||||
str_b = buf_b;
|
||||
} else {
|
||||
snprintf(buf_b, sizeof(buf_b), "%ld", (long)rava_value_as_int(b));
|
||||
snprintf(buf_b, sizeof(buf_b), "%d", rava_value_as_int(b));
|
||||
str_b = buf_b;
|
||||
}
|
||||
size_t len = strlen(str_a) + strlen(str_b) + 1;
|
||||
@ -738,26 +738,46 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
case RAVA_OP_DIV: {
|
||||
RavaValue_t b = rava_stack_pop(stack);
|
||||
RavaValue_t a = rava_stack_pop(stack);
|
||||
int64_t divisor = rava_value_as_int(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) {
|
||||
int64_t divisor = rava_value_as_long(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
}
|
||||
rava_stack_push(stack, rava_value_long(rava_value_as_long(a) / divisor));
|
||||
} else {
|
||||
int32_t divisor = rava_value_as_int(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
}
|
||||
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) / divisor));
|
||||
}
|
||||
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) / divisor));
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_MOD: {
|
||||
RavaValue_t b = rava_stack_pop(stack);
|
||||
RavaValue_t a = rava_stack_pop(stack);
|
||||
int64_t divisor = rava_value_as_int(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) {
|
||||
int64_t divisor = rava_value_as_long(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
}
|
||||
rava_stack_push(stack, rava_value_long(rava_value_as_long(a) % divisor));
|
||||
} else {
|
||||
int32_t divisor = rava_value_as_int(b);
|
||||
if (divisor == 0) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = strdup("Division by zero");
|
||||
return false;
|
||||
}
|
||||
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) % divisor));
|
||||
}
|
||||
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) % divisor));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1136,7 +1156,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
printf("[array@%p]", (void*)value.data.array_val);
|
||||
break;
|
||||
default:
|
||||
printf("%ld", (long)rava_value_as_int(value));
|
||||
printf("%d", rava_value_as_int(value));
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
@ -1168,7 +1188,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
printf("[array@%p]\n", (void*)value.data.array_val);
|
||||
break;
|
||||
default:
|
||||
printf("%ld\n", (long)rava_value_as_int(value));
|
||||
printf("%d\n", rava_value_as_int(value));
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
@ -1188,7 +1208,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
|
||||
case RAVA_OP_NEW_ARRAY: {
|
||||
RavaValue_t length_val = rava_stack_pop(stack);
|
||||
int64_t length = rava_value_as_int(length_val);
|
||||
int32_t length = rava_value_as_int(length_val);
|
||||
if (length < 0) length = 0;
|
||||
RavaArray_t *array = rava_array_create(RAVA_VAL_INT, (size_t)length);
|
||||
if (array) {
|
||||
@ -1201,7 +1221,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
|
||||
case RAVA_OP_NEW_ARRAY_OF_ARRAYS: {
|
||||
RavaValue_t length_val = rava_stack_pop(stack);
|
||||
int64_t length = rava_value_as_int(length_val);
|
||||
int32_t length = rava_value_as_int(length_val);
|
||||
if (length < 0) length = 0;
|
||||
RavaArray_t *array = rava_array_create(RAVA_VAL_ARRAY, (size_t)length);
|
||||
if (array) {
|
||||
@ -1236,7 +1256,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
RavaValue_t array_val = rava_stack_pop(stack);
|
||||
if (array_val.type == RAVA_VAL_ARRAY) {
|
||||
size_t length = rava_array_length(array_val.data.array_val);
|
||||
rava_stack_push(stack, rava_value_int((int64_t)length));
|
||||
rava_stack_push(stack, rava_value_int((int32_t)length));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_int(0));
|
||||
}
|
||||
@ -1247,12 +1267,12 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
RavaValue_t index_val = rava_stack_pop(stack);
|
||||
RavaValue_t array_val = rava_stack_pop(stack);
|
||||
if (array_val.type == RAVA_VAL_ARRAY) {
|
||||
int64_t index = rava_value_as_int(index_val);
|
||||
int32_t index = rava_value_as_int(index_val);
|
||||
RavaArray_t *arr = array_val.data.array_val;
|
||||
if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) {
|
||||
rava_stack_push(stack, rava_array_get_value(arr, (size_t)index));
|
||||
} else {
|
||||
int64_t value = rava_array_get_int(arr, (size_t)index);
|
||||
int32_t value = rava_array_get_int(arr, (size_t)index);
|
||||
rava_stack_push(stack, rava_value_int(value));
|
||||
}
|
||||
} else {
|
||||
@ -1266,12 +1286,12 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
RavaValue_t index_val = rava_stack_pop(stack);
|
||||
RavaValue_t array_val = rava_stack_pop(stack);
|
||||
if (array_val.type == RAVA_VAL_ARRAY) {
|
||||
int64_t index = rava_value_as_int(index_val);
|
||||
int32_t index = rava_value_as_int(index_val);
|
||||
RavaArray_t *arr = array_val.data.array_val;
|
||||
if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) {
|
||||
rava_array_set_value(arr, (size_t)index, value_val);
|
||||
} else {
|
||||
int64_t value = rava_value_as_int(value_val);
|
||||
int32_t value = rava_value_as_int(value_val);
|
||||
rava_array_set_int(arr, (size_t)index, value);
|
||||
}
|
||||
}
|
||||
@ -1281,7 +1301,7 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
case RAVA_OP_STRING_LENGTH: {
|
||||
RavaValue_t str_val = rava_stack_pop(stack);
|
||||
if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) {
|
||||
rava_stack_push(stack, rava_value_int((int64_t)strlen(str_val.data.string_val)));
|
||||
rava_stack_push(stack, rava_value_int((int32_t)strlen(str_val.data.string_val)));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_int(0));
|
||||
}
|
||||
@ -2269,10 +2289,10 @@ op_add: {
|
||||
const char *str_a, *str_b;
|
||||
if (a.type == RAVA_VAL_STRING) str_a = a.data.string_val ? a.data.string_val : "null";
|
||||
else if (VALUE_IS_LONG(a)) { snprintf(buf_a, 64, "%ld", (long)VALUE_AS_LONG_FAST(a)); str_a = buf_a; }
|
||||
else { snprintf(buf_a, 64, "%ld", (long)rava_value_as_int(a)); str_a = buf_a; }
|
||||
else { snprintf(buf_a, 64, "%d", rava_value_as_int(a)); str_a = buf_a; }
|
||||
if (b.type == RAVA_VAL_STRING) str_b = b.data.string_val ? b.data.string_val : "null";
|
||||
else if (VALUE_IS_LONG(b)) { snprintf(buf_b, 64, "%ld", (long)VALUE_AS_LONG_FAST(b)); str_b = buf_b; }
|
||||
else { snprintf(buf_b, 64, "%ld", (long)rava_value_as_int(b)); str_b = buf_b; }
|
||||
else { snprintf(buf_b, 64, "%d", rava_value_as_int(b)); str_b = buf_b; }
|
||||
size_t len_a = strlen(str_a);
|
||||
size_t len_b = strlen(str_b);
|
||||
size_t len = len_a + len_b + 1;
|
||||
@ -2847,7 +2867,7 @@ op_print: {
|
||||
case RAVA_VAL_DOUBLE: printf("%g", value.data.double_val); break;
|
||||
case RAVA_VAL_LONG: printf("%ld", (long)value.data.long_val); break;
|
||||
case RAVA_VAL_NULL: printf("null"); break;
|
||||
default: printf("%ld", (long)rava_value_as_int(value)); break;
|
||||
default: printf("%d", rava_value_as_int(value)); break;
|
||||
}
|
||||
fflush(stdout);
|
||||
DISPATCH();
|
||||
@ -2861,7 +2881,7 @@ op_println: {
|
||||
case RAVA_VAL_DOUBLE: printf("%g\n", value.data.double_val); break;
|
||||
case RAVA_VAL_LONG: printf("%ld\n", (long)value.data.long_val); break;
|
||||
case RAVA_VAL_NULL: printf("null\n"); break;
|
||||
default: printf("%ld\n", (long)rava_value_as_int(value)); break;
|
||||
default: printf("%d\n", rava_value_as_int(value)); break;
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
@ -2928,7 +2948,7 @@ op_string_equals: {
|
||||
STACK_PUSH_BOOL(stack, a.data.string_val == b.data.string_val);
|
||||
}
|
||||
} else {
|
||||
STACK_PUSH_BOOL(stack, rava_object_equals(a, b));
|
||||
STACK_PUSH_BOOL(stack, false);
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
@ -3481,13 +3501,13 @@ uf_add: {
|
||||
char buf_a[64], buf_b[64];
|
||||
const char *str_a, *str_b;
|
||||
if (rava_nanbox_is_string(a)) str_a = rava_nanbox_as_string(a) ? rava_nanbox_as_string(a) : "null";
|
||||
else if (rava_nanbox_is_int(a)) { snprintf(buf_a, 64, "%ld", (long)rava_nanbox_as_int(a)); str_a = buf_a; }
|
||||
else if (rava_nanbox_is_int(a)) { snprintf(buf_a, 64, "%d", rava_nanbox_as_int(a)); str_a = buf_a; }
|
||||
else if (rava_nanbox_is_long(a)) { snprintf(buf_a, 64, "%ld", (long)rava_nanbox_as_long(a)); str_a = buf_a; }
|
||||
else if (rava_nanbox_is_double(a)) { snprintf(buf_a, 64, "%g", rava_nanbox_as_double(a)); str_a = buf_a; }
|
||||
else if (rava_nanbox_is_bool(a)) { str_a = rava_nanbox_as_bool(a) ? "true" : "false"; }
|
||||
else { str_a = "null"; }
|
||||
if (rava_nanbox_is_string(b)) str_b = rava_nanbox_as_string(b) ? rava_nanbox_as_string(b) : "null";
|
||||
else if (rava_nanbox_is_int(b)) { snprintf(buf_b, 64, "%ld", (long)rava_nanbox_as_int(b)); str_b = buf_b; }
|
||||
else if (rava_nanbox_is_int(b)) { snprintf(buf_b, 64, "%d", rava_nanbox_as_int(b)); str_b = buf_b; }
|
||||
else if (rava_nanbox_is_long(b)) { snprintf(buf_b, 64, "%ld", (long)rava_nanbox_as_long(b)); str_b = buf_b; }
|
||||
else if (rava_nanbox_is_double(b)) { snprintf(buf_b, 64, "%g", rava_nanbox_as_double(b)); str_b = buf_b; }
|
||||
else if (rava_nanbox_is_bool(b)) { str_b = rava_nanbox_as_bool(b) ? "true" : "false"; }
|
||||
@ -3973,13 +3993,13 @@ uf_load_array: {
|
||||
RavaNanboxValue_t idx = UF_POP();
|
||||
RavaNanboxValue_t arr_val = UF_POP();
|
||||
RavaArray_t *arr = rava_nanbox_as_array(arr_val);
|
||||
int64_t i = rava_nanbox_to_int(idx);
|
||||
int32_t i = rava_nanbox_to_int(idx);
|
||||
if (arr && i >= 0 && (size_t)i < arr->length) {
|
||||
if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) {
|
||||
RavaValue_t v = rava_array_get_value(arr, (size_t)i);
|
||||
UF_PUSH(rava_value_to_nanbox(v));
|
||||
} else {
|
||||
int64_t val = rava_array_get_int(arr, (size_t)i);
|
||||
int32_t val = rava_array_get_int(arr, (size_t)i);
|
||||
UF_PUSH(rava_nanbox_int(val));
|
||||
}
|
||||
} else {
|
||||
@ -3997,7 +4017,7 @@ uf_load_array_unchecked: {
|
||||
RavaValue_t v = rava_array_get_value(arr, i);
|
||||
UF_PUSH(rava_value_to_nanbox(v));
|
||||
} else {
|
||||
int64_t val = rava_array_get_int(arr, i);
|
||||
int32_t val = rava_array_get_int(arr, i);
|
||||
UF_PUSH(rava_nanbox_int(val));
|
||||
}
|
||||
UF_DISPATCH();
|
||||
@ -4008,7 +4028,7 @@ uf_store_array: {
|
||||
RavaNanboxValue_t idx = UF_POP();
|
||||
RavaNanboxValue_t arr_val = UF_POP();
|
||||
RavaArray_t *arr = rava_nanbox_as_array(arr_val);
|
||||
int64_t i = rava_nanbox_to_int(idx);
|
||||
int32_t i = rava_nanbox_to_int(idx);
|
||||
if (arr && i >= 0 && (size_t)i < arr->length) {
|
||||
if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) {
|
||||
rava_array_set_value(arr, (size_t)i, rava_nanbox_to_value(val));
|
||||
@ -4197,9 +4217,9 @@ uf_dup: {
|
||||
uf_print: {
|
||||
RavaNanboxValue_t v = UF_POP();
|
||||
if (rava_nanbox_is_int(v)) {
|
||||
printf("%ld", (long)rava_nanbox_as_int(v));
|
||||
printf("%d", rava_nanbox_as_int(v));
|
||||
} else if (rava_nanbox_is_long(v)) {
|
||||
printf("%ld", (long)rava_nanbox_as_long(v));
|
||||
printf("%ld", rava_nanbox_as_long(v));
|
||||
} else if (rava_nanbox_is_double(v)) {
|
||||
printf("%g", rava_nanbox_as_double(v));
|
||||
} else if (rava_nanbox_is_bool(v)) {
|
||||
@ -4215,9 +4235,9 @@ uf_print: {
|
||||
uf_println: {
|
||||
RavaNanboxValue_t v = UF_POP();
|
||||
if (rava_nanbox_is_int(v)) {
|
||||
printf("%ld\n", (long)rava_nanbox_as_int(v));
|
||||
printf("%d\n", rava_nanbox_as_int(v));
|
||||
} else if (rava_nanbox_is_long(v)) {
|
||||
printf("%ld\n", (long)rava_nanbox_as_long(v));
|
||||
printf("%ld\n", rava_nanbox_as_long(v));
|
||||
} else if (rava_nanbox_is_double(v)) {
|
||||
printf("%g\n", rava_nanbox_as_double(v));
|
||||
} else if (rava_nanbox_is_bool(v)) {
|
||||
@ -4272,15 +4292,9 @@ uf_string_substring: {
|
||||
uf_string_equals: {
|
||||
RavaNanboxValue_t b = UF_POP();
|
||||
RavaNanboxValue_t a = UF_POP();
|
||||
if (rava_nanbox_is_string(a) && rava_nanbox_is_string(b)) {
|
||||
const char *sa = rava_nanbox_as_string(a);
|
||||
const char *sb = rava_nanbox_as_string(b);
|
||||
UF_PUSH(rava_nanbox_bool(sa && sb && strcmp(sa, sb) == 0));
|
||||
} else {
|
||||
RavaValue_t val_a = rava_nanbox_to_value(a);
|
||||
RavaValue_t val_b = rava_nanbox_to_value(b);
|
||||
UF_PUSH(rava_nanbox_bool(rava_object_equals(val_a, val_b)));
|
||||
}
|
||||
const char *sa = rava_nanbox_as_string(a);
|
||||
const char *sb = rava_nanbox_as_string(b);
|
||||
UF_PUSH(rava_nanbox_bool(sa && sb && strcmp(sa, sb) == 0));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ struct RavaObject_t {
|
||||
struct RavaValue_t {
|
||||
RavaValueType_e type;
|
||||
union {
|
||||
int64_t int_val;
|
||||
int32_t int_val;
|
||||
int64_t long_val;
|
||||
float float_val;
|
||||
double double_val;
|
||||
@ -227,7 +227,7 @@ typedef struct {
|
||||
RavaInternTable_t intern_table;
|
||||
} RavaVM_t;
|
||||
|
||||
static inline RavaValue_t rava_value_int(int64_t value) {
|
||||
static inline RavaValue_t rava_value_int(int32_t value) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_INT;
|
||||
val.data.int_val = value;
|
||||
@ -299,7 +299,7 @@ static inline RavaValue_t rava_value_hashmap(RavaHashMap_t *map) {
|
||||
|
||||
RavaValue_t rava_value_string(const char *str);
|
||||
|
||||
int64_t rava_value_as_int(RavaValue_t value);
|
||||
int32_t rava_value_as_int(RavaValue_t value);
|
||||
int64_t rava_value_as_long(RavaValue_t value);
|
||||
double rava_value_as_double(RavaValue_t value);
|
||||
bool rava_value_as_boolean(RavaValue_t value);
|
||||
@ -307,8 +307,8 @@ const char* rava_value_as_string(RavaValue_t value);
|
||||
|
||||
RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length);
|
||||
void rava_array_destroy(RavaArray_t *array);
|
||||
void rava_array_set_int(RavaArray_t *array, size_t index, int64_t value);
|
||||
int64_t rava_array_get_int(RavaArray_t *array, size_t index);
|
||||
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value);
|
||||
int32_t rava_array_get_int(RavaArray_t *array, size_t index);
|
||||
void rava_array_set_long(RavaArray_t *array, size_t index, int64_t value);
|
||||
int64_t rava_array_get_long(RavaArray_t *array, size_t index);
|
||||
void rava_array_set_double(RavaArray_t *array, size_t index, double value);
|
||||
|
||||
@ -25,7 +25,7 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
|
||||
|
||||
switch (element_type) {
|
||||
case RAVA_VAL_INT:
|
||||
array->data = calloc(length, sizeof(int64_t));
|
||||
array->data = calloc(length, sizeof(int32_t));
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
array->data = calloc(length, sizeof(int64_t));
|
||||
@ -57,14 +57,14 @@ void rava_array_destroy(RavaArray_t *array) {
|
||||
free(array->data);
|
||||
}
|
||||
|
||||
void rava_array_set_int(RavaArray_t *array, size_t index, int64_t value) {
|
||||
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) {
|
||||
if (!array || !array->data || index >= array->length) return;
|
||||
((int64_t*)array->data)[index] = value;
|
||||
((int32_t*)array->data)[index] = value;
|
||||
}
|
||||
|
||||
int64_t rava_array_get_int(RavaArray_t *array, size_t index) {
|
||||
int32_t rava_array_get_int(RavaArray_t *array, size_t index) {
|
||||
if (!array || !array->data || index >= array->length) return 0;
|
||||
return ((int64_t*)array->data)[index];
|
||||
return ((int32_t*)array->data)[index];
|
||||
}
|
||||
|
||||
void rava_array_set_long(RavaArray_t *array, size_t index, int64_t value) {
|
||||
|
||||
@ -234,10 +234,10 @@ char* rava_object_tostring(RavaValue_t value) {
|
||||
strcpy(buffer, "null");
|
||||
break;
|
||||
case RAVA_VAL_INT:
|
||||
snprintf(buffer, 128, "%ld", (long)value.data.int_val);
|
||||
snprintf(buffer, 128, "%d", value.data.int_val);
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
snprintf(buffer, 128, "%ld", (long)value.data.long_val);
|
||||
snprintf(buffer, 128, "%ld", value.data.long_val);
|
||||
break;
|
||||
case RAVA_VAL_FLOAT:
|
||||
snprintf(buffer, 128, "%g", (double)value.data.float_val);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user