| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
use proc_macro2::{Span, TokenStream}; |
| 28 |
use quote::{format_ident, quote}; |
| 29 |
use syn::{Ident, Result}; |
| 30 |
|
| 31 |
use crate::ast::{Declaration, Hole, Step}; |
| 32 |
use crate::symbolic::Fill; |
| 33 |
|
| 34 |
|
| 35 |
pub fn fill_name(name: &Ident) -> Ident { |
| 36 |
format_ident!("{}_fill", name, span = name.span()) |
| 37 |
} |
| 38 |
|
| 39 |
|
| 40 |
fn serve_name(name: &Ident) -> Ident { |
| 41 |
format_ident!("{}_serve", name, span = name.span()) |
| 42 |
} |
| 43 |
|
| 44 |
|
| 45 |
pub fn filler(declaration: &Declaration, fill: &[Fill]) -> Result<TokenStream> { |
| 46 |
let name = fill_name(&declaration.name); |
| 47 |
let serve = serve_name(&declaration.name); |
| 48 |
let vis = &declaration.vis; |
| 49 |
|
| 50 |
let params: Vec<TokenStream> = declaration |
| 51 |
.params |
| 52 |
.iter() |
| 53 |
.map(|param| { |
| 54 |
let name = ¶m.name; |
| 55 |
let ty = ¶m.ty; |
| 56 |
quote!(#name: #ty) |
| 57 |
}) |
| 58 |
.collect(); |
| 59 |
let forwarded: Vec<&Ident> = declaration.params.iter().map(|param| ¶m.name).collect(); |
| 60 |
|
| 61 |
let body = self::body(fill)?; |
| 62 |
|
| 63 |
let fill_doc = format!( |
| 64 |
" Write a request's values into [`{}`]'s residual.", |
| 65 |
declaration.name |
| 66 |
); |
| 67 |
let serve_doc = format!( |
| 68 |
" Serve [`{}`] from a residual, building no `Node`.", |
| 69 |
declaration.name |
| 70 |
); |
| 71 |
|
| 72 |
Ok(quote! { |
| 73 |
#[doc = #fill_doc] |
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
|
| 78 |
|
| 79 |
|
| 80 |
|
| 81 |
|
| 82 |
#[allow(clippy::ptr_arg)] |
| 83 |
#vis fn #name( |
| 84 |
cursor: &mut ::quasi_router::stage::Cursor<'_>, |
| 85 |
out: &mut ::std::string::String, |
| 86 |
#(#params),* |
| 87 |
) { |
| 88 |
#body |
| 89 |
} |
| 90 |
|
| 91 |
#[doc = #serve_doc] |
| 92 |
#vis fn #serve( |
| 93 |
residual: &::quasi_router::stage::Residual, |
| 94 |
#(#params),* |
| 95 |
) -> ::std::string::String { |
| 96 |
let mut out = ::std::string::String::with_capacity(residual.literal_len() + 64); |
| 97 |
let mut cursor = residual.cursor(); |
| 98 |
#name(&mut cursor, &mut out, #(#forwarded),*); |
| 99 |
::quasi_router::stage::Cursor::finish(&mut cursor, &mut out); |
| 100 |
out |
| 101 |
} |
| 102 |
}) |
| 103 |
} |
| 104 |
|
| 105 |
|
| 106 |
|
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
|
| 111 |
|
| 112 |
|
| 113 |
|
| 114 |
|
| 115 |
|
| 116 |
|
| 117 |
|
| 118 |
|
| 119 |
|
| 120 |
|
| 121 |
|
| 122 |
|
| 123 |
|
| 124 |
fn body(fill: &[Fill]) -> Result<TokenStream> { |
| 125 |
let holes: Vec<&Fill> = fill |
| 126 |
.iter() |
| 127 |
.filter(|one| matches!(one, Fill::Hole { .. })) |
| 128 |
.collect(); |
| 129 |
|
| 130 |
let mut out = TokenStream::new(); |
| 131 |
for one in fill { |
| 132 |
if matches!(one, Fill::Hole { .. }) { |
| 133 |
continue; |
| 134 |
} |
| 135 |
out.extend(run(&holes)?); |
| 136 |
out.extend(control(one, &holes)?); |
| 137 |
} |
| 138 |
out.extend(run(&holes)?); |
| 139 |
Ok(out) |
| 140 |
} |
| 141 |
|
| 142 |
|
| 143 |
fn run(holes: &[&Fill]) -> Result<TokenStream> { |
| 144 |
if holes.is_empty() { |
| 145 |
return Ok(TokenStream::new()); |
| 146 |
} |
| 147 |
let arms = answers(holes)?; |
| 148 |
|
| 149 |
Ok(quote! { |
| 150 |
::quasi_router::stage::Cursor::fill(cursor, out, &mut |which, out| match which { |
| 151 |
#(#arms)* |
| 152 |
|
| 153 |
|
| 154 |
|
| 155 |
_ => ::core::unreachable!("the residual has a hole the filler does not"), |
| 156 |
}); |
| 157 |
}) |
| 158 |
} |
| 159 |
|
| 160 |
|
| 161 |
fn answers(holes: &[&Fill]) -> Result<Vec<TokenStream>> { |
| 162 |
holes |
| 163 |
.iter() |
| 164 |
.map(|one| { |
| 165 |
let Fill::Hole { id, hole } = one else { |
| 166 |
unreachable!("only holes are collected here"); |
| 167 |
}; |
| 168 |
let value = crate::emit::hole(&owned(hole))?; |
| 169 |
Ok(quote!(#id => ::quasi_webview::stage::Fill::fill(&(#value), out),)) |
| 170 |
}) |
| 171 |
.collect() |
| 172 |
} |
| 173 |
|
| 174 |
|
| 175 |
|
| 176 |
|
| 177 |
|
| 178 |
|
| 179 |
|
| 180 |
|
| 181 |
fn control(one: &Fill, level: &[&Fill]) -> Result<TokenStream> { |
| 182 |
Ok(match one { |
| 183 |
Fill::Hole { .. } => unreachable!("handled by the caller"), |
| 184 |
Fill::Branch { guard, body } => { |
| 185 |
let predicate = crate::emit::predicate(guard)?; |
| 186 |
let inner = self::body(body)?; |
| 187 |
|
| 188 |
|
| 189 |
|
| 190 |
|
| 191 |
let mut reachable: Vec<&Fill> = level.to_vec(); |
| 192 |
reachable.extend(body.iter().filter(|one| matches!(one, Fill::Hole { .. }))); |
| 193 |
let answers = answers(&reachable)?; |
| 194 |
quote! { |
| 195 |
{ |
| 196 |
let taken = #predicate; |
| 197 |
::quasi_router::stage::Cursor::choose( |
| 198 |
cursor, |
| 199 |
out, |
| 200 |
taken, |
| 201 |
&mut |which, out| match which { |
| 202 |
#(#answers)* |
| 203 |
_ => ::core::unreachable!( |
| 204 |
"the residual has a hole the filler does not" |
| 205 |
), |
| 206 |
}, |
| 207 |
&mut |cursor, out| { |
| 208 |
#inner |
| 209 |
::quasi_router::stage::Cursor::finish(cursor, out); |
| 210 |
}, |
| 211 |
); |
| 212 |
} |
| 213 |
} |
| 214 |
} |
| 215 |
Fill::Repeat { |
| 216 |
dereferenced, |
| 217 |
binder, |
| 218 |
iterable, |
| 219 |
body, |
| 220 |
} => { |
| 221 |
let over = crate::emit::hole(iterable)?; |
| 222 |
let inner = self::body(body)?; |
| 223 |
let bound = if *dereferenced { |
| 224 |
quote!(&#binder) |
| 225 |
} else { |
| 226 |
quote!(#binder) |
| 227 |
}; |
| 228 |
quote! { |
| 229 |
{ |
| 230 |
let repeated = ::quasi_router::stage::Cursor::repeat(cursor, out); |
| 231 |
let scope = ::quasi_router::stage::Cursor::scope(cursor); |
| 232 |
for #bound in #over { |
| 233 |
let mut cursor = |
| 234 |
&mut ::quasi_router::stage::Cursor::over(repeated, scope); |
| 235 |
#inner |
| 236 |
::quasi_router::stage::Cursor::finish(cursor, out); |
| 237 |
} |
| 238 |
} |
| 239 |
} |
| 240 |
} |
| 241 |
|
| 242 |
|
| 243 |
|
| 244 |
Fill::Swap { guard } => { |
| 245 |
let predicate = crate::emit::predicate(guard)?; |
| 246 |
let answers = answers(level)?; |
| 247 |
quote! { |
| 248 |
{ |
| 249 |
let taken = usize::from(!(#predicate)); |
| 250 |
::quasi_router::stage::Cursor::pick( |
| 251 |
cursor, |
| 252 |
out, |
| 253 |
taken, |
| 254 |
&mut |which, out| match which { |
| 255 |
#(#answers)* |
| 256 |
_ => ::core::unreachable!( |
| 257 |
"the residual has a hole the filler does not" |
| 258 |
), |
| 259 |
}, |
| 260 |
); |
| 261 |
} |
| 262 |
} |
| 263 |
} |
| 264 |
|
| 265 |
|
| 266 |
|
| 267 |
Fill::Arms { |
| 268 |
scrutinee, |
| 269 |
patterns, |
| 270 |
} => { |
| 271 |
let value = crate::emit::hole(scrutinee)?; |
| 272 |
let which = patterns |
| 273 |
.iter() |
| 274 |
.enumerate() |
| 275 |
.map(|(at, pattern)| { |
| 276 |
let pattern = crate::emit::pattern(pattern); |
| 277 |
Ok(quote!(#pattern => #at,)) |
| 278 |
}) |
| 279 |
.collect::<Result<Vec<_>>>()?; |
| 280 |
let last = patterns.len(); |
| 281 |
let answers = answers(level)?; |
| 282 |
quote! { |
| 283 |
{ |
| 284 |
let taken = match #value { |
| 285 |
#(#which)* |
| 286 |
_ => #last, |
| 287 |
}; |
| 288 |
::quasi_router::stage::Cursor::pick( |
| 289 |
cursor, |
| 290 |
out, |
| 291 |
taken, |
| 292 |
&mut |which, out| match which { |
| 293 |
#(#answers)* |
| 294 |
_ => ::core::unreachable!( |
| 295 |
"the residual has a hole the filler does not" |
| 296 |
), |
| 297 |
}, |
| 298 |
); |
| 299 |
} |
| 300 |
} |
| 301 |
} |
| 302 |
|
| 303 |
|
| 304 |
Fill::Include { callee, args, site } => { |
| 305 |
let mut path = callee.clone(); |
| 306 |
let last = path |
| 307 |
.segments |
| 308 |
.last_mut() |
| 309 |
.ok_or_else(|| syn::Error::new(Span::call_site(), "an empty path"))?; |
| 310 |
last.ident = fill_name(&last.ident); |
| 311 |
let args = args |
| 312 |
.iter() |
| 313 |
.map(crate::emit::arg) |
| 314 |
.collect::<Result<Vec<_>>>()?; |
| 315 |
quote! { |
| 316 |
{ |
| 317 |
|
| 318 |
|
| 319 |
let held = ::quasi_router::stage::Cursor::enter(cursor, #site); |
| 320 |
#path(cursor, out, #(#args),*); |
| 321 |
::quasi_router::stage::Cursor::leave(cursor, held); |
| 322 |
} |
| 323 |
} |
| 324 |
} |
| 325 |
}) |
| 326 |
} |
| 327 |
|
| 328 |
|
| 329 |
|
| 330 |
|
| 331 |
|
| 332 |
|
| 333 |
|
| 334 |
fn owned(hole: &Hole) -> Hole { |
| 335 |
let mut trimmed = hole.clone(); |
| 336 |
if let Some(Step::Method { name, args }) = trimmed.steps.last() |
| 337 |
&& name == "clone" |
| 338 |
&& args.is_empty() |
| 339 |
{ |
| 340 |
trimmed.steps.pop(); |
| 341 |
} |
| 342 |
trimmed |
| 343 |
} |
| 344 |
|