@@ -9,17 +9,26 @@ use crate::ast::{
99
1010#[ derive( Clone , Copy , Default ) ]
1111struct LoweringContext < ' a > {
12- dependency_scope : Option < DependencyScope < ' a > > ,
12+ choice_alternative_scope : Option < ChoiceAlternativeScope < ' a > > ,
1313}
1414
1515#[ derive( Clone , Copy ) ]
16- struct DependencyScope < ' a > {
17- preparations : & ' a RefCell < Vec < DependencyPreparation > > ,
16+ struct ChoiceAlternativeScope < ' a > {
17+ interpolations : & ' a RefCell < Vec < GuardingInterpolation > > ,
1818}
1919
20- struct DependencyPreparation {
20+ /// A `#{expr}` interpolation that must succeed before constructing a choice
21+ /// alternative. Lowering first emits `expression`, which evaluates `expr` and
22+ /// returns its rendered text and optional source range. A `None` result rejects
23+ /// the alternative without constructing any nodes. On success, the generated
24+ /// bindings are reused later when constructing the interpolated leaf.
25+ struct GuardingInterpolation {
26+ /// Generated binding for the interpolation's rendered text.
2127 value : Ident ,
28+ /// Generated binding for the interpolation's optional source range.
2229 source_range : Ident ,
30+ /// Generated `Option<(String, Option<Range>)>` expression that evaluates
31+ /// the original interpolation exactly once.
2332 expression : TokenStream ,
2433}
2534
@@ -368,20 +377,20 @@ impl Template {
368377
369378impl Alternative {
370379 fn lower_candidate ( & self , fallback : TokenStream ) -> TokenStream {
371- let preparations = RefCell :: new ( Vec :: new ( ) ) ;
380+ let interpolations = RefCell :: new ( Vec :: new ( ) ) ;
372381 let context = LoweringContext {
373- dependency_scope : Some ( DependencyScope {
374- preparations : & preparations ,
382+ choice_alternative_scope : Some ( ChoiceAlternativeScope {
383+ interpolations : & interpolations ,
375384 } ) ,
376385 } ;
377386 let value = self . template . lower_single ( context) ;
378- let preparations = preparations . into_inner ( ) ;
379- let prepared_values = preparations
387+ let interpolations = interpolations . into_inner ( ) ;
388+ let prepared_values = interpolations
380389 . iter ( )
381- . flat_map ( |preparation | {
390+ . flat_map ( |interpolation | {
382391 [
383- preparation . value . clone ( ) ,
384- preparation . source_range . clone ( ) ,
392+ interpolation . value . clone ( ) ,
393+ interpolation . source_range . clone ( ) ,
385394 ]
386395 } )
387396 . collect :: < Vec < _ > > ( ) ;
@@ -393,14 +402,14 @@ impl Alternative {
393402 // evaluated in source order. Construction happens only after the
394403 // resulting option has been matched, keeping it in a separate branch
395404 // from the fallback.
396- let prepared = preparations . into_iter ( ) . rev ( ) . fold (
405+ let prepared = interpolations . into_iter ( ) . rev ( ) . fold (
397406 prepared,
398- |candidate, preparation | {
399- let DependencyPreparation {
407+ |candidate, interpolation | {
408+ let GuardingInterpolation {
400409 value,
401410 source_range,
402411 expression,
403- } = preparation ;
412+ } = interpolation ;
404413 // Do not use `map`/`and_then` here: `candidate` may contain
405414 // embedded user Rust, and putting it in a closure would change
406415 // the target of `return` and the result type seen by `?`.
@@ -446,10 +455,13 @@ impl Node {
446455 Content :: Static ( lit) => quote ! { #ctx. literal( #kind_str, #lit) } ,
447456 Content :: Computed ( block) => {
448457 let block = rust_block ( block) ;
449- if let Some ( scope) = context. dependency_scope {
458+ if let Some ( scope) = context. choice_alternative_scope {
450459 let value = fresh_prepared_ident ( "value" ) ;
451460 let source_range = fresh_prepared_ident ( "source_range" ) ;
452- scope. preparations . borrow_mut ( ) . push ( DependencyPreparation {
461+ scope
462+ . interpolations
463+ . borrow_mut ( )
464+ . push ( GuardingInterpolation {
453465 value : value. clone ( ) ,
454466 source_range : source_range. clone ( ) ,
455467 expression : quote ! {
@@ -471,7 +483,7 @@ impl Node {
471483 )
472484 }
473485 } ,
474- } ) ;
486+ } ) ;
475487 quote ! {
476488 #ctx. literal_with_source_range(
477489 #kind_str,
0 commit comments