Skip to content

Commit 3f1006b

Browse files
committed
refactor(ast_tools): parse attributes more deeply
1 parent f4662a9 commit 3f1006b

5 files changed

Lines changed: 65 additions & 34 deletions

File tree

tasks/ast_tools/src/generators/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
output::Output,
3-
parse::attr::{attr_positions, AttrLocation, AttrPart, AttrPositions},
3+
parse::attr::{attr_positions, AttrLocation, AttrPart, AttrPartListElement, AttrPositions},
44
Codegen, Result, Runner, Schema,
55
};
66

tasks/ast_tools/src/generators/visit.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ use cow_utils::CowUtils;
44
use oxc_index::IndexVec;
55
use proc_macro2::TokenStream;
66
use quote::{format_ident, quote, ToTokens};
7-
use syn::{parse_str, punctuated::Punctuated, token::Comma, Expr, Ident, Meta};
7+
use syn::{parse_str, Expr, Ident};
88

99
use crate::{
1010
output::{output_path, Output},
11-
parse::convert_expr_to_string,
1211
schema::{
1312
extensions::visit::Scope, Def, EnumDef, FieldDef, OptionDef, Schema, StructDef, TypeDef,
1413
TypeId, VecDef,
@@ -17,7 +16,9 @@ use crate::{
1716
Codegen, Generator, Result, AST_CRATE_PATH,
1817
};
1918

20-
use super::{attr_positions, define_generator, AttrLocation, AttrPart, AttrPositions};
19+
use super::{
20+
attr_positions, define_generator, AttrLocation, AttrPart, AttrPartListElement, AttrPositions,
21+
};
2122

2223
/// Generator for `Visit` and `VisitMut` traits.
2324
pub struct VisitGenerator;
@@ -72,21 +73,14 @@ fn parse_visit_attr(location: AttrLocation, part: AttrPart) -> Result<()> {
7273
enum_def.visit.is_visited = true;
7374
}
7475
// `#[visit(args(flags = ...))]` on struct field or enum variant
75-
(AttrPart::List("args", meta_list), location) => {
76-
// Parse args as a list of `x = expr` parts
77-
let metas = meta_list
78-
.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
79-
.map_err(|_| ())?;
80-
let mut args = vec![];
81-
for meta in metas {
82-
if let Meta::NameValue(name_value) = meta {
83-
let arg_name = name_value.path.get_ident().ok_or(())?.to_string();
84-
let arg_value = convert_expr_to_string(&name_value.value);
85-
args.push((arg_name, arg_value));
86-
} else {
87-
return Err(());
88-
}
89-
}
76+
(AttrPart::List("args", args), location) => {
77+
let args = args
78+
.into_iter()
79+
.map(|list_element| match list_element {
80+
AttrPartListElement::String(name, value) => Ok((name, value)),
81+
_ => Err(()),
82+
})
83+
.collect::<Result<Vec<(String, String)>>>()?;
9084
if args.is_empty() {
9185
return Err(());
9286
}

tasks/ast_tools/src/parse/attr.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::fmt::{self, Display};
22

33
use bitflags::bitflags;
4-
use syn::MetaList;
54

65
use crate::{
76
codegen::{DeriveId, GeneratorId},
@@ -146,5 +145,21 @@ pub enum AttrPart<'p> {
146145
String(&'p str, String),
147146
/// List part.
148147
/// e.g. `#[visit(args(flags = ScopeFlags::Function))]`.
149-
List(&'p str, &'p MetaList),
148+
List(&'p str, Vec<AttrPartListElement>),
149+
}
150+
151+
/// An element of an [`AttrPart::List`].
152+
#[derive(Debug)]
153+
pub enum AttrPartListElement {
154+
/// Named part.
155+
/// e.g. `qux` in `#[foo(bar(qux))]`.
156+
#[expect(dead_code)]
157+
Tag(String),
158+
/// String part.
159+
/// e.g. `flags = ScopeFlags::Function` in `#[visit(args(flags = ScopeFlags::Function))]`.
160+
String(String, String),
161+
/// List part.
162+
/// e.g. `qux(doof, bing = donk)` in `#[foo(bar(qux(doof, bing = donk)))]`.
163+
#[expect(dead_code)]
164+
List(String, Vec<AttrPartListElement>),
150165
}

tasks/ast_tools/src/parse/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ mod load;
6565
mod parse;
6666
mod skeleton;
6767
use load::load_file;
68-
pub use parse::convert_expr_to_string;
6968
use parse::parse;
7069
use skeleton::Skeleton;
7170

tasks/ast_tools/src/parse/parse.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use quote::ToTokens;
33
use rustc_hash::FxHashMap;
44
use syn::{
55
punctuated::Punctuated, token::Comma, AttrStyle, Attribute, Expr, ExprLit, Field, Fields,
6-
GenericArgument, Generics, Ident, ItemEnum, ItemStruct, Lit, Meta, PathArguments, PathSegment,
7-
Type, TypePath, TypeReference, Variant, Visibility as SynVisibility,
6+
GenericArgument, Generics, Ident, ItemEnum, ItemStruct, Lit, Meta, MetaList, PathArguments,
7+
PathSegment, Type, TypePath, TypeReference, Variant, Visibility as SynVisibility,
88
};
99

1010
use crate::{
@@ -17,7 +17,7 @@ use crate::{
1717
};
1818

1919
use super::{
20-
attr::{AttrLocation, AttrPart, AttrPositions, AttrProcessor},
20+
attr::{AttrLocation, AttrPart, AttrPartListElement, AttrPositions, AttrProcessor},
2121
ident_name,
2222
skeleton::{EnumSkeleton, Skeleton, StructSkeleton},
2323
Derives, FxIndexMap, FxIndexSet,
@@ -707,23 +707,24 @@ fn process_attr(
707707
AttrPart::Tag(&part_name),
708708
)?;
709709
}
710-
Meta::List(meta_list) => {
711-
let part_name = meta_list.path.get_ident().ok_or(())?.to_string();
710+
Meta::NameValue(name_value) => {
711+
let part_name = name_value.path.get_ident().ok_or(())?.to_string();
712+
let str = convert_expr_to_string(&name_value.value);
712713
process_attr_part(
713714
processor,
714715
attr_name,
715716
location.unpack(),
716-
AttrPart::List(&part_name, meta_list),
717+
AttrPart::String(&part_name, str),
717718
)?;
718719
}
719-
Meta::NameValue(name_value) => {
720-
let part_name = name_value.path.get_ident().ok_or(())?.to_string();
721-
let str = convert_expr_to_string(&name_value.value);
720+
Meta::List(meta_list) => {
721+
let part_name = meta_list.path.get_ident().ok_or(())?.to_string();
722+
let list = parse_attr_part_list(meta_list)?;
722723
process_attr_part(
723724
processor,
724725
attr_name,
725726
location.unpack(),
726-
AttrPart::String(&part_name, str),
727+
AttrPart::List(&part_name, list),
727728
)?;
728729
}
729730
};
@@ -734,12 +735,34 @@ fn process_attr(
734735
}
735736
}
736737

738+
fn parse_attr_part_list(meta_list: &MetaList) -> Result<Vec<AttrPartListElement>> {
739+
let metas =
740+
meta_list.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated).map_err(|_| ())?;
741+
metas
742+
.into_iter()
743+
.map(|meta| match meta {
744+
Meta::Path(path) => {
745+
let part_name = path.get_ident().ok_or(())?.to_string();
746+
Ok(AttrPartListElement::Tag(part_name))
747+
}
748+
Meta::NameValue(name_value) => {
749+
let part_name = name_value.path.get_ident().ok_or(())?.to_string();
750+
let str = convert_expr_to_string(&name_value.value);
751+
Ok(AttrPartListElement::String(part_name, str))
752+
}
753+
Meta::List(meta_list) => {
754+
let part_name = meta_list.path.get_ident().ok_or(())?.to_string();
755+
let list = parse_attr_part_list(&meta_list)?;
756+
Ok(AttrPartListElement::List(part_name, list))
757+
}
758+
})
759+
.collect()
760+
}
761+
737762
/// Convert an [`Expr`] to a string.
738763
///
739764
/// If the `Expr` is a string literal, get the value of the string.
740765
/// Otherwise print the `Expr` as a string.
741-
///
742-
/// This function is also used in `Visit` generator.
743766
pub fn convert_expr_to_string(expr: &Expr) -> String {
744767
if let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = expr {
745768
s.value()

0 commit comments

Comments
 (0)