From fb3e40e41774dc15b449819079507dbe00186c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Catarino=20Fran=C3=A7a?= Date: Sun, 16 Jan 2022 10:15:39 -0300 Subject: [PATCH 01/13] Zig language added --- .github/workflows/cbindgen.yml | 5 + docs.md | 6 +- src/bindgen/bindings.rs | 23 +++- src/bindgen/cdecl.rs | 96 +++++++++++++++-- src/bindgen/config.rs | 33 +++++- src/bindgen/ir/constant.rs | 17 ++- src/bindgen/ir/documentation.rs | 8 ++ src/bindgen/ir/enumeration.rs | 28 ++++- src/bindgen/ir/field.rs | 14 ++- src/bindgen/ir/function.rs | 44 +++++--- src/bindgen/ir/opaque.rs | 5 + src/bindgen/ir/structure.rs | 13 ++- src/bindgen/ir/ty.rs | 100 ++++++++++++++++++ src/bindgen/ir/typedef.rs | 4 + src/bindgen/ir/union.rs | 1 + src/bindgen/writer.rs | 4 +- src/main.rs | 2 +- tests/expectations/alias.zig | 31 ++++++ tests/expectations/annotation.zig | 1 + tests/expectations/array.zig | 1 + tests/expectations/asserted_cast.zig | 1 + tests/expectations/assoc_const_conflict.zig | 1 + tests/expectations/bitfield.zig | 8 ++ tests/expectations/bitflags.zig | 35 ++++++ tests/expectations/body.zig | 75 +++++++++++++ tests/expectations/box.zig | 11 ++ tests/expectations/cdecl.zig | 22 ++++ tests/expectations/cell.zig | 1 + tests/expectations/cfg.zig | 1 + tests/expectations/char.zig | 6 ++ tests/expectations/constant.zig | 9 ++ tests/expectations/constant_big.zig | 9 ++ tests/expectations/cython_options.zig | 1 + tests/expectations/dep_v2.zig | 8 ++ tests/expectations/derive_eq.zig | 39 +++++++ tests/expectations/display_list.zig | 38 +++++++ tests/expectations/doclength_short.zig | 14 +++ tests/expectations/docstyle.c99.zig | 4 + tests/expectations/docstyle_auto.zig | 4 + tests/expectations/documentation.zig | 21 ++++ tests/expectations/enum.zig | 1 + tests/expectations/enum_self.zig | 1 + tests/expectations/euclid.zig | 1 + .../exclude_generic_monomorph.zig | 1 + tests/expectations/expand.zig | 1 + tests/expectations/export_name.zig | 3 + tests/expectations/extern.zig | 10 ++ tests/expectations/extern_2.zig | 5 + .../expectations/external_workspace_child.zig | 1 + tests/expectations/fns.tag.zig | 1 + tests/expectations/fns.zig | 13 +++ tests/expectations/forward_declaration.zig | 1 + tests/expectations/function_args.zig | 1 + tests/expectations/function_noreturn.zig | 1 + tests/expectations/generic_pointer.zig | 1 + tests/expectations/global_attr.zig | 1 + tests/expectations/ignore.zig | 1 + tests/expectations/include.zig | 1 + tests/expectations/include_guard.zig | 1 + tests/expectations/include_item.zig | 1 + .../infinite_recursion_typedef_monomorph.zig | 1 + tests/expectations/inner_mod.zig | 1 + tests/expectations/item_types.zig | 1 + tests/expectations/layout.zig | 1 + tests/expectations/layout_aligned_opaque.zig | 1 + tests/expectations/layout_packed_opaque.zig | 1 + tests/expectations/lifetime_arg.zig | 1 + tests/expectations/linestyle_cr.zig | 1 + tests/expectations/linestyle_if.zig | 1 + tests/expectations/literal_target.zig | 1 + tests/expectations/mangle.zig | 1 + tests/expectations/manuallydrop.zig | 1 + tests/expectations/maybeuninit.zig | 1 + tests/expectations/mod_2015.zig | 1 + tests/expectations/mod_2018.zig | 1 + tests/expectations/monomorph_2.zig | 19 ++++ tests/expectations/must_use.zig | 10 ++ tests/expectations/nested_import.zig | 1 + tests/expectations/no_includes.zig | 1 + tests/expectations/nonnull.zig | 17 +++ tests/expectations/nonzero.zig | 18 ++++ tests/expectations/opaque.zig | 1 + tests/expectations/pin.zig | 8 ++ tests/expectations/pragma_once.zig | 1 + tests/expectations/prefix.zig | 23 ++++ .../prefixed_struct_literal_deep.zig | 1 + tests/expectations/ptrs_as_arrays.zig | 11 ++ tests/expectations/raw_ident.zig | 14 +++ tests/expectations/raw_lines.zig | 5 + tests/expectations/rename.zig | 1 + tests/expectations/rename_crates.zig | 1 + .../renaming_overrides_prefixing.zig | 1 + tests/expectations/reserved.zig | 34 ++++++ tests/expectations/sentinel.zig | 1 + tests/expectations/simplify_option_ptr.zig | 1 + tests/expectations/size_types.zig | 1 + tests/expectations/static.zig | 1 + tests/expectations/std_lib.zig | 1 + tests/expectations/struct.zig | 1 + tests/expectations/struct_literal.zig | 1 + tests/expectations/style_crash.zig | 1 + tests/expectations/swift_name.zig | 1 + tests/expectations/transform_op.zig | 1 + tests/expectations/transparent.zig | 25 +++++ tests/expectations/typedef.zig | 10 ++ tests/expectations/union.zig | 1 + tests/expectations/va_list.zig | 1 + tests/expectations/workspace.zig | 1 + tests/expectations/zst.zig | 8 ++ tests/tests.rs | 12 +++ 110 files changed, 992 insertions(+), 49 deletions(-) create mode 100644 tests/expectations/alias.zig create mode 100644 tests/expectations/annotation.zig create mode 100644 tests/expectations/array.zig create mode 100644 tests/expectations/asserted_cast.zig create mode 100644 tests/expectations/assoc_const_conflict.zig create mode 100644 tests/expectations/bitfield.zig create mode 100644 tests/expectations/bitflags.zig create mode 100644 tests/expectations/body.zig create mode 100644 tests/expectations/box.zig create mode 100644 tests/expectations/cdecl.zig create mode 100644 tests/expectations/cell.zig create mode 100644 tests/expectations/cfg.zig create mode 100644 tests/expectations/char.zig create mode 100644 tests/expectations/constant.zig create mode 100644 tests/expectations/constant_big.zig create mode 100644 tests/expectations/cython_options.zig create mode 100644 tests/expectations/dep_v2.zig create mode 100644 tests/expectations/derive_eq.zig create mode 100644 tests/expectations/display_list.zig create mode 100644 tests/expectations/doclength_short.zig create mode 100644 tests/expectations/docstyle.c99.zig create mode 100644 tests/expectations/docstyle_auto.zig create mode 100644 tests/expectations/documentation.zig create mode 100644 tests/expectations/enum.zig create mode 100644 tests/expectations/enum_self.zig create mode 100644 tests/expectations/euclid.zig create mode 100644 tests/expectations/exclude_generic_monomorph.zig create mode 100644 tests/expectations/expand.zig create mode 100644 tests/expectations/export_name.zig create mode 100644 tests/expectations/extern.zig create mode 100644 tests/expectations/extern_2.zig create mode 100644 tests/expectations/external_workspace_child.zig create mode 100644 tests/expectations/fns.tag.zig create mode 100644 tests/expectations/fns.zig create mode 100644 tests/expectations/forward_declaration.zig create mode 100644 tests/expectations/function_args.zig create mode 100644 tests/expectations/function_noreturn.zig create mode 100644 tests/expectations/generic_pointer.zig create mode 100644 tests/expectations/global_attr.zig create mode 100644 tests/expectations/ignore.zig create mode 100644 tests/expectations/include.zig create mode 100644 tests/expectations/include_guard.zig create mode 100644 tests/expectations/include_item.zig create mode 100644 tests/expectations/infinite_recursion_typedef_monomorph.zig create mode 100644 tests/expectations/inner_mod.zig create mode 100644 tests/expectations/item_types.zig create mode 100644 tests/expectations/layout.zig create mode 100644 tests/expectations/layout_aligned_opaque.zig create mode 100644 tests/expectations/layout_packed_opaque.zig create mode 100644 tests/expectations/lifetime_arg.zig create mode 100644 tests/expectations/linestyle_cr.zig create mode 100644 tests/expectations/linestyle_if.zig create mode 100644 tests/expectations/literal_target.zig create mode 100644 tests/expectations/mangle.zig create mode 100644 tests/expectations/manuallydrop.zig create mode 100644 tests/expectations/maybeuninit.zig create mode 100644 tests/expectations/mod_2015.zig create mode 100644 tests/expectations/mod_2018.zig create mode 100644 tests/expectations/monomorph_2.zig create mode 100644 tests/expectations/must_use.zig create mode 100644 tests/expectations/nested_import.zig create mode 100644 tests/expectations/no_includes.zig create mode 100644 tests/expectations/nonnull.zig create mode 100644 tests/expectations/nonzero.zig create mode 100644 tests/expectations/opaque.zig create mode 100644 tests/expectations/pin.zig create mode 100644 tests/expectations/pragma_once.zig create mode 100644 tests/expectations/prefix.zig create mode 100644 tests/expectations/prefixed_struct_literal_deep.zig create mode 100644 tests/expectations/ptrs_as_arrays.zig create mode 100644 tests/expectations/raw_ident.zig create mode 100644 tests/expectations/raw_lines.zig create mode 100644 tests/expectations/rename.zig create mode 100644 tests/expectations/rename_crates.zig create mode 100644 tests/expectations/renaming_overrides_prefixing.zig create mode 100644 tests/expectations/reserved.zig create mode 100644 tests/expectations/sentinel.zig create mode 100644 tests/expectations/simplify_option_ptr.zig create mode 100644 tests/expectations/size_types.zig create mode 100644 tests/expectations/static.zig create mode 100644 tests/expectations/std_lib.zig create mode 100644 tests/expectations/struct.zig create mode 100644 tests/expectations/struct_literal.zig create mode 100644 tests/expectations/style_crash.zig create mode 100644 tests/expectations/swift_name.zig create mode 100644 tests/expectations/transform_op.zig create mode 100644 tests/expectations/transparent.zig create mode 100644 tests/expectations/typedef.zig create mode 100644 tests/expectations/union.zig create mode 100644 tests/expectations/va_list.zig create mode 100644 tests/expectations/workspace.zig create mode 100644 tests/expectations/zst.zig diff --git a/.github/workflows/cbindgen.yml b/.github/workflows/cbindgen.yml index f2614e9b3..bf2791329 100644 --- a/.github/workflows/cbindgen.yml +++ b/.github/workflows/cbindgen.yml @@ -71,6 +71,11 @@ jobs: python -m pip install --upgrade pip wheel pip install Cython==0.29.* + - name: Install Zig + uses: goto-bus-stop/setup-zig@v1 + with: + version: master + - name: Build run: | cargo build --verbose diff --git a/docs.md b/docs.md index 9a434aa06..e24ca0c1f 100644 --- a/docs.md +++ b/docs.md @@ -37,8 +37,8 @@ cbindgen --config cbindgen.toml --crate my_rust_library --output my_header.h ``` This produces a header file for C++. For C, add the `--lang c` switch. \ -`cbindgen` also supports generation of [Cython](https://cython.org) bindings, -use `--lang cython` for that. +`cbindgen` also supports generation of [Cython](https://cython.org) and [Zig](https://ziglang.org) bindings, +use `--lang cython` or `--lang zig` for that. See `cbindgen --help` for more options. @@ -385,7 +385,7 @@ Note that many options defined here only apply for one of C or C++. Usually it's ```toml # The language to output bindings in # -# possible values: "C", "C++", "Cython" +# possible values: "C", "C++", "Cython", "Zig" # # default: "C++" language = "C" diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index a03b2826d..8a576c147 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -177,7 +177,7 @@ impl Bindings { write!(out, "#define {}", f); out.new_line(); } - if self.config.pragma_once && self.config.language != Language::Cython { + if self.config.pragma_once && self.config.language != Language::Cython && self.config.language != Language::Zig { out.new_line_if_not_start(); write!(out, "#pragma once"); out.new_line(); @@ -264,6 +264,10 @@ impl Bindings { out.new_line(); out.close_brace(false); } + Language::Zig => { + out.write("const std = @import(\"std\");"); + out.new_line(); + } } } @@ -284,6 +288,13 @@ impl Bindings { } } + if self.config.language == Language::Zig { + for (module, names) in &self.config.zig.cimports { + write!(out, "const {} = @cImport ({{ @cInclude(\"{}\")}});", names.join(""), module); + out.new_line(); + } + } + if let Some(ref line) = self.config.after_includes { write!(out, "{}", line); out.new_line(); @@ -356,6 +367,16 @@ impl Bindings { } } + if self.config.language == Language::Zig { + if let Some(ref using_namespaces) = self.config.using_namespaces { + for namespace in using_namespaces { + out.new_line(); + write!(out, "usingnamespace {};", namespace); + } + out.new_line(); + } + } + if self.config.language == Language::Cxx || self.config.cpp_compatible_c() { out.new_line(); out.write("extern \"C\" {"); diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index c909121df..fd745c724 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -113,7 +113,9 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_qualifers = "const".to_owned(); + if config.language != Language::Zig { + self.type_qualifers = "const".to_owned(); + } } assert!( @@ -137,7 +139,9 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_qualifers = "const".to_owned(); + if config.language != Language::Zig { + self.type_qualifers = "const".to_owned(); + } } assert!( @@ -145,7 +149,12 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_name = p.to_repr_c(config).to_string(); + + if config.language == Language::Zig { + self.type_name = p.to_repr_zig().to_string(); + } else { + self.type_name = p.to_repr_c(config).to_string(); + } } Type::Ptr { ref ty, @@ -202,7 +211,9 @@ impl CDecl { } } - write!(out, "{}", self.type_name); + if config.language != Language::Zig { + write!(out, "{}", self.type_name); + } if !self.type_generic_args.is_empty() { out.write("<"); @@ -212,11 +223,16 @@ impl CDecl { // When we have an identifier, put a space between the type and the declarators if ident.is_some() { - out.write(" "); + if config.language == Language::Zig && self.declarators.is_empty() { + out.write(""); + } else { + out.write(" "); + } } // Write the left part of declarators before the identifier let mut iter_rev = self.declarators.iter().rev().peekable(); + let mut is_functors = false; #[allow(clippy::while_let_on_iterator)] while let Some(declarator) = iter_rev.next() { @@ -228,9 +244,23 @@ impl CDecl { is_nullable, is_ref, } => { - out.write(if is_ref { "&" } else { "*" }); + if config.language != Language::Zig { + out.write(if is_ref { "&" } else { "*" }); + } else { + if !self.type_qualifers.is_empty() { + write!(out, "{}", self.type_qualifers); + } else { + if config.language != Language::Zig { + out.write("_"); + } + } + } if is_const { - out.write("const "); + if config.language == Language::Zig { + write!(out, "{} ", config.style.zig_def()); + } else { + out.write("const "); + } } if !is_nullable && !is_ref && config.language != Language::Cython { if let Some(attr) = &config.pointer.non_null_attribute { @@ -244,16 +274,25 @@ impl CDecl { } } CDeclarator::Func { .. } => { - if next_is_pointer { + if next_is_pointer && config.language != Language::Zig { out.write("("); } + is_functors = true; } } } // Write the identifier if let Some(ident) = ident { - write!(out, "{}", ident); + if config.language == Language::Zig && self.declarators.is_empty() { + if ident.is_empty() { + write!(out, "{}", self.type_name); + } else { + write!(out, "{}: {}", ident, self.type_name); + } + } else { + write!(out, "{}", ident); + } } // Write the right part of declarators after the identifier @@ -265,12 +304,42 @@ impl CDecl { match *declarator { CDeclarator::Ptr { .. } => { last_was_pointer = true; + + if config.language == Language::Zig { + if self.type_name.contains("u8") + || self.type_name.contains("const u8") + || self.type_name.contains("CStr") + || self.type_name.contains("c_char") + { + write!(out, ": ?[*:0]{}", self.type_name); + } else if is_functors { + out.write(": ?fn"); + } else { + write!(out, ": ?*{}", self.type_name); + } + + if self.type_name.contains("c_void") && !last_was_pointer { + out.write(": callconv(.C) void"); + } + } } CDeclarator::Array(ref constant) => { if last_was_pointer { out.write(")"); } - write!(out, "[{}]", constant); + if config.language == Language::Zig { + if constant.is_empty() { + write!(out, "{}: [*]{}", self.type_qualifers, self.type_name); + } else { + write!( + out, + "{}: [{}]{}", + self.type_qualifers, constant, self.type_name + ); + } + } else { + write!(out, "[{}]", constant); + } last_was_pointer = false; } @@ -279,9 +348,10 @@ impl CDecl { layout_vertical, never_return, } => { - if last_was_pointer { + if last_was_pointer && config.language != Language::Zig { out.write(")"); } + is_functors = true; out.write("("); if args.is_empty() && config.language == Language::C { @@ -322,6 +392,10 @@ impl CDecl { } } + if config.language == Language::Zig { + write!(out, " {}", self.type_name); + } + last_was_pointer = true; } } diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index fbf35cbe1..a48286ec3 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -23,6 +23,7 @@ pub enum Language { Cxx, C, Cython, + Zig, } impl FromStr for Language { @@ -42,6 +43,8 @@ impl FromStr for Language { "C" => Ok(Language::C), "cython" => Ok(Language::Cython), "Cython" => Ok(Language::Cython), + "zig" => Ok(Language::Zig), + "Zig" => Ok(Language::Zig), _ => Err(format!("Unrecognized Language: '{}'.", s)), } } @@ -54,6 +57,7 @@ impl Language { match self { Language::Cxx | Language::C => "typedef", Language::Cython => "ctypedef", + Language::Zig => "pub const", } } } @@ -243,6 +247,14 @@ impl Style { "ctypedef " } } + + pub fn zig_def(self) -> &'static str { + if self.generate_tag() { + "pub const " + } else { + "pub extern" + } + } } impl Default for Style { @@ -698,6 +710,8 @@ pub struct ConstantConfig { pub allow_static_const: bool, /// Whether a generated constant should be constexpr in C++ mode. pub allow_constexpr: bool, + /// Whether a generated compile-time should be comptime in Zig mode. + pub allow_comptime: bool, /// Sort key for constants pub sort_by: Option, } @@ -707,6 +721,7 @@ impl Default for ConstantConfig { ConstantConfig { allow_static_const: true, allow_constexpr: true, + allow_comptime: true, sort_by: None, } } @@ -881,6 +896,15 @@ pub struct CythonConfig { pub cimports: BTreeMap>, } +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(deny_unknown_fields)] +#[serde(default)] +pub struct ZigConfig { + pub header: Option, + pub cimports: BTreeMap>, +} + /// A collection of settings to customize the generated bindings. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -1003,6 +1027,8 @@ pub struct Config { pub only_target_dependencies: bool, /// Configuration options specific to Cython. pub cython: CythonConfig, + /// Configuration options specific to Zig. + pub zig: ZigConfig, } impl Default for Config { @@ -1045,6 +1071,7 @@ impl Default for Config { pointer: PtrConfig::default(), only_target_dependencies: false, cython: CythonConfig::default(), + zig: ZigConfig::default(), } } } @@ -1055,7 +1082,7 @@ impl Config { } pub(crate) fn include_guard(&self) -> Option<&str> { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { None } else { self.include_guard.as_deref() @@ -1063,7 +1090,7 @@ impl Config { } pub(crate) fn includes(&self) -> &[String] { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { &[] } else { &self.includes @@ -1071,7 +1098,7 @@ impl Config { } pub(crate) fn sys_includes(&self) -> &[String] { - if self.language == Language::Cython { + if self.language == Language::Cython || self.language == Language::Zig { &[] } else { &self.sys_includes diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 42182ab92..e8a5ffc10 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -489,7 +489,7 @@ impl Literal { return write!(out, "{}", known); } let path_separator = match config.language { - Language::Cython | Language::C => "_", + Language::Cython | Language::Zig | Language::C => "_", Language::Cxx => { if config.structure.associated_constants_in_body { "::" @@ -548,6 +548,7 @@ impl Literal { Language::C => write!(out, "({})", export_name), Language::Cxx => write!(out, "{}", export_name), Language::Cython => write!(out, "<{}>", export_name), + Language::Zig => write!(out, ":{} = ", export_name), } write!(out, "{{ "); @@ -565,6 +566,7 @@ impl Literal { Language::Cxx => write!(out, "/* .{} = */ ", ordered_key), Language::C => write!(out, ".{} = ", ordered_key), Language::Cython => {} + Language::Zig => write!(out, ".{} = ", ordered_key), } lit.write(config, out); } @@ -773,6 +775,7 @@ impl Constant { self.documentation.write(config, out); let allow_constexpr = config.constant.allow_constexpr && self.value.can_be_constexpr(); + let allow_comptime = config.constant.allow_comptime; match config.language { Language::Cxx if config.constant.allow_static_const || allow_constexpr => { if allow_constexpr { @@ -806,6 +809,18 @@ impl Constant { write!(out, " {} # = ", name); value.write(config, out); } + Language::Zig if allow_comptime => { + if allow_comptime { + out.write("comptime "); + } + } + Language::Zig => { + out.write(config.style.zig_def()); + self.ty.write(config, out); + write!(out, "{} = ", name); + value.write(config, out); + write!(out, ";"); + } } condition.write_after(config, out); diff --git a/src/bindgen/ir/documentation.rs b/src/bindgen/ir/documentation.rs index 6822c0eaf..2cfcac3f0 100644 --- a/src/bindgen/ir/documentation.rs +++ b/src/bindgen/ir/documentation.rs @@ -57,6 +57,14 @@ impl Source for Documentation { return; } + if config.language == Language::Zig { + for line in &self.doc_comment[..end] { + write!(out, "///{}", line); + out.new_line(); + } + return; + } + let style = match config.documentation_style { DocumentationStyle::Auto if config.language == Language::C => DocumentationStyle::Doxy, DocumentationStyle::Auto if config.language == Language::Cxx => DocumentationStyle::Cxx, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 6409a7913..1db4fdc18 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -656,7 +656,11 @@ impl Item for Enum { impl Source for Enum { fn write(&self, config: &Config, out: &mut SourceWriter) { - let size = self.repr.ty.map(|ty| ty.to_primitive().to_repr_c(config)); + let size = if config.language == Language::Zig { + self.repr.ty.map(|ty| ty.to_primitive().to_repr_zig()) + } else { + self.repr.ty.map(|ty| ty.to_primitive().to_repr_c(config)) + }; let has_data = self.tag.is_some(); let inline_tag_field = Self::inline_tag_field(&self.repr); let tag_name = self.tag_name(); @@ -801,6 +805,9 @@ impl Enum { write!(out, "{}enum {}", config.style.cython_def(), tag_name); } } + Language::Zig => { + write!(out, "{}{} = enum", config.style.zig_def(), tag_name); + } } out.open_brace(); @@ -829,7 +836,7 @@ impl Enum { out.write("#ifndef __cplusplus"); } - if config.language != Language::Cxx { + if config.language != Language::Cxx && config.language != Language::Zig { out.new_line(); write!(out, "{} {} {};", config.language.typedef(), prim, tag_name); } @@ -855,6 +862,9 @@ impl Enum { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => { + write!(out, "{}{} = extern ", config.style.zig_def(), self.export_name()); + } } out.write(if inline_tag_field { "union" } else { "struct" }); @@ -865,7 +875,7 @@ impl Enum { } } - if config.language != Language::C || config.style.generate_tag() { + if config.language != Language::C && config.language != Language::Zig { write!(out, " {}", self.export_name()); } @@ -927,7 +937,11 @@ impl Enum { out.write("enum "); } - write!(out, "{} tag;", tag_name); + if config.language != Language::Zig { + write!(out, "{} tag;", tag_name); + }else { + write!(out, "tag: {},", tag_name); + } if wrap_tag { out.close_brace(true); @@ -974,10 +988,14 @@ impl Enum { if config.language != Language::Cython { out.close_brace(true); } + } else if config.language == Language::Zig { + write!(out, "{}: {},", name, body.export_name()); } else if config.style.generate_typedef() || config.language == Language::Cython { write!(out, "{} {};", body.export_name(), name); } else { - write!(out, "struct {} {};", body.export_name(), name); + if config.language != Language::Zig { + write!(out, "struct {} {};", body.export_name(), name); + } } if config.language != Language::Cython { condition.write_after(config, out); diff --git a/src/bindgen/ir/field.rs b/src/bindgen/ir/field.rs index 6e132bfaf..d7a8826f0 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -28,6 +28,16 @@ impl Field { } } + pub fn from_type(ty: Type) -> Field { + Field { + name: "".to_string(), + ty, + cfg: None, + annotations: AnnotationSet::new(), + documentation: Documentation::none(), + } + } + pub fn load(field: &syn::Field, self_path: &Path) -> Result, String> { Ok(if let Some(mut ty) = Type::load(&field.ty)? { ty.replace_self_with(self_path); @@ -61,13 +71,13 @@ impl Source for Field { cdecl::write_field(out, &self.ty, &self.name, config); // Cython extern declarations don't manage layouts, layouts are defined entierly by the // corresponding C code. So we can omit bitfield sizes which are not supported by Cython. - if config.language != Language::Cython { + if config.language != Language::Cython || config.language != Language::Zig { if let Some(bitfield) = self.annotations.atom("bitfield") { write!(out, ": {}", bitfield.unwrap_or_default()); } } - if config.language != Language::Cython { + if config.language != Language::Cython || config.language != Language::Zig { condition.write_after(config, out); // FIXME(#634): `write_vertical_source_list` should support // configuring list elements natively. For now we print a newline diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 8119db572..6f22e55b5 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -231,14 +231,21 @@ impl Source for Function { func.documentation.write(config, out); if func.extern_decl { - out.write("extern "); - } else { - if let Some(ref prefix) = prefix { - write!(out, "{} ", prefix); + out.write("pub extern "); + if config.language == Language::Zig { + out.write("fn"); } - if func.annotations.must_use(config) { - if let Some(ref anno) = config.function.must_use { - write!(out, "{} ", anno); + } else { + if config.language == Language::Zig { + out.write("pub extern fn"); + } else { + if let Some(ref prefix) = prefix { + write!(out, "{} ", prefix); + } + if func.annotations.must_use(config) { + if let Some(ref anno) = config.function.must_use { + write!(out, "{} ", anno); + } } } } @@ -272,16 +279,21 @@ impl Source for Function { func.documentation.write(config, out); if func.extern_decl { - out.write("extern "); - } else { - if let Some(ref prefix) = prefix { - write!(out, "{}", prefix); - out.new_line(); + out.write("pub extern "); + if config.language == Language::Zig { + out.write("fn"); } - if func.annotations.must_use(config) { - if let Some(ref anno) = config.function.must_use { - write!(out, "{}", anno); - out.new_line(); + } else { + if config.language == Language::Zig { + out.write("pub extern fn"); + } else { + if let Some(ref prefix) = prefix { + write!(out, "{} ", prefix); + } + if func.annotations.must_use(config) { + if let Some(ref anno) = config.function.must_use { + write!(out, "{} ", anno); + } } } } diff --git a/src/bindgen/ir/opaque.rs b/src/bindgen/ir/opaque.rs index 4451d4a16..3140a99e1 100644 --- a/src/bindgen/ir/opaque.rs +++ b/src/bindgen/ir/opaque.rs @@ -169,6 +169,11 @@ impl Source for OpaqueItem { out.write("pass"); out.close_brace(false); } + Language::Zig => { + write!(out,"const {} = opaque", self.export_name()); + out.open_brace(); + out.close_brace(true); + } } condition.write_after(config, out); diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 2cb26a044..07d33212c 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -420,12 +420,13 @@ impl Source for Struct { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => out.write(config.style.zig_def()), } // Cython extern declarations don't manage layouts, layouts are defined entierly by the // corresponding C code. So this `packed` is only for documentation, and missing // `aligned(n)` is also not a problem. - if config.language == Language::Cython { + if config.language == Language::Cython || config.language == Language::Zig { if let Some(align) = self.alignment { match align { ReprAlign::Packed => out.write("packed "), @@ -434,7 +435,11 @@ impl Source for Struct { } } - out.write("struct"); + if config.language == Language::Zig { + write!(out, "{} = extern struct", self.export_name()); + } else { + out.write("struct"); + } if config.language != Language::Cython { if let Some(align) = self.alignment { @@ -459,7 +464,7 @@ impl Source for Struct { } } - if config.language != Language::C || config.style.generate_tag() { + if config.language != Language::Zig && config.language != Language::C { write!(out, " {}", self.export_name()); } @@ -471,7 +476,7 @@ impl Source for Struct { out.new_line(); } - out.write_vertical_source_list(&self.fields, ListType::Cap(";")); + out.write_vertical_source_list(&self.fields, ListType::Cap(if config.language != Language::Zig {";"}else{","})); if config.language == Language::Cython && self.fields.is_empty() { out.write("pass"); } diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 5c68e4ca1..85a2930bb 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -194,6 +194,106 @@ impl PrimitiveType { } } + pub fn to_repr_zig(&self) -> &'static str { + match *self { + PrimitiveType::Bool => "bool", + PrimitiveType::Void => "anyopaque", + PrimitiveType::Char => "u8", + PrimitiveType::SChar => "i8", + PrimitiveType::UChar => "u8", + PrimitiveType::Char32 => "u32", + PrimitiveType::Integer { + kind, + signed, + zeroable: _, + } => match kind { + IntKind::Short => { + if signed { + "c_short" + } else { + "c_ushort" + } + } + IntKind::Int => { + if signed { + "c_int" + } else { + "c_uint" + } + } + IntKind::Long => { + if signed { + "c_long" + } else { + "c_ulong" + } + } + IntKind::LongLong => { + if signed { + "c_longlong" + } else { + "c_ulonglong" + } + } + IntKind::SizeT => { + if signed { + "ssize_t" + } else { + "size_t" + } + } + IntKind::Size => { + if signed { + "isize" + } else { + "usize" + } + } + IntKind::B8 => { + if signed { + "i8" + } else { + "u8" + } + } + IntKind::B16 => { + if signed { + "i16" + } else { + "u16" + } + } + IntKind::B32 => { + if signed { + "i32" + } else { + "u32" + } + } + IntKind::B64 => { + if signed { + "i64" + } else { + "u64" + } + } + }, + PrimitiveType::Float => "f32", + PrimitiveType::Double => "f64", + PrimitiveType::PtrDiffT => "ptrdiff_t", + PrimitiveType::VaList => { + #[cfg(target_os = "windows")] + { + "va_list" + } + #[cfg(not(target_os = "windows"))] + { + "..." + } + } + } + } + pub fn to_repr_c(&self, config: &Config) -> &'static str { match *self { PrimitiveType::Void => "void", diff --git a/src/bindgen/ir/typedef.rs b/src/bindgen/ir/typedef.rs index 626732e2a..a7a31c67e 100644 --- a/src/bindgen/ir/typedef.rs +++ b/src/bindgen/ir/typedef.rs @@ -199,6 +199,10 @@ impl Source for Typedef { Field::from_name_and_type(self.export_name().to_owned(), self.aliased.clone()) .write(config, out); } + Language::Zig => { + write!(out, "{}{} = ", config.style.zig_def(), self.export_name()); + Field::from_type(self.aliased.clone()).write(config, out); + } } out.write(";"); diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index 07bd16c58..e1888093f 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -279,6 +279,7 @@ impl Source for Union { Language::C if config.style.generate_typedef() => out.write("typedef "), Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), + Language::Zig => out.write(config.style.zig_def()), } out.write("union"); diff --git a/src/bindgen/writer.rs b/src/bindgen/writer.rs index 3291af911..ecfc5de6d 100644 --- a/src/bindgen/writer.rs +++ b/src/bindgen/writer.rs @@ -154,7 +154,7 @@ impl<'a, F: Write> SourceWriter<'a, F> { pub fn open_brace(&mut self) { match self.bindings.config.language { - Language::Cxx | Language::C => match self.bindings.config.braces { + Language::Cxx | Language::C | Language::Zig => match self.bindings.config.braces { Braces::SameLine => { self.write(" {"); self.push_tab(); @@ -178,7 +178,7 @@ impl<'a, F: Write> SourceWriter<'a, F> { pub fn close_brace(&mut self, semicolon: bool) { self.pop_tab(); match self.bindings.config.language { - Language::Cxx | Language::C => { + Language::Cxx | Language::C | Language::Zig => { self.new_line(); if semicolon { self.write("};"); diff --git a/src/main.rs b/src/main.rs index 0004cf70e..35489c1c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,7 +157,7 @@ fn main() { .long("lang") .value_name("LANGUAGE") .help("Specify the language to output bindings in") - .possible_values(&["c++", "C++", "c", "C", "cython", "Cython"]), + .possible_values(&["c++", "C++", "c", "C", "cython", "Cython", "zig", "Zig"]), ) .arg( Arg::new("cpp-compat") diff --git a/tests/expectations/alias.zig b/tests/expectations/alias.zig new file mode 100644 index 000000000..ec8586f1f --- /dev/null +++ b/tests/expectations/alias.zig @@ -0,0 +1,31 @@ +const std = @import("std"); + +pub const Status = enum(c_int) { + Ok = 0, + Err = -1, +}; + +pub const Dep = extern struct { + a: i32, + b: f32, +}; + +pub const Foo_i32 = extern struct { + a: i32, + b: i32, + c: Dep, +}; + +pub const IntFoo = Foo_i32; + +pub const Foo_f64 = extern struct { + a: f64, + b: f64, + c: Dep, +}; + +pub const DoubleFoo = Foo_f64; +pub const Unit = i32; +pub const SpecialStatus = Status; + +extern fn root(x: IntFoo, y: DoubleFoo, z: Unit, w: SpecialStatus) anyopaque; diff --git a/tests/expectations/annotation.zig b/tests/expectations/annotation.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/annotation.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/array.zig b/tests/expectations/array.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/array.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/asserted_cast.zig b/tests/expectations/asserted_cast.zig new file mode 100644 index 000000000..f3db0c9de --- /dev/null +++ b/tests/expectations/asserted_cast.zig @@ -0,0 +1 @@ +const std = @import("std"); \ No newline at end of file diff --git a/tests/expectations/assoc_const_conflict.zig b/tests/expectations/assoc_const_conflict.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/assoc_const_conflict.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/bitfield.zig b/tests/expectations/bitfield.zig new file mode 100644 index 000000000..773348024 --- /dev/null +++ b/tests/expectations/bitfield.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const HasBitfields = packed struct { + foo: u8, + bar: u56, +}; + +extern fn root(?*const HasBitfields) anyopaque; diff --git a/tests/expectations/bitflags.zig b/tests/expectations/bitflags.zig new file mode 100644 index 000000000..5b5676341 --- /dev/null +++ b/tests/expectations/bitflags.zig @@ -0,0 +1,35 @@ +const std = @import("std"); + +pub const AlignFlags = extern struct { + bits: u8, +}; + +pub const DebugFlags = extern struct { + bits: u32, +}; + +extern fn root(flags: AlignFlags, bigger_flags: DebugFlags) void; + +pub const AlignFlags_AUTO = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 0)), +}); + +pub const AlignFlags_NORMAL = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1)), +}); + +pub const AlignFlags_START = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 1)), +}); + +pub const AlignFlags_END = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 2)), +}); + +pub const AlignFlags_FLEX_START = std.mem.zeroInit(AlignFlags, .{ + .bits = std.zig.c_translation.cast(u8, @as(c_int, 1) << @as(c_int, 3)), +}); + +pub const DebugFlags_BIGGEST_ALLOWED = std.mem.zeroInit(DebugFlags, .{ + .bits = std.zig.c_translation.cast(u32, @as(c_int, 1) << @as(c_int, 31)), +}); diff --git a/tests/expectations/body.zig b/tests/expectations/body.zig new file mode 100644 index 000000000..0dd0a2cc2 --- /dev/null +++ b/tests/expectations/body.zig @@ -0,0 +1,75 @@ +const std = @import("std"); + +pub const MyCLikeEnum = extern union(c_uint) { + Foo1, + Bar1, + Baz1, +}; + +pub const MyCLikeEnum_Prepended = extern union(c_uint) { + Foo1_Prepended, + Bar1_Prepended, + Baz1_Prepended, +}; + +pub const MyFancyStruct = extern struct { + i: i32, +}; + +pub const MyFancyEnum_Tag = extern union(c_uint) { + Foo, + Bar, + Baz, +}; + +const struct_unnamed_2 = extern struct { + bar: i32, +}; +const struct_unnamed_3 = extern struct { + baz: i32, +}; +const union_unnamed_1 = extern union { + unnamed_0: struct_unnamed_2, + unnamed_1: struct_unnamed_3, +}; +pub const MyFancyEnum = extern struct { + tag: MyFancyEnum_Tag, + unnamed_0: union_unnamed_1, +}; +pub const MyUnion = extern union { + f: f32, + u: u32, + extra_member: i32, +}; +pub const MyFancyStruct_Prepended = extern struct { + i: i32, +}; + +pub const MyFancyEnum_Prepended_Tag = extern union(c_uint) { + Foo_Prepended, + Bar_Prepended, + Baz_Prepended, +}; + +const struct_unnamed_5 = extern struct { + bar_prepended: i32, +}; +const struct_unnamed_6 = extern struct { + baz_prepended: i32, +}; +const union_unnamed_4 = extern union { + unnamed_0: struct_unnamed_5, + unnamed_1: struct_unnamed_6, +}; +pub const MyFancyEnum_Prepended = extern struct { + tag: MyFancyEnum_Prepended_Tag, + unnamed_0: union_unnamed_4, +}; + +pub const MyUnion_Prepended = extern union { + extra_member: i32, + f: f32, + u: u32, +}; + +extern fn root(s: MyFancyStruct, e: MyFancyEnum, c: MyCLikeEnum, u: MyUnion, sp: MyFancyStruct_Prepended, ep: MyFancyEnum_Prepended, cp: MyCLikeEnum_Prepended, up: MyUnion_Prepended) anyopaque; diff --git a/tests/expectations/box.zig b/tests/expectations/box.zig new file mode 100644 index 000000000..90f4f06cb --- /dev/null +++ b/tests/expectations/box.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +pub const struct_NotReprC_____i32 = opaque {}; +pub const NotReprC_____i32 = struct_NotReprC_____i32; +pub const Foo = NotReprC_____i32; +pub const MyStruct = extern struct { + number: [*c]i32, +}; +extern fn root(a: ?*const Foo, with_box: [*c]const MyStruct) anyopaque; +extern fn drop_box(x: [*c]i32) anyopaque; +extern fn drop_box_opt(x: [*c]i32) anyopaque; diff --git a/tests/expectations/cdecl.zig b/tests/expectations/cdecl.zig new file mode 100644 index 000000000..14fe62d67 --- /dev/null +++ b/tests/expectations/cdecl.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +pub const A = ?fn () callconv(.C) void; +pub const B = ?fn () callconv(.C) void; +pub const C = ?fn (i32, i32) callconv(.C) bool; +pub const D = ?fn (i32) callconv(.C) ?fn (f32) callconv(.C) bool; +pub const E = ?fn () callconv(.C) [*c]const [16]i32; +pub const F = [*c]const i32; +pub const G = [*c]const [*c]const i32; +pub const H = [*c]const [*c]i32; +pub const I = [*c]const [16]i32; +pub const J = [*c]?fn (f32) callconv(.C) f64; +pub const K = [16]i32; +pub const L = [16][*c]const i32; +pub const M = [16]?fn (i32, i32) callconv(.C) bool; +pub const N = [16]?fn (i32, i32) callconv(.C) void; + +pub const P = ?fn (i32, bool, bool, i32) callconv(.C) void; + +extern fn O() ?fn () callconv(.C) void; + +extern fn root(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: [*c]i32, l: [*c][*c]const i32, m: [*c]?fn (i32, i32) callconv(.C) bool, n: [*c]?fn (i32, i32) callconv(.C) void, p: P) void; diff --git a/tests/expectations/cell.zig b/tests/expectations/cell.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cell.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/cfg.zig b/tests/expectations/cfg.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cfg.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/char.zig b/tests/expectations/char.zig new file mode 100644 index 000000000..cddd27b90 --- /dev/null +++ b/tests/expectations/char.zig @@ -0,0 +1,6 @@ +const std = @import("std"); + +pub const Foo = extern struct { + a: u32, +}; +extern fn root(a: Foo) anyopaque; diff --git a/tests/expectations/constant.zig b/tests/expectations/constant.zig new file mode 100644 index 000000000..a18511539 --- /dev/null +++ b/tests/expectations/constant.zig @@ -0,0 +1,9 @@ +const std = @import("std"); + +pub const FOO: u32 = 10; + +pub const Foo = extern struct { + x: [FOO]i32, +}; + +extern fn root(x: Foo) anyopaque; diff --git a/tests/expectations/constant_big.zig b/tests/expectations/constant_big.zig new file mode 100644 index 000000000..b656ec5d3 --- /dev/null +++ b/tests/expectations/constant_big.zig @@ -0,0 +1,9 @@ +const std = @import("std"); + +const UNSIGNED_NEEDS_ULL_SUFFIX: c_ulonglong = 9223372036854775808; + +const UNSIGNED_DOESNT_NEED_ULL_SUFFIX: c_ulonglong = 8070450532247928832; + +const SIGNED_NEEDS_ULL_SUFFIX: c_longlong = -9223372036854775808; + +const SIGNED_DOESNT_NEED_ULL_SUFFIX : c_longlong = -9223372036854775807; \ No newline at end of file diff --git a/tests/expectations/cython_options.zig b/tests/expectations/cython_options.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/cython_options.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/dep_v2.zig b/tests/expectations/dep_v2.zig new file mode 100644 index 000000000..e458840ff --- /dev/null +++ b/tests/expectations/dep_v2.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const dep_struct = extern struct { + x: u32, + y: f64, +}; + +extern fn get_x(dep_struct: ?*const dep_struct) c_int; diff --git a/tests/expectations/derive_eq.zig b/tests/expectations/derive_eq.zig new file mode 100644 index 000000000..9e398dd92 --- /dev/null +++ b/tests/expectations/derive_eq.zig @@ -0,0 +1,39 @@ +const std = @import("std"); + +pub const Foo = extern struct { + a: bool, + b: i32, +}; + +pub const Bar_Tag = enum { + Baz, + Bazz, + FooNamed, + FooParen, +}; + +pub const Bazz_Body = extern struct { + tag: Bar_Tag, + named: Foo, +}; + +pub const FooNamed_Body = extern struct { + tag: Bar_Tag, + different: i32, + fields: u32, +}; + +pub const FooParen_Body = extern struct { + tag: Bar_Tag, + _0: i32, + _1: Foo, +}; + +pub const Bar = extern union { + tag: Bar_Tag, + bazz: Bazz_Body, + foo_named: FooNamed_Body, + foo_paren: FooParen_Body, +}; + +extern fn root(bar: Bar) Foo; diff --git a/tests/expectations/display_list.zig b/tests/expectations/display_list.zig new file mode 100644 index 000000000..a98128020 --- /dev/null +++ b/tests/expectations/display_list.zig @@ -0,0 +1,38 @@ +const std = @import("std"); + +pub const Rect = extern struct { + x: f32, + y: f32, + w: f32, + h: f32, +}; +pub const Color = extern struct { + r: u8, + g: u8, + b: u8, + a: u8, +}; + +pub const DisplayItem_Tag = enum(c_int) { + Fill, + Image, + ClearScreen, +}; + +pub const Fill_Body = extern struct { + tag: DisplayItem_Tag, + _0: Rect, + _1: Color, +}; +pub const Image_Body = extern struct { + tag: DisplayItem_Tag, + id: u32, + bounds: Rect, +}; +pub const DisplayItem = extern union { + tag: DisplayItem_Tag, + fill: Fill_Body, + image: Image_Body, +}; + +extern fn push_item(item: DisplayItem) bool; diff --git a/tests/expectations/doclength_short.zig b/tests/expectations/doclength_short.zig new file mode 100644 index 000000000..e5f799e73 --- /dev/null +++ b/tests/expectations/doclength_short.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +// The root of all evil. +// +// But at least it contains some more documentation as someone would expect +// from a simple test case like this. Though, this shouldn't appear in the +// output. +extern fn root() anyopaque; + +// A little above the root, and a lot more visible, with a run-on sentence +// to test going over the first line. +// +// Still not here, though. +extern fn trunk() anyopaque; diff --git a/tests/expectations/docstyle.c99.zig b/tests/expectations/docstyle.c99.zig new file mode 100644 index 000000000..ca42cf937 --- /dev/null +++ b/tests/expectations/docstyle.c99.zig @@ -0,0 +1,4 @@ +const std = @import("std"); + +// The root of all evil. +extern fn root() anyopaque; diff --git a/tests/expectations/docstyle_auto.zig b/tests/expectations/docstyle_auto.zig new file mode 100644 index 000000000..ca42cf937 --- /dev/null +++ b/tests/expectations/docstyle_auto.zig @@ -0,0 +1,4 @@ +const std = @import("std"); + +// The root of all evil. +extern fn root() anyopaque; diff --git a/tests/expectations/documentation.zig b/tests/expectations/documentation.zig new file mode 100644 index 000000000..67ef12342 --- /dev/null +++ b/tests/expectations/documentation.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +// The root of all evil. +// +// But at least it contains some more documentation as someone would expect +// from a simple test case like this. +// +// # Hint +// +// Always ensure that everything is properly documented, even if you feel lazy. +// **Sometimes** it is also helpful to include some markdown formatting. +// +// //////////////////////////////////////////////////////////////////////////// +// +// Attention: +// +// Rust is going to trim all leading `/` symbols. If you want to use them as a +// marker you need to add at least a single whitespace inbetween the tripple +// slash doc-comment marker and the rest. +// +extern fn root() anyopaque; diff --git a/tests/expectations/enum.zig b/tests/expectations/enum.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/enum.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/enum_self.zig b/tests/expectations/enum_self.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/enum_self.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/euclid.zig b/tests/expectations/euclid.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/euclid.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/exclude_generic_monomorph.zig b/tests/expectations/exclude_generic_monomorph.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/exclude_generic_monomorph.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/expand.zig b/tests/expectations/expand.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/expand.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/export_name.zig b/tests/expectations/export_name.zig new file mode 100644 index 000000000..fbb98c225 --- /dev/null +++ b/tests/expectations/export_name.zig @@ -0,0 +1,3 @@ +const std = @import("std"); + +extern fn do_the_thing_with_export_name() anyopaque; diff --git a/tests/expectations/extern.zig b/tests/expectations/extern.zig new file mode 100644 index 000000000..07da36837 --- /dev/null +++ b/tests/expectations/extern.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const Normal = extern struct { + x: i32, + y: f32, +}; + +extern fn foo() i32; + +extern fn bar(a: Normal) anyopaque; diff --git a/tests/expectations/extern_2.zig b/tests/expectations/extern_2.zig new file mode 100644 index 000000000..017e415e3 --- /dev/null +++ b/tests/expectations/extern_2.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +extern fn first() anyopaque; + +extern fn second() anyopaque; diff --git a/tests/expectations/external_workspace_child.zig b/tests/expectations/external_workspace_child.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/external_workspace_child.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/fns.tag.zig b/tests/expectations/fns.tag.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/fns.tag.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/fns.zig b/tests/expectations/fns.zig new file mode 100644 index 000000000..c06f8fde9 --- /dev/null +++ b/tests/expectations/fns.zig @@ -0,0 +1,13 @@ +const std = @import("std"); + +pub const Fns = extern struct { + _noArgs: ?fn() anyopaque, + _anonymousArg: ?fn() anyopaque, + _returnsNumber: ?fn() i32, + _namedArgs: ?fn(first: i32, snd: i16) i8, + _namedArgsWildcards: ?fn(_: i32, named: i16, _1: i64) i8, +}; + +extern fn root(_fns: Fns) anyopaque; + +extern fn no_return() anyopaque; diff --git a/tests/expectations/forward_declaration.zig b/tests/expectations/forward_declaration.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/forward_declaration.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/function_args.zig b/tests/expectations/function_args.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/function_args.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/function_noreturn.zig b/tests/expectations/function_noreturn.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/function_noreturn.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/generic_pointer.zig b/tests/expectations/generic_pointer.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/generic_pointer.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/global_attr.zig b/tests/expectations/global_attr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/global_attr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/ignore.zig b/tests/expectations/ignore.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/ignore.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include.zig b/tests/expectations/include.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include_guard.zig b/tests/expectations/include_guard.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include_guard.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/include_item.zig b/tests/expectations/include_item.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/include_item.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/infinite_recursion_typedef_monomorph.zig b/tests/expectations/infinite_recursion_typedef_monomorph.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/infinite_recursion_typedef_monomorph.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/inner_mod.zig b/tests/expectations/inner_mod.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/inner_mod.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/item_types.zig b/tests/expectations/item_types.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/item_types.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout.zig b/tests/expectations/layout.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout_aligned_opaque.zig b/tests/expectations/layout_aligned_opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout_aligned_opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/layout_packed_opaque.zig b/tests/expectations/layout_packed_opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/layout_packed_opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/lifetime_arg.zig b/tests/expectations/lifetime_arg.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/lifetime_arg.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/linestyle_cr.zig b/tests/expectations/linestyle_cr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/linestyle_cr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/linestyle_if.zig b/tests/expectations/linestyle_if.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/linestyle_if.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/literal_target.zig b/tests/expectations/literal_target.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/literal_target.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mangle.zig b/tests/expectations/mangle.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mangle.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/manuallydrop.zig b/tests/expectations/manuallydrop.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/manuallydrop.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/maybeuninit.zig b/tests/expectations/maybeuninit.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/maybeuninit.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mod_2015.zig b/tests/expectations/mod_2015.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mod_2015.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/mod_2018.zig b/tests/expectations/mod_2018.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/mod_2018.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/monomorph_2.zig b/tests/expectations/monomorph_2.zig new file mode 100644 index 000000000..587190cc8 --- /dev/null +++ b/tests/expectations/monomorph_2.zig @@ -0,0 +1,19 @@ +const std = @import("std"); + +const A = opaque {}; + +const B = opaque {}; + +pub const List_A = extern struct { + _members: ?*A, + count: usize, +}; + +pub const List_B = extern struct { + _members: ?*B, + count: usize, +}; + +extern fn foo(a: List_A) anyopaque; + +extern fn bar(b: List_B) anyopaque; diff --git a/tests/expectations/must_use.zig b/tests/expectations/must_use.zig new file mode 100644 index 000000000..1e954ddf5 --- /dev/null +++ b/tests/expectations/must_use.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const MaybeOwnedPtr_i32_Tag = enum { + Owned_i32, + None_i32, +}; + +pub const MaybeOwnedPtr_i32 = extern struct { + tag: MaybeOwnedPtr_i32_Tag, +}; \ No newline at end of file diff --git a/tests/expectations/nested_import.zig b/tests/expectations/nested_import.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/nested_import.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/no_includes.zig b/tests/expectations/no_includes.zig new file mode 100644 index 000000000..69bb11bab --- /dev/null +++ b/tests/expectations/no_includes.zig @@ -0,0 +1 @@ +extern fn root() anyopaque; diff --git a/tests/expectations/nonnull.zig b/tests/expectations/nonnull.zig new file mode 100644 index 000000000..ca190d57c --- /dev/null +++ b/tests/expectations/nonnull.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +const Opaque = opaque {}; + +pub const Foo_u64 = extern struct { + _a: ?*f32, + _b: ?*u64, + _c: ?*Opaque, + __d: ?*u64, + __e: ?*f32, + __f: ?*Opaque, + _g: ?*u64, + _h: ?*i32, + __i: ?*i32, +}; + +extern fn root(_arg: ?*i32, _foo: ?*Foo_u64, __d: ?*Opaque) anyopaque; diff --git a/tests/expectations/nonzero.zig b/tests/expectations/nonzero.zig new file mode 100644 index 000000000..dee33e26f --- /dev/null +++ b/tests/expectations/nonzero.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +const Option_i64 = opaque {}; + +pub const NonZeroTest = extern struct { + a: u8, + b: u16, + c: u32, + d: u64, + e: i8, + f: i16, + g: i32, + h: i64, + i: i64, + j: ?*const Option_i64, +}; + +extern fn root(_test: NonZeroTest, a: u8, b: u16, c: u32, d: u64, e: i8, f: i16, g: i32, h: i64, i: i64, j: ?*const Option_i64) anyopaque; diff --git a/tests/expectations/opaque.zig b/tests/expectations/opaque.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/opaque.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/pin.zig b/tests/expectations/pin.zig new file mode 100644 index 000000000..7e0594944 --- /dev/null +++ b/tests/expectations/pin.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const PinTest = extern struct { + _pinned_box: ?*i32, + _pinned_ref: ?*i32, +}; + +extern fn root(_s: ?*i32, p: PinTest) anyopaque; diff --git a/tests/expectations/pragma_once.zig b/tests/expectations/pragma_once.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/pragma_once.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/prefix.zig b/tests/expectations/prefix.zig new file mode 100644 index 000000000..bc19218c2 --- /dev/null +++ b/tests/expectations/prefix.zig @@ -0,0 +1,23 @@ +const std = @import("std"); + +pub const LEN = 22; + +pub const X = (22 << 22); + +pub const Y = (X + X); + +pub const NamedLenArray = [LEN]i32; + +pub const ValuedLenArray = [22]i32; + +pub const AbsoluteFontWeight_Tag = enum { + Weight, + Normal, + Bold, +}; + +pub const AbsoluteFontWeight = extern union { + tag: AbsoluteFontWeight_Tag, + weight_tag: AbsoluteFontWeight_Tag, + weight: f32, +}; diff --git a/tests/expectations/prefixed_struct_literal_deep.zig b/tests/expectations/prefixed_struct_literal_deep.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/prefixed_struct_literal_deep.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/ptrs_as_arrays.zig b/tests/expectations/ptrs_as_arrays.zig new file mode 100644 index 000000000..af351be15 --- /dev/null +++ b/tests/expectations/ptrs_as_arrays.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +extern fn ptr_as_array(n: u32, arg: [3]u32, _v: ?*u64) anyopaque; + +extern fn ptr_as_array1(n: u32, arg: [3]u32, v: [4]u64) anyopaque; + +extern fn ptr_as_array2(n: u32, arg: [*]u32, v: [*]u64) anyopaque; + +extern fn ptr_as_array_wrong_syntax(_arg: ?*u32, _v: ?*u32, _: ?*u32) anyopaque; + +extern fn ptr_as_array_unnamed(_: ?*u32, _: ?*u32) anyopaque; diff --git a/tests/expectations/raw_ident.zig b/tests/expectations/raw_ident.zig new file mode 100644 index 000000000..334089796 --- /dev/null +++ b/tests/expectations/raw_ident.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +pub const Enum = enum(c_int) { + a, + b, +}; + +pub const Struct = extern struct { + field: Enum, +}; + +pub const STATIC = Enum; + +extern fn (arg: Struct) anyopaque; diff --git a/tests/expectations/raw_lines.zig b/tests/expectations/raw_lines.zig new file mode 100644 index 000000000..643bb5513 --- /dev/null +++ b/tests/expectations/raw_lines.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub const VERSION = 1; + +extern fn root() anyopaque; diff --git a/tests/expectations/rename.zig b/tests/expectations/rename.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/rename.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/rename_crates.zig b/tests/expectations/rename_crates.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/rename_crates.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/renaming_overrides_prefixing.zig b/tests/expectations/renaming_overrides_prefixing.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/renaming_overrides_prefixing.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/reserved.zig b/tests/expectations/reserved.zig new file mode 100644 index 000000000..a85f06f1e --- /dev/null +++ b/tests/expectations/reserved.zig @@ -0,0 +1,34 @@ +const std = @import("std"); + +pub const A = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const B = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const C_Tag = enum { + D, +}; + +pub const D_Body = extern struct { + namespace_: i32, + float_: f32, +}; + +pub const C = extern struct { + tag: C_Tag, +}; + +pub const E_Tag = enum { + Double, + Float, +}; + +pub const E = extern struct { + tag: E_Tag, + float_: f32, +}; \ No newline at end of file diff --git a/tests/expectations/sentinel.zig b/tests/expectations/sentinel.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/sentinel.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/simplify_option_ptr.zig b/tests/expectations/simplify_option_ptr.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/simplify_option_ptr.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/size_types.zig b/tests/expectations/size_types.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/size_types.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/static.zig b/tests/expectations/static.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/static.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/std_lib.zig b/tests/expectations/std_lib.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/std_lib.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/struct.zig b/tests/expectations/struct.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/struct.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/struct_literal.zig b/tests/expectations/struct_literal.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/struct_literal.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/style_crash.zig b/tests/expectations/style_crash.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/style_crash.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/swift_name.zig b/tests/expectations/swift_name.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/swift_name.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/transform_op.zig b/tests/expectations/transform_op.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/transform_op.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/transparent.zig b/tests/expectations/transparent.zig new file mode 100644 index 000000000..252ed751d --- /dev/null +++ b/tests/expectations/transparent.zig @@ -0,0 +1,25 @@ +const std = @import("std"); + +const DummyStruct = opaque {}; + +const EnumWithAssociatedConstantInImpl = opaque {}; + +pub const TransparentComplexWrappingStructTuple = DummyStruct; + +pub const TransparentPrimitiveWrappingStructTuple = u32; + +pub const TransparentComplexWrappingStructure = DummyStruct; + +pub const TransparentPrimitiveWrappingStructure = u32; + +pub const TransparentComplexWrapper_i32 = DummyStruct; + +pub const TransparentPrimitiveWrapper_i32 = u32; + +pub const TransparentPrimitiveWithAssociatedConstants = u32; +pub const TransparentPrimitiveWithAssociatedConstants_ZERO = 0; +pub const TransparentPrimitiveWithAssociatedConstants_ONE = 1; + +pub const EnumWithAssociatedConstantInImpl_TEN = 10; + +extern fn root(a: TransparentComplexWrappingStructTuple, b: TransparentPrimitiveWrappingStructTuple, c: TransparentComplexWrappingStructure, d: TransparentPrimitiveWrappingStructure, e: TransparentComplexWrapper_i32, f: TransparentPrimitiveWrapper_i32, g: TransparentPrimitiveWithAssociatedConstants, h: EnumWithAssociatedConstantInImpl) anyopaque; diff --git a/tests/expectations/typedef.zig b/tests/expectations/typedef.zig new file mode 100644 index 000000000..69ab58042 --- /dev/null +++ b/tests/expectations/typedef.zig @@ -0,0 +1,10 @@ +const std = @import("std"); + +pub const Foo_i32__i32 = extern struct { + x: i32, + y: i32, +}; + +pub const IntFoo_i32 = Foo_i32__i32; + +extern fn root(a: IntFoo_i32) anyopaque; diff --git a/tests/expectations/union.zig b/tests/expectations/union.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/union.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/va_list.zig b/tests/expectations/va_list.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/va_list.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/workspace.zig b/tests/expectations/workspace.zig new file mode 100644 index 000000000..95a0b682a --- /dev/null +++ b/tests/expectations/workspace.zig @@ -0,0 +1 @@ +const std = @import("std"); diff --git a/tests/expectations/zst.zig b/tests/expectations/zst.zig new file mode 100644 index 000000000..191e35d9c --- /dev/null +++ b/tests/expectations/zst.zig @@ -0,0 +1,8 @@ +const std = @import("std"); + +pub const TraitObject = extern struct { + data: ?*anyopaque, + vtable: ?*anyopaque, +}; + +extern fn root(ptr: ?*const anyopaque, t: TraitObject) ?*anyopaque; diff --git a/tests/tests.rs b/tests/tests.rs index 3b44eac3c..f79bc55f6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -36,6 +36,9 @@ fn run_cbindgen( Language::Cython => { command.arg("--lang").arg("cython"); } + Language::Zig => { + command.arg("--lang").arg("zig"); + } } if let Some(style) = style { @@ -72,6 +75,7 @@ fn compile( Language::Cxx => env::var("CXX").unwrap_or_else(|_| "g++".to_owned()), Language::C => env::var("CC").unwrap_or_else(|_| "gcc".to_owned()), Language::Cython => env::var("CYTHON").unwrap_or_else(|_| "cython".to_owned()), + Language::Zig => env::var("ZIG").unwrap_or_else(|_| "zig".to_owned()), }; let file_name = cbindgen_output @@ -129,6 +133,13 @@ fn compile( command.arg("-o").arg(&object); command.arg(cbindgen_output); } + Language::Zig => { + command.arg("build-obj"); + command.arg("-O").arg("ReleaseSafe"); + command.arg("-fsingle-threaded"); + command.arg("-name").arg(&object); + command.arg("-femit-bin").arg(cbindgen_output); + } } println!("Running: {:?}", command); @@ -173,6 +184,7 @@ fn run_compile_test( // is extension-sensitive and won't work on them, so we use implementation files (`.pyx`) // in the test suite. Language::Cython => ".pyx", + Language::Zig => ".zig", }; let skip_warning_as_error = name.rfind(SKIP_WARNING_AS_ERROR_SUFFIX).is_some(); From 1d04557a5c9b3fc75f10e98357b97943b2e7ffcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Catarino=20Fran=C3=A7a?= Date: Sat, 14 May 2022 15:32:42 -0300 Subject: [PATCH 02/13] More tests --- tests/expectations/opaque.zig | 13 +++ tests/expectations/pin.zig | 2 +- tests/expectations/pragma_once.zig | 2 + .../prefixed_struct_literal_deep.zig | 19 ++++ tests/expectations/rename_crate.zig | 20 ++++ tests/expectations/rename_crates.zig | 1 - .../renaming_overrides_prefixing.zig | 11 +++ tests/expectations/sentinel.zig | 36 ++++++++ tests/expectations/simplify_option_ptr.zig | 19 ++++ tests/expectations/size_types.zig | 14 +++ tests/expectations/static.zig | 12 +++ tests/expectations/std_lib.zig | 8 ++ tests/expectations/struct.zig | 30 ++++++ tests/expectations/struct_literal.zig | 25 ++++- tests/expectations/struct_self.zig | 12 +++ tests/expectations/swift_name.zig | 48 ++++++++++ tests/expectations/transform_op.zig | 92 +++++++++++++++++++ tests/expectations/union.zig | 14 +++ tests/expectations/union_self.zig | 12 +++ tests/expectations/using_namespaces.zig | 3 + tests/expectations/va_list.zig | 2 + tests/expectations/workspace.zig | 6 ++ 22 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 tests/expectations/rename_crate.zig delete mode 100644 tests/expectations/rename_crates.zig create mode 100644 tests/expectations/struct_self.zig create mode 100644 tests/expectations/union_self.zig create mode 100644 tests/expectations/using_namespaces.zig diff --git a/tests/expectations/opaque.zig b/tests/expectations/opaque.zig index 95a0b682a..7aa8c07f3 100644 --- a/tests/expectations/opaque.zig +++ b/tests/expectations/opaque.zig @@ -1 +1,14 @@ const std = @import("std"); + +const HashMap_i32__i32__BuildHasherDefault_DefaultHasher = opaque {}; + +const Result_Foo = opaque {}; + +/// Fast hash map used internally. +pub const FastHashMap_i32__i32 = HashMap_i32__i32__BuildHasherDefault_DefaultHasher; + +pub const Foo = FastHashMap_i32__i32; + +pub const Bar = Result_Foo; + +pub extern fn root(a: ?*Foo, b: ?*Bar) anyopaque; diff --git a/tests/expectations/pin.zig b/tests/expectations/pin.zig index 7e0594944..161d81bfa 100644 --- a/tests/expectations/pin.zig +++ b/tests/expectations/pin.zig @@ -5,4 +5,4 @@ pub const PinTest = extern struct { _pinned_ref: ?*i32, }; -extern fn root(_s: ?*i32, p: PinTest) anyopaque; +pub extern fn root(_s: ?*i32, p: PinTest) anyopaque; diff --git a/tests/expectations/pragma_once.zig b/tests/expectations/pragma_once.zig index 95a0b682a..d4c2e15c7 100644 --- a/tests/expectations/pragma_once.zig +++ b/tests/expectations/pragma_once.zig @@ -1 +1,3 @@ const std = @import("std"); + +pub extern fn root() anyopaque; diff --git a/tests/expectations/prefixed_struct_literal_deep.zig b/tests/expectations/prefixed_struct_literal_deep.zig index 95a0b682a..8bdf63994 100644 --- a/tests/expectations/prefixed_struct_literal_deep.zig +++ b/tests/expectations/prefixed_struct_literal_deep.zig @@ -1 +1,20 @@ const std = @import("std"); + +pub const PREFIXBar = extern struct { + a: i32, +}; +pub const PREFIXFoo = extern struct { + a: i32, + b: u32, + bar: PREFIXBar, +}; + +pub extern fn root(x: PREFIXFoo) anyopaque; + +pub const PREFIXVAL = @import("std").mem.zeroInit(PREFIXFoo, .{ + .a = @as(c_int, 42), + .b = @as(c_int, 1337), + .bar = @import("std").mem.zeroInit(PREFIXBar, .{ + .a = @as(c_int, 323), + }), +}); diff --git a/tests/expectations/rename_crate.zig b/tests/expectations/rename_crate.zig new file mode 100644 index 000000000..ba040f389 --- /dev/null +++ b/tests/expectations/rename_crate.zig @@ -0,0 +1,20 @@ +const std = @import("std"); + +pub const Foo = extern struct { + x: i32, +}; +pub const RenamedTy = extern struct { + y: u64, +}; +pub const NoExternTy = extern struct { + field: u8, +}; +pub const ContainsNoExternTy = extern struct { + field: NoExternTy, +}; + +pub extern fn root(a: Foo) anyopaque; + +pub extern fn renamed_func(a: RenamedTy) anyopaque; + +pub extern fn no_extern_func(a: ContainsNoExternTy) anyopaque; diff --git a/tests/expectations/rename_crates.zig b/tests/expectations/rename_crates.zig deleted file mode 100644 index 95a0b682a..000000000 --- a/tests/expectations/rename_crates.zig +++ /dev/null @@ -1 +0,0 @@ -const std = @import("std"); diff --git a/tests/expectations/renaming_overrides_prefixing.zig b/tests/expectations/renaming_overrides_prefixing.zig index 95a0b682a..72dace5fc 100644 --- a/tests/expectations/renaming_overrides_prefixing.zig +++ b/tests/expectations/renaming_overrides_prefixing.zig @@ -1 +1,12 @@ const std = @import("std"); + +const A = opaque { + +}; + +pub const B = extern struct { + x: i32, + y: f32, +}; + +pub extern fn root( a: ?*A, b: B) anyopaque; diff --git a/tests/expectations/sentinel.zig b/tests/expectations/sentinel.zig index 95a0b682a..409ea7932 100644 --- a/tests/expectations/sentinel.zig +++ b/tests/expectations/sentinel.zig @@ -1 +1,37 @@ const std = @import("std"); + +pub const A = enum { + A1, + A2, + A3, +}; + +pub const B = enum { + B1, + B2, + B3, +}; + +pub const C_Tag = enum { + C1, + C2, + C3, +}; + +pub const C1_Body = extern struct { + tag: C_Tag, + a: u32, +}; + +pub const C2_Body = extern struct { + tag: C_Tag, + b: u32, +}; + +pub const C = extern union { + tag: C_Tag, + c1: C1_Body, + c2: C2_Body, +}; + +pub extern fn root(a: A, b: B, c: C) anyopaque; diff --git a/tests/expectations/simplify_option_ptr.zig b/tests/expectations/simplify_option_ptr.zig index 95a0b682a..1f9e5c82b 100644 --- a/tests/expectations/simplify_option_ptr.zig +++ b/tests/expectations/simplify_option_ptr.zig @@ -1 +1,20 @@ const std = @import("std"); + +pub const Opaque = opaque {}; +pub const Option_____Opaque = opaque {}; + +pub const Foo = extern struct { + x: ?*const Opaque, + y: ?*Opaque, + z: ?*const fn () anyopaque, + zz: [*]?*const fn () anyopaque, +}; + +pub const Bar = extern union { + x: ?*const Opaque, + y: ?*Opaque, + z: ?*const fn () anyopaque, + zz: [*]?*const fn () anyopaque, +}; + +pub extern fn root(a: ?*const Opaque, b: ?*Opaque, c: Foo, d: Bar, e: ?*Option_____Opaque, f: ?*const fn (?*const Opaque) anyopaque) anyopaque; diff --git a/tests/expectations/size_types.zig b/tests/expectations/size_types.zig index 95a0b682a..e0cd28725 100644 --- a/tests/expectations/size_types.zig +++ b/tests/expectations/size_types.zig @@ -1 +1,15 @@ const std = @import("std"); + +pub const IE = enum { + IV, +}; + +pub const UE = enum { + UV, +}; + +pub const Usize = usize; + +pub const Isize = isize; + +pub extern fn root(Usize, Isize, UE, IE) anyopaque; diff --git a/tests/expectations/static.zig b/tests/expectations/static.zig index 95a0b682a..1b2ebcccb 100644 --- a/tests/expectations/static.zig +++ b/tests/expectations/static.zig @@ -1 +1,13 @@ const std = @import("std"); + +const Bar = opaque {}; + +pub const Foo = extern struct {}; + +pub extern const NUMBER: i32; + +pub extern const FOO: Foo; + +pub extern const BAR: Bar; + +pub extern fn root() anyopaque; diff --git a/tests/expectations/std_lib.zig b/tests/expectations/std_lib.zig index 95a0b682a..5af07d1ff 100644 --- a/tests/expectations/std_lib.zig +++ b/tests/expectations/std_lib.zig @@ -1 +1,9 @@ const std = @import("std"); + +const Option_i32 = opaque {}; + +const Result_i32__String = opaque {}; + +const Vec_String = opaque {}; + +pub extern fn root(a: ?*Vec_String, b: ?*Option_i32, c: ?*Result_i32__String) anyopaque; diff --git a/tests/expectations/struct.zig b/tests/expectations/struct.zig index 95a0b682a..b14ced846 100644 --- a/tests/expectations/struct.zig +++ b/tests/expectations/struct.zig @@ -1 +1,31 @@ const std = @import("std"); + +const Opaque = opaque { + +}; + +pub const Normal = extern struct { + x: i32, + y: f32, +}; + +pub const NormalWithZST = extern struct { + x: i32, + y: f32, +}; + +pub const TupleRenamed = extern struct { + m0: i32, + m1: f32, +}; + +pub const TupleNamed = extern struct { + x: i32, + y: f32, +}; + +pub extern fn root( a: ?*Opaque, + b: Normal, + c: NormalWithZST, + d: TupleRenamed, + e: TupleNamed) anyopaque; diff --git a/tests/expectations/struct_literal.zig b/tests/expectations/struct_literal.zig index 95a0b682a..2cb5b0308 100644 --- a/tests/expectations/struct_literal.zig +++ b/tests/expectations/struct_literal.zig @@ -1 +1,24 @@ -const std = @import("std"); +pub const Bar = opaque {}; +pub const Foo = extern struct { + a: i32, + b: u32, +}; + +pub const Foo_FOO = @import("std").mem.zeroInit(Foo, .{ + .a = @as(c_int, 42), + .b = @as(c_int, 47), +}); +pub const Foo_FOO2 = @import("std").mem.zeroInit(Foo, .{ + .a = @as(c_int, 42), + .b = @as(c_int, 47), +}); +pub const Foo_FOO3 = @import("std").mem.zeroInit(Foo, .{ + .a = @as(c_int, 42), + .b = @as(c_int, 47), +}); +pub const BAR = @import("std").mem.zeroInit(Foo, .{ + .a = @as(c_int, 42), + .b = @as(c_int, 1337), +}); + +pub extern fn root(x: Foo, bar: Bar) void; diff --git a/tests/expectations/struct_self.zig b/tests/expectations/struct_self.zig new file mode 100644 index 000000000..e9e179f30 --- /dev/null +++ b/tests/expectations/struct_self.zig @@ -0,0 +1,12 @@ +const std = @import("std"); + +pub const Foo_Bar = extern struct { + something: ?*i32, +}; + +pub const Bar = extern struct { + something: i32, + subexpressions: Foo_Bar, +}; + +pub extern fn root(b: Bar) anyopaque; diff --git a/tests/expectations/swift_name.zig b/tests/expectations/swift_name.zig index 95a0b682a..24351d4f6 100644 --- a/tests/expectations/swift_name.zig +++ b/tests/expectations/swift_name.zig @@ -1 +1,49 @@ const std = @import("std"); + +pub const Opaque = opaque {}; + +pub const SelfTypeTestStruct = extern struct { + times: u8, +}; + +pub const PointerToOpaque = extern struct { + ptr: ?*Opaque, +}; + +pub extern fn rust_print_hello_world() anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_ref(self: [*]const SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_ref_mut(self: [*]SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_not_exist_box(self: [*]SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_not_exist_return_box() [*]SelfTypeTestStruct; + +pub extern fn SelfTypeTestStruct_should_exist_annotated_self(self: SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_annotated_mut_self(self: SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_annotated_by_name(self: SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_annotated_mut_by_name(self: SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_unannotated(self: SelfTypeTestStruct) anyopaque; + +pub extern fn SelfTypeTestStruct_should_exist_mut_unannotated(self: SelfTypeTestStruct) anyopaque; + +pub extern fn free_function_should_exist_ref(test_struct: [*]const SelfTypeTestStruct) anyopaque; + +pub extern fn free_function_should_exist_ref_mut(test_struct: [*]SelfTypeTestStruct) anyopaque; + +pub extern fn unnamed_argument([*]SelfTypeTestStruct) anyopaque; + +pub extern fn free_function_should_not_exist_box(boxed: [*]SelfTypeTestStruct) anyopaque; + +pub extern fn free_function_should_exist_annotated_by_name(test_struct: SelfTypeTestStruct) anyopaque; + +pub extern fn free_function_should_exist_annotated_mut_by_name(test_struct: SelfTypeTestStruct) anyopaque; + +pub extern fn PointerToOpaque_create(times: u8) PointerToOpaque; + +pub extern fn PointerToOpaque_sayHello(self: PointerToOpaque) anyopaque; diff --git a/tests/expectations/transform_op.zig b/tests/expectations/transform_op.zig index 95a0b682a..c99bd318a 100644 --- a/tests/expectations/transform_op.zig +++ b/tests/expectations/transform_op.zig @@ -1 +1,93 @@ const std = @import("std"); + +pub const Point_i32 = extern struct { + x: i32, + y: i32, +}; + +pub const Point_f32 = extern struct { + x: f32, + y: f32, +}; + +pub const Foo_i32_Tag = enum { + Foo_i32, + Bar_i32, + Baz_i32, + Bazz_i32, +}; + +pub const Foo_Body_i32 = extern struct { + tag: Foo_i32_Tag, + x: i32, + y: Point_i32, + z: Point_f32, +}; + +pub const Foo_i32 = extern union { + tag: Foo_i32_Tag, + foo: Foo_Body_i32, +}; + +pub const Bar_i32_Tag = enum { + Bar1_i32, + Bar2_i32, + Bar3_i32, + Bar4_i32, +}; + +pub const Bar1_Body_i32 = extern struct { + x: i32, + y: Point_i32, + z: Point_f32, + u: ?fn () i32, +}; + +pub const Bar_i32 = extern struct { + tag: Bar_i32_Tag, +}; + +pub const Point_u32 = extern struct { + x: u32, + y: u32, +}; + +pub const Bar_u32_Tag = enum { + Bar1_u32, + Bar2_u32, + Bar3_u32, + Bar4_u32, +}; + +pub const Bar1_Body_u32 = extern struct { + x: i32, + y: Point_u32, + z: Point_f32, + u: ?fn () i32, +}; + +pub const Bar_u32 = extern struct { + tag: Bar_u32_Tag, +}; + +pub const Baz_Tag = enum { + Baz1, + Baz2, + Baz3, +}; + +pub const Baz = extern union { + tag: Baz_Tag, +}; + +pub const Taz_Tag = enum { + Taz1, + Taz2, + Taz3, +}; + +pub const Taz = extern struct { + tag: Taz_Tag, +}; + +pub extern fn foo(foo: ?*Foo_i32, bar: ?*Bar_i32, baz: ?*Baz, taz: ?*Taz) anyopaque; diff --git a/tests/expectations/union.zig b/tests/expectations/union.zig index 95a0b682a..4f251c11e 100644 --- a/tests/expectations/union.zig +++ b/tests/expectations/union.zig @@ -1 +1,15 @@ const std = @import("std"); + +const Opaque = opaque {}; + +pub const Normal = extern union { + x: i32, + y: f32, +}; + +pub const NormalWithZST = extern union { + x: i32, + y: f32, +}; + +pub extern fn root(a: ?*Opaque, b: Normal, c: NormalWithZST) anyopaque; diff --git a/tests/expectations/union_self.zig b/tests/expectations/union_self.zig new file mode 100644 index 000000000..8b85870b7 --- /dev/null +++ b/tests/expectations/union_self.zig @@ -0,0 +1,12 @@ +const std = @import("std"); + +pub const Foo_Bar = extern struct { + something: ?*i32, +}; + +pub const Bar = extern union { + something: i32, + subexpressions: Foo_Bar, +}; + +pub extern fn root(b: Bar) anyopaque; diff --git a/tests/expectations/using_namespaces.zig b/tests/expectations/using_namespaces.zig new file mode 100644 index 000000000..d4c2e15c7 --- /dev/null +++ b/tests/expectations/using_namespaces.zig @@ -0,0 +1,3 @@ +const std = @import("std"); + +pub extern fn root() anyopaque; diff --git a/tests/expectations/va_list.zig b/tests/expectations/va_list.zig index 95a0b682a..9e7a71bf8 100644 --- a/tests/expectations/va_list.zig +++ b/tests/expectations/va_list.zig @@ -1 +1,3 @@ const std = @import("std"); + +pub extern fn va_list_test(ap: ...) i32; diff --git a/tests/expectations/workspace.zig b/tests/expectations/workspace.zig index 95a0b682a..72f50096d 100644 --- a/tests/expectations/workspace.zig +++ b/tests/expectations/workspace.zig @@ -1 +1,7 @@ const std = @import("std"); + +pub const ExtType = extern struct { + data: u32, +}; + +pub extern fn consume_ext(_ext: ExtType) anyopaque; From 6fee4b37c472a84eba6d2553d2debe2a4300ca05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Catarino=20Fran=C3=A7a?= Date: Sun, 26 Jun 2022 13:36:29 -0300 Subject: [PATCH 03/13] Fixes - remove anonymous struct; - fix union namespace; - remove comptime global variables --- src/bindgen/ir/constant.rs | 6 ------ src/bindgen/ir/enumeration.rs | 22 +++++++++++++++++----- src/bindgen/ir/structure.rs | 17 +++++++++++++---- src/bindgen/ir/union.rs | 19 ++++++++++++++++--- tests/expectations/enum_self.zig | 20 ++++++++++++++++++++ 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index e8a5ffc10..79d328c4d 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -775,7 +775,6 @@ impl Constant { self.documentation.write(config, out); let allow_constexpr = config.constant.allow_constexpr && self.value.can_be_constexpr(); - let allow_comptime = config.constant.allow_comptime; match config.language { Language::Cxx if config.constant.allow_static_const || allow_constexpr => { if allow_constexpr { @@ -809,11 +808,6 @@ impl Constant { write!(out, " {} # = ", name); value.write(config, out); } - Language::Zig if allow_comptime => { - if allow_comptime { - out.write("comptime "); - } - } Language::Zig => { out.write(config.style.zig_def()); self.ty.write(config, out); diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 1db4fdc18..31f078799 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -863,7 +863,12 @@ impl Enum { Language::C | Language::Cxx => {} Language::Cython => out.write(config.style.cython_def()), Language::Zig => { - write!(out, "{}{} = extern ", config.style.zig_def(), self.export_name()); + write!( + out, + "{}{} = extern ", + config.style.zig_def(), + self.export_name() + ); } } @@ -939,7 +944,7 @@ impl Enum { if config.language != Language::Zig { write!(out, "{} tag;", tag_name); - }else { + } else { write!(out, "tag: {},", tag_name); } @@ -978,14 +983,21 @@ impl Enum { // support unnamed structs. // For the same reason with Cython we can omit per-variant tags (the first // field) to avoid extra noise, the main `tag` is enough in this case. - if config.language != Language::Cython { + if config.language != Language::Cython && config.language != Language::Zig { out.write("struct"); out.open_brace(); } let start_field = usize::from(inline_tag_field && config.language == Language::Cython); - out.write_vertical_source_list(&body.fields[start_field..], ListType::Cap(";")); - if config.language != Language::Cython { + out.write_vertical_source_list( + &body.fields[start_field..], + ListType::Cap(if config.language != Language::Zig { + ";" + } else { + "," + }), + ); + if config.language != Language::Cython && config.language != Language::Zig { out.close_brace(true); } } else if config.language == Language::Zig { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 07d33212c..9f10cfccd 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -439,7 +439,7 @@ impl Source for Struct { write!(out, "{} = extern struct", self.export_name()); } else { out.write("struct"); - } + } if config.language != Language::Cython { if let Some(align) = self.alignment { @@ -464,8 +464,10 @@ impl Source for Struct { } } - if config.language != Language::Zig && config.language != Language::C { - write!(out, " {}", self.export_name()); + if config.language != Language::C || config.style.generate_tag() { + if config.language != Language::Zig { + write!(out, " {}", self.export_name); + } } out.open_brace(); @@ -476,7 +478,14 @@ impl Source for Struct { out.new_line(); } - out.write_vertical_source_list(&self.fields, ListType::Cap(if config.language != Language::Zig {";"}else{","})); + out.write_vertical_source_list( + &self.fields, + ListType::Cap(if config.language != Language::Zig { + ";" + } else { + "," + }), + ); if config.language == Language::Cython && self.fields.is_empty() { out.write("pass"); } diff --git a/src/bindgen/ir/union.rs b/src/bindgen/ir/union.rs index e1888093f..8736e83fa 100644 --- a/src/bindgen/ir/union.rs +++ b/src/bindgen/ir/union.rs @@ -282,7 +282,11 @@ impl Source for Union { Language::Zig => out.write(config.style.zig_def()), } - out.write("union"); + if config.language == Language::Zig { + write!(out, "{} = extern union", self.export_name()); + } else { + out.write("union"); + } // Cython supports `packed` on structs (see comments there), but not on unions. if config.language != Language::Cython { @@ -303,7 +307,9 @@ impl Source for Union { } if config.language != Language::C || config.style.generate_tag() { - write!(out, " {}", self.export_name); + if config.language != Language::Zig { + write!(out, " {}", self.export_name); + } } out.open_brace(); @@ -314,7 +320,14 @@ impl Source for Union { out.new_line(); } - out.write_vertical_source_list(&self.fields, ListType::Cap(";")); + out.write_vertical_source_list( + &self.fields, + ListType::Cap(if config.language != Language::Zig { + ";" + } else { + "," + }), + ); if config.language == Language::Cython && self.fields.is_empty() { out.write("pass"); } diff --git a/tests/expectations/enum_self.zig b/tests/expectations/enum_self.zig index 95a0b682a..5d441e60e 100644 --- a/tests/expectations/enum_self.zig +++ b/tests/expectations/enum_self.zig @@ -1 +1,21 @@ const std = @import("std"); + +pub const Foo_Bar = extern struct { + something: ?*i32, +}; + +pub const Bar_Tag = enum { + Min, + Max, + Other, +}; + +pub const Bar = extern union { + tag: Bar_Tag, + min_tag: Bar_Tag, + min: Foo_Bar, + max_tag: Bar_Tag, + max: Foo_Bar, +}; + +pub extern fn root(b: Bar) anyopaque; From df94e7ef6ee635278a5860107ecf7c60f6c00962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Catarino=20Fran=C3=A7a?= Date: Sun, 26 Jun 2022 15:27:29 -0300 Subject: [PATCH 04/13] literal struct & constants condition fixed --- src/bindgen/ir/constant.rs | 8 ++++++-- src/bindgen/ir/field.rs | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 79d328c4d..4022a09e2 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -548,7 +548,7 @@ impl Literal { Language::C => write!(out, "({})", export_name), Language::Cxx => write!(out, "{}", export_name), Language::Cython => write!(out, "<{}>", export_name), - Language::Zig => write!(out, ":{} = ", export_name), + Language::Zig => write!(out, ":{} = .", export_name), } write!(out, "{{ "); @@ -811,7 +811,11 @@ impl Constant { Language::Zig => { out.write(config.style.zig_def()); self.ty.write(config, out); - write!(out, "{} = ", name); + if let Literal::Struct { .. } = &self.value { + write!(out, "{} ", name); + } else { + write!(out, "{} = ", name); + } value.write(config, out); write!(out, ";"); } diff --git a/src/bindgen/ir/field.rs b/src/bindgen/ir/field.rs index d7a8826f0..3af9a3348 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -71,13 +71,13 @@ impl Source for Field { cdecl::write_field(out, &self.ty, &self.name, config); // Cython extern declarations don't manage layouts, layouts are defined entierly by the // corresponding C code. So we can omit bitfield sizes which are not supported by Cython. - if config.language != Language::Cython || config.language != Language::Zig { + if config.language != Language::Cython && config.language != Language::Zig { if let Some(bitfield) = self.annotations.atom("bitfield") { write!(out, ": {}", bitfield.unwrap_or_default()); } } - if config.language != Language::Cython || config.language != Language::Zig { + if config.language != Language::Cython && config.language != Language::Zig { condition.write_after(config, out); // FIXME(#634): `write_vertical_source_list` should support // configuring list elements natively. For now we print a newline From 4de7c6975bd08f77a56c05fc37edb994a6569475 Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Wed, 7 Sep 2022 12:41:54 -0300 Subject: [PATCH 05/13] Someones fixes: - Opaque return type 'anyopaque' not allowed replaced to `callconv(.C) void` --- src/bindgen/cdecl.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index fd745c724..6083c49dc 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -306,21 +306,13 @@ impl CDecl { last_was_pointer = true; if config.language == Language::Zig { - if self.type_name.contains("u8") - || self.type_name.contains("const u8") - || self.type_name.contains("CStr") - || self.type_name.contains("c_char") - { + if self.type_name.contains("u8") || self.type_name.contains("const u8") { write!(out, ": ?[*:0]{}", self.type_name); } else if is_functors { out.write(": ?fn"); } else { write!(out, ": ?*{}", self.type_name); } - - if self.type_name.contains("c_void") && !last_was_pointer { - out.write(": callconv(.C) void"); - } } } CDeclarator::Array(ref constant) => { @@ -351,7 +343,7 @@ impl CDecl { if last_was_pointer && config.language != Language::Zig { out.write(")"); } - is_functors = true; + is_functors = false; out.write("("); if args.is_empty() && config.language == Language::C { @@ -393,7 +385,11 @@ impl CDecl { } if config.language == Language::Zig { - write!(out, " {}", self.type_name); + if !last_was_pointer && self.type_name.contains("anyopaque") { + out.write(" callconv(.C) void") + } else { + write!(out, " {}", self.type_name); + } } last_was_pointer = true; From 00bb882c3e8e4a06d3fd9e9f8d00f03fac76536d Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Tue, 22 Nov 2022 16:22:20 -0300 Subject: [PATCH 06/13] small fixes: - extern functions - cstring to const cstring (z-stage2/3) --- src/bindgen/cdecl.rs | 2 +- src/bindgen/ir/function.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 6083c49dc..c962291ad 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -307,7 +307,7 @@ impl CDecl { if config.language == Language::Zig { if self.type_name.contains("u8") || self.type_name.contains("const u8") { - write!(out, ": ?[*:0]{}", self.type_name); + write!(out, ": ?[*:0]const {}", self.type_name); } else if is_functors { out.write(": ?fn"); } else { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 6f22e55b5..d08d4e00e 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -231,9 +231,8 @@ impl Source for Function { func.documentation.write(config, out); if func.extern_decl { - out.write("pub extern "); if config.language == Language::Zig { - out.write("fn"); + out.write("extern fn"); } } else { if config.language == Language::Zig { From d18704e69c90aa7e918aa7d94a72039680fd3c4a Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Tue, 22 Nov 2022 17:22:26 -0300 Subject: [PATCH 07/13] More changes: - new test - refactor zig build-tests flags --- .github/workflows/cbindgen.yml | 2 +- tests/expectations/function_ptr.zig | 11 +++++++++++ tests/tests.rs | 6 +++--- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 tests/expectations/function_ptr.zig diff --git a/.github/workflows/cbindgen.yml b/.github/workflows/cbindgen.yml index bf2791329..9bee086ce 100644 --- a/.github/workflows/cbindgen.yml +++ b/.github/workflows/cbindgen.yml @@ -72,7 +72,7 @@ jobs: pip install Cython==0.29.* - name: Install Zig - uses: goto-bus-stop/setup-zig@v1 + uses: goto-bus-stop/setup-zig@v2 with: version: master diff --git a/tests/expectations/function_ptr.zig b/tests/expectations/function_ptr.zig new file mode 100644 index 000000000..b2d3a733b --- /dev/null +++ b/tests/expectations/function_ptr.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +pub const MyCallback = : ?fn(a: usize, b: usize) anyopaque; + +pub const MyOtherCallback = : ?fn(a: usize, + lot: usize, + of: usize, + args: usize, + and_then_some: usize) anyopaque; + +pub extern fn my_function(a: MyCallback, b: MyOtherCallback) callconv(.C) void; diff --git a/tests/tests.rs b/tests/tests.rs index f79bc55f6..8bc185178 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -135,10 +135,10 @@ fn compile( } Language::Zig => { command.arg("build-obj"); - command.arg("-O").arg("ReleaseSafe"); + command.arg("-O").arg("ReleaseSmall"); command.arg("-fsingle-threaded"); - command.arg("-name").arg(&object); - command.arg("-femit-bin").arg(cbindgen_output); + command.arg("--name").arg(&object); + command.arg("-femit-bin=").arg(cbindgen_output); } } From 344751de201f0c5337509a6d4fb6c11e379c53b4 Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 10:21:44 -0300 Subject: [PATCH 08/13] zig: updated --- src/bindgen/bindings.rs | 4 +- src/bindgen/config.rs | 2 + src/bindgen/ir/constant.rs | 9 +- src/bindgen/language_backend/clike.rs | 1 + src/bindgen/language_backend/mod.rs | 2 + src/bindgen/language_backend/zig.rs | 556 ++++++++++++++++++++++++++ 6 files changed, 564 insertions(+), 10 deletions(-) create mode 100644 src/bindgen/language_backend/zig.rs diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index faae054bf..57650d50d 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -16,7 +16,7 @@ use crate::bindgen::ir::{ Constant, Function, ItemContainer, ItemMap, Path as BindgenPath, Static, Struct, Type, Typedef, }; use crate::bindgen::language_backend::{ - CLikeLanguageBackend, CythonLanguageBackend, LanguageBackend, + CLikeLanguageBackend, CythonLanguageBackend, ZigLanguageBackend, LanguageBackend, }; use crate::bindgen::writer::SourceWriter; @@ -211,7 +211,7 @@ impl Bindings { self.write_with_backend(file, &mut CythonLanguageBackend::new(&self.config)) } Language::Zig => { - // self.write_with_backend(file, &mut ZigLanguageBackend::new(&self.config)) + self.write_with_backend(file, &mut ZigLanguageBackend::new(&self.config)) } } } diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index a08b31ee1..42fb4eb02 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -171,6 +171,7 @@ pub enum DocumentationStyle { Doxy, Cxx, Auto, + Zig, } impl FromStr for DocumentationStyle { @@ -184,6 +185,7 @@ impl FromStr for DocumentationStyle { "c++" => Ok(DocumentationStyle::Cxx), "doxy" => Ok(DocumentationStyle::Doxy), "auto" => Ok(DocumentationStyle::Auto), + "zig" => Ok(DocumentationStyle::Zig), _ => Err(format!("Unrecognized documentation style: '{}'.", s)), } } diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index b48d8342e..f363dd541 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -710,14 +710,7 @@ impl Constant { } Language::Zig => { out.write(config.style.zig_def()); - self.ty.write(config, out); - if let Literal::Struct { .. } = &self.value { - write!(out, "{} ", name); - } else { - write!(out, "{} = ", name); - } - value.write(config, out); - write!(out, ";"); + language_backend.write_literal(out, value); } } diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index 1e3b76196..8876478e8 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -828,6 +828,7 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { DocumentationStyle::Doxy => out.write(" *"), DocumentationStyle::C99 => out.write("//"), DocumentationStyle::Cxx => out.write("///"), + DocumentationStyle::Zig => out.write("///"), DocumentationStyle::Auto => unreachable!(), // Auto case should always be covered } diff --git a/src/bindgen/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index adb7d8507..688902e33 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -10,9 +10,11 @@ use std::io::Write; mod clike; mod cython; +mod zig; pub use clike::CLikeLanguageBackend; pub use cython::CythonLanguageBackend; +pub use zig::ZigLanguageBackend; pub trait LanguageBackend: Sized { fn open_namespaces(&mut self, out: &mut SourceWriter); diff --git a/src/bindgen/language_backend/zig.rs b/src/bindgen/language_backend/zig.rs new file mode 100644 index 000000000..084f8751d --- /dev/null +++ b/src/bindgen/language_backend/zig.rs @@ -0,0 +1,556 @@ +use crate::bindgen::ir::{ + to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, EnumVariant, + Field, GenericParams, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, ToCondition, Type, + Typedef, Union, +}; +use crate::bindgen::language_backend::LanguageBackend; +use crate::bindgen::writer::{ListType, SourceWriter}; +use crate::bindgen::{cdecl, Bindings, Config, Language}; +use crate::bindgen::{DocumentationLength, DocumentationStyle}; +use std::io::Write; + +pub struct ZigLanguageBackend<'a> { + config: &'a Config, +} + +impl<'a> ZigLanguageBackend<'a> { + pub fn new(config: &'a Config) -> Self { + Self { config } + } + + fn write_enum_variant(&mut self, out: &mut SourceWriter, u: &EnumVariant) { + let condition = u.cfg.to_condition(self.config); + + condition.write_before(self.config, out); + + self.write_documentation(out, &u.documentation); + write!(out, "{}", u.export_name); + if let Some(note) = u + .body + .annotations() + .deprecated_note(self.config, DeprecatedNoteKind::EnumVariant) + { + write!(out, " {}", note); + } + if let Some(discriminant) = &u.discriminant { + out.write(" = "); + + self.write_literal(out, discriminant); + } + out.write(","); + condition.write_after(self.config, out); + } + + fn write_field(&mut self, out: &mut SourceWriter, f: &Field) { + let condition = f.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &f.documentation); + cdecl::write_field(self, out, &f.ty, &f.name, self.config); + + // if let Some(bitfield) = f.annotations.atom("bitfield") { + // write!(out, ": {}", bitfield.unwrap_or_default()); + // } + + condition.write_after(self.config, out); + // FIXME(#634): `write_vertical_source_list` should support + // configuring list elements natively. For now we print a newline + // here to avoid printing `#endif;` with semicolon. + if condition.is_some() { + out.new_line(); + } + } + + fn write_generic_param(&mut self, out: &mut SourceWriter, g: &GenericParams) { + g.write_internal(self, self.config, out, false); + } + + fn open_close_namespaces(&mut self, out: &mut SourceWriter, _: bool) { + out.new_line(); + } +} + +impl LanguageBackend for ZigLanguageBackend<'_> { + fn write_headers(&self, out: &mut SourceWriter, package_version: &str) { + if self.config.package_version { + write!(out, "//! Package version: {}", package_version); + out.new_line(); + } + if let Some(ref f) = self.config.header { + out.new_line_if_not_start(); + write!(out, "{}", f); + out.new_line(); + } + if self.config.include_version { + out.new_line_if_not_start(); + write!( + out, + "//! Generated with cbindgen:{}", + crate::bindgen::config::VERSION + ); + out.new_line(); + } + if let Some(ref f) = self.config.autogen_warning { + out.new_line_if_not_start(); + write!(out, "{}", f); + out.new_line(); + } + + if self.config.no_includes + && self.config.sys_includes().is_empty() + && self.config.includes().is_empty() + && self.config.after_includes.is_none() + { + return; + } + + out.new_line_if_not_start(); + + if !self.config.no_includes { + match self.config.language { + Language::Zig => { + out.write("const std = @import(\"std\");"); + out.new_line(); + } + _ => {} + } + } + + for include in self.config.sys_includes() { + write!(out, "#include <{}>", include); + out.new_line(); + } + + for include in self.config.includes() { + write!(out, "#include \"{}\"", include); + out.new_line(); + } + + if let Some(ref line) = self.config.after_includes { + write!(out, "{}", line); + out.new_line(); + } + } + + fn open_namespaces(&mut self, out: &mut SourceWriter) { + self.open_close_namespaces(out, true); + } + + fn close_namespaces(&mut self, out: &mut SourceWriter) { + self.open_close_namespaces(out, false) + } + + fn write_footers(&mut self, _: &mut SourceWriter) { + // out.new_line(); + } + + fn write_enum(&mut self, out: &mut SourceWriter, e: &Enum) { + let size = e.repr.ty.map(|ty| ty.to_primitive().to_repr_c(self.config)); + let has_data = e.tag.is_some(); + let inline_tag_field = Enum::inline_tag_field(&e.repr); + let tag_name = e.tag_name(); + + let condition = e.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &e.documentation); + self.write_generic_param(out, &e.generic_params); + + // Emit the tag enum and everything related to it. + e.write_tag_enum(self.config, self, out, size, Self::write_enum_variant); + + // If the enum has data, we need to emit structs for the variants and gather them together. + if has_data { + e.write_variant_defs(self.config, self, out); + out.new_line(); + out.new_line(); + + // Open the struct or union for the data (**), gathering all the variants with data + // together, unless it's C++, then we have already opened that struct/union at (*) and + // are currently inside it. + if self.config.language != Language::Cxx { + e.open_struct_or_union(self.config, out, inline_tag_field); + } + + // Emit tag field that is separate from all variants. + e.write_tag_field(self.config, out, size, inline_tag_field, tag_name); + out.new_line(); + + // Open union of all variants with data, only in the non-inline tag scenario. + // if !inline_tag_field { + // out.write("union"); + // out.open_brace(); + // } + + // Emit fields for all variants with data. + // e.write_variant_fields(self.config, self, out, inline_tag_field, Self::write_field); + + // Close union of all variants with data, only in the non-inline tag scenario. + // if !inline_tag_field { + // out.close_brace(true); + // } + + // Emit convenience methods for the struct or enum for the data. + e.write_derived_functions_data(self.config, self, out, tag_name, Self::write_field); + + // Emit the post_body section, if relevant. + if let Some(body) = self.config.export.post_body(&e.path) { + out.new_line(); + out.write_raw_block(body); + } + + // Close the struct or union opened either at (*) or at (**). + out.close_brace(false); + write!(out, ";"); + } + + condition.write_after(self.config, out); + } + + fn write_struct(&mut self, out: &mut SourceWriter, s: &Struct) { + if s.is_transparent { + let typedef = Typedef { + path: s.path.clone(), + export_name: s.export_name.to_owned(), + generic_params: s.generic_params.clone(), + aliased: s.fields[0].ty.clone(), + cfg: s.cfg.clone(), + annotations: s.annotations.clone(), + documentation: s.documentation.clone(), + }; + self.write_type_def(out, &typedef); + for constant in &s.associated_constants { + out.new_line(); + constant.write(self.config, self, out, Some(s)); + } + return; + } + + let condition = s.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &s.documentation); + + if !s.is_enum_variant_body { + self.write_generic_param(out, &s.generic_params); + } + + write!(out, "const {} = extern struct", s.export_name); + + if let Some(align) = s.alignment { + match align { + ReprAlign::Packed => { + if let Some(ref anno) = self.config.layout.packed { + write!(out, " {}", anno); + } + } + ReprAlign::Align(n) => { + if let Some(ref anno) = self.config.layout.aligned_n { + write!(out, " {}({})", anno, n); + } + } + } + } + + if s.annotations.must_use(self.config) { + if let Some(ref anno) = self.config.structure.must_use { + write!(out, " {}", anno); + } + } + + if let Some(note) = s + .annotations + .deprecated_note(self.config, DeprecatedNoteKind::Struct) + { + write!(out, " {}", note); + } + + out.open_brace(); + + // Emit the pre_body section, if relevant + if let Some(body) = self.config.export.pre_body(&s.path) { + out.write_raw_block(body); + out.new_line(); + } + + out.write_vertical_source_list(self, &s.fields, ListType::Cap(","), Self::write_field); + + // Emit the post_body section, if relevant + if let Some(body) = self.config.export.post_body(&s.path) { + out.new_line(); + out.write_raw_block(body); + } + + if self.config.language == Language::Cxx + && self.config.structure.associated_constants_in_body + && self.config.constant.allow_static_const + { + for constant in &s.associated_constants { + out.new_line(); + constant.write_declaration(self.config, self, out, s); + } + } + + out.close_brace(false); + write!(out, ";"); + + for constant in &s.associated_constants { + out.new_line(); + constant.write(self.config, self, out, Some(s)); + } + + condition.write_after(self.config, out); + } + + fn write_union(&mut self, out: &mut SourceWriter, u: &Union) { + let condition = u.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &u.documentation); + + self.write_generic_param(out, &u.generic_params); + + write!(out, "const {} = union", u.export_name); + + if let Some(align) = u.alignment { + match align { + ReprAlign::Packed => { + if let Some(ref anno) = self.config.layout.packed { + write!(out, " {}", anno); + } + } + ReprAlign::Align(n) => { + if let Some(ref anno) = self.config.layout.aligned_n { + write!(out, " {}({})", anno, n); + } + } + } + } + // todo!("See union tag"); + // if self.config.language != Language::C || self.config.style.generate_tag() { + // write!(out, " {}", u.export_name); + // } + + out.open_brace(); + + // Emit the pre_body section, if relevant + if let Some(body) = self.config.export.pre_body(&u.path) { + out.write_raw_block(body); + out.new_line(); + } + + out.write_vertical_source_list(self, &u.fields, ListType::Cap(","), Self::write_field); + + // Emit the post_body section, if relevant + if let Some(body) = self.config.export.post_body(&u.path) { + out.new_line(); + out.write_raw_block(body); + } + + out.close_brace(false); + write!(out, ";"); + + condition.write_after(self.config, out); + } + + fn write_opaque_item(&mut self, out: &mut SourceWriter, o: &OpaqueItem) { + let condition = o.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &o.documentation); + + o.generic_params.write_with_default(self, self.config, out); + + // like 'void*' in ziglang (optional null or ptr) + write!(out, "const {} = ?*anyopaque;", o.export_name()); + condition.write_after(self.config, out); + } + + fn write_type_def(&mut self, out: &mut SourceWriter, t: &Typedef) { + let condition = t.cfg.to_condition(self.config); + condition.write_before(self.config, out); + + self.write_documentation(out, &t.documentation); + + self.write_generic_param(out, &t.generic_params); + + if self.config.language == Language::Cxx { + write!(out, "using {} = ", t.export_name()); + self.write_type(out, &t.aliased); + } else { + write!(out, "{} ", self.config.language.typedef()); + self.write_field( + out, + &Field::from_name_and_type(t.export_name().to_owned(), t.aliased.clone()), + ); + } + + out.write(";"); + + condition.write_after(self.config, out); + } + + fn write_static(&mut self, out: &mut SourceWriter, s: &Static) { + self.write_documentation(out, &s.documentation); + out.write("extern "); + if let Type::Ptr { is_const: true, .. } = s.ty { + } else if !s.mutable { + out.write("const "); + } + cdecl::write_field(self, out, &s.ty, &s.export_name, self.config); + out.write(";"); + } + + fn write_type(&mut self, out: &mut SourceWriter, t: &Type) { + cdecl::write_type(self, out, t, self.config); + } + + fn write_documentation(&mut self, out: &mut SourceWriter, d: &Documentation) { + if d.doc_comment.is_empty() || !self.config.documentation { + return; + } + + let end = match self.config.documentation_length { + DocumentationLength::Short => 1, + DocumentationLength::Full => d.doc_comment.len(), + }; + + let style = match self.config.documentation_style { + DocumentationStyle::Auto => DocumentationStyle::Zig, // Fallback if `Language` gets extended. + other => other, + }; + + // Following these documents for style conventions: + // https://en.wikibooks.org/wiki/C++_Programming/Code/Style_Conventions/Comments + // https://www.cs.cmu.edu/~410/doc/doxygen.html + match style { + DocumentationStyle::Zig => { + out.write(" ///"); + out.new_line(); + } + + _ => (), + } + + for line in &d.doc_comment[..end] { + match style { + DocumentationStyle::C => out.write(""), + DocumentationStyle::Doxy => out.write(" *"), + DocumentationStyle::C99 => out.write("//"), + DocumentationStyle::Cxx => out.write("///"), + DocumentationStyle::Zig => out.write("///"), + DocumentationStyle::Auto => unreachable!(), // Auto case should always be covered + } + + write!(out, "{}", line); + out.new_line(); + } + + match style { + DocumentationStyle::Zig => { + out.write(" ///"); + out.new_line(); + } + + _ => (), + } + } + + fn write_literal(&mut self, out: &mut SourceWriter, l: &Literal) { + match l { + Literal::Expr(v) => write!(out, "{}", v), + Literal::Path { + ref associated_to, + ref name, + } => { + if let Some((ref path, ref export_name)) = associated_to { + if let Some(known) = to_known_assoc_constant(path, name) { + return write!(out, "{}", known); + } + let path_separator = "_"; + write!(out, "{}{}", export_name, path_separator) + } + write!(out, "{}", name) + } + Literal::FieldAccess { + ref base, + ref field, + } => { + write!(out, "("); + self.write_literal(out, base); + write!(out, ").{}", field); + } + Literal::PostfixUnaryOp { op, ref value } => { + write!(out, "{}", op); + self.write_literal(out, value); + } + Literal::BinOp { + ref left, + op, + ref right, + } => { + write!(out, "("); + self.write_literal(out, left); + write!(out, " {} ", op); + self.write_literal(out, right); + write!(out, ")"); + } + Literal::Cast { ref ty, ref value } => { + out.write("("); + self.write_type(out, ty); + out.write(")"); + self.write_literal(out, value); + } + Literal::Struct { + export_name, + fields, + path, + } => { + write!(out, ":{} = .", export_name); + + write!(out, "{{ "); + let mut is_first_field = true; + // In C++, same order as defined is required. + let ordered_fields = out.bindings().struct_field_names(path); + for ordered_key in ordered_fields.iter() { + if let Some(lit) = fields.get(ordered_key) { + if !is_first_field { + write!(out, ", "); + } + is_first_field = false; + write!(out, ".{} = ", ordered_key); + self.write_literal(out, lit); + } + } + write!(out, " }}"); + } + } + } + + fn write_globals(&mut self, out: &mut SourceWriter, b: &Bindings) { + // Override default method to open various blocs containing both globals and functions + // these blocks are closed in [`write_functions`] that is also overridden + if !b.functions.is_empty() || !b.globals.is_empty() { + + // if b.config.language == Language::Zig { + // if let Some(ref using_namespaces) = b.config.using_namespaces { + // for namespace in using_namespaces { + // out.new_line(); + // write!(out, "usingnamespace {};", namespace); + // } + // out.new_line(); + // } + // } + + self.write_globals_default(out, b); + } + } + + fn write_functions(&mut self, out: &mut SourceWriter, b: &Bindings) { + // Override default method to close various blocks containing both globals and functions + // these blocks are opened in [`write_globals`] that is also overridden + if !b.functions.is_empty() || !b.globals.is_empty() { + self.write_functions_default(out, b); + } + } +} From d156169a8f010f183d9d8f07622b9624a43174fd Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 11:58:07 -0300 Subject: [PATCH 09/13] some fixes update * fn funtions * extern struct * none_argname --- src/bindgen/cdecl.rs | 14 +++++++++----- src/bindgen/ir/enumeration.rs | 6 +++--- src/bindgen/ir/field.rs | 12 +----------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 2f46675fa..d953e9aae 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -116,9 +116,8 @@ impl CDecl { t ); if config.language != Language::Zig { - self.type_qualifers = "const".to_owned(); + "const".clone_into(&mut self.type_qualifers); } - "const".clone_into(&mut self.type_qualifers); } assert!( @@ -143,9 +142,8 @@ impl CDecl { t ); if config.language != Language::Zig { - self.type_qualifers = "const".to_owned(); + "const".clone_into(&mut self.type_qualifers); } - "const".clone_into(&mut self.type_qualifers); } assert!( @@ -241,7 +239,7 @@ impl CDecl { // When we have an identifier, put a space between the type and the declarators if ident.is_some() { - if config.language == Language::Zig && self.declarators.is_empty() { + if config.language == Language::Zig { out.write(""); } else { out.write(" "); @@ -268,6 +266,9 @@ impl CDecl { if !self.type_qualifers.is_empty() { write!(out, "{}", self.type_qualifers); } else { + if ident.is_none() && config.language == Language::Zig { + out.write("_"); + } if config.language != Language::Zig { out.write("_"); } @@ -295,6 +296,9 @@ impl CDecl { if next_is_pointer && config.language != Language::Zig { out.write("("); } + if !next_is_pointer && config.language == Language::Zig { + out.write("fn "); + } is_functors = true; } } diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 0c42d6bf0..d1aa765b3 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -811,9 +811,9 @@ impl Enum { write!(out, " {} ", note); } - if config.language != Language::C || config.language != Language::Zig || config.style.generate_tag() { - write!(out, " {}", self.export_name()); - } + // if config.language != Language::C || config.language != Language::Zig || config.style.generate_tag() { + // write!(out, " {}", self.export_name()); + // } out.open_brace(); diff --git a/src/bindgen/ir/field.rs b/src/bindgen/ir/field.rs index 1e59ba87b..f1a3dbdae 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -23,16 +23,6 @@ impl Field { } } - pub fn from_type(ty: Type) -> Field { - Field { - name: "".to_string(), - ty, - cfg: None, - annotations: AnnotationSet::new(), - documentation: Documentation::none(), - } - } - pub fn load(field: &syn::Field, self_path: &Path) -> Result, String> { Ok(if let Some(mut ty) = Type::load(&field.ty)? { ty.replace_self_with(self_path); @@ -52,4 +42,4 @@ impl Field { None }) } -} +} \ No newline at end of file From 4ce0d3a19d53f88cb2558937646d06010d435ff0 Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 12:18:47 -0300 Subject: [PATCH 10/13] zig: extern fns --- src/bindgen/cdecl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index d953e9aae..1bcf5731d 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -297,7 +297,7 @@ impl CDecl { out.write("("); } if !next_is_pointer && config.language == Language::Zig { - out.write("fn "); + out.write("extern fn "); } is_functors = true; } From d6c215047f46086715c762233e13af2e34b5786f Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 12:27:54 -0300 Subject: [PATCH 11/13] zig: constants semicolon --- src/bindgen/ir/constant.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 8238adc9d..c7b90fd79 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -723,7 +723,9 @@ impl Constant { } Language::Zig => { out.write(config.style.zig_def()); + write!(out, "{} ", name); language_backend.write_literal(out, value); + out.write(";"); } } From 10a57d0498ea2c7cfb57f6d287d9032754b9e7ee Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 12:40:53 -0300 Subject: [PATCH 12/13] zig: extern union --- src/bindgen/language_backend/zig.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bindgen/language_backend/zig.rs b/src/bindgen/language_backend/zig.rs index 084f8751d..7538a261d 100644 --- a/src/bindgen/language_backend/zig.rs +++ b/src/bindgen/language_backend/zig.rs @@ -66,7 +66,7 @@ impl<'a> ZigLanguageBackend<'a> { } fn open_close_namespaces(&mut self, out: &mut SourceWriter, _: bool) { - out.new_line(); + out.new_line(); } } @@ -310,7 +310,7 @@ impl LanguageBackend for ZigLanguageBackend<'_> { self.write_generic_param(out, &u.generic_params); - write!(out, "const {} = union", u.export_name); + write!(out, "const {} = extern union", u.export_name); if let Some(align) = u.alignment { match align { @@ -531,7 +531,6 @@ impl LanguageBackend for ZigLanguageBackend<'_> { // Override default method to open various blocs containing both globals and functions // these blocks are closed in [`write_functions`] that is also overridden if !b.functions.is_empty() || !b.globals.is_empty() { - // if b.config.language == Language::Zig { // if let Some(ref using_namespaces) = b.config.using_namespaces { // for namespace in using_namespaces { From f66477043ca6af5f6a0e5a22d42b374b3c05c91d Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Sun, 29 Sep 2024 12:44:17 -0300 Subject: [PATCH 13/13] zig: constants attribution --- src/bindgen/ir/constant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index c7b90fd79..4d1140225 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -723,7 +723,7 @@ impl Constant { } Language::Zig => { out.write(config.style.zig_def()); - write!(out, "{} ", name); + write!(out, "{} = ", name); language_backend.write_literal(out, value); out.write(";"); }