generator: Convert #define
generation from vkxml
to vk-parse
(#708)
For upcoming `vk.xml` features (the new `api` attribute) some of our codegen has to be converted to work on `vk-parse` types to make this ergonomic (and there's a longstanding plan of factoring out `vkxml` regardless). Start with converting the `#define` code and showcasing that it does not affect the output (beyond removing the unneeded edgecase for `VK_HEADER_VERSION` resulting in a doc link).
This commit is contained in:
parent
8c63c9e08b
commit
90ccc31f97
|
@ -57,7 +57,8 @@ pub const API_VERSION_1_1: u32 = make_api_version(0, 1, 1, 0);
|
||||||
pub const API_VERSION_1_2: u32 = make_api_version(0, 1, 2, 0);
|
pub const API_VERSION_1_2: u32 = make_api_version(0, 1, 2, 0);
|
||||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_API_VERSION_1_3.html>"]
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_API_VERSION_1_3.html>"]
|
||||||
pub const API_VERSION_1_3: u32 = make_api_version(0, 1, 3, 0);
|
pub const API_VERSION_1_3: u32 = make_api_version(0, 1, 3, 0);
|
||||||
pub const HEADER_VERSION: u32 = 238u32;
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_HEADER_VERSION.html>"]
|
||||||
|
pub const HEADER_VERSION: u32 = 238;
|
||||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_HEADER_VERSION_COMPLETE.html>"]
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_HEADER_VERSION_COMPLETE.html>"]
|
||||||
pub const HEADER_VERSION_COMPLETE: u32 = make_api_version(0, 1, 3, HEADER_VERSION);
|
pub const HEADER_VERSION_COMPLETE: u32 = make_api_version(0, 1, 3, HEADER_VERSION);
|
||||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSampleMask.html>"]
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSampleMask.html>"]
|
||||||
|
|
|
@ -3,15 +3,14 @@
|
||||||
|
|
||||||
use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
|
use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nom::sequence::pair;
|
|
||||||
use nom::{
|
use nom::{
|
||||||
branch::alt,
|
branch::alt,
|
||||||
bytes::streaming::tag,
|
bytes::complete::{tag, take_until, take_while1},
|
||||||
character::complete::{char, digit1, hex_digit1, multispace1, none_of, one_of},
|
character::complete::{char, digit1, hex_digit1, multispace1, newline, none_of, one_of},
|
||||||
combinator::{complete, map, opt, value},
|
combinator::{map, opt, value},
|
||||||
error::{ParseError, VerboseError},
|
error::{ParseError, VerboseError},
|
||||||
multi::many1,
|
multi::{many1, separated_list1},
|
||||||
sequence::{delimited, preceded, terminated},
|
sequence::{delimited, pair, preceded, terminated},
|
||||||
IResult, Parser,
|
IResult, Parser,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
@ -72,10 +71,7 @@ impl quote::ToTokens for CType {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ctype<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, CType, E> {
|
fn parse_ctype<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, CType, E> {
|
||||||
(alt((
|
(alt((value(CType::U64, tag("ULL")), value(CType::U32, tag("U")))))(i)
|
||||||
value(CType::U64, complete(tag("ULL"))),
|
|
||||||
value(CType::U32, complete(tag("U"))),
|
|
||||||
)))(i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cexpr<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (CType, String), E> {
|
fn parse_cexpr<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (CType, String), E> {
|
||||||
|
@ -156,6 +152,41 @@ fn parse_hexadecimal_number<'a, E: ParseError<&'a str>>(
|
||||||
))(i)
|
))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_c_identifier<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
|
||||||
|
take_while1(|c: char| c == '_' || c.is_alphanumeric())(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_comment_suffix<'a, E: ParseError<&'a str>>(
|
||||||
|
i: &'a str,
|
||||||
|
) -> IResult<&'a str, Option<&'a str>, E> {
|
||||||
|
opt(delimited(tag("//"), take_until("\n"), newline))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_parameter_names<'a, E: ParseError<&'a str>>(
|
||||||
|
i: &'a str,
|
||||||
|
) -> IResult<&'a str, Vec<&'a str>, E> {
|
||||||
|
delimited(
|
||||||
|
char('('),
|
||||||
|
separated_list1(tag(", "), parse_c_identifier),
|
||||||
|
char(')'),
|
||||||
|
)(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a C macro define optionally prefixed by a comment and optionally
|
||||||
|
/// containing parameter names. The expression is left in the remainder
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn parse_c_define_header<'a, E: ParseError<&'a str>>(
|
||||||
|
i: &'a str,
|
||||||
|
) -> IResult<&'a str, (Option<&'a str>, (&'a str, Option<Vec<&'a str>>)), E> {
|
||||||
|
(pair(
|
||||||
|
parse_comment_suffix,
|
||||||
|
preceded(
|
||||||
|
tag("#define "),
|
||||||
|
pair(parse_c_identifier, opt(parse_parameter_names)),
|
||||||
|
),
|
||||||
|
))(i)
|
||||||
|
}
|
||||||
|
|
||||||
fn khronos_link<S: Display + ?Sized>(name: &S) -> Literal {
|
fn khronos_link<S: Display + ?Sized>(name: &S) -> Literal {
|
||||||
Literal::string(&format!(
|
Literal::string(&format!(
|
||||||
"<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/{name}.html>"
|
"<https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/{name}.html>"
|
||||||
|
@ -1094,35 +1125,33 @@ pub fn generate_extension<'a>(
|
||||||
Some(q)
|
Some(q)
|
||||||
}
|
}
|
||||||
pub fn generate_define(
|
pub fn generate_define(
|
||||||
define: &vkxml::Define,
|
define: &vk_parse::Type,
|
||||||
identifier_renames: &mut BTreeMap<String, Ident>,
|
identifier_renames: &mut BTreeMap<String, Ident>,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let name = constant_name(&define.name);
|
let vk_parse::TypeSpec::Code(spec) = &define.spec else {
|
||||||
|
return quote!();
|
||||||
|
};
|
||||||
|
let [vk_parse::TypeCodeMarkup::Name(define_name), ..] = &spec.markup[..] else {
|
||||||
|
return quote!();
|
||||||
|
};
|
||||||
|
let name = constant_name(define_name);
|
||||||
let ident = format_ident!("{}", name);
|
let ident = format_ident!("{}", name);
|
||||||
|
|
||||||
if name == "NULL_HANDLE" {
|
if define_name.contains("VERSION") && !spec.code.contains("//#define") {
|
||||||
quote!()
|
let link = khronos_link(define_name);
|
||||||
} else if let Some(value) = &define.value {
|
let (c_expr, (comment, (_name, parameters))) =
|
||||||
str::parse::<u32>(value).map_or(quote!(), |v| quote!(pub const #ident: u32 = #v;))
|
parse_c_define_header::<VerboseError<&str>>(&spec.code).unwrap();
|
||||||
} else if let Some(c_expr) = &define.c_expression {
|
let c_expr = c_expr.trim().trim_start_matches('\\');
|
||||||
if define.name.contains(&"VERSION".to_string()) {
|
|
||||||
let link = khronos_link(&define.name);
|
|
||||||
let c_expr = c_expr.trim_start_matches('\\');
|
|
||||||
let c_expr = c_expr.replace("(uint32_t)", "");
|
let c_expr = c_expr.replace("(uint32_t)", "");
|
||||||
let c_expr = convert_c_expression(&c_expr, identifier_renames);
|
let c_expr = convert_c_expression(&c_expr, identifier_renames);
|
||||||
let c_expr = discard_outmost_delimiter(c_expr);
|
let c_expr = discard_outmost_delimiter(c_expr);
|
||||||
|
|
||||||
let deprecated = define
|
let deprecated = comment
|
||||||
.comment
|
.and_then(|c| c.trim().strip_prefix("DEPRECATED: "))
|
||||||
.as_ref()
|
.map(|comment| (quote!(#[deprecated = #comment])));
|
||||||
.and_then(|c| c.strip_prefix("DEPRECATED: "))
|
|
||||||
.map(|comment| quote!(#[deprecated = #comment]));
|
|
||||||
|
|
||||||
let (code, ident) = if define.parameters.is_empty() {
|
let (code, ident) = if let Some(parameters) = parameters {
|
||||||
(quote!(pub const #ident: u32 = #c_expr;), ident)
|
let params = parameters
|
||||||
} else {
|
|
||||||
let params = define
|
|
||||||
.parameters
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| format_ident!("{}", param))
|
.map(|param| format_ident!("{}", param))
|
||||||
.map(|i| quote!(#i: u32));
|
.map(|i| quote!(#i: u32));
|
||||||
|
@ -1131,9 +1160,11 @@ pub fn generate_define(
|
||||||
quote!(pub const fn #ident(#(#params),*) -> u32 { #c_expr }),
|
quote!(pub const fn #ident(#(#params),*) -> u32 { #c_expr }),
|
||||||
ident,
|
ident,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
(quote!(pub const #ident: u32 = #c_expr;), ident)
|
||||||
};
|
};
|
||||||
|
|
||||||
identifier_renames.insert(define.name.clone(), ident);
|
identifier_renames.insert(define_name.clone(), ident);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#deprecated
|
#deprecated
|
||||||
|
@ -1143,9 +1174,6 @@ pub fn generate_define(
|
||||||
} else {
|
} else {
|
||||||
quote!()
|
quote!()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
quote!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn generate_typedef(typedef: &vkxml::Typedef) -> TokenStream {
|
pub fn generate_typedef(typedef: &vkxml::Typedef) -> TokenStream {
|
||||||
if typedef.basetype.is_empty() {
|
if typedef.basetype.is_empty() {
|
||||||
|
@ -2133,6 +2161,15 @@ pub fn root_structs(definitions: &[&vkxml::DefinitionsElement]) -> HashSet<Ident
|
||||||
}
|
}
|
||||||
root_structs
|
root_structs
|
||||||
}
|
}
|
||||||
|
pub fn generate_definition_vk_parse(
|
||||||
|
definition: &vk_parse::Type,
|
||||||
|
identifier_renames: &mut BTreeMap<String, Ident>,
|
||||||
|
) -> Option<TokenStream> {
|
||||||
|
match definition.category.as_deref() {
|
||||||
|
Some("define") => Some(generate_define(definition, identifier_renames)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn generate_definition(
|
pub fn generate_definition(
|
||||||
definition: &vkxml::DefinitionsElement,
|
definition: &vkxml::DefinitionsElement,
|
||||||
union_types: &HashSet<&str>,
|
union_types: &HashSet<&str>,
|
||||||
|
@ -2140,12 +2177,8 @@ pub fn generate_definition(
|
||||||
has_lifetimes: &HashSet<Ident>,
|
has_lifetimes: &HashSet<Ident>,
|
||||||
bitflags_cache: &mut HashSet<Ident>,
|
bitflags_cache: &mut HashSet<Ident>,
|
||||||
const_values: &mut BTreeMap<Ident, ConstantTypeInfo>,
|
const_values: &mut BTreeMap<Ident, ConstantTypeInfo>,
|
||||||
identifier_renames: &mut BTreeMap<String, Ident>,
|
|
||||||
) -> Option<TokenStream> {
|
) -> Option<TokenStream> {
|
||||||
match *definition {
|
match *definition {
|
||||||
vkxml::DefinitionsElement::Define(ref define) => {
|
|
||||||
Some(generate_define(define, identifier_renames))
|
|
||||||
}
|
|
||||||
vkxml::DefinitionsElement::Typedef(ref typedef) => Some(generate_typedef(typedef)),
|
vkxml::DefinitionsElement::Typedef(ref typedef) => Some(generate_typedef(typedef)),
|
||||||
vkxml::DefinitionsElement::Struct(ref struct_) => Some(generate_struct(
|
vkxml::DefinitionsElement::Struct(ref struct_) => Some(generate_struct(
|
||||||
struct_,
|
struct_,
|
||||||
|
@ -2576,11 +2609,22 @@ pub fn write_source_code<P: AsRef<Path>>(vk_headers_dir: &Path, src_dir: P) {
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
let vk_parse_definitions: Vec<_> = spec2
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.filter_map(get_variant!(vk_parse::RegistryChild::Types))
|
||||||
|
.flat_map(|ty| {
|
||||||
|
ty.children
|
||||||
|
.iter()
|
||||||
|
.filter_map(get_variant!(vk_parse::TypesChild::Type))
|
||||||
|
})
|
||||||
|
.filter_map(|def| generate_definition_vk_parse(def, &mut identifier_renames))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let root_structs = root_structs(&definitions);
|
let root_structs = root_structs(&definitions);
|
||||||
let definition_code: Vec<_> = definitions
|
let definition_code: Vec<_> = vk_parse_definitions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|def| {
|
.chain(definitions.into_iter().filter_map(|def| {
|
||||||
generate_definition(
|
generate_definition(
|
||||||
def,
|
def,
|
||||||
&union_types,
|
&union_types,
|
||||||
|
@ -2588,9 +2632,8 @@ pub fn write_source_code<P: AsRef<Path>>(vk_headers_dir: &Path, src_dir: P) {
|
||||||
&has_lifetimes,
|
&has_lifetimes,
|
||||||
&mut bitflags_cache,
|
&mut bitflags_cache,
|
||||||
&mut const_values,
|
&mut const_values,
|
||||||
&mut identifier_renames,
|
|
||||||
)
|
)
|
||||||
})
|
}))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut ty_cache = HashSet::new();
|
let mut ty_cache = HashSet::new();
|
||||||
|
|
Loading…
Reference in a new issue