Add parser support for hyphenated IDs in arguments (#425)

The syntax description for [`cp.async`](https://docs.nvidia.com/cuda/parallel-thread-execution/#data-movement-and-conversion-instructions-cp-async) has several elements not supported by the current parser. One such element is that the `cp-size` and `src-size` operands have hyphens in their IDs. This PR adds support for these IDs, and translates them as `cp_size` and `src_size`
This commit is contained in:
Violet
2025-07-18 13:45:09 -07:00
committed by GitHub
parent 2f27c47acc
commit f5712d9d5a
2 changed files with 66 additions and 11 deletions

View File

@ -197,7 +197,7 @@ impl SingleOpcodeDefinition {
}) })
}) })
.chain(self.arguments.0.iter().map(|arg| { .chain(self.arguments.0.iter().map(|arg| {
let name = &arg.ident; let name = &arg.ident.ident();
let arg_type = if arg.unified { let arg_type = if arg.unified {
quote! { (ParsedOperandStr<'input>, bool) } quote! { (ParsedOperandStr<'input>, bool) }
} else if arg.can_be_negated { } else if arg.can_be_negated {
@ -225,7 +225,7 @@ impl SingleOpcodeDefinition {
}) })
}) })
.chain(self.arguments.0.iter().map(|arg| { .chain(self.arguments.0.iter().map(|arg| {
let name = &arg.ident; let name = &arg.ident.ident();
quote! { #name } quote! { #name }
})) }))
} }
@ -817,7 +817,7 @@ fn emit_definition_parser(
let pattern = quote! { let pattern = quote! {
(#comma, #pre_bracket, #pre_pipe, #can_be_negated, #operand, #post_bracket, #unified) (#comma, #pre_bracket, #pre_pipe, #can_be_negated, #operand, #post_bracket, #unified)
}; };
let arg_name = &arg.ident; let arg_name = &arg.ident.ident();
if arg.unified && arg.can_be_negated { if arg.unified && arg.can_be_negated {
panic!("TODO: argument can't be both prefixed by `!` and suffixed by `.unified`") panic!("TODO: argument can't be both prefixed by `!` and suffixed by `.unified`")
} }

View File

@ -394,6 +394,45 @@ impl Parse for DotModifier {
} }
} }
#[derive(PartialEq, Eq)]
pub struct HyphenatedIdent {
idents: Punctuated<Ident, Token![-]>,
}
impl HyphenatedIdent {
fn span(&self) -> Span {
self.idents.span()
}
pub fn ident(&self) -> Ident {
Ident::new(&self.to_string().to_string(), self.span())
}
}
impl std::fmt::Display for HyphenatedIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut idents = self.idents.iter();
if let Some(id) = idents.next() {
write!(f, "{}", id)?;
}
for id in idents {
write!(f, "_{}", id)?;
}
Ok(())
}
}
impl Parse for HyphenatedIdent {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let idents = Punctuated::parse_separated_nonempty(input)?;
Ok(Self { idents })
}
}
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
enum IdentLike { enum IdentLike {
Type(Token![type]), Type(Token![type]),
@ -452,7 +491,7 @@ impl Parse for IdentLike {
} }
} }
// Arguments decalaration can loook like this: // Arguments declaration can loook like this:
// a{, b} // a{, b}
// That's why we don't parse Arguments as Punctuated<Argument, Token![,]> // That's why we don't parse Arguments as Punctuated<Argument, Token![,]>
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
@ -477,11 +516,11 @@ impl Parse for Arguments {
if lookahead.peek(Token![!]) { if lookahead.peek(Token![!]) {
content.parse::<Token![!]>()?; content.parse::<Token![!]>()?;
can_be_negated = true; can_be_negated = true;
ident = input.parse::<Ident>()?; ident = input.parse::<HyphenatedIdent>()?;
} else if lookahead.peek(Token![,]) { } else if lookahead.peek(Token![,]) {
optional = true; optional = true;
content.parse::<Token![,]>()?; content.parse::<Token![,]>()?;
ident = content.parse::<Ident>()?; ident = content.parse::<HyphenatedIdent>()?;
} else { } else {
return Err(lookahead.error()); return Err(lookahead.error());
} }
@ -492,7 +531,7 @@ impl Parse for Arguments {
optional = true; optional = true;
bracketed.parse::<Token![|]>()?; bracketed.parse::<Token![|]>()?;
pre_pipe = true; pre_pipe = true;
ident = bracketed.parse::<Ident>()?; ident = bracketed.parse::<HyphenatedIdent>()?;
} else { } else {
let mut sub_args = Self::parse(&bracketed)?; let mut sub_args = Self::parse(&bracketed)?;
sub_args.0.first_mut().unwrap().pre_bracket = true; sub_args.0.first_mut().unwrap().pre_bracket = true;
@ -505,7 +544,7 @@ impl Parse for Arguments {
if unified_ident.to_string() != "unified" { if unified_ident.to_string() != "unified" {
return Err(syn::Error::new( return Err(syn::Error::new(
unified_ident.span(), unified_ident.span(),
format!("Exptected `unified`, got `{}`", unified_ident), format!("Expected `unified`, got `{}`", unified_ident),
)); ));
} }
for a in sub_args.0.iter_mut() { for a in sub_args.0.iter_mut() {
@ -516,11 +555,11 @@ impl Parse for Arguments {
continue; continue;
} }
} else if lookahead.peek(Ident) { } else if lookahead.peek(Ident) {
ident = input.parse::<Ident>()?; ident = input.parse::<HyphenatedIdent>()?;
} else if lookahead.peek(Token![|]) { } else if lookahead.peek(Token![|]) {
input.parse::<Token![|]>()?; input.parse::<Token![|]>()?;
pre_pipe = true; pre_pipe = true;
ident = input.parse::<Ident>()?; ident = input.parse::<HyphenatedIdent>()?;
} else { } else {
break; break;
} }
@ -555,7 +594,7 @@ pub struct Argument {
pub pre_bracket: bool, pub pre_bracket: bool,
pub pre_pipe: bool, pub pre_pipe: bool,
pub can_be_negated: bool, pub can_be_negated: bool,
pub ident: Ident, pub ident: HyphenatedIdent,
pub post_bracket: bool, pub post_bracket: bool,
pub unified: bool, pub unified: bool,
} }
@ -843,6 +882,22 @@ mod tests {
assert!(a.unified); assert!(a.unified);
} }
#[test]
fn args_hyphenated() {
let input = quote! {
d, cp-size, b
};
let args = syn::parse2::<super::Arguments>(input).unwrap();
let cp_size = &args.0[1];
assert!(!cp_size.optional);
assert_eq!("cp_size", cp_size.ident.to_string());
assert!(!cp_size.pre_bracket);
assert!(!cp_size.pre_pipe);
assert!(!cp_size.post_bracket);
assert!(!cp_size.can_be_negated);
assert!(!cp_size.unified);
}
#[test] #[test]
fn special_block() { fn special_block() {
let input = quote! { let input = quote! {