Skip to content
This repository has been archived by the owner on Jun 8, 2024. It is now read-only.

Commit

Permalink
work on error reporting for uncaptured and uninterpolated key values
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Nov 26, 2023
1 parent e1ece0b commit f93c4cf
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 33 deletions.
6 changes: 3 additions & 3 deletions macros/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ impl Parse for TemplateArgs {
}

pub fn expand_template_tokens(opts: ExpandTemplateTokens) -> Result<TokenStream, syn::Error> {
let (_, template, props) = template::parse2::<TemplateArgs>(opts.input)?;
let (_, template, props) = template::parse2::<TemplateArgs>(opts.input, false)?;

// Ensure that a standalone template only specifies identifiers
for key_value in props.iter() {
if key_value.has_expr {
if !key_value.interpolated {
return Err(syn::Error::new(
key_value.span(),
"key-values in raw templates cannot capture values",
"key-values in raw templates must be in the template itself",
));
}
}
Expand Down
13 changes: 10 additions & 3 deletions macros/src/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub fn key_value_with_hook(
attrs: &[Attribute],
fv: &FieldValue,
interpolated: bool,
captured: bool,
) -> TokenStream {
let fn_name = match &*fv.key_name() {
emit_core::well_known::LVL_KEY => quote_spanned!(fv.span()=> __private_capture_as_level),
Expand All @@ -60,10 +61,16 @@ pub fn key_value_with_hook(
quote!(.__private_uninterpolated())
};

let captured_expr = if captured {
quote!(.__private_captured())
} else {
quote!(.__private_uncaptured())
};

let key_tokens = key::key_with_hook(&[], &key_expr);
let value_tokens = quote_spanned!(fv.span()=> {
use emit::__private::{__PrivateCaptureHook as _, __PrivateOptionalCaptureHook as _, __PrivateOptionalMapHook as _, __PrivateInterpolatedHook as _};
(#expr).__private_optional_capture_some().__private_optional_map_some(|v| v.#fn_name())#interpolated_expr
(#expr).__private_optional_capture_some().__private_optional_map_some(|v| v.#fn_name()) #interpolated_expr #captured_expr
});

quote_spanned!(fv.span()=>
Expand All @@ -90,10 +97,10 @@ pub fn rename_hook_tokens(
args: opts.args,
expr: opts.expr,
predicate: |ident: &str| {
ident.starts_with("__private_capture") || ident.starts_with("__private_interpolated")
ident.starts_with("__private_capture") || ident.starts_with("__private_captured")
},
to: move |args: &Args, ident: &Ident, _: &Punctuated<Expr, Comma>| {
if ident.to_string().starts_with("__private_interpolated") {
if ident.to_string().starts_with("__private_captured") {
return None;
}

Expand Down
18 changes: 11 additions & 7 deletions macros/src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,25 @@ impl Parse for Args {
}

pub fn expand_tokens(opts: ExpandTokens) -> Result<TokenStream, syn::Error> {
let (args, template, mut props) = template::parse2::<Args>(opts.input)?;
let (args, template, mut props) = template::parse2::<Args>(opts.input, true)?;

// Add the level as a property
let level_ident = Ident::new(emit_core::well_known::LVL_KEY, Span::call_site());
let level_value = opts.level;

props.push(&syn::parse2::<FieldValue>(
quote!(#level_ident: emit::Level::#level_value),
)?)?;
props.push(
&syn::parse2::<FieldValue>(quote!(#level_ident: emit::Level::#level_value))?,
false,
true,
)?;

// Add the location as a property
let loc_ident = Ident::new(emit_core::well_known::LOCATION_KEY, Span::call_site());
props.push(&syn::parse2::<FieldValue>(
quote!(#loc_ident: emit::__private::loc!()),
)?)?;
props.push(
&syn::parse2::<FieldValue>(quote!(#loc_ident: emit::__private::loc!()))?,
false,
true,
)?;

let props_match_input_tokens = props.match_input_tokens();
let props_match_binding_tokens = props.match_binding_tokens();
Expand Down
9 changes: 8 additions & 1 deletion macros/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ pub fn template_hole_with_hook(
attrs: &[Attribute],
hole: &ExprLit,
interpolated: bool,
captured: bool,
) -> TokenStream {
let interpolated_expr = if interpolated {
quote!(.__private_interpolated())
} else {
quote!(.__private_uninterpolated())
};

let captured_expr = if captured {
quote!(.__private_captured())
} else {
quote!(.__private_uncaptured())
};

quote_spanned!(hole.span()=>
#(#attrs)*
{
use emit::__private::{__PrivateFmtHook as _, __PrivateInterpolatedHook as _};
emit::template::Part::hole(#hole).__private_fmt_as_default()#interpolated_expr
emit::template::Part::hole(#hole).__private_fmt_as_default()#interpolated_expr #captured_expr
}
)
}
Expand Down
31 changes: 22 additions & 9 deletions macros/src/props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::{
};

pub struct Props {
interpolated: bool,
match_value_tokens: Vec<TokenStream>,
match_binding_tokens: Vec<TokenStream>,
key_values: BTreeMap<String, KeyValue>,
Expand All @@ -20,10 +19,10 @@ impl Parse for Props {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let fv = input.parse_terminated(FieldValue::parse, Token![,])?;

let mut props = Props::new(false);
let mut props = Props::new();

for fv in fv {
props.push(&fv)?;
props.push(&fv, false, true)?;
}

Ok(props)
Expand All @@ -34,10 +33,11 @@ pub struct KeyValue {
match_bound_tokens: TokenStream,
direct_bound_tokens: TokenStream,
span: Span,
pub interpolated: bool,
pub captured: bool,
pub label: String,
pub cfg_attr: Option<Attribute>,
pub attrs: Vec<Attribute>,
pub has_expr: bool,
}

impl KeyValue {
Expand All @@ -47,9 +47,8 @@ impl KeyValue {
}

impl Props {
pub fn new(interpolated: bool) -> Self {
pub fn new() -> Self {
Props {
interpolated,
match_value_tokens: Vec::new(),
match_binding_tokens: Vec::new(),
key_values: BTreeMap::new(),
Expand Down Expand Up @@ -94,7 +93,12 @@ impl Props {
self.key_values.values()
}

pub fn push(&mut self, fv: &FieldValue) -> Result<(), syn::Error> {
pub fn push(
&mut self,
fv: &FieldValue,
interpolated: bool,
captured: bool,
) -> Result<(), syn::Error> {
let mut attrs = vec![];
let mut cfg_attr = None;

Expand All @@ -116,7 +120,8 @@ impl Props {
let match_bound_ident = self.next_match_binding_ident(fv.span());

let key_value_tokens = {
let key_value_tokens = capture::key_value_with_hook(&attrs, &fv, self.interpolated);
let key_value_tokens =
capture::key_value_with_hook(&attrs, &fv, interpolated, captured);

match cfg_attr {
Some(ref cfg_attr) => quote_spanned!(fv.span()=>
Expand Down Expand Up @@ -147,6 +152,13 @@ impl Props {

let label = fv.key_name();

if fv.colon_token.is_some() && !captured {
return Err(syn::Error::new(
fv.span(),
"uncaptured key values must be plain identifiers",
));
}

// Make sure keys aren't duplicated
let previous = self.key_values.insert(
label.clone(),
Expand All @@ -155,9 +167,10 @@ impl Props {
direct_bound_tokens: quote_spanned!(fv.span()=> #key_value_tokens),
span: fv.span(),
label,
has_expr: fv.colon_token.is_some(),
cfg_attr,
attrs,
captured,
interpolated,
},
);

Expand Down
25 changes: 15 additions & 10 deletions macros/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use syn::{parse::Parse, punctuated::Punctuated, spanned::Spanned, Expr, ExprPath

use crate::{fmt, props::Props, util::FieldValueKey};

pub fn parse2<A: Parse>(input: TokenStream) -> Result<(A, Template, Props), syn::Error> {
pub fn parse2<A: Parse>(
input: TokenStream,
captured: bool,
) -> Result<(A, Template, Props), syn::Error> {
let template =
fv_template::Template::parse2(input).map_err(|e| syn::Error::new(e.span(), e))?;

Expand All @@ -25,7 +28,7 @@ pub fn parse2<A: Parse>(input: TokenStream) -> Result<(A, Template, Props), syn:
.map(|fv| Ok((fv.key_name(), fv)))
.collect::<Result<_, syn::Error>>()?;

let mut props = Props::new(true);
let mut props = Props::new();

// Push the field-values that appear in the template
for fv in template.literal_field_values() {
Expand All @@ -35,7 +38,7 @@ pub fn parse2<A: Parse>(input: TokenStream) -> Result<(A, Template, Props), syn:
// then it will be used as the source for the value and attributes
// In this case, it's expected that the field-value in the template is
// just a single identifier
let fv = match extra_field_values.remove(&k) {
match extra_field_values.remove(&k) {
Some(extra_fv) => {
if let Expr::Path(ExprPath { ref path, .. }) = fv.expr {
// Make sure the field-value in the template is just a plain identifier
Expand All @@ -55,18 +58,18 @@ pub fn parse2<A: Parse>(input: TokenStream) -> Result<(A, Template, Props), syn:
));
}

extra_fv
props.push(extra_fv, true, captured)?;
}
None => fv,
};

props.push(fv)?;
None => {
props.push(fv, true, captured)?;
}
}
}

// Push any remaining extra field-values
// This won't include any field values that also appear in the template
for (_, fv) in extra_field_values {
props.push(fv)?;
props.push(fv, false, captured)?;
}

// A runtime representation of the template
Expand Down Expand Up @@ -108,7 +111,9 @@ impl<'a> fv_template::LiteralVisitor for TemplateVisitor<'a> {

let field = self.props.get(&label).expect("missing prop");

let hole_tokens = fmt::template_hole_with_hook(&field.attrs, &hole, true);
debug_assert!(field.interpolated);

let hole_tokens = fmt::template_hole_with_hook(&field.attrs, &hole, true, field.captured);

match field.cfg_attr {
Some(ref cfg_attr) => self.parts.push(quote!(#cfg_attr { #hole_tokens })),
Expand Down
11 changes: 11 additions & 0 deletions src/macro_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ impl<T> __PrivateOptionalMapHook<T> for Option<T> {
pub trait __PrivateInterpolatedHook {
fn __private_interpolated(self) -> Self;
fn __private_uninterpolated(self) -> Self;

fn __private_captured(self) -> Self;
fn __private_uncaptured(self) -> Self;
}

impl<T> __PrivateInterpolatedHook for T {
Expand All @@ -273,6 +276,14 @@ impl<T> __PrivateInterpolatedHook for T {
fn __private_uninterpolated(self) -> Self {
self
}

fn __private_captured(self) -> Self {
self
}

fn __private_uncaptured(self) -> Self {
self
}
}

/**
Expand Down

0 comments on commit f93c4cf

Please sign in to comment.