11use proc_macro2:: { Span , TokenStream } ;
2+ use std:: fs;
23use std:: path:: { Path , PathBuf } ;
34use syn:: parse:: { Error , Parse , ParseStream , Result } ;
45use syn:: punctuated:: Punctuated ;
56use syn:: { token, Token } ;
6- use wit_bindgen_core:: wit_parser:: { PackageId , Resolve , UnresolvedPackage , WorldId } ;
7+ use wit_bindgen_core:: wit_parser:: { self , PackageId , Resolve , UnresolvedPackage , WorldId } ;
78use wit_bindgen_rust:: Opts ;
89
910#[ proc_macro]
@@ -32,6 +33,7 @@ impl Parse for Config {
3233 let mut opts = Opts :: default ( ) ;
3334 let mut world = None ;
3435 let mut source = None ;
36+ let mut substitutions = None ;
3537
3638 if input. peek ( token:: Brace ) {
3739 let content;
@@ -57,6 +59,24 @@ impl Parse for Config {
5759 }
5860 source = Some ( Source :: Inline ( s. value ( ) ) ) ;
5961 }
62+ Opt :: SubstitutionsPath ( s) => {
63+ if substitutions. is_some ( ) {
64+ return Err ( Error :: new (
65+ s. span ( ) ,
66+ "cannot specify second substitutions" ,
67+ ) ) ;
68+ }
69+ substitutions = Some ( Source :: Path ( s. value ( ) ) ) ;
70+ }
71+ Opt :: SubstitutionsInline ( s) => {
72+ if substitutions. is_some ( ) {
73+ return Err ( Error :: new (
74+ s. span ( ) ,
75+ "cannot specify second substitutions" ,
76+ ) ) ;
77+ }
78+ substitutions = Some ( Source :: Inline ( s. value ( ) ) ) ;
79+ }
6080 Opt :: UseStdFeature => opts. std_feature = true ,
6181 Opt :: RawStrings => opts. raw_strings = true ,
6282 Opt :: MacroExport => opts. macro_export = true ,
@@ -71,8 +91,8 @@ impl Parse for Config {
7191 source = Some ( Source :: Path ( input. parse :: < syn:: LitStr > ( ) ?. value ( ) ) ) ;
7292 }
7393 }
74- let ( resolve, pkg, files) =
75- parse_source ( & source ) . map_err ( |err| Error :: new ( call_site, format ! ( "{err:?}" ) ) ) ?;
94+ let ( resolve, pkg, files) = parse_source ( & source , & substitutions )
95+ . map_err ( |err| Error :: new ( call_site, format ! ( "{err:?}" ) ) ) ?;
7696 let world = resolve
7797 . select_world ( pkg, world. as_deref ( ) )
7898 . map_err ( |e| Error :: new ( call_site, format ! ( "{e:?}" ) ) ) ?;
@@ -85,7 +105,10 @@ impl Parse for Config {
85105 }
86106}
87107
88- fn parse_source ( source : & Option < Source > ) -> anyhow:: Result < ( Resolve , PackageId , Vec < PathBuf > ) > {
108+ fn parse_source (
109+ source : & Option < Source > ,
110+ substitutions : & Option < Source > ,
111+ ) -> anyhow:: Result < ( Resolve , PackageId , Vec < PathBuf > ) > {
89112 let mut resolve = Resolve :: default ( ) ;
90113 let mut files = Vec :: new ( ) ;
91114 let root = PathBuf :: from ( std:: env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) ) ;
@@ -108,7 +131,14 @@ fn parse_source(source: &Option<Source>) -> anyhow::Result<(Resolve, PackageId,
108131 Some ( Source :: Path ( s) ) => parse ( & root. join ( & s) ) ?,
109132 None => parse ( & root. join ( "wit" ) ) ?,
110133 } ;
111-
134+ match substitutions {
135+ Some ( Source :: Inline ( s) ) => wit_parser:: expand ( & mut resolve, toml:: from_str ( s) ?) ?,
136+ Some ( Source :: Path ( s) ) => wit_parser:: expand (
137+ & mut resolve,
138+ toml:: from_str ( & fs:: read_to_string ( & root. join ( & s) ) ?) ?,
139+ ) ?,
140+ None => ( ) ,
141+ }
112142 Ok ( ( resolve, pkg, files) )
113143}
114144
@@ -146,12 +176,16 @@ mod kw {
146176 syn:: custom_keyword!( world) ;
147177 syn:: custom_keyword!( path) ;
148178 syn:: custom_keyword!( inline) ;
179+ syn:: custom_keyword!( substitutions_path) ;
180+ syn:: custom_keyword!( substitutions_inline) ;
149181}
150182
151183enum Opt {
152184 World ( syn:: LitStr ) ,
153185 Path ( syn:: LitStr ) ,
154186 Inline ( syn:: LitStr ) ,
187+ SubstitutionsPath ( syn:: LitStr ) ,
188+ SubstitutionsInline ( syn:: LitStr ) ,
155189 UseStdFeature ,
156190 RawStrings ,
157191 MacroExport ,
@@ -171,6 +205,14 @@ impl Parse for Opt {
171205 input. parse :: < kw:: inline > ( ) ?;
172206 input. parse :: < Token ! [ : ] > ( ) ?;
173207 Ok ( Opt :: Inline ( input. parse ( ) ?) )
208+ } else if l. peek ( kw:: substitutions_path) {
209+ input. parse :: < kw:: substitutions_path > ( ) ?;
210+ input. parse :: < Token ! [ : ] > ( ) ?;
211+ Ok ( Opt :: SubstitutionsPath ( input. parse ( ) ?) )
212+ } else if l. peek ( kw:: substitutions_inline) {
213+ input. parse :: < kw:: substitutions_inline > ( ) ?;
214+ input. parse :: < Token ! [ : ] > ( ) ?;
215+ Ok ( Opt :: SubstitutionsInline ( input. parse ( ) ?) )
174216 } else if l. peek ( kw:: world) {
175217 input. parse :: < kw:: world > ( ) ?;
176218 input. parse :: < Token ! [ : ] > ( ) ?;
0 commit comments