diff --git a/tools/banjo/banjo/src/backends/c.rs b/tools/banjo/banjo/src/backends/c.rs index 8569ece566ba58f8a17404e69e9d8ee5cdee6056..685bd3380ba9bf9f2b7bf6739f71447f3c0e4007 100644 --- a/tools/banjo/banjo/src/backends/c.rs +++ b/tools/banjo/banjo/src/backends/c.rs @@ -167,6 +167,88 @@ fn struct_attrs_to_c_str(attributes: &Attrs) -> String { .join(" ") } +fn field_to_c_str( + attrs: &Attrs, + ty: &ast::Ty, + ident: &Ident, + indent: &str, + ast: &ast::BanjoAst, +) -> Result<String, Error> { + let mut accum = String::new(); + accum.push_str(get_doc_comment(attrs, 1).as_str()); + let prefix = if ty.is_reference() { "" } else { "const " }; + match ty { + ast::Ty::Vector { ty: ref inner_ty, .. } => { + let ty_name = ty_to_c_str(ast, &ty)?; + // TODO(surajmalhotra): Support multi-dimensional vectors. + let ptr = if inner_ty.is_reference() { "*" } else { "" }; + accum.push_str( + format!( + "{indent}{prefix}{ty}{ptr}* {c_name}_{buffer};\n\ + {indent}size_t {c_name}_{size};", + indent = indent, + buffer = name_buffer(&ty_name), + size = name_size(&ty_name), + c_name = to_c_name(ident.name()), + prefix = prefix, + ty = ty_name, + ptr = ptr, + ) + .as_str(), + ); + } + ast::Ty::Array { .. } => { + let bounds = array_bounds(ast, &ty).unwrap(); + accum.push_str( + format!( + "{indent}{ty} {c_name}{bounds};", + indent = indent, + c_name = to_c_name(ident.name()), + bounds = bounds, + ty = ty_to_c_str(ast, &ty)? + ) + .as_str(), + ); + } + ast::Ty::Str { ref size, .. } => { + if let Some(size) = size { + accum.push_str( + format!( + "{indent}char {c_name}[{size}];", + indent = indent, + c_name = to_c_name(ident.name()), + size = size, + ) + .as_str(), + ); + } else { + accum.push_str( + format!( + "{indent}{prefix}{ty} {c_name};", + indent = indent, + c_name = to_c_name(ident.name()), + prefix = prefix, + ty = ty_to_c_str(ast, &ty)? + ) + .as_str(), + ); + } + } + _ => { + accum.push_str( + format!( + "{indent}{ty} {c_name};", + indent = indent, + c_name = to_c_name(ident.name()), + ty = ty_to_c_str(ast, &ty)? + ) + .as_str(), + ); + } + } + Ok(accum) +} + fn get_first_param(ast: &BanjoAst, method: &ast::Method) -> Result<(bool, String), Error> { // Return parameter if a primitive type. if method.out_params.get(0).map_or(false, |p| p.1.is_primitive(&ast)) { @@ -475,18 +557,9 @@ impl<'a, W: io::Write> CBackend<'a, W> { let attrs = struct_attrs_to_c_str(attributes); let members = fields .iter() - .map(|f| { - let mut accum = String::new(); - accum.push_str(get_doc_comment(&f.attributes, 1).as_str()); - accum.push_str( - format!( - " {ty} {c_name};", - c_name = to_c_name(f.ident.name()), - ty = ty_to_c_str(ast, &f.ty)? - ) - .as_str(), - ); - Ok(accum) + .map(|f| match f.ty { + ast::Ty::Vector { .. } => Err(format_err!("unsupported for UnionField: {:?}", f)), + _ => field_to_c_str(&f.attributes, &f.ty, &f.ident, " ", &ast), }) .collect::<Result<Vec<_>, Error>>()? .join("\n"); @@ -533,75 +606,7 @@ impl<'a, W: io::Write> CBackend<'a, W> { let attrs = struct_attrs_to_c_str(attributes); let members = fields .iter() - .map(|f| { - let mut accum = String::new(); - accum.push_str(get_doc_comment(&f.attributes, 1).as_str()); - let prefix = if f.ty.is_reference() { "" } else { "const " }; - match f.ty { - ast::Ty::Vector { ty: ref inner_ty, .. } => { - let ty_name = ty_to_c_str(ast, &f.ty)?; - // TODO(surajmalhotra): Support multi-dimensional vectors. - let ptr = if inner_ty.is_reference() { "*" } else { "" }; - accum.push_str( - format!( - " {prefix}{ty}{ptr}* {c_name}_{buffer};\n size_t {c_name}_{size};", - buffer = name_buffer(&ty_name), - size = name_size(&ty_name), - c_name = to_c_name(f.ident.name()), - prefix = prefix, - ty = ty_name, - ptr = ptr, - ) - .as_str(), - ); - } - ast::Ty::Array { .. } => { - let bounds = array_bounds(ast, &f.ty).unwrap(); - accum.push_str( - format!( - " {ty} {c_name}{bounds};", - c_name = to_c_name(f.ident.name()), - bounds = bounds, - ty = ty_to_c_str(ast, &f.ty)? - ) - .as_str(), - ); - } - ast::Ty::Str { ref size, .. } => { - if let Some(size) = size { - accum.push_str( - format!( - " char {c_name}[{size}];", - c_name = to_c_name(f.ident.name()), - size = size, - ) - .as_str(), - ); - } else { - accum.push_str( - format!( - " {prefix}{ty} {c_name};", - c_name = to_c_name(f.ident.name()), - prefix = prefix, - ty = ty_to_c_str(ast, &f.ty)? - ) - .as_str(), - ); - } - } - _ => { - accum.push_str( - format!( - " {ty} {c_name};", - c_name = to_c_name(f.ident.name()), - ty = ty_to_c_str(ast, &f.ty)? - ) - .as_str(), - ); - } - } - Ok(accum) - }) + .map(|f| field_to_c_str(&f.attributes, &f.ty, &f.ident, " ", &ast)) .collect::<Result<Vec<_>, Error>>()? .join("\n"); let mut accum = String::new(); diff --git a/tools/banjo/banjo/test/ast/types.test.ast b/tools/banjo/banjo/test/ast/types.test.ast index 618baa275c0045adb2cf78f242e2ff7045687ad2..4dfd5973888c910b66b17575d505430fba53688c 100644 --- a/tools/banjo/banjo/test/ast/types.test.ast +++ b/tools/banjo/banjo/test/ast/types.test.ast @@ -4846,6 +4846,361 @@ BanjoAst { }, ], }, + Union { + attributes: Attrs( + [], + ), + name: Ident { + namespace: Some( + "banjo.examples.types", + ), + name: "union_types", + }, + fields: [ + UnionField { + attributes: Attrs( + [], + ), + ty: Bool, + ident: Ident { + namespace: None, + name: "b", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Int8, + ident: Ident { + namespace: None, + name: "i8", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Int16, + ident: Ident { + namespace: None, + name: "i16", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Int32, + ident: Ident { + namespace: None, + name: "i32", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Int64, + ident: Ident { + namespace: None, + name: "i64", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: UInt8, + ident: Ident { + namespace: None, + name: "u8", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: UInt16, + ident: Ident { + namespace: None, + name: "u16", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: UInt32, + ident: Ident { + namespace: None, + name: "u32", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: UInt64, + ident: Ident { + namespace: None, + name: "u64", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Float32, + ident: Ident { + namespace: None, + name: "f32", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Float64, + ident: Ident { + namespace: None, + name: "f64", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Bool, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "b_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Int8, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "i8_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Int16, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "i16_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Int32, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "i32_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Int64, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "i64_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: UInt8, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "u8_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: UInt16, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "u16_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: UInt32, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "u32_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: UInt64, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "u64_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Float32, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "f32_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Float64, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "f64_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Array { + ty: Handle { + ty: Handle, + reference: false, + }, + size: Constant( + "1", + ), + }, + ident: Ident { + namespace: None, + name: "handle_0", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Str { + size: None, + nullable: false, + }, + ident: Ident { + namespace: None, + name: "str", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Identifier { + id: Ident { + namespace: Some( + "banjo.examples.types", + ), + name: "this_is_a_struct", + }, + reference: false, + }, + ident: Ident { + namespace: None, + name: "s", + }, + }, + UnionField { + attributes: Attrs( + [], + ), + ty: Identifier { + id: Ident { + namespace: Some( + "banjo.examples.types", + ), + name: "this_is_a_union", + }, + reference: false, + }, + ident: Ident { + namespace: None, + name: "u", + }, + }, + ], + }, ], }, } diff --git a/tools/banjo/banjo/test/banjo/types.test.banjo b/tools/banjo/banjo/test/banjo/types.test.banjo index d00e7ee35036c4cef3736848e30c75c9d9b8b7da..51fbb464965924941e5cf0b1dcd7d71be1ff3764 100644 --- a/tools/banjo/banjo/test/banjo/types.test.banjo +++ b/tools/banjo/banjo/test/banjo/types.test.banjo @@ -337,3 +337,34 @@ struct interfaces { this_is_an_interface i; this_is_an_interface? nullable_i; }; + +union union_types { + bool b; + int8 i8; + int16 i16; + int32 i32; + int64 i64; + uint8 u8; + uint16 u16; + uint32 u32; + uint64 u64; + float32 f32; + float64 f64; + + array<bool>:1 b_0; + array<int8>:1 i8_0; + array<int16>:1 i16_0; + array<int32>:1 i32_0; + array<int64>:1 i64_0; + array<uint8>:1 u8_0; + array<uint16>:1 u16_0; + array<uint32>:1 u32_0; + array<uint64>:1 u64_0; + array<float32>:1 f32_0; + array<float64>:1 f64_0; + array<handle>:1 handle_0; + + string str; + this_is_a_struct s; + this_is_a_union u; +}; diff --git a/tools/banjo/banjo/test/c/protocol-other-types.h b/tools/banjo/banjo/test/c/protocol-other-types.h index 2a6dc35aa97c4ca2eb90906aa7841690606a0bb9..cd4e7fdacdfd0fb70a9c7b39d9fcf0b7737da619 100644 --- a/tools/banjo/banjo/test/c/protocol-other-types.h +++ b/tools/banjo/banjo/test/c/protocol-other-types.h @@ -44,7 +44,7 @@ struct this_is_astruct { }; union this_is_aunion { - char* s; + const char* s; }; typedef struct other_types_reference_protocol_ops { diff --git a/tools/banjo/banjo/test/c/types.h b/tools/banjo/banjo/test/c/types.h index 300f7b721b21ab5ae031be7524cc3fdda04f731d..aa4d7ae1bd3eb0fe06f7f3ae3dd4743ec6b28c8c 100644 --- a/tools/banjo/banjo/test/c/types.h +++ b/tools/banjo/banjo/test/c/types.h @@ -46,6 +46,7 @@ typedef uint8_t u8_enum_t; typedef struct this_is_an_interface_protocol this_is_an_interface_protocol_t; typedef struct structs structs_t; typedef struct unions unions_t; +typedef union union_types union_types_t; typedef struct interfaces interfaces_t; typedef struct interfaces interfaces_t; @@ -421,7 +422,7 @@ struct handles { }; union this_is_a_union { - char* s; + const char* s; }; typedef struct this_is_an_interface_protocol_ops { @@ -449,6 +450,35 @@ struct unions { this_is_a_union_t nullable_u; }; +union union_types { + bool b; + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + float f32; + double f64; + bool b_0[1]; + int8_t i8_0[1]; + int16_t i16_0[1]; + int32_t i32_0[1]; + int64_t i64_0[1]; + uint8_t u8_0[1]; + uint16_t u16_0[1]; + uint32_t u32_0[1]; + uint64_t u64_0[1]; + float f32_0[1]; + double f64_0[1]; + zx_handle_t handle_0[1]; + const char* str; + this_is_a_struct_t s; + this_is_a_union_t u; +}; + struct interfaces { this_is_an_interface_protocol_t nonnullable_interface; this_is_an_interface_protocol_t nullable_interface;