Track xml:lang throughout parsing
This commit is contained in:
parent
31d7bbf622
commit
d9a21dd8c9
21 changed files with 446 additions and 88 deletions
|
|
@ -318,7 +318,7 @@ impl Compound {
|
|||
substate_data,
|
||||
&builder,
|
||||
).with_mut(substate_data).with_impl(quote! {
|
||||
match #feed(&mut #substate_data, ev)? {
|
||||
match #feed(&mut #substate_data, ev, ctx)? {
|
||||
::core::option::Option::Some(#substate_result) => {
|
||||
#collect
|
||||
::core::result::Result::Ok(::core::ops::ControlFlow::Break(Self::#default_state_ident {
|
||||
|
|
@ -467,7 +467,7 @@ impl Compound {
|
|||
substate_data,
|
||||
&discard_builder_ty,
|
||||
).with_mut(substate_data).with_impl(quote! {
|
||||
match #discard_feed(&mut #substate_data, ev)? {
|
||||
match #discard_feed(&mut #substate_data, ev, ctx)? {
|
||||
::core::option::Option::Some(#substate_result) => {
|
||||
::core::result::Result::Ok(::core::ops::ControlFlow::Break(Self::#default_state_ident {
|
||||
#builder_data_ident,
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ impl ItemDef for EnumDef {
|
|||
Ok(FromXmlParts {
|
||||
defs,
|
||||
from_events_body: quote! {
|
||||
#builder_ty_ident::new(#name_ident, #attrs_ident)
|
||||
#builder_ty_ident::new(#name_ident, #attrs_ident, ctx)
|
||||
},
|
||||
builder_ty_ident: builder_ty_ident.clone(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl Field for ChildField {
|
|||
|
||||
let from_events = from_events_fn(element_ty.clone());
|
||||
|
||||
let matcher = quote! { #from_events(name, attrs) };
|
||||
let matcher = quote! { #from_events(name, attrs, ctx) };
|
||||
let builder = from_xml_builder_ty(element_ty.clone());
|
||||
|
||||
(
|
||||
|
|
@ -307,7 +307,7 @@ impl ExtractDef {
|
|||
)?;
|
||||
let from_xml_builder_ty = ty_from_ident(from_xml_builder_ty_ident.clone()).into();
|
||||
|
||||
let matcher = quote! { #state_ty_ident::new(name, attrs).map(|x| #from_xml_builder_ty_ident(::core::option::Option::Some(x))) };
|
||||
let matcher = quote! { #state_ty_ident::new(name, attrs, ctx).map(|x| #from_xml_builder_ty_ident(::core::option::Option::Some(x))) };
|
||||
|
||||
let inner_ty = self.parts.to_single_or_tuple_ty();
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl Field for ElementField {
|
|||
if #field_access.is_some() {
|
||||
::core::result::Result::Err(::xso::error::FromEventsError::Mismatch { name, attrs })
|
||||
} else {
|
||||
#from_events(name, attrs)
|
||||
#from_events(name, attrs, ctx)
|
||||
}
|
||||
}),
|
||||
builder,
|
||||
|
|
|
|||
72
xso-proc/src/field/lang.rs
Normal file
72
xso-proc/src/field/lang.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2025 Jonas Schäfer <jonas@zombofant.net>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//! This module concerns the processing of inherited `xml:lang` values.
|
||||
//!
|
||||
//! In particular, it provides the `#[xml(lang)]` implementation.
|
||||
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::*;
|
||||
|
||||
use crate::error_message::ParentRef;
|
||||
use crate::scope::{AsItemsScope, FromEventsScope};
|
||||
use crate::types::{as_optional_xml_text_fn, option_ty, string_ty};
|
||||
|
||||
use super::{Field, FieldBuilderPart, FieldIteratorPart, FieldTempInit};
|
||||
|
||||
/// The field maps to a potentially inherited `xml:lang` value.
|
||||
pub(super) struct LangField;
|
||||
|
||||
impl Field for LangField {
|
||||
fn make_builder_part(
|
||||
&self,
|
||||
_scope: &FromEventsScope,
|
||||
_container_name: &ParentRef,
|
||||
_member: &Member,
|
||||
_ty: &Type,
|
||||
) -> Result<FieldBuilderPart> {
|
||||
let string_ty = string_ty(Span::call_site());
|
||||
let ty = option_ty(string_ty.clone());
|
||||
|
||||
Ok(FieldBuilderPart::Init {
|
||||
value: FieldTempInit {
|
||||
ty,
|
||||
init: quote! {
|
||||
ctx.language().map(#string_ty::from).into()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn make_iterator_part(
|
||||
&self,
|
||||
_scope: &AsItemsScope,
|
||||
_container_name: &ParentRef,
|
||||
bound_name: &Ident,
|
||||
_member: &Member,
|
||||
ty: &Type,
|
||||
) -> Result<FieldIteratorPart> {
|
||||
let as_optional_xml_text = as_optional_xml_text_fn(ty.clone());
|
||||
|
||||
Ok(FieldIteratorPart::Header {
|
||||
generator: quote! {
|
||||
#as_optional_xml_text(#bound_name)?.map(|#bound_name|
|
||||
::xso::Item::Attribute(
|
||||
::xso::exports::rxml::Namespace::XML,
|
||||
// SAFETY: `lang` is a known-good NcName
|
||||
unsafe {
|
||||
::xso::exports::alloc::borrow::Cow::Borrowed(
|
||||
::xso::exports::rxml::NcNameStr::from_str_unchecked("lang"),
|
||||
)
|
||||
},
|
||||
#bound_name,
|
||||
)
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ mod child;
|
|||
#[cfg(feature = "minidom")]
|
||||
mod element;
|
||||
mod flag;
|
||||
mod lang;
|
||||
mod text;
|
||||
|
||||
use self::attribute::AttributeField;
|
||||
|
|
@ -28,6 +29,7 @@ use self::child::{ChildField, ExtractDef};
|
|||
#[cfg(feature = "minidom")]
|
||||
use self::element::ElementField;
|
||||
use self::flag::FlagField;
|
||||
use self::lang::LangField;
|
||||
use self::text::TextField;
|
||||
|
||||
/// Code slices necessary for declaring and initializing a temporary variable
|
||||
|
|
@ -444,6 +446,8 @@ fn new_field(
|
|||
xml_name,
|
||||
}))
|
||||
}
|
||||
|
||||
XmlFieldMeta::Language { span: _ } => Ok(Box::new(LangField)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ fn from_xml_impl(input: Item) -> Result<TokenStream> {
|
|||
fn from_events(
|
||||
name: ::xso::exports::rxml::QName,
|
||||
attrs: ::xso::exports::rxml::AttrMap,
|
||||
ctx: &::xso::Context<'_>,
|
||||
) -> ::core::result::Result<Self::Builder, ::xso::error::FromEventsError> {
|
||||
#from_events_body
|
||||
}
|
||||
|
|
|
|||
|
|
@ -874,6 +874,14 @@ pub(crate) enum XmlFieldMeta {
|
|||
/// The namespace/name keys.
|
||||
qname: QNameRef,
|
||||
},
|
||||
|
||||
/// `#[xml(lang)]`
|
||||
Language {
|
||||
/// The span of the `#[xml(lang)]` meta from which this was parsed.
|
||||
///
|
||||
/// This is useful for error messages.
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl XmlFieldMeta {
|
||||
|
|
@ -1182,6 +1190,13 @@ impl XmlFieldMeta {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse a `#[xml(lang)]` meta.
|
||||
fn lang_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
|
||||
Ok(Self::Language {
|
||||
span: meta.path.span(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse [`Self`] from a nestd meta, switching on the identifier
|
||||
/// of that nested meta.
|
||||
fn parse_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
|
||||
|
|
@ -1197,6 +1212,8 @@ impl XmlFieldMeta {
|
|||
Self::element_from_meta(meta)
|
||||
} else if meta.path.is_ident("flag") {
|
||||
Self::flag_from_meta(meta)
|
||||
} else if meta.path.is_ident("lang") {
|
||||
Self::lang_from_meta(meta)
|
||||
} else {
|
||||
Err(Error::new_spanned(meta.path, "unsupported field meta"))
|
||||
}
|
||||
|
|
@ -1280,6 +1297,7 @@ impl XmlFieldMeta {
|
|||
Self::Extract { ref span, .. } => *span,
|
||||
Self::Element { ref span, .. } => *span,
|
||||
Self::Flag { ref span, .. } => *span,
|
||||
Self::Language { ref span, .. } => *span,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ impl FromEventsStateMachine {
|
|||
}
|
||||
|
||||
impl #state_ty_ident {
|
||||
fn advance(mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::ops::ControlFlow<Self, #output_ty>, ::xso::error::Error> {
|
||||
fn advance(mut self, ev: ::xso::exports::rxml::Event, ctx: &::xso::Context<'_>) -> ::core::result::Result<::core::ops::ControlFlow<Self, #output_ty>, ::xso::error::Error> {
|
||||
match self {
|
||||
#advance_match_arms
|
||||
}.and_then(|__ok| {
|
||||
|
|
@ -527,8 +527,9 @@ impl FromEventsStateMachine {
|
|||
fn new(
|
||||
name: ::xso::exports::rxml::QName,
|
||||
attrs: ::xso::exports::rxml::AttrMap,
|
||||
ctx: &::xso::Context<'_>,
|
||||
) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
|
||||
#state_ty_ident::new(name, attrs).map(|ok| Self(::core::option::Option::Some(ok)))
|
||||
#state_ty_ident::new(name, attrs, ctx).map(|ok| Self(::core::option::Option::Some(ok)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -539,9 +540,9 @@ impl FromEventsStateMachine {
|
|||
impl ::xso::FromEventsBuilder for #builder_ty_ident {
|
||||
type Output = #output_ty;
|
||||
|
||||
fn feed(&mut self, ev: ::xso::exports::rxml::Event) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
||||
fn feed(&mut self, ev: ::xso::exports::rxml::Event, ctx: &::xso::Context<'_>) -> ::core::result::Result<::core::option::Option<Self::Output>, ::xso::error::Error> {
|
||||
let inner = self.0.take().expect("feed called after completion");
|
||||
match inner.advance(ev)? {
|
||||
match inner.advance(ev, ctx)? {
|
||||
::core::ops::ControlFlow::Continue(mut value) => {
|
||||
#validate_call
|
||||
::core::result::Result::Ok(::core::option::Option::Some(value))
|
||||
|
|
@ -558,6 +559,7 @@ impl FromEventsStateMachine {
|
|||
fn new(
|
||||
name: ::xso::exports::rxml::QName,
|
||||
mut attrs: ::xso::exports::rxml::AttrMap,
|
||||
ctx: &::xso::Context<'_>,
|
||||
) -> ::core::result::Result<Self, ::xso::error::FromEventsError> {
|
||||
#init_body
|
||||
{ let _ = &mut attrs; }
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ impl StructInner {
|
|||
&from_xml_builder_ty,
|
||||
)
|
||||
.with_impl(quote! {
|
||||
match #feed_fn(&mut #builder_data_ident, ev)? {
|
||||
match #feed_fn(&mut #builder_data_ident, ev, ctx)? {
|
||||
::core::option::Option::Some(result) => {
|
||||
::core::result::Result::Ok(::core::ops::ControlFlow::Continue(#output_cons))
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ impl StructInner {
|
|||
})
|
||||
],
|
||||
init: quote! {
|
||||
#from_events_fn(name, attrs).map(|#builder_data_ident| Self::#state_name { #builder_data_ident })
|
||||
#from_events_fn(name, attrs, ctx).map(|#builder_data_ident| Self::#state_name { #builder_data_ident })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -392,7 +392,7 @@ impl ItemDef for StructDef {
|
|||
Ok(FromXmlParts {
|
||||
defs,
|
||||
from_events_body: quote! {
|
||||
#builder_ty_ident::new(#name_ident, #attrs_ident)
|
||||
#builder_ty_ident::new(#name_ident, #attrs_ident, ctx)
|
||||
},
|
||||
builder_ty_ident: builder_ty_ident.clone(),
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue