Skip to content

Commit 449c1e3

Browse files
committed
implement (and use) precedence in parsing
1 parent 6cf0caa commit 449c1e3

File tree

6 files changed

+80
-33
lines changed

6 files changed

+80
-33
lines changed

crates/formality-macros/src/attrs.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use syn::{spanned::Spanned, Attribute, DeriveInput};
44

5-
use crate::custom::Customize;
5+
use crate::{custom::Customize, precedence::Precedence};
66

77
/// Checks for any kind of attribute that indicates an "is-a" relationship,
88
/// e.g. `#[cast]` and `#[variable]`.
@@ -39,30 +39,42 @@ pub(crate) fn has_variable_attr(attrs: &[Attribute]) -> bool {
3939
attrs.iter().any(|a| a.path().is_ident("variable"))
4040
}
4141

42+
/// Extract a `#[precedence]` level, defaults to 0
43+
pub(crate) fn precedence(attrs: &[Attribute]) -> syn::Result<Precedence> {
44+
parse_attr_named(attrs, "precedence")
45+
}
46+
4247
/// Extracts any customization attribute from a list of attributes.
4348
pub(crate) fn customize(attrs: &[Attribute]) -> syn::Result<Customize> {
44-
let mut v: Vec<Customize> = attrs
49+
parse_attr_named(attrs, "customize")
50+
}
51+
52+
fn parse_attr_named<T>(attrs: &[Attribute], name: &str) -> syn::Result<T>
53+
where
54+
T: Default + syn::parse::Parse,
55+
{
56+
let mut v: Vec<T> = attrs
4557
.iter()
46-
.filter(|a| a.path().is_ident("customize"))
58+
.filter(|a| a.path().is_ident(name))
4759
.map(|a| a.parse_args())
4860
.collect::<syn::Result<_>>()?;
4961

5062
if v.len() > 1 {
5163
Err(syn::Error::new(
5264
attrs
5365
.iter()
54-
.filter(|a| a.path().is_ident("customize"))
66+
.filter(|a| a.path().is_ident(name))
5567
.skip(1)
5668
.next()
5769
.unwrap()
5870
.path()
5971
.span(),
60-
"multiple customize attributes",
72+
format!("multiple `{}` attributes", name),
6173
))
6274
} else if v.len() == 1 {
6375
Ok(v.pop().unwrap())
6476
} else {
65-
Ok(Customize::default())
77+
Ok(T::default())
6678
}
6779
}
6880

@@ -82,5 +94,6 @@ fn remove_formality_attributes_from_vec(attrs: &mut Vec<Attribute>) {
8294
&& !attr.path().is_ident("cast")
8395
&& !attr.path().is_ident("variable")
8496
&& !attr.path().is_ident("customize")
97+
&& !attr.path().is_ident("precedence")
8598
});
8699
}

crates/formality-macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod debug;
1212
mod fixed_point;
1313
mod fold;
1414
mod parse;
15+
mod precedence;
1516
mod spec;
1617
mod term;
1718
mod test;

crates/formality-macros/src/parse.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
extern crate proc_macro;
2+
23
use convert_case::{Case, Casing};
34
use proc_macro2::{Ident, Literal, TokenStream};
45
use quote::{quote, quote_spanned};
56
use syn::{spanned::Spanned, Attribute};
67
use synstructure::BindingInfo;
78

89
use crate::{
9-
attrs::{has_cast_attr, has_variable_attr},
10+
attrs::{has_cast_attr, has_variable_attr, precedence},
1011
spec::{self, FieldMode, FormalitySpec},
1112
};
1213

