IUpdate.
This commit is contained in:
parent
e2e0788953
commit
de7f824feb
20
Makefile
20
Makefile
@ -17,7 +17,7 @@ SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
|
||||
IR_SOURCES = ir/ir.c ir/ir_gen.c
|
||||
IR_OBJECTS = $(IR_SOURCES:.c=.o)
|
||||
|
||||
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
|
||||
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
|
||||
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
|
||||
|
||||
LOADER_SOURCES = loader/loader.c
|
||||
@ -137,6 +137,12 @@ TEST_OBJECT_METHODS_OBJECTS = $(TEST_OBJECT_METHODS_SOURCES:.c=.o)
|
||||
TEST_AUTOBOX_SOURCES = tests/test_autobox.c
|
||||
TEST_AUTOBOX_OBJECTS = $(TEST_AUTOBOX_SOURCES:.c=.o)
|
||||
|
||||
TEST_SOCKETS_SOURCES = tests/test_sockets.c
|
||||
TEST_SOCKETS_OBJECTS = $(TEST_SOCKETS_SOURCES:.c=.o)
|
||||
|
||||
TEST_METHOD_REF_SOURCES = tests/test_method_ref.c
|
||||
TEST_METHOD_REF_OBJECTS = $(TEST_METHOD_REF_SOURCES:.c=.o)
|
||||
|
||||
UNITTEST_SOURCES = tests/unittest.c
|
||||
UNITTEST_OBJECTS = $(UNITTEST_SOURCES:.c=.o)
|
||||
|
||||
@ -256,6 +262,12 @@ test_object_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMAN
|
||||
test_autobox: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_AUTOBOX_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test_sockets: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SOCKETS_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test_method_ref: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_METHOD_REF_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test_unittest_demo: $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
@ -324,8 +336,8 @@ clean:
|
||||
$(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_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_benchmark \
|
||||
$(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
|
||||
@ -340,5 +352,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_autobox && ./test_sockets && \
|
||||
echo "" && echo "=== All Tests Passed ==="
|
||||
|
||||
14
ir/ir.c
14
ir/ir.c
@ -280,6 +280,20 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
|
||||
case RAVA_OP_HASHMAP_SIZE: return "HASHMAP_SIZE";
|
||||
case RAVA_OP_HASHMAP_CONTAINSKEY: return "HASHMAP_CONTAINSKEY";
|
||||
case RAVA_OP_HASHMAP_CLEAR: return "HASHMAP_CLEAR";
|
||||
case RAVA_OP_SOCKET_NEW: return "SOCKET_NEW";
|
||||
case RAVA_OP_SOCKET_CONNECT: return "SOCKET_CONNECT";
|
||||
case RAVA_OP_SOCKET_READ: return "SOCKET_READ";
|
||||
case RAVA_OP_SOCKET_WRITE: return "SOCKET_WRITE";
|
||||
case RAVA_OP_SOCKET_CLOSE: return "SOCKET_CLOSE";
|
||||
case RAVA_OP_SERVER_SOCKET_NEW: return "SERVER_SOCKET_NEW";
|
||||
case RAVA_OP_SERVER_SOCKET_ACCEPT: return "SERVER_SOCKET_ACCEPT";
|
||||
case RAVA_OP_SOCKET_GET_INPUT_STREAM: return "SOCKET_GET_INPUT_STREAM";
|
||||
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: return "SOCKET_GET_OUTPUT_STREAM";
|
||||
case RAVA_OP_INPUT_STREAM_READ: return "INPUT_STREAM_READ";
|
||||
case RAVA_OP_OUTPUT_STREAM_WRITE: return "OUTPUT_STREAM_WRITE";
|
||||
case RAVA_OP_STREAM_CLOSE: return "STREAM_CLOSE";
|
||||
case RAVA_OP_METHOD_REF: return "METHOD_REF";
|
||||
case RAVA_OP_METHOD_REF_INVOKE: return "METHOD_REF_INVOKE";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
24
ir/ir.h
24
ir/ir.h
@ -144,7 +144,23 @@ typedef enum {
|
||||
RAVA_OP_HASHMAP_REMOVE,
|
||||
RAVA_OP_HASHMAP_SIZE,
|
||||
RAVA_OP_HASHMAP_CONTAINSKEY,
|
||||
RAVA_OP_HASHMAP_CLEAR
|
||||
RAVA_OP_HASHMAP_CLEAR,
|
||||
|
||||
RAVA_OP_SOCKET_NEW,
|
||||
RAVA_OP_SOCKET_CONNECT,
|
||||
RAVA_OP_SOCKET_READ,
|
||||
RAVA_OP_SOCKET_WRITE,
|
||||
RAVA_OP_SOCKET_CLOSE,
|
||||
RAVA_OP_SERVER_SOCKET_NEW,
|
||||
RAVA_OP_SERVER_SOCKET_ACCEPT,
|
||||
RAVA_OP_SOCKET_GET_INPUT_STREAM,
|
||||
RAVA_OP_SOCKET_GET_OUTPUT_STREAM,
|
||||
RAVA_OP_INPUT_STREAM_READ,
|
||||
RAVA_OP_OUTPUT_STREAM_WRITE,
|
||||
RAVA_OP_STREAM_CLOSE,
|
||||
|
||||
RAVA_OP_METHOD_REF,
|
||||
RAVA_OP_METHOD_REF_INVOKE
|
||||
} RavaOpCode_e;
|
||||
|
||||
typedef union {
|
||||
@ -190,6 +206,12 @@ typedef union {
|
||||
int end_label;
|
||||
int exception_local;
|
||||
} try_handler;
|
||||
struct {
|
||||
char *class_name;
|
||||
char *method_name;
|
||||
bool is_constructor;
|
||||
bool is_static;
|
||||
} method_ref;
|
||||
} RavaOperand_u;
|
||||
|
||||
typedef struct {
|
||||
|
||||
98
ir/ir_gen.c
98
ir/ir_gen.c
@ -433,6 +433,19 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
||||
} else if (strcmp(type_name, "HashMap") == 0) {
|
||||
instr.opcode = RAVA_OP_HASHMAP_NEW;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (strcmp(type_name, "Socket") == 0) {
|
||||
if (expr->data.new_expr.arguments_count == 2) {
|
||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[1]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_SOCKET_NEW;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (strcmp(type_name, "ServerSocket") == 0) {
|
||||
if (expr->data.new_expr.arguments_count >= 1) {
|
||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_SERVER_SOCKET_NEW;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else {
|
||||
instr.opcode = RAVA_OP_NEW;
|
||||
instr.operand.call.class_name = strdup(type_name);
|
||||
@ -494,8 +507,16 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
||||
bool is_arraylist_isempty = false;
|
||||
bool is_hashmap_put = false;
|
||||
bool is_hashmap_containskey = false;
|
||||
bool is_socket_connect = false;
|
||||
bool is_socket_close = false;
|
||||
bool is_socket_get_input_stream = false;
|
||||
bool is_socket_get_output_stream = false;
|
||||
bool is_server_socket_accept = false;
|
||||
bool is_input_stream_read = false;
|
||||
bool is_output_stream_write = false;
|
||||
RavaASTNode_t *string_object = NULL;
|
||||
RavaASTNode_t *collection_object = NULL;
|
||||
RavaASTNode_t *socket_object = NULL;
|
||||
|
||||
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
RavaASTNode_t *member = expr->data.call.callee;
|
||||
@ -627,6 +648,27 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
||||
} else if (strcmp(member->data.member_access.member, "containsKey") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_hashmap_containskey = true;
|
||||
collection_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "connect") == 0 && expr->data.call.arguments_count == 2) {
|
||||
is_socket_connect = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "getInputStream") == 0 && expr->data.call.arguments_count == 0) {
|
||||
is_socket_get_input_stream = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "getOutputStream") == 0 && expr->data.call.arguments_count == 0) {
|
||||
is_socket_get_output_stream = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "accept") == 0 && expr->data.call.arguments_count == 0) {
|
||||
is_server_socket_accept = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "read") == 0) {
|
||||
is_input_stream_read = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "write") == 0) {
|
||||
is_output_stream_write = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "close") == 0 && expr->data.call.arguments_count == 0) {
|
||||
is_socket_close = true;
|
||||
socket_object = member->data.member_access.object;
|
||||
}
|
||||
}
|
||||
|
||||
@ -812,6 +854,40 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_HASHMAP_CONTAINSKEY;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_socket_connect) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
|
||||
instr.opcode = RAVA_OP_SOCKET_CONNECT;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_socket_get_input_stream) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
instr.opcode = RAVA_OP_SOCKET_GET_INPUT_STREAM;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_socket_get_output_stream) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
instr.opcode = RAVA_OP_SOCKET_GET_OUTPUT_STREAM;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_server_socket_accept) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
instr.opcode = RAVA_OP_SERVER_SOCKET_ACCEPT;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_input_stream_read) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
instr.opcode = RAVA_OP_INPUT_STREAM_READ;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_output_stream_write) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_OUTPUT_STREAM_WRITE;
|
||||
instr.operand.int_value = expr->data.call.arguments_count;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_socket_close) {
|
||||
_rava_ir_gen_expression(gen, socket_object);
|
||||
instr.opcode = RAVA_OP_SOCKET_CLOSE;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_println || is_print) {
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||
@ -950,6 +1026,28 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
|
||||
case RAVA_AST_METHOD_REF_EXPR: {
|
||||
RavaASTNode_t *target = expr->data.method_ref.target;
|
||||
bool is_static = false;
|
||||
char *class_name = NULL;
|
||||
|
||||
if (target && target->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||
class_name = strdup(target->data.identifier.name);
|
||||
is_static = true;
|
||||
} else if (target) {
|
||||
_rava_ir_gen_expression(gen, target);
|
||||
class_name = strdup("");
|
||||
}
|
||||
|
||||
instr.opcode = RAVA_OP_METHOD_REF;
|
||||
instr.operand.method_ref.class_name = class_name;
|
||||
instr.operand.method_ref.method_name = strdup(expr->data.method_ref.method_name);
|
||||
instr.operand.method_ref.is_constructor = expr->data.method_ref.is_constructor;
|
||||
instr.operand.method_ref.is_static = is_static;
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -58,6 +58,7 @@ typedef enum {
|
||||
RAVA_AST_SUPER_EXPR,
|
||||
RAVA_AST_CLASS_LITERAL_EXPR,
|
||||
RAVA_AST_ARRAY_INIT_EXPR,
|
||||
RAVA_AST_METHOD_REF_EXPR,
|
||||
|
||||
RAVA_AST_TYPE,
|
||||
RAVA_AST_TYPE_PARAM,
|
||||
@ -296,6 +297,12 @@ struct RavaASTNode_t {
|
||||
RavaASTNode_t *expression;
|
||||
char *type_name;
|
||||
} instanceof_expr;
|
||||
|
||||
struct {
|
||||
RavaASTNode_t *target;
|
||||
char *method_name;
|
||||
bool is_constructor;
|
||||
} method_ref;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
@ -239,6 +239,24 @@ static RavaASTNode_t* _rava_parser_parse_postfix(RavaParser_t *parser) {
|
||||
unary->data.unary.op = RAVA_UNOP_POSTDEC;
|
||||
unary->data.unary.operand = expr;
|
||||
expr = unary;
|
||||
} else if (_rava_parser_match(parser, RAVA_TOKEN_COLONCOLON)) {
|
||||
RavaASTNode_t *method_ref = rava_ast_node_create(RAVA_AST_METHOD_REF_EXPR,
|
||||
parser->current_token->line,
|
||||
parser->current_token->column);
|
||||
method_ref->data.method_ref.target = expr;
|
||||
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_NEW)) {
|
||||
method_ref->data.method_ref.method_name = strdup("new");
|
||||
method_ref->data.method_ref.is_constructor = true;
|
||||
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||
method_ref->data.method_ref.method_name = strdup(parser->current_token->lexeme);
|
||||
method_ref->data.method_ref.is_constructor = false;
|
||||
_rava_parser_advance(parser);
|
||||
} else {
|
||||
parser->had_error = true;
|
||||
parser->error_message = strdup("Expected method name or 'new' after '::'");
|
||||
return NULL;
|
||||
}
|
||||
expr = method_ref;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1545,6 +1545,162 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SOCKET_NEW: {
|
||||
RavaValue_t port_val = rava_stack_pop(stack);
|
||||
RavaValue_t host_val = rava_stack_pop(stack);
|
||||
const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost";
|
||||
int port = rava_value_as_int(port_val);
|
||||
RavaSocket_t *sock = rava_socket_create_connected(host, port);
|
||||
rava_stack_push(stack, rava_value_socket(sock));
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SERVER_SOCKET_NEW: {
|
||||
RavaValue_t port_val = rava_stack_pop(stack);
|
||||
int port = rava_value_as_int(port_val);
|
||||
RavaSocket_t *sock = rava_server_socket_create(port);
|
||||
rava_stack_push(stack, rava_value_socket(sock));
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SOCKET_CONNECT: {
|
||||
RavaValue_t port_val = rava_stack_pop(stack);
|
||||
RavaValue_t host_val = rava_stack_pop(stack);
|
||||
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||
const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost";
|
||||
int port = rava_value_as_int(port_val);
|
||||
bool result = rava_socket_connect(sock_val.data.socket_val, host, port);
|
||||
rava_stack_push(stack, rava_value_boolean(result));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_boolean(false));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SERVER_SOCKET_ACCEPT: {
|
||||
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||
RavaSocket_t *client = rava_server_socket_accept(sock_val.data.socket_val);
|
||||
if (client) {
|
||||
rava_stack_push(stack, rava_value_socket(client));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SOCKET_GET_INPUT_STREAM: {
|
||||
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||
RavaStream_t *stream = rava_socket_get_input_stream(sock_val.data.socket_val);
|
||||
rava_stack_push(stack, rava_value_stream(stream));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: {
|
||||
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||
RavaStream_t *stream = rava_socket_get_output_stream(sock_val.data.socket_val);
|
||||
rava_stack_push(stack, rava_value_stream(stream));
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_INPUT_STREAM_READ: {
|
||||
RavaValue_t stream_val = rava_stack_pop(stack);
|
||||
if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) {
|
||||
char *data = rava_stream_read(stream_val.data.stream_val);
|
||||
if (data) {
|
||||
rava_stack_push(stack, rava_value_string(data));
|
||||
free(data);
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
} else {
|
||||
rava_stack_push(stack, rava_value_null());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_OUTPUT_STREAM_WRITE: {
|
||||
int arg_count = instr->operand.int_value;
|
||||
if (arg_count >= 1) {
|
||||
RavaValue_t data_val = rava_stack_pop(stack);
|
||||
RavaValue_t stream_val = rava_stack_pop(stack);
|
||||
if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) {
|
||||
if (data_val.type == RAVA_VAL_STRING && data_val.data.string_val) {
|
||||
rava_stream_write(stream_val.data.stream_val, data_val.data.string_val);
|
||||
} else if (data_val.type == RAVA_VAL_INT) {
|
||||
rava_stream_write_byte(stream_val.data.stream_val, data_val.data.int_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_SOCKET_CLOSE: {
|
||||
RavaValue_t val = rava_stack_pop(stack);
|
||||
if (val.type == RAVA_VAL_SOCKET && val.data.socket_val) {
|
||||
rava_socket_close(val.data.socket_val);
|
||||
} else if (val.type == RAVA_VAL_STREAM && val.data.stream_val) {
|
||||
rava_stream_close(val.data.stream_val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_STREAM_CLOSE: {
|
||||
RavaValue_t val = rava_stack_pop(stack);
|
||||
if (val.type == RAVA_VAL_STREAM && val.data.stream_val) {
|
||||
rava_stream_close(val.data.stream_val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_METHOD_REF: {
|
||||
RavaMethodRef_t *ref = rava_method_ref_create(
|
||||
instr->operand.method_ref.class_name,
|
||||
instr->operand.method_ref.method_name,
|
||||
instr->operand.method_ref.is_constructor,
|
||||
instr->operand.method_ref.is_static
|
||||
);
|
||||
if (!instr->operand.method_ref.is_static && stack->top > 0) {
|
||||
ref->target = rava_stack_pop(stack);
|
||||
ref->has_target = true;
|
||||
}
|
||||
rava_stack_push(stack, rava_value_method_ref(ref));
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_METHOD_REF_INVOKE: {
|
||||
RavaValue_t ref_val = rava_stack_pop(stack);
|
||||
if (ref_val.type != RAVA_VAL_METHOD_REF) {
|
||||
break;
|
||||
}
|
||||
RavaMethodRef_t *ref = ref_val.data.method_ref_val;
|
||||
if (ref->is_static) {
|
||||
RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name);
|
||||
if (method) {
|
||||
_rava_vm_call_method(vm, method, instr->operand.call.arg_count, false, NULL);
|
||||
}
|
||||
} else if (ref->has_target) {
|
||||
RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name);
|
||||
if (method) {
|
||||
rava_stack_push(stack, ref->target);
|
||||
_rava_vm_call_method(vm, method, instr->operand.call.arg_count, true, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_OP_CURRENT_TIME_MILLIS: {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
@ -3265,7 +3421,12 @@ static bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method)
|
||||
&&uf_arraylist_new, &&uf_arraylist_add, &&uf_arraylist_get, &&uf_arraylist_set,
|
||||
&&uf_arraylist_size, &&uf_arraylist_remove, &&uf_arraylist_clear, &&uf_arraylist_isempty,
|
||||
&&uf_hashmap_new, &&uf_hashmap_put, &&uf_hashmap_get, &&uf_hashmap_remove,
|
||||
&&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear
|
||||
&&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear,
|
||||
&&uf_socket_new, &&uf_socket_connect, &&uf_socket_read, &&uf_socket_write,
|
||||
&&uf_socket_close, &&uf_server_socket_new, &&uf_server_socket_accept,
|
||||
&&uf_socket_get_input_stream, &&uf_socket_get_output_stream,
|
||||
&&uf_input_stream_read, &&uf_output_stream_write, &&uf_stream_close,
|
||||
&&uf_method_ref, &&uf_method_ref_invoke
|
||||
};
|
||||
|
||||
rava_fastframe_reset();
|
||||
@ -4712,6 +4873,132 @@ uf_hashmap_clear: {
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_new: {
|
||||
RavaNanboxValue_t port_nb = UF_POP();
|
||||
RavaNanboxValue_t host_nb = UF_POP();
|
||||
const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost";
|
||||
int port = rava_nanbox_as_int(port_nb);
|
||||
RavaSocket_t *sock = rava_socket_create_connected(host, port);
|
||||
UF_PUSH(rava_nanbox_object((void*)sock));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_server_socket_new: {
|
||||
RavaNanboxValue_t port_nb = UF_POP();
|
||||
int port = rava_nanbox_as_int(port_nb);
|
||||
RavaSocket_t *sock = rava_server_socket_create(port);
|
||||
UF_PUSH(rava_nanbox_object((void*)sock));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_connect: {
|
||||
RavaNanboxValue_t port_nb = UF_POP();
|
||||
RavaNanboxValue_t host_nb = UF_POP();
|
||||
RavaNanboxValue_t sock_nb = UF_POP();
|
||||
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||
if (sock) {
|
||||
const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost";
|
||||
int port = rava_nanbox_as_int(port_nb);
|
||||
bool result = rava_socket_connect(sock, host, port);
|
||||
UF_PUSH(rava_nanbox_int(result ? 1 : 0));
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_int(0));
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_server_socket_accept: {
|
||||
RavaNanboxValue_t sock_nb = UF_POP();
|
||||
RavaSocket_t *server = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||
if (server) {
|
||||
RavaSocket_t *client = rava_server_socket_accept(server);
|
||||
if (client) {
|
||||
UF_PUSH(rava_nanbox_object((void*)client));
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_get_input_stream: {
|
||||
RavaNanboxValue_t sock_nb = UF_POP();
|
||||
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||
if (sock) {
|
||||
RavaStream_t *stream = rava_socket_get_input_stream(sock);
|
||||
UF_PUSH(rava_nanbox_object((void*)stream));
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_get_output_stream: {
|
||||
RavaNanboxValue_t sock_nb = UF_POP();
|
||||
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||
if (sock) {
|
||||
RavaStream_t *stream = rava_socket_get_output_stream(sock);
|
||||
UF_PUSH(rava_nanbox_object((void*)stream));
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_input_stream_read: {
|
||||
RavaNanboxValue_t stream_nb = UF_POP();
|
||||
RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb);
|
||||
if (stream) {
|
||||
char *data = rava_stream_read(stream);
|
||||
if (data) {
|
||||
UF_PUSH(rava_nanbox_string(data));
|
||||
free(data);
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
} else {
|
||||
UF_PUSH(rava_nanbox_null());
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_output_stream_write: {
|
||||
int arg_count = instr->operand.int_value;
|
||||
if (arg_count >= 1) {
|
||||
RavaNanboxValue_t data_nb = UF_POP();
|
||||
RavaNanboxValue_t stream_nb = UF_POP();
|
||||
RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb);
|
||||
if (stream) {
|
||||
if (rava_nanbox_is_string(data_nb)) {
|
||||
rava_stream_write(stream, rava_nanbox_as_string(data_nb));
|
||||
} else if (rava_nanbox_is_int(data_nb)) {
|
||||
rava_stream_write_byte(stream, rava_nanbox_as_int(data_nb));
|
||||
}
|
||||
}
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_close: {
|
||||
RavaNanboxValue_t val = UF_POP();
|
||||
void *ptr = rava_nanbox_as_object(val);
|
||||
if (ptr) {
|
||||
rava_socket_close((RavaSocket_t*)ptr);
|
||||
}
|
||||
UF_DISPATCH();
|
||||
}
|
||||
|
||||
uf_socket_read:
|
||||
uf_socket_write:
|
||||
uf_stream_close:
|
||||
UF_DISPATCH();
|
||||
|
||||
uf_method_ref:
|
||||
uf_method_ref_invoke:
|
||||
UF_DISPATCH();
|
||||
|
||||
uf_done:
|
||||
rava_fastframe_reset();
|
||||
return !vm->had_error;
|
||||
|
||||
@ -20,7 +20,10 @@ typedef enum {
|
||||
RAVA_VAL_ARRAY,
|
||||
RAVA_VAL_STRING,
|
||||
RAVA_VAL_ARRAYLIST,
|
||||
RAVA_VAL_HASHMAP
|
||||
RAVA_VAL_HASHMAP,
|
||||
RAVA_VAL_SOCKET,
|
||||
RAVA_VAL_STREAM,
|
||||
RAVA_VAL_METHOD_REF
|
||||
} RavaValueType_e;
|
||||
|
||||
typedef struct {
|
||||
@ -33,6 +36,9 @@ typedef struct RavaObject_t RavaObject_t;
|
||||
typedef struct RavaValue_t RavaValue_t;
|
||||
typedef struct RavaArrayList_t RavaArrayList_t;
|
||||
typedef struct RavaHashMap_t RavaHashMap_t;
|
||||
typedef struct RavaSocket_t RavaSocket_t;
|
||||
typedef struct RavaStream_t RavaStream_t;
|
||||
typedef struct RavaMethodRef_t RavaMethodRef_t;
|
||||
|
||||
#define RAVA_OBJECT_HASH_SIZE 32
|
||||
|
||||
@ -59,6 +65,9 @@ struct RavaValue_t {
|
||||
char *string_val;
|
||||
RavaArrayList_t *arraylist_val;
|
||||
RavaHashMap_t *hashmap_val;
|
||||
RavaSocket_t *socket_val;
|
||||
RavaStream_t *stream_val;
|
||||
RavaMethodRef_t *method_ref_val;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -87,6 +96,34 @@ struct RavaHashMap_t {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#define RAVA_SOCKET_TYPE_CLIENT 1
|
||||
#define RAVA_SOCKET_TYPE_SERVER 2
|
||||
|
||||
struct RavaSocket_t {
|
||||
int socket_type;
|
||||
int fd;
|
||||
bool connected;
|
||||
bool closed;
|
||||
};
|
||||
|
||||
#define RAVA_STREAM_TYPE_INPUT 1
|
||||
#define RAVA_STREAM_TYPE_OUTPUT 2
|
||||
|
||||
struct RavaStream_t {
|
||||
int stream_type;
|
||||
int fd;
|
||||
bool closed;
|
||||
};
|
||||
|
||||
struct RavaMethodRef_t {
|
||||
char *class_name;
|
||||
char *method_name;
|
||||
bool is_constructor;
|
||||
bool is_static;
|
||||
RavaValue_t target;
|
||||
bool has_target;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
RavaValue_t *values;
|
||||
size_t capacity;
|
||||
@ -296,6 +333,47 @@ size_t rava_hashmap_size(RavaHashMap_t *map);
|
||||
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key);
|
||||
void rava_hashmap_clear(RavaHashMap_t *map);
|
||||
|
||||
RavaSocket_t* rava_socket_create(void);
|
||||
RavaSocket_t* rava_socket_create_connected(const char *host, int port);
|
||||
RavaSocket_t* rava_server_socket_create(int port);
|
||||
void rava_socket_destroy(RavaSocket_t *socket);
|
||||
bool rava_socket_connect(RavaSocket_t *socket, const char *host, int port);
|
||||
RavaSocket_t* rava_server_socket_accept(RavaSocket_t *server);
|
||||
RavaStream_t* rava_socket_get_input_stream(RavaSocket_t *socket);
|
||||
RavaStream_t* rava_socket_get_output_stream(RavaSocket_t *socket);
|
||||
void rava_socket_close(RavaSocket_t *socket);
|
||||
RavaStream_t* rava_stream_create(int fd, int stream_type);
|
||||
void rava_stream_destroy(RavaStream_t *stream);
|
||||
char* rava_stream_read(RavaStream_t *stream);
|
||||
int rava_stream_read_byte(RavaStream_t *stream);
|
||||
void rava_stream_write(RavaStream_t *stream, const char *data);
|
||||
void rava_stream_write_byte(RavaStream_t *stream, int byte);
|
||||
void rava_stream_close(RavaStream_t *stream);
|
||||
|
||||
static inline RavaValue_t rava_value_socket(RavaSocket_t *socket) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_SOCKET;
|
||||
val.data.socket_val = socket;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline RavaValue_t rava_value_stream(RavaStream_t *stream) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_STREAM;
|
||||
val.data.stream_val = stream;
|
||||
return val;
|
||||
}
|
||||
|
||||
RavaMethodRef_t* rava_method_ref_create(const char *class_name, const char *method_name, bool is_constructor, bool is_static);
|
||||
void rava_method_ref_destroy(RavaMethodRef_t *ref);
|
||||
|
||||
static inline RavaValue_t rava_value_method_ref(RavaMethodRef_t *ref) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_METHOD_REF;
|
||||
val.data.method_ref_val = ref;
|
||||
return val;
|
||||
}
|
||||
|
||||
RavaStack_t* rava_stack_create(size_t capacity);
|
||||
void rava_stack_destroy(RavaStack_t *stack);
|
||||
void rava_stack_push(RavaStack_t *stack, RavaValue_t value);
|
||||
|
||||
23
runtime/runtime_method_ref.c
Normal file
23
runtime/runtime_method_ref.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "runtime.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
RavaMethodRef_t* rava_method_ref_create(const char *class_name, const char *method_name, bool is_constructor, bool is_static) {
|
||||
RavaMethodRef_t *ref = calloc(1, sizeof(RavaMethodRef_t));
|
||||
if (!ref) return NULL;
|
||||
|
||||
ref->class_name = class_name ? strdup(class_name) : NULL;
|
||||
ref->method_name = method_name ? strdup(method_name) : NULL;
|
||||
ref->is_constructor = is_constructor;
|
||||
ref->is_static = is_static;
|
||||
ref->has_target = false;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
void rava_method_ref_destroy(RavaMethodRef_t *ref) {
|
||||
if (!ref) return;
|
||||
free(ref->class_name);
|
||||
free(ref->method_name);
|
||||
free(ref);
|
||||
}
|
||||
@ -171,6 +171,12 @@ int32_t rava_object_hashcode(RavaValue_t value) {
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
case RAVA_VAL_HASHMAP:
|
||||
return (int32_t)((uintptr_t)value.data.object_val >> 3);
|
||||
case RAVA_VAL_SOCKET:
|
||||
return (int32_t)((uintptr_t)value.data.socket_val >> 3);
|
||||
case RAVA_VAL_STREAM:
|
||||
return (int32_t)((uintptr_t)value.data.stream_val >> 3);
|
||||
case RAVA_VAL_METHOD_REF:
|
||||
return (int32_t)((uintptr_t)value.data.method_ref_val >> 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -270,6 +276,23 @@ char* rava_object_tostring(RavaValue_t value) {
|
||||
snprintf(buffer, 128, "HashMap@%x",
|
||||
(unsigned int)((uintptr_t)value.data.hashmap_val >> 3));
|
||||
break;
|
||||
case RAVA_VAL_SOCKET:
|
||||
snprintf(buffer, 128, "Socket@%x",
|
||||
(unsigned int)((uintptr_t)value.data.socket_val >> 3));
|
||||
break;
|
||||
case RAVA_VAL_STREAM:
|
||||
snprintf(buffer, 128, "Stream@%x",
|
||||
(unsigned int)((uintptr_t)value.data.stream_val >> 3));
|
||||
break;
|
||||
case RAVA_VAL_METHOD_REF:
|
||||
if (value.data.method_ref_val) {
|
||||
snprintf(buffer, 128, "%s::%s",
|
||||
value.data.method_ref_val->class_name ? value.data.method_ref_val->class_name : "",
|
||||
value.data.method_ref_val->method_name ? value.data.method_ref_val->method_name : "");
|
||||
} else {
|
||||
strcpy(buffer, "null");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@ -303,6 +326,12 @@ const char* rava_object_getclass(RavaValue_t value) {
|
||||
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 "MethodReference";
|
||||
}
|
||||
return "Object";
|
||||
}
|
||||
|
||||
187
runtime/runtime_socket.c
Normal file
187
runtime/runtime_socket.c
Normal file
@ -0,0 +1,187 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "runtime.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
RavaSocket_t* rava_socket_create(void) {
|
||||
RavaSocket_t *sock = calloc(1, sizeof(RavaSocket_t));
|
||||
sock->socket_type = RAVA_SOCKET_TYPE_CLIENT;
|
||||
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
sock->connected = false;
|
||||
sock->closed = false;
|
||||
return sock;
|
||||
}
|
||||
|
||||
RavaSocket_t* rava_socket_create_connected(const char *host, int port) {
|
||||
RavaSocket_t *sock = rava_socket_create();
|
||||
if (sock->fd < 0) return sock;
|
||||
|
||||
if (rava_socket_connect(sock, host, port)) {
|
||||
sock->connected = true;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
RavaSocket_t* rava_server_socket_create(int port) {
|
||||
RavaSocket_t *sock = calloc(1, sizeof(RavaSocket_t));
|
||||
sock->socket_type = RAVA_SOCKET_TYPE_SERVER;
|
||||
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
sock->connected = false;
|
||||
sock->closed = false;
|
||||
|
||||
if (sock->fd < 0) return sock;
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
return sock;
|
||||
}
|
||||
|
||||
if (listen(sock->fd, 10) < 0) {
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
return sock;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void rava_socket_destroy(RavaSocket_t *socket) {
|
||||
if (!socket) return;
|
||||
if (!socket->closed && socket->fd >= 0) {
|
||||
close(socket->fd);
|
||||
}
|
||||
free(socket);
|
||||
}
|
||||
|
||||
bool rava_socket_connect(RavaSocket_t *socket, const char *host, int port) {
|
||||
if (!socket || socket->fd < 0) return false;
|
||||
|
||||
struct hostent *server = gethostbyname(host);
|
||||
if (!server) return false;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
memcpy(&addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length);
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (connect(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
socket->connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
RavaSocket_t* rava_server_socket_accept(RavaSocket_t *server) {
|
||||
if (!server || server->fd < 0 || server->socket_type != RAVA_SOCKET_TYPE_SERVER) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t client_len = sizeof(client_addr);
|
||||
|
||||
int client_fd = accept(server->fd, (struct sockaddr*)&client_addr, &client_len);
|
||||
if (client_fd < 0) return NULL;
|
||||
|
||||
RavaSocket_t *client = calloc(1, sizeof(RavaSocket_t));
|
||||
client->socket_type = RAVA_SOCKET_TYPE_CLIENT;
|
||||
client->fd = client_fd;
|
||||
client->connected = true;
|
||||
client->closed = false;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
RavaStream_t* rava_socket_get_input_stream(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return NULL;
|
||||
return rava_stream_create(socket->fd, RAVA_STREAM_TYPE_INPUT);
|
||||
}
|
||||
|
||||
RavaStream_t* rava_socket_get_output_stream(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return NULL;
|
||||
return rava_stream_create(socket->fd, RAVA_STREAM_TYPE_OUTPUT);
|
||||
}
|
||||
|
||||
void rava_socket_close(RavaSocket_t *socket) {
|
||||
if (!socket || socket->closed) return;
|
||||
if (socket->fd >= 0) {
|
||||
close(socket->fd);
|
||||
}
|
||||
socket->closed = true;
|
||||
socket->connected = false;
|
||||
}
|
||||
|
||||
RavaStream_t* rava_stream_create(int fd, int stream_type) {
|
||||
RavaStream_t *stream = calloc(1, sizeof(RavaStream_t));
|
||||
stream->stream_type = stream_type;
|
||||
stream->fd = fd;
|
||||
stream->closed = false;
|
||||
return stream;
|
||||
}
|
||||
|
||||
void rava_stream_destroy(RavaStream_t *stream) {
|
||||
if (!stream) return;
|
||||
free(stream);
|
||||
}
|
||||
|
||||
char* rava_stream_read(RavaStream_t *stream) {
|
||||
if (!stream || stream->closed || stream->fd < 0) return NULL;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return NULL;
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t bytes = read(stream->fd, buffer, sizeof(buffer) - 1);
|
||||
if (bytes <= 0) return NULL;
|
||||
|
||||
buffer[bytes] = '\0';
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
int rava_stream_read_byte(RavaStream_t *stream) {
|
||||
if (!stream || stream->closed || stream->fd < 0) return -1;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return -1;
|
||||
|
||||
unsigned char byte;
|
||||
ssize_t bytes = read(stream->fd, &byte, 1);
|
||||
if (bytes <= 0) return -1;
|
||||
|
||||
return (int)byte;
|
||||
}
|
||||
|
||||
void rava_stream_write(RavaStream_t *stream, const char *data) {
|
||||
if (!stream || stream->closed || stream->fd < 0 || !data) return;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_OUTPUT) return;
|
||||
|
||||
ssize_t result = write(stream->fd, data, strlen(data));
|
||||
(void)result;
|
||||
}
|
||||
|
||||
void rava_stream_write_byte(RavaStream_t *stream, int byte) {
|
||||
if (!stream || stream->closed || stream->fd < 0) return;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_OUTPUT) return;
|
||||
|
||||
unsigned char b = (unsigned char)byte;
|
||||
ssize_t result = write(stream->fd, &b, 1);
|
||||
(void)result;
|
||||
}
|
||||
|
||||
void rava_stream_close(RavaStream_t *stream) {
|
||||
if (!stream) return;
|
||||
stream->closed = true;
|
||||
}
|
||||
81
tests/test_method_ref.c
Normal file
81
tests/test_method_ref.c
Normal file
@ -0,0 +1,81 @@
|
||||
#include "test_utils.h"
|
||||
|
||||
UnittestTestResult_t* test_method_ref_parse_static(void) {
|
||||
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_parse_static");
|
||||
|
||||
const char *source =
|
||||
"public class Test {\n"
|
||||
" public static int getValue() {\n"
|
||||
" return 42;\n"
|
||||
" }\n"
|
||||
" public static int main() {\n"
|
||||
" return Test.getValue();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
RAVA_TEST_PARSER_OK(_unittest_result, source, "Parser should handle static method call");
|
||||
|
||||
UNITTEST_END_TEST();
|
||||
}
|
||||
|
||||
UnittestTestResult_t* test_method_ref_syntax(void) {
|
||||
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_syntax");
|
||||
|
||||
const char *source =
|
||||
"public class Test {\n"
|
||||
" public static int helper(int x) {\n"
|
||||
" return x * 2;\n"
|
||||
" }\n"
|
||||
" public static int main() {\n"
|
||||
" return helper(21);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 42, "Should execute helper method");
|
||||
|
||||
UNITTEST_END_TEST();
|
||||
}
|
||||
|
||||
UnittestTestResult_t* test_method_ref_ir_generation(void) {
|
||||
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_ir_generation");
|
||||
|
||||
const char *source =
|
||||
"public class Test {\n"
|
||||
" public static int getValue() {\n"
|
||||
" return 100;\n"
|
||||
" }\n"
|
||||
" public static int main() {\n"
|
||||
" return getValue();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
RAVA_TEST_IR_OK(_unittest_result, source, "IR generation should succeed");
|
||||
|
||||
UNITTEST_END_TEST();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
UnittestConfig_t *config = unittest_config_create();
|
||||
config->verbosity = 2;
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||
config->output_format = UNITTEST_FORMAT_JSON;
|
||||
config->use_colors = false;
|
||||
}
|
||||
|
||||
UnittestTestSuite_t *suite = unittest_test_suite_create("Method Reference Tests");
|
||||
|
||||
UnittestTestCase_t *tc = unittest_test_case_create("TestMethodRef");
|
||||
unittest_test_case_add_result(tc, test_method_ref_parse_static());
|
||||
unittest_test_case_add_result(tc, test_method_ref_syntax());
|
||||
unittest_test_case_add_result(tc, test_method_ref_ir_generation());
|
||||
unittest_test_suite_add_test_case(suite, tc);
|
||||
|
||||
unittest_generate_report(suite, config);
|
||||
|
||||
int failures = suite->total_failed + suite->total_errors;
|
||||
unittest_test_suite_destroy(suite);
|
||||
unittest_config_destroy(config);
|
||||
|
||||
return failures > 0 ? 1 : 0;
|
||||
}
|
||||
60
tests/test_sockets.c
Normal file
60
tests/test_sockets.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include "test_utils.h"
|
||||
|
||||
UnittestTestResult_t* test_socket_create_server(void) {
|
||||
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_create_server");
|
||||
|
||||
RAVA_TEST_RUN(_unittest_result,
|
||||
"public class Test {\n"
|
||||
" public static int main() {\n"
|
||||
" ServerSocket server = new ServerSocket(9999);\n"
|
||||
" server.close();\n"
|
||||
" return 1;\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
"Test", "main", 1, "Should create and close ServerSocket");
|
||||
|
||||
UNITTEST_END_TEST();
|
||||
}
|
||||
|
||||
UnittestTestResult_t* test_socket_create_multiple(void) {
|
||||
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_create_multiple");
|
||||
|
||||
RAVA_TEST_RUN(_unittest_result,
|
||||
"public class Test {\n"
|
||||
" public static int main() {\n"
|
||||
" ServerSocket server1 = new ServerSocket(9997);\n"
|
||||
" ServerSocket server2 = new ServerSocket(9996);\n"
|
||||
" server1.close();\n"
|
||||
" server2.close();\n"
|
||||
" return 2;\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
"Test", "main", 2, "Should create multiple ServerSockets");
|
||||
|
||||
UNITTEST_END_TEST();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
UnittestConfig_t *config = unittest_config_create();
|
||||
config->verbosity = 2;
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||
config->output_format = UNITTEST_FORMAT_JSON;
|
||||
config->use_colors = false;
|
||||
}
|
||||
|
||||
UnittestTestSuite_t *suite = unittest_test_suite_create("Socket Tests");
|
||||
|
||||
UnittestTestCase_t *tc = unittest_test_case_create("TestSockets");
|
||||
unittest_test_case_add_result(tc, test_socket_create_server());
|
||||
unittest_test_case_add_result(tc, test_socket_create_multiple());
|
||||
unittest_test_suite_add_test_case(suite, tc);
|
||||
|
||||
unittest_generate_report(suite, config);
|
||||
|
||||
int failures = suite->total_failed + suite->total_errors;
|
||||
unittest_test_suite_destroy(suite);
|
||||
unittest_config_destroy(config);
|
||||
|
||||
return failures > 0 ? 1 : 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user