Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

D language support #1005

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bindgen/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ impl Bindings {

pub fn write<F: Write>(&self, file: F) {
match self.config.language {
Language::Cxx | Language::C => {
Language::Cxx | Language::C | Language::D => {
self.write_with_backend(file, &mut CLikeLanguageBackend::new(&self.config))
}
Language::Cython => {
Expand Down
63 changes: 54 additions & 9 deletions src/bindgen/cdecl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ impl CDecl {
"error generating cdecl for {:?}",
t
);
self.type_name = p.to_repr_c(config).to_string();
if config.language == Language::D {
self.type_name = p.to_repr_d(config).to_string();
} else {
self.type_name = p.to_repr_c(config).to_string();
}
}
Type::Ptr {
ref ty,
Expand Down Expand Up @@ -213,7 +217,11 @@ impl CDecl {
write!(out, "{}", self.type_name);

if !self.type_generic_args.is_empty() {
out.write("<");
if config.language == Language::D {
out.write("!(");
} else {
out.write("<");
}
out.write_horizontal_source_list(
language_backend,
&self.type_generic_args,
Expand All @@ -223,7 +231,11 @@ impl CDecl {
GenericArgument::Const(ref expr) => write!(out, "{}", expr.as_str()),
},
);
out.write(">");
if config.language == Language::D {
out.write(")");
} else {
out.write(">");
}
}

// When we have an identifier, put a space between the type and the declarators
Expand All @@ -233,6 +245,7 @@ impl CDecl {

// 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() {
Expand All @@ -244,7 +257,17 @@ impl CDecl {
is_nullable,
is_ref,
} => {
out.write(if is_ref { "&" } else { "*" });
if config.language == Language::D {
// out.write(if is_ref { "ref " } else { "*" });
if is_ref {
out.write("ref ");
} else if is_functors {
} else {
out.write("*");
}
} else {
out.write(if is_ref { "&" } else { "*" });
}
if is_const {
out.write("const ");
}
Expand All @@ -254,22 +277,34 @@ impl CDecl {
}
}
}
CDeclarator::Array(..) => {
CDeclarator::Array(ref constant) => {
if next_is_pointer {
out.write("(");
}
if config.language == Language::D {
write!(out, "[{}] ", constant);
}
}
CDeclarator::Func { .. } => {
if next_is_pointer {
out.write("(");
if config.language == Language::D {
out.write(" function");
is_functors = true;
} else {
out.write("(");
}
}
}
}
}

// Write the identifier
if let Some(ident) = ident {
write!(out, "{}", ident);
if is_functors {
// out.write(" ");
} else {
write!(out, "{}", ident);
}
}

// Write the right part of declarators after the identifier
Expand All @@ -286,7 +321,9 @@ impl CDecl {
if last_was_pointer {
out.write(")");
}
write!(out, "[{}]", constant);
if config.language != Language::D {
write!(out, "[{}]", constant);
}

last_was_pointer = false;
}
Expand All @@ -296,7 +333,9 @@ impl CDecl {
never_return,
} => {
if last_was_pointer {
out.write(")");
if config.language != Language::D {
out.write(")");
}
}

out.write("(");
Expand Down Expand Up @@ -363,6 +402,12 @@ impl CDecl {
out.write_fmt(format_args!(" {}", no_return_attr));
}
}
if config.language == Language::D && is_functors {
if let Some(ident) = ident {
write!(out, " {}", ident);
}
}
is_functors = false;

last_was_pointer = true;
}
Expand Down
7 changes: 7 additions & 0 deletions src/bindgen/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum Language {
Cxx,
C,
Cython,
D,
}

impl FromStr for Language {
Expand All @@ -42,6 +43,9 @@ impl FromStr for Language {
"C" => Ok(Language::C),
"cython" => Ok(Language::Cython),
"Cython" => Ok(Language::Cython),
"d" => Ok(Language::D),
"dlang" => Ok(Language::D),
"D" => Ok(Language::D),
_ => Err(format!("Unrecognized Language: '{}'.", s)),
}
}
Expand All @@ -54,6 +58,7 @@ impl Language {
match self {
Language::Cxx | Language::C => "typedef",
Language::Cython => "ctypedef",
Language::D => "alias",
}
}
}
Expand Down Expand Up @@ -166,6 +171,7 @@ pub enum DocumentationStyle {
C99,
Doxy,
Cxx,
D,
Auto,
}

Expand All @@ -179,6 +185,7 @@ impl FromStr for DocumentationStyle {
"cxx" => Ok(DocumentationStyle::Cxx),
"c++" => Ok(DocumentationStyle::Cxx),
"doxy" => Ok(DocumentationStyle::Doxy),
"dlang" => Ok(DocumentationStyle::D),
"auto" => Ok(DocumentationStyle::Auto),
_ => Err(format!("Unrecognized documentation style: '{}'.", s)),
}
Expand Down
6 changes: 6 additions & 0 deletions src/bindgen/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ impl Constant {
) {
debug_assert!(self.associated_to.is_some());
debug_assert!(config.language == Language::Cxx);
debug_assert!(config.language == Language::D);
debug_assert!(!associated_to_struct.is_transparent);
debug_assert!(config.structure.associated_constants_in_body);
debug_assert!(config.constant.allow_static_const);
Expand Down Expand Up @@ -721,6 +722,11 @@ impl Constant {
write!(out, " {} # = ", name);
language_backend.write_literal(out, value);
}
Language::D => {
write!(out, "enum {} = ", name);
language_backend.write_literal(out, value);
out.write(";");
}
}

condition.write_after(config, out);
Expand Down
31 changes: 28 additions & 3 deletions src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,27 @@ impl Enum {
write!(out, "{}enum {}", config.style.cython_def(), tag_name);
}
}
Language::D => {
out.write("enum");

if self.annotations.must_use(config) {
if let Some(ref anno) = config.enumeration.must_use {
write!(out, " {}", anno)
}
}

if let Some(note) = self
.annotations
.deprecated_note(config, DeprecatedNoteKind::Enum)
{
write!(out, " {}", note);
}

write!(out, " {}", tag_name);
if let Some(prim) = size {
write!(out, " : {}", prim);
}
}
}
out.open_brace();

Expand All @@ -748,7 +769,11 @@ impl Enum {
out.close_brace(false);
write!(out, " {};", tag_name);
} else {
out.close_brace(true);
if config.language != Language::D {
out.close_brace(true);
} else {
out.close_brace(false);
}
}

// Emit typedef specifying the tag enum's size if necessary.
Expand All @@ -760,7 +785,7 @@ impl Enum {
out.write("#ifndef __cplusplus");
}

if config.language != Language::Cxx {
if config.language != Language::Cxx && config.language != Language::D {
out.new_line();
write!(out, "{} {} {};", config.language.typedef(), prim, tag_name);
}
Expand All @@ -784,7 +809,7 @@ impl Enum {
) {
match config.language {
Language::C if config.style.generate_typedef() => out.write("typedef "),
Language::C | Language::Cxx => {}
Language::C | Language::Cxx | Language::D => {}
Language::Cython => out.write(config.style.cython_def()),
}

Expand Down
24 changes: 19 additions & 5 deletions src/bindgen/ir/generic_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,23 @@ impl GenericParams {
out: &mut SourceWriter<F>,
with_default: bool,
) {
if !self.0.is_empty() && config.language == Language::Cxx {
out.write("template<");
if (!self.0.is_empty() && config.language == Language::Cxx) || (!self.0.is_empty() && config.language == Language::D) {
out.write(if config.language == Language::D {
"("
} else {
"template<"
});
for (i, item) in self.0.iter().enumerate() {
if i != 0 {
out.write(", ");
}
match item.ty {
GenericParamType::Type => {
write!(out, "typename {}", item.name);
if config.language == Language::D {
write!(out, "{}", item.name);
} else {
write!(out, "typename {}", item.name);
}
if let Some(GenericArgument::Type(ref ty)) = item.default {
write!(out, " = ");
cdecl::write_type(language_backend, out, ty, config);
Expand All @@ -171,8 +179,14 @@ impl GenericParams {
}
}
}
out.write(">");
out.new_line();
out.write(if config.language == Language::D {
")"
} else {
">"
});
if config.language != Language::D {
out.new_line();
}
}
}

Expand Down
51 changes: 51 additions & 0 deletions src/bindgen/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,57 @@ impl PrimitiveType {
}
}

pub fn to_repr_d(&self, config: &Config) -> &'static str {
match *self {
PrimitiveType::Void => "void",
PrimitiveType::Bool => "bool",
PrimitiveType::Char => "char",
PrimitiveType::SChar => "byte",
PrimitiveType::UChar => "ubyte",
// NOTE: It'd be nice to use a char32_t, but:
//
// * uchar.h is not present on mac (see #423).
//
// * char32_t isn't required to be compatible with Rust's char, as
// the C++ spec only requires it to be the same size as
// uint_least32_t, which is _not_ guaranteed to be 4-bytes.
//
PrimitiveType::Char32 => "uint",
PrimitiveType::Integer {
kind,
signed,
zeroable: _,
} => match (kind, signed) {
(IntKind::Short, true) => "short",
(IntKind::Short, false) => "ushort",
(IntKind::Int, true) => "int",
(IntKind::Int, false) => "uint",
(IntKind::Long, true) => "long",
(IntKind::Long, false) => "ulong",
(IntKind::LongLong, true) => "long long",
(IntKind::LongLong, false) => "ulong long",
(IntKind::SizeT, true) => "long",
(IntKind::SizeT, false) => "ulong",
(IntKind::Size, true) if config.usize_is_size_t => "long",
(IntKind::Size, false) if config.usize_is_size_t => "ulong",
(IntKind::Size, true) => "long",
(IntKind::Size, false) => "ulong",
(IntKind::B8, true) => "byte",
(IntKind::B8, false) => "ubyte",
(IntKind::B16, true) => "short",
(IntKind::B16, false) => "ushort",
(IntKind::B32, true) => "int",
(IntKind::B32, false) => "uint",
(IntKind::B64, true) => "long",
(IntKind::B64, false) => "ulong",
},
PrimitiveType::Float => "float",
PrimitiveType::Double => "double",
PrimitiveType::PtrDiffT => "long",
PrimitiveType::VaList => "...",
}
}

fn can_cmp_order(&self) -> bool {
!matches!(*self, PrimitiveType::Bool)
}
Expand Down
Loading