@@ -40,13 +41,11 @@ pub(crate) fn derive_parse_with_spec(
4041
for variant in s.variants() {
4142
let variant_name = as_literal(variant.ast().ident);
4243
let v = parse_variant(variant, external_spec)?;
43-
parse_variants.extend(quote! {
44-
{
45-
let __span = tracing::span!(tracing::Level::TRACE, "parse", variant_name = #variant_name);
46-
let __guard = __span.enter();
47-
__parser.parse_variant(#variant_name, 0, |__p| { #v });
48-
}
49-
});
44+
let precedence = precedence(&variant.ast().attrs)?.literal();
45+
parse_variants.extend(quote_spanned!(
46+
variant.ast().ident.span() =>
47+
__parser.parse_variant(#variant_name, #precedence, |__p| { #v });
48+
));
5049
}
5150

5251
let type_name: Literal = as_literal(&s.ast().ident);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use std::str::FromStr;
2+
3+
use proc_macro2::{Literal, TokenStream};
4+
use syn::spanned::Spanned;
5+
6+
#[derive(Default, Debug)]
7+
pub(crate) struct Precedence {
8+
pub level: usize,
9+
}
10+
11+
impl Precedence {
12+
pub fn literal(&self) -> Literal {
13+
Literal::usize_unsuffixed(self.level)
14+
}
15+
}
16+
17+
impl syn::parse::Parse for Precedence {
18+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
19+
let token_stream: TokenStream = input.parse()?;
20+
let span = token_stream.span();
21+
let mut tokens = token_stream.into_iter();
22+
23+
let Some(token) = tokens.next() else {
24+
return Err(syn::Error::new(span, "precedence expected"));
25+
};
26+
27+
let level;
28+
match token {
29+
proc_macro2::TokenTree::Literal(l) => {
30+
let l_str = l.to_string();
31+
match usize::from_str(&l_str) {
32+
Ok(l) => level = l,
33+
Err(_) => return Err(syn::Error::new(l.span(), "integer precedence expected")),
34+
}
35+
}
36+
37+
_ => {
38+
return Err(syn::Error::new(
39+
token.span(),
40+
"unexpected token in precedence",
41+
));
42+
}
43+
}
44+
45+
if let Some(token) = tokens.next() {
46+
return Err(syn::Error::new(token.span(), "extra tokens"));
47+
}
48+
49+
Ok(Precedence { level })
50+
}
51+
}

crates/formality-types/src/grammar/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ impl DowncastTo<TyData> for Ty {
9999
// NB: TyData doesn't implement Fold; you fold types, not TyData,
100100
// because variables might not map to the same variant.
101101
#[term]
102-
#[customize(parse)]
103102
pub enum TyData {
104103
#[cast]
105104
RigidTy(RigidTy),
@@ -108,6 +107,7 @@ pub enum TyData {
108107
#[cast]
109108
PredicateTy(PredicateTy),
110109
#[variable]
110+
#[precedence(1)]
111111
Variable(Variable),
112112
}
113113

crates/formality-types/src/grammar/ty/parse_impls.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,10 @@ use formality_core::{seq, Set};
66

77
use crate::grammar::{AdtId, AssociatedItemId, Bool, Const, RefKind, RigidName, Scalar, TraitId};
88

9-
use super::{
10-
AliasTy, AssociatedTyName, Lt, LtData, Parameter, PredicateTy, RigidTy, ScalarId, Ty, TyData,
11-
};
9+
use super::{AliasTy, AssociatedTyName, Lt, LtData, Parameter, RigidTy, ScalarId, Ty};
1210

1311
use crate::rust::FormalityLang as Rust;
1412

15-
// ANCHOR: ty_parse_impl
16-
// For types, we invest some effort into parsing them decently because it makes
17-
// writing tests so much more pleasant.
18-
impl CoreParse<Rust> for TyData {
19-
fn parse<'t>(scope: &Scope<Rust>, text0: &'t str) -> ParseResult<'t, Self> {
20-
let mut parser = Parser::new(scope, text0, "Ty");
21-
parser.parse_variant("Variable", 1, |p| p.variable());
22-
parser.parse_variant_cast::<RigidTy>(0);
23-
parser.parse_variant_cast::<AliasTy>(0);
24-
parser.parse_variant_cast::<PredicateTy>(0);
25-
parser.finish()
26-
}
27-
}
28-
// ANCHOR_END: ty_parse_impl
29-
3013
impl CoreParse<Rust> for RigidTy {
3114
fn parse<'t>(scope: &Scope<Rust>, text: &'t str) -> ParseResult<'t, Self> {
3215
let mut parser: Parser<'_, '_, RigidTy, Rust> = Parser::new(scope, text, "AliasTy");

0 commit comments

Comments
 (0)