chore: remove trailing whitespace from README.md formatting
This commit is contained in:
+174
-2
@@ -504,7 +504,8 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) {
|
||||
vm->static_fields = rava_static_field_table_create();
|
||||
vm->method_cache = rava_methodcache_create();
|
||||
vm->exception_stack = rava_exception_stack_create();
|
||||
if (!vm->call_stack || !vm->static_fields || !vm->method_cache || !vm->exception_stack) {
|
||||
vm->native_registry = rava_native_registry_create();
|
||||
if (!vm->call_stack || !vm->static_fields || !vm->method_cache || !vm->exception_stack || !vm->native_registry) {
|
||||
rava_vm_destroy(vm);
|
||||
return NULL;
|
||||
}
|
||||
@@ -532,6 +533,7 @@ void rava_vm_destroy(RavaVM_t *vm) {
|
||||
rava_methodcache_destroy((MethodCache_t*)vm->method_cache);
|
||||
}
|
||||
rava_exception_stack_destroy(vm->exception_stack);
|
||||
rava_native_registry_destroy(vm->native_registry);
|
||||
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
|
||||
free(vm->intern_table.strings[i]);
|
||||
}
|
||||
@@ -951,6 +953,25 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
||||
if (strcmp(instr->operand.call.method_name, "<init>") == 0 && instr->operand.call.arg_count == 0) {
|
||||
break;
|
||||
}
|
||||
const char *mname = instr->operand.call.method_name;
|
||||
if (strcmp(mname, "hashCode") == 0 && instr->operand.call.arg_count == 0) {
|
||||
rava_stack_push(stack, rava_value_int(rava_object_hashcode(obj_val)));
|
||||
break;
|
||||
}
|
||||
if (strcmp(mname, "equals") == 0 && instr->operand.call.arg_count == 1) {
|
||||
rava_stack_push(stack, rava_value_boolean(rava_object_equals(obj_val, args[0])));
|
||||
break;
|
||||
}
|
||||
if (strcmp(mname, "toString") == 0 && instr->operand.call.arg_count == 0) {
|
||||
char *str = rava_object_tostring(obj_val);
|
||||
rava_stack_push(stack, rava_value_string(str));
|
||||
free(str);
|
||||
break;
|
||||
}
|
||||
if (strcmp(mname, "getClass") == 0 && instr->operand.call.arg_count == 0) {
|
||||
rava_stack_push(stack, rava_value_string(rava_object_getclass(obj_val)));
|
||||
break;
|
||||
}
|
||||
vm->had_error = true;
|
||||
vm->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
|
||||
snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "Method not found: %s.%s",
|
||||
@@ -3628,11 +3649,54 @@ uf_call_virtual: {
|
||||
vm->had_error = true;
|
||||
goto uf_done;
|
||||
}
|
||||
const char *mname = instr->operand.call.method_name;
|
||||
if (!rava_nanbox_is_object(obj_val)) {
|
||||
RavaValue_t val = rava_nanbox_to_value(obj_val);
|
||||
if (strcmp(mname, "hashCode") == 0 && arg_count == 0) {
|
||||
UF_PUSH(rava_nanbox_int(rava_object_hashcode(val)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "equals") == 0 && arg_count == 1) {
|
||||
RavaValue_t other = rava_nanbox_to_value(args[0]);
|
||||
UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "toString") == 0 && arg_count == 0) {
|
||||
char *str = rava_object_tostring(val);
|
||||
UF_PUSH(rava_nanbox_string(str));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "getClass") == 0 && arg_count == 0) {
|
||||
UF_PUSH(rava_nanbox_string(rava_object_getclass(val)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
vm->had_error = true;
|
||||
goto uf_done;
|
||||
}
|
||||
RavaObject_t *obj = rava_nanbox_as_object(obj_val);
|
||||
const char *class_name = obj->class_name;
|
||||
RavaMethod_t *target = _rava_vm_find_method_cached(vm, class_name, instr->operand.call.method_name);
|
||||
if (!target) {
|
||||
if (strcmp(instr->operand.call.method_name, "<init>") == 0 && arg_count == 0) {
|
||||
if (strcmp(mname, "<init>") == 0 && arg_count == 0) {
|
||||
UF_DISPATCH();
|
||||
}
|
||||
RavaValue_t val = rava_nanbox_to_value(obj_val);
|
||||
if (strcmp(mname, "hashCode") == 0 && arg_count == 0) {
|
||||
UF_PUSH(rava_nanbox_int(rava_object_hashcode(val)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "equals") == 0 && arg_count == 1) {
|
||||
RavaValue_t other = rava_nanbox_to_value(args[0]);
|
||||
UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "toString") == 0 && arg_count == 0) {
|
||||
char *str = rava_object_tostring(val);
|
||||
UF_PUSH(rava_nanbox_string(str));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
if (strcmp(mname, "getClass") == 0 && arg_count == 0) {
|
||||
UF_PUSH(rava_nanbox_string(rava_object_getclass(val)));
|
||||
UF_DISPATCH();
|
||||
}
|
||||
vm->had_error = true;
|
||||
@@ -4734,3 +4798,111 @@ RavaValue_t rava_vm_get_result(RavaVM_t *vm) {
|
||||
}
|
||||
return rava_value_int(0);
|
||||
}
|
||||
|
||||
RavaNativeValue_t rava_value_to_native(RavaValue_t value) {
|
||||
RavaNativeValue_t native;
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT:
|
||||
native.type = RAVA_NATIVE_INT;
|
||||
native.data.int_val = value.data.int_val;
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
native.type = RAVA_NATIVE_LONG;
|
||||
native.data.long_val = value.data.long_val;
|
||||
break;
|
||||
case RAVA_VAL_FLOAT:
|
||||
case RAVA_VAL_DOUBLE:
|
||||
native.type = RAVA_NATIVE_DOUBLE;
|
||||
native.data.double_val = (value.type == RAVA_VAL_FLOAT) ?
|
||||
(double)value.data.float_val : value.data.double_val;
|
||||
break;
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
native.type = RAVA_NATIVE_BOOLEAN;
|
||||
native.data.bool_val = value.data.bool_val;
|
||||
break;
|
||||
case RAVA_VAL_STRING:
|
||||
native.type = RAVA_NATIVE_STRING;
|
||||
native.data.string_val = value.data.string_val;
|
||||
break;
|
||||
case RAVA_VAL_OBJECT:
|
||||
native.type = RAVA_NATIVE_OBJECT;
|
||||
native.data.object_val = value.data.object_val;
|
||||
break;
|
||||
case RAVA_VAL_ARRAY:
|
||||
native.type = RAVA_NATIVE_ARRAY;
|
||||
native.data.array_val = value.data.array_val;
|
||||
break;
|
||||
default:
|
||||
native.type = RAVA_NATIVE_VOID;
|
||||
break;
|
||||
}
|
||||
return native;
|
||||
}
|
||||
|
||||
RavaValue_t rava_native_to_value(RavaNativeValue_t native) {
|
||||
RavaValue_t value;
|
||||
switch (native.type) {
|
||||
case RAVA_NATIVE_INT:
|
||||
value = rava_value_int(native.data.int_val);
|
||||
break;
|
||||
case RAVA_NATIVE_LONG:
|
||||
value = rava_value_long(native.data.long_val);
|
||||
break;
|
||||
case RAVA_NATIVE_DOUBLE:
|
||||
value = rava_value_double(native.data.double_val);
|
||||
break;
|
||||
case RAVA_NATIVE_BOOLEAN:
|
||||
value = rava_value_boolean(native.data.bool_val);
|
||||
break;
|
||||
case RAVA_NATIVE_STRING:
|
||||
value = rava_value_string(native.data.string_val);
|
||||
break;
|
||||
case RAVA_NATIVE_OBJECT:
|
||||
value.type = RAVA_VAL_OBJECT;
|
||||
value.data.object_val = native.data.object_val;
|
||||
break;
|
||||
case RAVA_NATIVE_ARRAY:
|
||||
value.type = RAVA_VAL_ARRAY;
|
||||
value.data.array_val = native.data.array_val;
|
||||
break;
|
||||
default:
|
||||
value = rava_value_null();
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool rava_vm_load_native_library(RavaVM_t *vm, const char *path) {
|
||||
if (!vm || !vm->native_registry || !path) return false;
|
||||
RavaNativeLibrary_t *lib = rava_native_library_load(vm->native_registry, path);
|
||||
return lib != NULL;
|
||||
}
|
||||
|
||||
bool rava_vm_register_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||
RavaNativeType_e return_type, RavaNativeType_e *param_types,
|
||||
size_t param_count, RavaNativeFunction_fn function, void *user_data) {
|
||||
if (!vm || !vm->native_registry) return false;
|
||||
return rava_native_register_method(vm->native_registry, class_name, method_name,
|
||||
return_type, param_types, param_count, function, user_data);
|
||||
}
|
||||
|
||||
RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||
RavaValue_t *args, size_t arg_count) {
|
||||
if (!vm || !vm->native_registry) return rava_value_null();
|
||||
|
||||
RavaNativeMethod_t *method = rava_native_find_method(vm->native_registry, class_name, method_name);
|
||||
if (!method) {
|
||||
vm->had_error = true;
|
||||
vm->error_message = malloc(256);
|
||||
snprintf(vm->error_message, 256, "Native method not found: %s.%s", class_name, method_name);
|
||||
return rava_value_null();
|
||||
}
|
||||
|
||||
RavaNativeValue_t native_args[RAVA_MAX_METHOD_PARAMS];
|
||||
for (size_t i = 0; i < arg_count && i < RAVA_MAX_METHOD_PARAMS; i++) {
|
||||
native_args[i] = rava_value_to_native(args[i]);
|
||||
}
|
||||
|
||||
RavaNativeValue_t result = rava_native_invoke(method, native_args, arg_count);
|
||||
return rava_native_to_value(result);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "../ir/ir.h"
|
||||
#include "../types/types.h"
|
||||
#include "../loader/loader.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -162,6 +163,7 @@ typedef struct {
|
||||
RavaCallStack_t *call_stack;
|
||||
RavaStaticFieldTable_t *static_fields;
|
||||
struct MethodCache_s *method_cache;
|
||||
RavaNativeRegistry_t *native_registry;
|
||||
char *error_message;
|
||||
bool had_error;
|
||||
bool has_exception;
|
||||
@@ -270,6 +272,11 @@ int rava_object_get_field_index(RavaObject_t *obj, const char *name);
|
||||
RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index);
|
||||
void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value);
|
||||
|
||||
int32_t rava_object_hashcode(RavaValue_t value);
|
||||
bool rava_object_equals(RavaValue_t a, RavaValue_t b);
|
||||
char* rava_object_tostring(RavaValue_t value);
|
||||
const char* rava_object_getclass(RavaValue_t value);
|
||||
|
||||
RavaArrayList_t* rava_arraylist_create(void);
|
||||
void rava_arraylist_destroy(RavaArrayList_t *list);
|
||||
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value);
|
||||
@@ -311,4 +318,14 @@ void rava_vm_destroy(RavaVM_t *vm);
|
||||
bool rava_vm_execute(RavaVM_t *vm, const char *class_name, const char *method_name);
|
||||
RavaValue_t rava_vm_get_result(RavaVM_t *vm);
|
||||
|
||||
bool rava_vm_load_native_library(RavaVM_t *vm, const char *path);
|
||||
bool rava_vm_register_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||
RavaNativeType_e return_type, RavaNativeType_e *param_types,
|
||||
size_t param_count, RavaNativeFunction_fn function, void *user_data);
|
||||
RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||
RavaValue_t *args, size_t arg_count);
|
||||
|
||||
RavaNativeValue_t rava_value_to_native(RavaValue_t value);
|
||||
RavaValue_t rava_native_to_value(RavaNativeValue_t native);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "../utils/safe_alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint32_t _rava_field_hash(const char *name) {
|
||||
uint32_t hash = 5381;
|
||||
@@ -131,3 +133,176 @@ void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t va
|
||||
if (!obj || index < 0 || (size_t)index >= obj->field_count) return;
|
||||
obj->field_values[index] = value;
|
||||
}
|
||||
|
||||
int32_t rava_object_hashcode(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_NULL:
|
||||
return 0;
|
||||
case RAVA_VAL_INT:
|
||||
return value.data.int_val;
|
||||
case RAVA_VAL_LONG: {
|
||||
int64_t v = value.data.long_val;
|
||||
return (int32_t)(v ^ (v >> 32));
|
||||
}
|
||||
case RAVA_VAL_FLOAT: {
|
||||
union { float f; int32_t i; } u;
|
||||
u.f = value.data.float_val;
|
||||
return u.i;
|
||||
}
|
||||
case RAVA_VAL_DOUBLE: {
|
||||
union { double d; int64_t l; } u;
|
||||
u.d = value.data.double_val;
|
||||
return (int32_t)(u.l ^ (u.l >> 32));
|
||||
}
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
return value.data.bool_val ? 1231 : 1237;
|
||||
case RAVA_VAL_CHAR:
|
||||
return (int32_t)value.data.char_val;
|
||||
case RAVA_VAL_STRING: {
|
||||
if (!value.data.string_val) return 0;
|
||||
int32_t hash = 0;
|
||||
for (const char *p = value.data.string_val; *p; p++) {
|
||||
hash = 31 * hash + (int32_t)(unsigned char)*p;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
case RAVA_VAL_OBJECT:
|
||||
case RAVA_VAL_ARRAY:
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
case RAVA_VAL_HASHMAP:
|
||||
return (int32_t)((uintptr_t)value.data.object_val >> 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool rava_object_equals(RavaValue_t a, RavaValue_t b) {
|
||||
if (a.type == RAVA_VAL_NULL && b.type == RAVA_VAL_NULL) {
|
||||
return true;
|
||||
}
|
||||
if (a.type == RAVA_VAL_NULL || b.type == RAVA_VAL_NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING) {
|
||||
if (!a.data.string_val && !b.data.string_val) return true;
|
||||
if (!a.data.string_val || !b.data.string_val) return false;
|
||||
return strcmp(a.data.string_val, b.data.string_val) == 0;
|
||||
}
|
||||
|
||||
if (a.type != b.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (a.type) {
|
||||
case RAVA_VAL_INT:
|
||||
return a.data.int_val == b.data.int_val;
|
||||
case RAVA_VAL_LONG:
|
||||
return a.data.long_val == b.data.long_val;
|
||||
case RAVA_VAL_FLOAT:
|
||||
return a.data.float_val == b.data.float_val;
|
||||
case RAVA_VAL_DOUBLE:
|
||||
return a.data.double_val == b.data.double_val;
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
return a.data.bool_val == b.data.bool_val;
|
||||
case RAVA_VAL_CHAR:
|
||||
return a.data.char_val == b.data.char_val;
|
||||
case RAVA_VAL_OBJECT:
|
||||
case RAVA_VAL_ARRAY:
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
case RAVA_VAL_HASHMAP:
|
||||
return a.data.object_val == b.data.object_val;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char* rava_object_tostring(RavaValue_t value) {
|
||||
char *buffer = malloc(128);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_NULL:
|
||||
strcpy(buffer, "null");
|
||||
break;
|
||||
case RAVA_VAL_INT:
|
||||
snprintf(buffer, 128, "%d", value.data.int_val);
|
||||
break;
|
||||
case RAVA_VAL_LONG:
|
||||
snprintf(buffer, 128, "%ld", value.data.long_val);
|
||||
break;
|
||||
case RAVA_VAL_FLOAT:
|
||||
snprintf(buffer, 128, "%g", (double)value.data.float_val);
|
||||
break;
|
||||
case RAVA_VAL_DOUBLE:
|
||||
snprintf(buffer, 128, "%g", value.data.double_val);
|
||||
break;
|
||||
case RAVA_VAL_BOOLEAN:
|
||||
strcpy(buffer, value.data.bool_val ? "true" : "false");
|
||||
break;
|
||||
case RAVA_VAL_CHAR:
|
||||
snprintf(buffer, 128, "%c", value.data.char_val);
|
||||
break;
|
||||
case RAVA_VAL_STRING:
|
||||
free(buffer);
|
||||
return value.data.string_val ? strdup(value.data.string_val) : strdup("null");
|
||||
case RAVA_VAL_OBJECT:
|
||||
if (!value.data.object_val) {
|
||||
strcpy(buffer, "null");
|
||||
} else {
|
||||
snprintf(buffer, 128, "%s@%x",
|
||||
value.data.object_val->class_name,
|
||||
(unsigned int)((uintptr_t)value.data.object_val >> 3));
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_ARRAY:
|
||||
if (!value.data.array_val) {
|
||||
strcpy(buffer, "null");
|
||||
} else {
|
||||
snprintf(buffer, 128, "[array@%x]",
|
||||
(unsigned int)((uintptr_t)value.data.array_val >> 3));
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
snprintf(buffer, 128, "ArrayList@%x",
|
||||
(unsigned int)((uintptr_t)value.data.arraylist_val >> 3));
|
||||
break;
|
||||
case RAVA_VAL_HASHMAP:
|
||||
snprintf(buffer, 128, "HashMap@%x",
|
||||
(unsigned int)((uintptr_t)value.data.hashmap_val >> 3));
|
||||
break;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* rava_object_getclass(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_NULL:
|
||||
return "null";
|
||||
case RAVA_VAL_INT:
|
||||
return "Integer";
|
||||
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 "Character";
|
||||
case RAVA_VAL_STRING:
|
||||
return "String";
|
||||
case RAVA_VAL_OBJECT:
|
||||
if (value.data.object_val) {
|
||||
return value.data.object_val->class_name;
|
||||
}
|
||||
return "null";
|
||||
case RAVA_VAL_ARRAY:
|
||||
return "Array";
|
||||
case RAVA_VAL_ARRAYLIST:
|
||||
return "ArrayList";
|
||||
case RAVA_VAL_HASHMAP:
|
||||
return "HashMap";
|
||||
}
|
||||
return "Object";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user