Clean up and improve ident parsing

This commit is contained in:
Andrzej Janik 2024-08-15 18:51:11 +02:00
parent 8d7c88c095
commit dbd37f97ad
3 changed files with 84 additions and 84 deletions

View file

@ -55,6 +55,7 @@ impl OpcodeDefinitions {
let candidate = if let DotModifierRef::Direct {
optional: false,
value,
..
} = candidate
{
value
@ -227,11 +228,13 @@ impl SingleOpcodeDefinition {
DotModifierRef::Direct {
optional,
value: alts.alternatives[0].clone(),
name: modifier,
}
} else {
DotModifierRef::Indirect {
optional,
value: alts.clone(),
name: modifier,
}
}
}
@ -239,7 +242,8 @@ impl SingleOpcodeDefinition {
possible_modifiers.insert(modifier.clone());
DotModifierRef::Direct {
optional,
value: modifier,
value: modifier.clone(),
name: modifier,
}
}
},
@ -306,8 +310,9 @@ pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
})
.collect::<FxHashMap<_, _>>();
let mut token_enum = parse_definitions.token_type;
let (_, all_modifier) = write_definitions_into_tokens(&definitions, &mut token_enum.variants);
let token_impl = emit_parse_function(&token_enum.ident, &definitions, all_modifier);
let (all_opcode, all_modifier) =
write_definitions_into_tokens(&definitions, &mut token_enum.variants);
let token_impl = emit_parse_function(&token_enum.ident, &definitions, all_opcode, all_modifier);
let tokens = quote! {
#enum_types_tokens
@ -364,6 +369,7 @@ fn emit_enum_types(
fn emit_parse_function(
type_name: &Ident,
defs: &FxHashMap<Ident, OpcodeDefinitions>,
all_opcode: Vec<&Ident>,
all_modifier: FxHashSet<&parser::DotModifier>,
) -> TokenStream {
use std::fmt::Write;
@ -437,9 +443,24 @@ fn emit_parse_function(
.to_tokens(&mut result);
result
});
let opcodes = all_opcode.into_iter().map(|op_ident| {
let op = op_ident.to_string();
let variant = Ident::new(&capitalize(&op), op_ident.span());
let value = op;
quote! {
#type_name :: #variant => Some(#value),
}
});
let modifier_names = all_modifier.iter().map(|m| m.dot_capitalized());
quote! {
impl<'input> #type_name<'input> {
fn opcode_text(self) -> Option<&'static str> {
match self {
#(#opcodes)*
_ => None
}
}
fn modifier(self) -> bool {
match self {
#(
@ -452,7 +473,7 @@ fn emit_parse_function(
#(#fns_)*
fn parse_instruction<'a, 'input>(stream: &mut ParserState<'a, 'input>) -> winnow::error::PResult<Instruction<ParsedOperand<'input>>>
fn parse_instruction<'a, 'input>(stream: &mut ParserState<'a, 'input>) -> winnow::error::PResult<Instruction<ParsedOperand<'input>>>
{
use winnow::Parser;
use winnow::token::*;
@ -490,9 +511,8 @@ fn emit_definition_parser(
});
let ordered_parse = definition.ordered_modifiers.iter().rev().map(|modifier| {
let arg_name = modifier.ident();
let arg_type = modifier.type_of();
match modifier {
DotModifierRef::Direct { optional, value } => {
DotModifierRef::Direct { optional, value, .. } => {
let variant = value.dot_capitalized();
if *optional {
quote! {
@ -504,7 +524,7 @@ fn emit_definition_parser(
}
}
}
DotModifierRef::Indirect { optional, value } => {
DotModifierRef::Indirect { optional, value, .. } => {
let variants = value.alternatives.iter().map(|alt| {
let type_ = value.type_.as_ref().unwrap();
let token_variant = alt.dot_capitalized();
@ -546,8 +566,8 @@ fn emit_definition_parser(
.unordered_modifiers
.iter()
.map(|modifier| match modifier {
DotModifierRef::Direct { value, .. } => {
let name = value.ident();
DotModifierRef::Direct { name, value, .. } => {
let name = name.ident();
let token_variant = value.dot_capitalized();
quote! {
#token_type :: #token_variant => {
@ -558,8 +578,8 @@ fn emit_definition_parser(
}
}
}
DotModifierRef::Indirect { value, .. } => {
let variable = value.modifier.ident();
DotModifierRef::Indirect { value, name, .. } => {
let variable = name.ident();
let type_ = value.type_.as_ref().unwrap();
let alternatives = value.alternatives.iter().map(|alt| {
let token_variant = alt.dot_capitalized();
@ -585,9 +605,10 @@ fn emit_definition_parser(
.map(|modifier| match modifier {
DotModifierRef::Direct {
optional: false,
value,
name,
..
} => {
let variable = value.ident();
let variable = name.ident();
quote! {
if !#variable {
#return_error;
@ -597,9 +618,10 @@ fn emit_definition_parser(
DotModifierRef::Direct { optional: true, .. } => TokenStream::new(),
DotModifierRef::Indirect {
optional: false,
value,
name,
..
} => {
let variable = value.modifier.ident();
let variable = name.ident();
quote! {
let #variable = match #variable {
Some(x) => x,
@ -749,9 +771,11 @@ enum DotModifierRef {
Direct {
optional: bool,
value: parser::DotModifier,
name: parser::DotModifier,
},
Indirect {
optional: bool,
name: parser::DotModifier,
value: Rc<parser::Rule>,
},
}
@ -759,8 +783,8 @@ enum DotModifierRef {
impl DotModifierRef {
fn ident(&self) -> Ident {
match self {
DotModifierRef::Direct { value, .. } => value.ident(),
DotModifierRef::Indirect { value, .. } => value.modifier.ident(),
DotModifierRef::Direct { name, .. } => name.ident(),
DotModifierRef::Indirect { name, .. } => name.ident(),
}
}
@ -770,7 +794,9 @@ impl DotModifierRef {
DotModifierRef::Direct {
optional: false, ..
} => return None,
DotModifierRef::Indirect { optional, value } => {
DotModifierRef::Indirect {
optional, value, ..
} => {
let type_ = value
.type_
.as_ref()
@ -798,55 +824,6 @@ impl DotModifierRef {
}
}
impl Hash for DotModifierRef {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
DotModifierRef::Direct { optional, value } => {
optional.hash(state);
value.hash(state);
}
DotModifierRef::Indirect { optional, value } => {
optional.hash(state);
(value.as_ref() as *const parser::Rule).hash(state);
}
}
}
}
impl PartialEq for DotModifierRef {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
Self::Direct {
optional: l_optional,
value: l_value,
},
Self::Direct {
optional: r_optional,
value: r_value,
},
) => l_optional == r_optional && l_value == r_value,
(
Self::Indirect {
optional: l_optional,
value: l_value,
},
Self::Indirect {
optional: r_optional,
value: r_value,
},
) => {
l_optional == r_optional
&& l_value.as_ref() as *const parser::Rule
== r_value.as_ref() as *const parser::Rule
}
_ => false,
}
}
}
impl Eq for DotModifierRef {}
#[proc_macro]
pub fn generate_instruction_type(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(tokens as gen_impl::GenerateInstructionType);

View file

@ -7,6 +7,7 @@ use std::fmt::Write;
use syn::bracketed;
use syn::parse::Peek;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::LitInt;
use syn::Type;
use syn::{braced, parse::Parse, token, Ident, ItemEnum, Token};
@ -155,6 +156,10 @@ impl Rule {
struct IdentOrTypeSuffix(IdentLike);
impl IdentOrTypeSuffix {
fn span(&self) -> Span {
self.0.span()
}
fn peek(input: syn::parse::ParseStream) -> bool {
input.peek(Token![::])
}
@ -278,6 +283,15 @@ impl std::fmt::Debug for DotModifier {
}
impl DotModifier {
pub fn span(&self) -> Span {
let part1 = self.part1.span();
if let Some(ref part2) = self.part2 {
part1.join(part2.span()).unwrap_or(part1)
} else {
part1
}
}
pub fn ident(&self) -> Ident {
let mut result = String::new();
write!(&mut result, "{}", self.part1).unwrap();
@ -285,11 +299,11 @@ impl DotModifier {
write!(&mut result, "_{}", part2.0).unwrap();
} else {
match self.part1 {
IdentLike::Type | IdentLike::Const => result.push('_'),
IdentLike::Type(_) | IdentLike::Const(_) => result.push('_'),
IdentLike::Ident(_) | IdentLike::Integer(_) => {}
}
}
Ident::new(&result.to_ascii_lowercase(), Span::call_site())
Ident::new(&result.to_ascii_lowercase(), self.span())
}
pub fn variant_capitalized(&self) -> Ident {
@ -321,7 +335,7 @@ impl DotModifier {
};
result.push(c);
}
Ident::new(&result, Span::call_site())
Ident::new(&result, self.span())
}
pub fn tokens(&self) -> TokenStream {
@ -353,17 +367,28 @@ impl Parse for DotModifier {
#[derive(PartialEq, Eq, Hash, Clone)]
enum IdentLike {
Type,
Const,
Type(Token![type]),
Const(Token![const]),
Ident(Ident),
Integer(LitInt),
}
impl IdentLike {
fn span(&self) -> Span {
match self {
IdentLike::Type(c) => c.span(),
IdentLike::Const(t) => t.span(),
IdentLike::Ident(i) => i.span(),
IdentLike::Integer(l) => l.span(),
}
}
}
impl std::fmt::Display for IdentLike {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IdentLike::Type => f.write_str("type"),
IdentLike::Const => f.write_str("const"),
IdentLike::Type(_) => f.write_str("type"),
IdentLike::Const(_) => f.write_str("const"),
IdentLike::Ident(ident) => write!(f, "{}", ident),
IdentLike::Integer(integer) => write!(f, "{}", integer),
}
@ -373,8 +398,8 @@ impl std::fmt::Display for IdentLike {
impl ToTokens for IdentLike {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
IdentLike::Type => quote! { type }.to_tokens(tokens),
IdentLike::Const => quote! { const }.to_tokens(tokens),
IdentLike::Type(_) => quote! { type }.to_tokens(tokens),
IdentLike::Const(_) => quote! { const }.to_tokens(tokens),
IdentLike::Ident(ident) => quote! { #ident }.to_tokens(tokens),
IdentLike::Integer(int) => quote! { #int }.to_tokens(tokens),
}
@ -385,11 +410,9 @@ impl Parse for IdentLike {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
Ok(if lookahead.peek(Token![const]) {
input.parse::<Token![const]>()?;
IdentLike::Const
IdentLike::Const(input.parse::<Token![const]>()?)
} else if lookahead.peek(Token![type]) {
input.parse::<Token![type]>()?;
IdentLike::Type
IdentLike::Type(input.parse::<Token![type]>()?)
} else if lookahead.peek(Ident) {
IdentLike::Ident(input.parse::<Ident>()?)
} else if lookahead.peek(LitInt) {

View file

@ -2,9 +2,8 @@ use gen::derive_parser;
use logos::Logos;
use std::mem;
use std::num::{ParseFloatError, ParseIntError};
use winnow::combinator::{alt, empty, fail, opt};
use winnow::stream::SliceLen;
use winnow::token::{any, literal};
use winnow::combinator::*;
use winnow::token::any;
use winnow::{
error::{ContextError, ParserError},
stream::{Offset, Stream, StreamIsPartial},
@ -206,6 +205,8 @@ fn ident<'a, 'input>(stream: &mut ParserState<'a, 'input>) -> PResult<&'input st
any.verify_map(|t| {
if let Token::Ident(text) = t {
Some(text)
} else if let Some(text) = t.opcode_text() {
Some(text)
} else {
None
}
@ -563,7 +564,6 @@ derive_parser!(
pub enum ScalarType { }
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-mov
mov.type d, a => {
Instruction::Mov{
data: MovDetails::new(type_.into()),