From: Brendan Hansen Date: Sun, 26 Nov 2023 05:06:06 +0000 (-0600) Subject: added: more functionality to cbindgen X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=effe68d4e684b0a879e3045c0123d4d109e8817e;p=onyx.git added: more functionality to cbindgen --- diff --git a/core/container/optional.onyx b/core/container/optional.onyx index c9c7a992..56a2045a 100644 --- a/core/container/optional.onyx +++ b/core/container/optional.onyx @@ -116,6 +116,34 @@ use core } } + #doc """ + Returns the value inside the optional, if there is one. + If not, an assertion is thrown and the context's assert + handler must take care of it. + """ + expect :: (o: ?$T, message: str) -> T { + switch o { + case v: .Some do return v; + case #default { + assert(false, message); + } + } + } + + #doc """ + Returns a pointer to the value inside the optional, if there is one. + If not, an assertion is thrown and the context's assert handler must + take care of it. + """ + expect_ptr :: (o: & ?$T, message: str) -> &T { + switch o { + case &v: .Some do return v; + case #default { + assert(false, message); + } + } + } + or_return :: #match { macro (o: ?$T) -> T { switch value := o; value { diff --git a/core/onyx/cbindgen.onyx b/core/onyx/cbindgen.onyx index fe97d219..360f2013 100644 --- a/core/onyx/cbindgen.onyx +++ b/core/onyx/cbindgen.onyx @@ -41,10 +41,17 @@ package cbindgen use runtime +#doc "Deprecated. Use `link_name`." customize :: struct { symbol_name: str; } +link_name :: customize +func_body :: struct { + body: str; +} +last_arg_is_return_value :: #distinct void + #if #defined (runtime.Generated_Foreign_Info) { use core {package, *} @@ -133,7 +140,9 @@ compile_c_file :: ( path: str, dest: str, includes: [] str = .[], libraries: [] str = .[], - flags := "") -> bool { + flags := "", + other_sources: [] str = .[] +) -> bool { #if runtime.compiler_os == .Linux || runtime.compiler_os == .MacOS { args: [..] str; args << "-shared"; @@ -160,6 +169,10 @@ compile_c_file :: ( args << "-o"; args << tprintf("{}.{}", dest, Library_Suffix); + for other_sources { + args << it; + } + for libraries { args << aprintf("-l{}", it); } @@ -231,7 +244,26 @@ compile_c_file :: ( method_name = name_map(method_name); } - print_body(writer, method_name, method_info, cast_map); + switch slice.find_opt(ff.tags, [it](it.type == func_body)) + ->transform(x => misc.any_as(x, func_body).body) + { + case body: .Some { + io.write(writer, body); + io.write(writer, " return NULL;"); + } + + case .None { + print_body( + writer, method_name, method_info, cast_map, + slice.some(ff.tags, [it]( + misc.any_as(*it, type_expr) + |> Optional.from_ptr() + |> Optional.transform(x => x == last_arg_is_return_value) + |> Optional.value_or(false) + )) + ); + } + } io.write(writer, "}\n\n"); } @@ -246,14 +278,19 @@ compile_c_file :: ( io.write(writer, "};"); } - print_body :: (writer, method_name, method_info, cast_map) => { + print_body :: (writer, method_name, method_info, cast_map, last_arg_is_return_value) => { use runtime.info {*}; callw, call := io.string_builder(); defer io.buffer_stream_free(call); defer cfree(call); + params := method_info.parameter_types; + if last_arg_is_return_value { + params = params[0 .. params.length - 1]; + } + param_num := 0; - for method_info.parameter_types { + for params { it_info := it->info(); if it_info.kind == .Slice { @@ -308,6 +345,14 @@ compile_c_file :: ( } } + } elseif it_info.kind == .Struct && it_info->as_struct().constructed_from != cptr { + param_type := it; + name := slice.find_opt(cast_map, [x](x.type == param_type)) + ->expect(tprintf("Structures used as parameter arguments MUST have a definition in the 'cast_map' in '{}'.", method_name)) + .name; + + io.write_format(&callw, "*({} *) ONYX_PTR(P({}, i32))", name, param_num); // This is dependent on the pointer size + } else { matched := false; for& m: cast_map { @@ -318,7 +363,9 @@ compile_c_file :: ( } } - if !matched do io.write_format(&callw, "P({}, {})", param_num, type_to_wasm_type(it)); + if !matched { + io.write_format(&callw, "P({}, {})", param_num, type_to_wasm_type(it)); + } } io.write_format(&callw, ", "); @@ -326,17 +373,33 @@ compile_c_file :: ( } 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 "cptr" do io.write_format(writer, " results->data[0] = WASM_I64_VAL((int64_t) {}({}));\n", method_name, call_str[0..call_str.count-2]); - case "ptr" { - printf("Returning a pointer-like object from C to Onyx in '{}'.\nWhile this is not an error, be careful with what you are doing, as this pointer MUST be allocated in Onyx's memory space, not in external memory. Use cptr(...) if the memory lives elsewhere.\n\n", method_name); - io.write_format(writer, " int out = ONYX_UNPTR({}({}));\n results->data[0] = WASM_I32_VAL(out);\n", method_name, call_str[0..call_str.count-2]); + call_str = call_str[0 .. call_str.count - 2]; + if last_arg_is_return_value { + return_type := slice.get(method_info.parameter_types, -1); + if return_type->info().kind != .Pointer { + assert(false, tprintf("last_arg_is_return_value requires last parameter to be a pointer. ({} in {})", method_info.parameter_types, method_name)); + } + + return_type = return_type->info()->as_pointer().to; + type_name := slice.find_opt(cast_map, [x](x.type == return_type)) + ->expect(tprintf("Types used as last argument return values MUST have a definition in the 'cast_map' in '{}'.", method_name)) + .name; + + io.write_format(writer, " *({} *) ONYX_PTR(P({}, i32)) = {}({});\n", type_name, param_num, method_name, call_str); + + } else { + 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); + case "i32" do io.write_format(writer, " results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str); + case "i64" do io.write_format(writer, " results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str); + case "f32" do io.write_format(writer, " results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str); + case "f64" do io.write_format(writer, " results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str); + case "cptr" do io.write_format(writer, " results->data[0] = WASM_I64_VAL((int64_t) {}({}));\n", method_name, call_str); + case "ptr" { + printf("Returning a pointer-like object from C to Onyx in '{}'.\nWhile this is not an error, be careful with what you are doing, as this pointer MUST be allocated in Onyx's memory space, not in external memory. Use cptr(...) if the memory lives elsewhere.\n\n", method_name); + io.write_format(writer, " int out = ONYX_UNPTR({}({}));\n results->data[0] = WASM_I32_VAL(out);\n", method_name, call_str); + } } } @@ -440,7 +503,8 @@ compile_c_file :: ( return type_encoding(s_info.members[0].type); } - assert(false, "Passing structures between wasm and c is not yet supported."); + // assert(false, "Passing structures between wasm and c is not yet supported."); + return "WASM_I32"; } } diff --git a/scripts/onyx-pkg.onyx b/scripts/onyx-pkg.onyx index 60aad7bf..398ed6cf 100644 --- a/scripts/onyx-pkg.onyx +++ b/scripts/onyx-pkg.onyx @@ -8,7 +8,7 @@ // argument, which the package name. Known_Repositories :: str.[ "{}", - "repo.onyxlang.io/repo/{}" + "github.com/onyx-lang/pkg-{}" ]