improvements to cbindgen and cptr
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 31 Aug 2022 02:52:57 +0000 (21:52 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 31 Aug 2022 02:52:57 +0000 (21:52 -0500)
core/onyx/cbindgen.onyx
core/onyx/cptr.onyx
src/onyx_runtime.c

index 01ec30aed8e86bdb98a88eefe6abe6acb2d69e33..76c67282eaedaade223bba39fb3cb642626070a7 100644 (file)
@@ -231,8 +231,8 @@ compile_c_file :: (
 
     print_body :: (writer, method_name, method_info, cast_map) => {
         use runtime.info;
-        call := io.dynamic_string_stream_make();
-        defer io.dynamic_string_stream_free(^call);
+        call := io.buffer_stream_make();
+        defer io.buffer_stream_free(^call);
         callw := io.writer_make(^call);
 
         param_num := 0;
@@ -261,20 +261,21 @@ compile_c_file :: (
             param_num += 1;
         }
 
-        call_str := call->to_str();
-        wasm_return_type := type_to_wasm_type(method_info.return_type);
+        call_str := io.buffer_stream_to_str(^call);
+        wasm_return_type := type_to_wasm_type(method_info.return_type, for_return=true);
         switch wasm_return_type {
-            case ""    do io.write_format(writer, "    {}({});\n", method_name, call_str[0..call_str.count-2]);
-            case "i32" do io.write_format(writer, "    results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-            case "i64" do io.write_format(writer, "    results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-            case "f32" do io.write_format(writer, "    results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-            case "f64" do io.write_format(writer, "    results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+            case ""    do io.write_format(writer,  "    {}({});\n", method_name, call_str[0..call_str.count-2]);
+            case "i32" do io.write_format(writer,  "    results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+            case "i64" do io.write_format(writer,  "    results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+            case "f32" do io.write_format(writer,  "    results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+            case "f64" do io.write_format(writer,  "    results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+            case "cptr" do io.write_format(writer, "    results->data[0] = WASM_I64_VAL((int64_t) {}({}));\n", method_name, call_str[0..call_str.count-2]);
         }
 
         io.write_format(writer, "    return NULL;\n");
     }
 
-    type_to_wasm_type :: (t: type_expr) -> str {
+    type_to_wasm_type :: (t: type_expr, for_return := false) -> str {
         use runtime.info;
 
         param_info := get_type_info(t);
@@ -309,6 +310,11 @@ compile_c_file :: (
 
             case .Struct {
                 s_info := cast(^Type_Info_Struct) param_info;
+                
+                if s_info.constructed_from == cptr && for_return {
+                    return "cptr";
+                }
+
                 if s_info.members.count == 1 {
                     return type_to_wasm_type(s_info.members[0].type);
                 }
index d8e913116d591313012587e1b939480eb010bee7..f1713f002985aa0469faa2e7f19c3c80b5ef10d4 100644 (file)
@@ -24,6 +24,14 @@ cptr :: struct (T: type_expr) {
     read_i32 :: (this: cptr(i32)) => cast(i32) __cptr_read_u32(this.data);
     read_i64 :: (this: cptr(i64)) => cast(i64) __cptr_read_u64(this.data);
 
+    // When given a non-zero-sized dest, this procedure
+    // fills the dest buffer with the contents of the string
+    // up to the number bytes in the dest buffer. This
+    // procedure returns the length of the string as given
+    // by strlen(). This exists because iterating byte by byte
+    // using __cptr_read_u8 would be slow compared to strlen().
+    extract_str :: (this: cptr(u8), dest: [] u8) => __cptr_extract_str(this.data, dest);
+
     to_rawptr :: (this: cptr($T)) -> ^T {
         // I'm treating NULL as more of a concept, than as an actual value here,
         // because if something returns a NULL pointer, it should logically map
@@ -50,12 +58,13 @@ cptr :: struct (T: type_expr) {
 
 #local {
     #foreign "onyx_runtime" {
-        __cptr_make     :: (x: rawptr) -> u64 ---
-        __cptr_read     :: (x: u64, dest: rawptr, size: u32) -> void ---
-        __cptr_read_u8  :: (x: u64) -> u8 ---
-        __cptr_read_u16 :: (x: u64) -> u16 ---
-        __cptr_read_u32 :: (x: u64) -> u32 ---
-        __cptr_read_u64 :: (x: u64) -> u64 ---
+        __cptr_make        :: (x: rawptr) -> u64 ---
+        __cptr_read        :: (x: u64, dest: rawptr, size: u32) -> void ---
+        __cptr_read_u8     :: (x: u64) -> u8 ---
+        __cptr_read_u16    :: (x: u64) -> u16 ---
+        __cptr_read_u32    :: (x: u64) -> u32 ---
+        __cptr_read_u64    :: (x: u64) -> u64 ---
+        __cptr_extract_str :: (x: u64, dest: [] u8) -> u32 ---
 
         //
         // The equivalent write instructions are pusposefully left out.
index 8a7473e8e610bffa8095ebcfbdda55a0216016eb..893e698956b89a13fbbeb0b90d7d0e37c8527c6c 100644 (file)
@@ -1341,6 +1341,16 @@ ONYX_DEF(__cptr_read_u64, (WASM_I64), (WASM_I64)) {
     return NULL;
 }
 
+ONYX_DEF(__cptr_extract_str, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    unsigned int len = strlen((char *) params->data[0].of.i64);
+
+    if (params->data[2].of.i32 != 0) {
+        strncpy(ONYX_PTR(params->data[1].of.i32), (char *) params->data[0].of.i64, params->data[2].of.i32);
+    }
+
+    results->data[0] = WASM_I32_VAL(len);
+    return NULL;
+}
 
 ONYX_LIBRARY {
     ONYX_FUNC(__file_open_impl)
@@ -1409,6 +1419,7 @@ ONYX_LIBRARY {
     ONYX_FUNC(__cptr_read_u16)
     ONYX_FUNC(__cptr_read_u32)
     ONYX_FUNC(__cptr_read_u64)
+    ONYX_FUNC(__cptr_extract_str)
 
     NULL
 };