1 use super::{get_template_source, CompileError, Integrations};
2 use crate::filters;
3 use crate::heritage::{Context, Heritage};
4 use crate::input::{Source, TemplateInput};
5 use crate::parser::{
6 parse, Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS,
7 };
8
9 use proc_macro2::Span;
10
11 use quote::{quote, ToTokens};
12
13 use std::collections::{HashMap, HashSet};
14 use std::path::PathBuf;
15 use std::{cmp, hash, mem, str};
16
generate<S: std::hash::BuildHasher>( input: &TemplateInput, contexts: &HashMap<&PathBuf, Context, S>, heritage: &Option<Heritage>, integrations: Integrations, ) -> Result<String, CompileError>17 pub fn generate<S: std::hash::BuildHasher>(
18 input: &TemplateInput,
19 contexts: &HashMap<&PathBuf, Context, S>,
20 heritage: &Option<Heritage>,
21 integrations: Integrations,
22 ) -> Result<String, CompileError> {
23 Generator::new(input, contexts, heritage, integrations, SetChain::new())
24 .build(&contexts[&input.path])
25 }
26
27 struct Generator<'a, S: std::hash::BuildHasher> {
28 // The template input state: original struct AST and attributes
29 input: &'a TemplateInput<'a>,
30 // All contexts, keyed by the package-relative template path
31 contexts: &'a HashMap<&'a PathBuf, Context<'a>, S>,
32 // The heritage contains references to blocks and their ancestry
33 heritage: &'a Option<Heritage<'a>>,
34 // What integrations need to be generated
35 integrations: Integrations,
36 // Variables accessible directly from the current scope (not redirected to context)
37 locals: SetChain<'a, &'a str>,
38 // Suffix whitespace from the previous literal. Will be flushed to the
39 // output buffer unless suppressed by whitespace suppression on the next
40 // non-literal.
41 next_ws: Option<&'a str>,
42 // Whitespace suppression from the previous non-literal. Will be used to
43 // determine whether to flush prefix whitespace from the next literal.
44 skip_ws: bool,
45 // If currently in a block, this will contain the name of a potential parent block
46 super_block: Option<(&'a str, usize)>,
47 // buffer for writable
48 buf_writable: Vec<Writable<'a>>,
49 // Counter for write! hash named arguments
50 named: usize,
51 }
52
53 impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
new<'n>( input: &'n TemplateInput, contexts: &'n HashMap<&'n PathBuf, Context<'n>, S>, heritage: &'n Option<Heritage>, integrations: Integrations, locals: SetChain<'n, &'n str>, ) -> Generator<'n, S>54 fn new<'n>(
55 input: &'n TemplateInput,
56 contexts: &'n HashMap<&'n PathBuf, Context<'n>, S>,
57 heritage: &'n Option<Heritage>,
58 integrations: Integrations,
59 locals: SetChain<'n, &'n str>,
60 ) -> Generator<'n, S> {
61 Generator {
62 input,
63 contexts,
64 heritage,
65 integrations,
66 locals,
67 next_ws: None,
68 skip_ws: false,
69 super_block: None,
70 buf_writable: vec![],
71 named: 0,
72 }
73 }
74
child(&mut self) -> Generator<'_, S>75 fn child(&mut self) -> Generator<'_, S> {
76 let locals = SetChain::with_parent(&self.locals);
77 Self::new(
78 self.input,
79 self.contexts,
80 self.heritage,
81 self.integrations,
82 locals,
83 )
84 }
85
86 // Takes a Context and generates the relevant implementations.
build(mut self, ctx: &'a Context) -> Result<String, CompileError>87 fn build(mut self, ctx: &'a Context) -> Result<String, CompileError> {
88 let mut buf = Buffer::new(0);
89 if !ctx.blocks.is_empty() {
90 if let Some(parent) = self.input.parent {
91 self.deref_to_parent(&mut buf, parent)?;
92 }
93 };
94
95 self.impl_template(ctx, &mut buf)?;
96 self.impl_display(&mut buf)?;
97
98 if self.integrations.actix {
99 self.impl_actix_web_responder(&mut buf)?;
100 }
101 if self.integrations.gotham {
102 self.impl_gotham_into_response(&mut buf)?;
103 }
104 if self.integrations.iron {
105 self.impl_iron_modifier_response(&mut buf)?;
106 }
107 if self.integrations.mendes {
108 self.impl_mendes_responder(&mut buf)?;
109 }
110 if self.integrations.rocket {
111 self.impl_rocket_responder(&mut buf)?;
112 }
113 if self.integrations.tide {
114 self.impl_tide_integrations(&mut buf)?;
115 }
116 if self.integrations.warp {
117 self.impl_warp_reply(&mut buf)?;
118 }
119 Ok(buf.buf)
120 }
121
122 // Implement `Template` for the given context struct.
impl_template(&mut self, ctx: &'a Context, buf: &mut Buffer) -> Result<(), CompileError>123 fn impl_template(&mut self, ctx: &'a Context, buf: &mut Buffer) -> Result<(), CompileError> {
124 self.write_header(buf, "::askama::Template", None)?;
125 buf.writeln(
126 "fn render_into(&self, writer: &mut dyn ::std::fmt::Write) -> \
127 ::askama::Result<()> {",
128 )?;
129
130 // Make sure the compiler understands that the generated code depends on the template files.
131 for path in self.contexts.keys() {
132 // Skip the fake path of templates defined in rust source.
133 let path_is_valid = match self.input.source {
134 Source::Path(_) => true,
135 Source::Source(_) => *path != &self.input.path,
136 };
137 if path_is_valid {
138 let path = path.to_str().unwrap();
139 buf.writeln(
140 "e! {
141 include_bytes!(#path);
142 }
143 .to_string(),
144 )?;
145 }
146 }
147
148 let size_hint = if let Some(heritage) = self.heritage {
149 self.handle(heritage.root, heritage.root.nodes, buf, AstLevel::Top)
150 } else {
151 self.handle(ctx, &ctx.nodes, buf, AstLevel::Top)
152 }?;
153
154 self.flush_ws(WS(false, false));
155 buf.writeln("Ok(())")?;
156 buf.writeln("}")?;
157
158 buf.writeln("fn extension(&self) -> Option<&'static str> {")?;
159 buf.writeln(&format!(
160 "{:?}",
161 self.input.path.extension().map(|s| s.to_str().unwrap())
162 ))?;
163 buf.writeln("}")?;
164
165 buf.writeln("fn size_hint(&self) -> usize {")?;
166 buf.writeln(&format!("{}", size_hint))?;
167 buf.writeln("}")?;
168
169 buf.writeln("}")?;
170
171 self.write_header(buf, "::askama::SizedTemplate", None)?;
172
173 buf.writeln("fn size_hint() -> usize {")?;
174 buf.writeln(&format!("{}", size_hint))?;
175 buf.writeln("}")?;
176
177 buf.writeln("fn extension() -> Option<&'static str> {")?;
178 buf.writeln(&format!(
179 "{:?}",
180 self.input.path.extension().map(|s| s.to_str().unwrap())
181 ))?;
182 buf.writeln("}")?;
183
184 buf.writeln("}")?;
185 Ok(())
186 }
187
188 // Implement `Deref<Parent>` for an inheriting context struct.
deref_to_parent( &mut self, buf: &mut Buffer, parent_type: &syn::Type, ) -> Result<(), CompileError>189 fn deref_to_parent(
190 &mut self,
191 buf: &mut Buffer,
192 parent_type: &syn::Type,
193 ) -> Result<(), CompileError> {
194 self.write_header(buf, "::std::ops::Deref", None)?;
195 buf.writeln(&format!(
196 "type Target = {};",
197 parent_type.into_token_stream()
198 ))?;
199 buf.writeln("fn deref(&self) -> &Self::Target {")?;
200 buf.writeln("&self._parent")?;
201 buf.writeln("}")?;
202 buf.writeln("}")
203 }
204
205 // Implement `Display` for the given context struct.
impl_display(&mut self, buf: &mut Buffer) -> Result<(), CompileError>206 fn impl_display(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
207 self.write_header(buf, "::std::fmt::Display", None)?;
208 buf.writeln("fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {")?;
209 buf.writeln("::askama::Template::render_into(self, f).map_err(|_| ::std::fmt::Error {})")?;
210 buf.writeln("}")?;
211 buf.writeln("}")
212 }
213
214 // Implement Actix-web's `Responder`.
impl_actix_web_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError>215 fn impl_actix_web_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
216 self.write_header(buf, "::actix_web::Responder", None)?;
217 buf.writeln("type Future = ::askama_actix::futures::Ready<::std::result::Result<::actix_web::HttpResponse, Self::Error>>;")?;
218 buf.writeln("type Error = ::actix_web::Error;")?;
219 buf.writeln(
220 "fn respond_to(self, _req: &::actix_web::HttpRequest) \
221 -> Self::Future {",
222 )?;
223
224 buf.writeln("use ::askama_actix::TemplateIntoResponse;")?;
225 buf.writeln("::askama_actix::futures::ready(self.into_response())")?;
226
227 buf.writeln("}")?;
228 buf.writeln("}")
229 }
230
231 // Implement gotham's `IntoResponse`.
impl_gotham_into_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError>232 fn impl_gotham_into_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
233 self.write_header(buf, "::askama_gotham::IntoResponse", None)?;
234 buf.writeln(
235 "fn into_response(self, _state: &::askama_gotham::State)\
236 -> ::askama_gotham::Response<::askama_gotham::Body> {",
237 )?;
238 let ext = match self.input.path.extension() {
239 Some(s) => s.to_str().unwrap(),
240 None => "txt",
241 };
242 buf.writeln(&format!("::askama_gotham::respond(&self, {:?})", ext))?;
243 buf.writeln("}")?;
244 buf.writeln("}")
245 }
246
247 // Implement iron's Modifier<Response> if enabled
impl_iron_modifier_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError>248 fn impl_iron_modifier_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
249 self.write_header(
250 buf,
251 "::askama_iron::Modifier<::askama_iron::Response>",
252 None,
253 )?;
254 buf.writeln("fn modify(self, res: &mut ::askama_iron::Response) {")?;
255 buf.writeln(
256 "res.body = Some(Box::new(::askama_iron::Template::render(&self).unwrap().into_bytes()));",
257 )?;
258
259 let ext = self
260 .input
261 .path
262 .extension()
263 .map_or("", |s| s.to_str().unwrap_or(""));
264 match ext {
265 "html" | "htm" => {
266 buf.writeln("::askama_iron::ContentType::html().0.modify(res);")?;
267 }
268 _ => (),
269 };
270
271 buf.writeln("}")?;
272 buf.writeln("}")
273 }
274
275 // Implement mendes' `Responder`.
impl_mendes_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError>276 fn impl_mendes_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
277 let param = syn::parse_str("A: ::mendes::Application").unwrap();
278
279 let mut generics = self.input.ast.generics.clone();
280 generics.params.push(param);
281 let (_, orig_ty_generics, _) = self.input.ast.generics.split_for_impl();
282 let (impl_generics, _, where_clause) = generics.split_for_impl();
283
284 let mut where_clause = match where_clause {
285 Some(clause) => clause.clone(),
286 None => syn::WhereClause {
287 where_token: syn::Token![where](Span::call_site()),
288 predicates: syn::punctuated::Punctuated::new(),
289 },
290 };
291
292 where_clause
293 .predicates
294 .push(syn::parse_str("A::ResponseBody: From<String>").unwrap());
295 where_clause
296 .predicates
297 .push(syn::parse_str("A::Error: From<::mendes::askama::Error>").unwrap());
298
299 buf.writeln(
300 format!(
301 "{} {} for {} {} {{",
302 quote!(impl#impl_generics),
303 "::mendes::application::Responder<A>",
304 self.input.ast.ident,
305 quote!(#orig_ty_generics #where_clause),
306 )
307 .as_ref(),
308 )?;
309
310 buf.writeln(
311 "fn into_response(self, app: &A, req: &::mendes::http::request::Parts) \
312 -> ::mendes::http::Response<A::ResponseBody> {",
313 )?;
314
315 buf.writeln(&format!(
316 "::mendes::askama::into_response(app, req, &self, {:?})",
317 self.input.path.extension()
318 ))?;
319 buf.writeln("}")?;
320 buf.writeln("}")?;
321 Ok(())
322 }
323
324 // Implement Rocket's `Responder`.
impl_rocket_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError>325 fn impl_rocket_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
326 let lifetime = syn::Lifetime::new("'askama", Span::call_site());
327 let param = syn::GenericParam::Lifetime(syn::LifetimeDef::new(lifetime));
328 self.write_header(
329 buf,
330 "::askama_rocket::Responder<'askama>",
331 Some(vec![param]),
332 )?;
333 buf.writeln(
334 "fn respond_to(self, _: &::askama_rocket::Request) \
335 -> ::askama_rocket::Result<'askama> {",
336 )?;
337
338 let ext = match self.input.path.extension() {
339 Some(s) => s.to_str().unwrap(),
340 None => "txt",
341 };
342 buf.writeln(&format!("::askama_rocket::respond(&self, {:?})", ext))?;
343
344 buf.writeln("}")?;
345 buf.writeln("}")?;
346 Ok(())
347 }
348
impl_tide_integrations(&mut self, buf: &mut Buffer) -> Result<(), CompileError>349 fn impl_tide_integrations(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
350 let ext = self
351 .input
352 .path
353 .extension()
354 .and_then(|s| s.to_str())
355 .unwrap_or("txt");
356
357 self.write_header(
358 buf,
359 "std::convert::TryInto<::askama_tide::tide::Body>",
360 None,
361 )?;
362 buf.writeln(
363 "type Error = ::askama_tide::askama::Error;\n\
364 fn try_into(self) -> ::askama_tide::askama::Result<::askama_tide::tide::Body> {",
365 )?;
366 buf.writeln(&format!("::askama_tide::try_into_body(&self, {:?})", &ext))?;
367 buf.writeln("}")?;
368 buf.writeln("}")?;
369 self.write_header(buf, "Into<::askama_tide::tide::Response>", None)?;
370 buf.writeln("fn into(self) -> ::askama_tide::tide::Response {")?;
371 buf.writeln(&format!("::askama_tide::into_response(&self, {:?})", ext))?;
372 buf.writeln("}\n}")
373 }
374
impl_warp_reply(&mut self, buf: &mut Buffer) -> Result<(), CompileError>375 fn impl_warp_reply(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
376 self.write_header(buf, "::askama_warp::warp::reply::Reply", None)?;
377 buf.writeln("fn into_response(self) -> ::askama_warp::warp::reply::Response {")?;
378 let ext = self
379 .input
380 .path
381 .extension()
382 .and_then(|s| s.to_str())
383 .unwrap_or("txt");
384 buf.writeln(&format!("::askama_warp::reply(&self, {:?})", ext))?;
385 buf.writeln("}")?;
386 buf.writeln("}")
387 }
388
389 // Writes header for the `impl` for `TraitFromPathName` or `Template`
390 // for the given context struct.
write_header( &mut self, buf: &mut Buffer, target: &str, params: Option<Vec<syn::GenericParam>>, ) -> Result<(), CompileError>391 fn write_header(
392 &mut self,
393 buf: &mut Buffer,
394 target: &str,
395 params: Option<Vec<syn::GenericParam>>,
396 ) -> Result<(), CompileError> {
397 let mut generics = self.input.ast.generics.clone();
398 if let Some(params) = params {
399 for param in params {
400 generics.params.push(param);
401 }
402 }
403 let (_, orig_ty_generics, _) = self.input.ast.generics.split_for_impl();
404 let (impl_generics, _, where_clause) = generics.split_for_impl();
405 buf.writeln(
406 format!(
407 "{} {} for {}{} {{",
408 quote!(impl#impl_generics),
409 target,
410 self.input.ast.ident,
411 quote!(#orig_ty_generics #where_clause),
412 )
413 .as_ref(),
414 )
415 }
416
417 /* Helper methods for handling node types */
418
handle( &mut self, ctx: &'a Context, nodes: &'a [Node], buf: &mut Buffer, level: AstLevel, ) -> Result<usize, CompileError>419 fn handle(
420 &mut self,
421 ctx: &'a Context,
422 nodes: &'a [Node],
423 buf: &mut Buffer,
424 level: AstLevel,
425 ) -> Result<usize, CompileError> {
426 let mut size_hint = 0;
427 for n in nodes {
428 match *n {
429 Node::Lit(lws, val, rws) => {
430 self.visit_lit(lws, val, rws);
431 }
432 Node::Comment(ws) => {
433 self.write_comment(ws);
434 }
435 Node::Expr(ws, ref val) => {
436 self.write_expr(ws, val);
437 }
438 Node::LetDecl(ws, ref var) => {
439 self.write_let_decl(buf, ws, var)?;
440 }
441 Node::Let(ws, ref var, ref val) => {
442 self.write_let(buf, ws, var, val)?;
443 }
444 Node::Cond(ref conds, ws) => {
445 self.write_cond(ctx, buf, conds, ws)?;
446 }
447 Node::Match(ws1, ref expr, inter, ref arms, ws2) => {
448 self.write_match(ctx, buf, ws1, expr, inter, arms, ws2)?;
449 }
450 Node::Loop(ws1, ref var, ref iter, ref body, ws2) => {
451 self.write_loop(ctx, buf, ws1, var, iter, body, ws2)?;
452 }
453 Node::BlockDef(ws1, name, _, ws2) => {
454 self.write_block(buf, Some(name), WS(ws1.0, ws2.1))?;
455 }
456 Node::Include(ws, path) => {
457 size_hint += self.handle_include(ctx, buf, ws, path)?;
458 }
459 Node::Call(ws, scope, name, ref args) => {
460 size_hint += self.write_call(ctx, buf, ws, scope, name, args)?;
461 }
462 Node::Macro(_, ref m) => {
463 if level != AstLevel::Top {
464 return Err("macro blocks only allowed at the top level".into());
465 }
466 self.flush_ws(m.ws1);
467 self.prepare_ws(m.ws2);
468 }
469 Node::Raw(ws1, contents, ws2) => {
470 self.handle_ws(ws1);
471 self.buf_writable.push(Writable::Lit(contents));
472 self.handle_ws(ws2);
473 }
474 Node::Import(ws, _, _) => {
475 if level != AstLevel::Top {
476 return Err("import blocks only allowed at the top level".into());
477 }
478 self.handle_ws(ws);
479 }
480 Node::Extends(_) => {
481 if level != AstLevel::Top {
482 return Err("extend blocks only allowed at the top level".into());
483 }
484 // No whitespace handling: child template top-level is not used,
485 // except for the blocks defined in it.
486 }
487 }
488 }
489
490 if AstLevel::Top == level {
491 size_hint += self.write_buf_writable(buf)?;
492 }
493 Ok(size_hint)
494 }
495
write_cond( &mut self, ctx: &'a Context, buf: &mut Buffer, conds: &'a [Cond], ws: WS, ) -> Result<usize, CompileError>496 fn write_cond(
497 &mut self,
498 ctx: &'a Context,
499 buf: &mut Buffer,
500 conds: &'a [Cond],
501 ws: WS,
502 ) -> Result<usize, CompileError> {
503 let mut flushed = 0;
504 let mut arm_sizes = Vec::new();
505 let mut has_else = false;
506 for (i, &(cws, ref cond, ref nodes)) in conds.iter().enumerate() {
507 self.handle_ws(cws);
508 if arm_sizes.is_empty() {
509 flushed += self.write_buf_writable(buf)?;
510 }
511
512 let mut arm_size = 0;
513 match *cond {
514 Some(ref expr) => {
515 if i == 0 {
516 buf.write("if ");
517 } else {
518 buf.dedent()?;
519 buf.write("} else if ");
520 }
521 let expr_code = self.visit_expr_root(expr)?;
522 buf.write(&expr_code);
523 }
524 None => {
525 buf.dedent()?;
526 buf.write("} else");
527 has_else = true;
528 }
529 }
530
531 buf.writeln(" {")?;
532 self.locals.push();
533
534 arm_size += self.handle(ctx, nodes, buf, AstLevel::Nested)?;
535 arm_size += self.write_buf_writable(buf)?;
536 arm_sizes.push(arm_size);
537
538 self.locals.pop();
539 }
540 self.handle_ws(ws);
541 buf.writeln("}")?;
542
543 if !has_else {
544 arm_sizes.push(0);
545 }
546 Ok(flushed + median(&mut arm_sizes))
547 }
548
549 #[allow(clippy::too_many_arguments)]
write_match( &mut self, ctx: &'a Context, buf: &mut Buffer, ws1: WS, expr: &Expr, inter: Option<&'a str>, arms: &'a [When], ws2: WS, ) -> Result<usize, CompileError>550 fn write_match(
551 &mut self,
552 ctx: &'a Context,
553 buf: &mut Buffer,
554 ws1: WS,
555 expr: &Expr,
556 inter: Option<&'a str>,
557 arms: &'a [When],
558 ws2: WS,
559 ) -> Result<usize, CompileError> {
560 self.flush_ws(ws1);
561 let flushed = self.write_buf_writable(buf)?;
562 let mut arm_sizes = Vec::new();
563 if let Some(inter) = inter {
564 if !inter.is_empty() {
565 self.next_ws = Some(inter);
566 }
567 }
568
569 let expr_code = self.visit_expr_root(expr)?;
570 buf.writeln(&format!("match &{} {{", expr_code))?;
571 for arm in arms {
572 let &(ws, ref variant, ref params, ref body) = arm;
573 self.locals.push();
574 match *variant {
575 Some(ref param) => {
576 self.visit_match_variant(buf, param);
577 }
578 None => buf.write("_"),
579 };
580
581 match params {
582 MatchParameters::Simple(params) => {
583 if !params.is_empty() {
584 buf.write("(");
585 for (i, param) in params.iter().enumerate() {
586 if let MatchParameter::Name(p) = *param {
587 self.locals.insert(p);
588 }
589 if i > 0 {
590 buf.write(", ");
591 }
592 self.visit_match_param(buf, param);
593 }
594 buf.write(")");
595 }
596 }
597 MatchParameters::Named(params) => {
598 buf.write("{");
599 for (i, param) in params.iter().enumerate() {
600 if let Some(MatchParameter::Name(p)) = param.1 {
601 self.locals.insert(p);
602 } else {
603 self.locals.insert(param.0);
604 }
605
606 if i > 0 {
607 buf.write(", ");
608 }
609 buf.write(param.0);
610 if let Some(param) = ¶m.1 {
611 buf.write(":");
612 self.visit_match_param(buf, ¶m);
613 }
614 }
615 buf.write("}");
616 }
617 }
618 buf.writeln(" => {")?;
619 self.handle_ws(ws);
620 let arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?;
621 arm_sizes.push(arm_size + self.write_buf_writable(buf)?);
622 buf.writeln("}")?;
623 self.locals.pop();
624 }
625
626 buf.writeln("}")?;
627 self.handle_ws(ws2);
628 Ok(flushed + median(&mut arm_sizes))
629 }
630
631 #[allow(clippy::too_many_arguments)]
write_loop( &mut self, ctx: &'a Context, buf: &mut Buffer, ws1: WS, var: &'a Target, iter: &Expr, body: &'a [Node], ws2: WS, ) -> Result<usize, CompileError>632 fn write_loop(
633 &mut self,
634 ctx: &'a Context,
635 buf: &mut Buffer,
636 ws1: WS,
637 var: &'a Target,
638 iter: &Expr,
639 body: &'a [Node],
640 ws2: WS,
641 ) -> Result<usize, CompileError> {
642 self.handle_ws(ws1);
643 self.locals.push();
644
645 let expr_code = self.visit_expr_root(iter)?;
646
647 let flushed = self.write_buf_writable(buf)?;
648 buf.write("for (");
649 self.visit_target(buf, var);
650 match iter {
651 Expr::Range(_, _, _) => buf.writeln(&format!(
652 ", _loop_item) in ::askama::helpers::TemplateLoop::new({}) {{",
653 expr_code
654 )),
655 _ => buf.writeln(&format!(
656 ", _loop_item) in ::askama::helpers::TemplateLoop::new((&{}).into_iter()) {{",
657 expr_code
658 )),
659 }?;
660
661 let mut size_hint = self.handle(ctx, body, buf, AstLevel::Nested)?;
662 self.handle_ws(ws2);
663
664 size_hint += self.write_buf_writable(buf)?;
665 buf.writeln("}")?;
666 self.locals.pop();
667 Ok(flushed + (size_hint * 3))
668 }
669
write_call( &mut self, ctx: &'a Context, buf: &mut Buffer, ws: WS, scope: Option<&str>, name: &str, args: &[Expr], ) -> Result<usize, CompileError>670 fn write_call(
671 &mut self,
672 ctx: &'a Context,
673 buf: &mut Buffer,
674 ws: WS,
675 scope: Option<&str>,
676 name: &str,
677 args: &[Expr],
678 ) -> Result<usize, CompileError> {
679 if name == "super" {
680 return self.write_block(buf, None, ws);
681 }
682
683 let (def, own_ctx) = if let Some(s) = scope {
684 let path = ctx.imports.get(s).ok_or_else(|| {
685 CompileError::String(format!("no import found for scope '{}'", s))
686 })?;
687 let mctx = self.contexts.get(path).ok_or_else(|| {
688 CompileError::String(format!("context for '{:?}' not found", path))
689 })?;
690 (
691 mctx.macros.get(name).ok_or_else(|| {
692 CompileError::String(format!("macro '{}' not found in scope '{}'", s, name))
693 })?,
694 mctx,
695 )
696 } else {
697 (
698 ctx.macros
699 .get(name)
700 .ok_or_else(|| CompileError::String(format!("macro '{}' not found", name)))?,
701 ctx,
702 )
703 };
704
705 self.flush_ws(ws); // Cannot handle_ws() here: whitespace from macro definition comes first
706 self.locals.push();
707 self.write_buf_writable(buf)?;
708 buf.writeln("{")?;
709 self.prepare_ws(def.ws1);
710
711 let mut names = Buffer::new(0);
712 let mut values = Buffer::new(0);
713 for (i, arg) in def.args.iter().enumerate() {
714 if i > 0 {
715 names.write(", ");
716 values.write(", ");
717 }
718 names.write(arg);
719
720 values.write("&");
721 values.write(&self.visit_expr_root(args.get(i).ok_or_else(|| {
722 CompileError::String(format!("macro '{}' takes more than {} arguments", name, i))
723 })?)?);
724 self.locals.insert(arg);
725 }
726
727 buf.writeln(&format!("let ({}) = ({});", names.buf, values.buf))?;
728 let mut size_hint = self.handle(own_ctx, &def.nodes, buf, AstLevel::Nested)?;
729
730 self.flush_ws(def.ws2);
731 size_hint += self.write_buf_writable(buf)?;
732 buf.writeln("}")?;
733 self.locals.pop();
734 self.prepare_ws(ws);
735 Ok(size_hint)
736 }
737
handle_include( &mut self, ctx: &'a Context, buf: &mut Buffer, ws: WS, path: &str, ) -> Result<usize, CompileError>738 fn handle_include(
739 &mut self,
740 ctx: &'a Context,
741 buf: &mut Buffer,
742 ws: WS,
743 path: &str,
744 ) -> Result<usize, CompileError> {
745 self.flush_ws(ws);
746 self.write_buf_writable(buf)?;
747 let path = self
748 .input
749 .config
750 .find_template(path, Some(&self.input.path))?;
751 let src = get_template_source(&path)?;
752 let nodes = parse(&src, self.input.syntax)?;
753
754 // Make sure the compiler understands that the generated code depends on the template file.
755 {
756 let path = path.to_str().unwrap();
757 buf.writeln(
758 "e! {
759 include_bytes!(#path);
760 }
761 .to_string(),
762 )?;
763 }
764
765 let size_hint = {
766 // Since nodes must not outlive the Generator, we instantiate
767 // a nested Generator here to handle the include's nodes.
768 let mut gen = self.child();
769 let mut size_hint = gen.handle(ctx, &nodes, buf, AstLevel::Nested)?;
770 size_hint += gen.write_buf_writable(buf)?;
771 size_hint
772 };
773 self.prepare_ws(ws);
774 Ok(size_hint)
775 }
776
write_let_decl( &mut self, buf: &mut Buffer, ws: WS, var: &'a Target, ) -> Result<(), CompileError>777 fn write_let_decl(
778 &mut self,
779 buf: &mut Buffer,
780 ws: WS,
781 var: &'a Target,
782 ) -> Result<(), CompileError> {
783 self.handle_ws(ws);
784 self.write_buf_writable(buf)?;
785 buf.write("let ");
786 match *var {
787 Target::Name(name) => {
788 self.locals.insert(name);
789 buf.write(name);
790 }
791 Target::Tuple(ref targets) => {
792 buf.write("(");
793 for name in targets {
794 self.locals.insert(name);
795 buf.write(name);
796 buf.write(",");
797 }
798 buf.write(")");
799 }
800 }
801 buf.writeln(";")
802 }
803
write_let( &mut self, buf: &mut Buffer, ws: WS, var: &'a Target, val: &Expr, ) -> Result<(), CompileError>804 fn write_let(
805 &mut self,
806 buf: &mut Buffer,
807 ws: WS,
808 var: &'a Target,
809 val: &Expr,
810 ) -> Result<(), CompileError> {
811 self.handle_ws(ws);
812 let mut expr_buf = Buffer::new(0);
813 self.visit_expr(&mut expr_buf, val)?;
814
815 match *var {
816 Target::Name(name) => {
817 if !self.locals.contains(name) {
818 buf.write("let ");
819 self.locals.insert(name);
820 }
821 buf.write(name);
822 }
823 Target::Tuple(ref targets) => {
824 buf.write("let (");
825 for name in targets {
826 self.locals.insert(name);
827 buf.write(name);
828 buf.write(",");
829 }
830 buf.write(")");
831 }
832 }
833 buf.writeln(&format!(" = {};", &expr_buf.buf))
834 }
835
836 // If `name` is `Some`, this is a call to a block definition, and we have to find
837 // the first block for that name from the ancestry chain. If name is `None`, this
838 // is from a `super()` call, and we can get the name from `self.super_block`.
write_block( &mut self, buf: &mut Buffer, name: Option<&'a str>, outer: WS, ) -> Result<usize, CompileError>839 fn write_block(
840 &mut self,
841 buf: &mut Buffer,
842 name: Option<&'a str>,
843 outer: WS,
844 ) -> Result<usize, CompileError> {
845 // Flush preceding whitespace according to the outer WS spec
846 self.flush_ws(outer);
847
848 let prev_block = self.super_block;
849 let cur = match (name, prev_block) {
850 // The top-level context contains a block definition
851 (Some(cur_name), None) => (cur_name, 0),
852 // A block definition contains a block definition of the same name
853 (Some(cur_name), Some((prev_name, _))) if cur_name == prev_name => {
854 return Err(format!("cannot define recursive blocks ({})", cur_name).into());
855 }
856 // A block definition contains a definition of another block
857 (Some(cur_name), Some((_, _))) => (cur_name, 0),
858 // `super()` was called inside a block
859 (None, Some((prev_name, gen))) => (prev_name, gen + 1),
860 // `super()` is called from outside a block
861 (None, None) => return Err("cannot call 'super()' outside block".into()),
862 };
863 self.super_block = Some(cur);
864
865 // Get the block definition from the heritage chain
866 let heritage = self
867 .heritage
868 .as_ref()
869 .ok_or(CompileError::Static("no block ancestors available"))?;
870 let (ctx, def) = heritage.blocks[cur.0].get(cur.1).ok_or_else(|| {
871 CompileError::from(match name {
872 None => format!("no super() block found for block '{}'", cur.0),
873 Some(name) => format!("no block found for name '{}'", name),
874 })
875 })?;
876
877 // Get the nodes and whitespace suppression data from the block definition
878 let (ws1, nodes, ws2) = if let Node::BlockDef(ws1, _, nodes, ws2) = def {
879 (ws1, nodes, ws2)
880 } else {
881 unreachable!()
882 };
883
884 // Handle inner whitespace suppression spec and process block nodes
885 self.prepare_ws(*ws1);
886 self.locals.push();
887 let size_hint = self.handle(ctx, nodes, buf, AstLevel::Block)?;
888
889 if !self.locals.is_current_empty() {
890 // Need to flush the buffer before popping the variable stack
891 self.write_buf_writable(buf)?;
892 }
893
894 self.locals.pop();
895 self.flush_ws(*ws2);
896
897 // Restore original block context and set whitespace suppression for
898 // succeeding whitespace according to the outer WS spec
899 self.super_block = prev_block;
900 self.prepare_ws(outer);
901 Ok(size_hint)
902 }
903
write_expr(&mut self, ws: WS, s: &'a Expr<'a>)904 fn write_expr(&mut self, ws: WS, s: &'a Expr<'a>) {
905 self.handle_ws(ws);
906 self.buf_writable.push(Writable::Expr(s));
907 }
908
909 // Write expression buffer and empty
write_buf_writable(&mut self, buf: &mut Buffer) -> Result<usize, CompileError>910 fn write_buf_writable(&mut self, buf: &mut Buffer) -> Result<usize, CompileError> {
911 if self.buf_writable.is_empty() {
912 return Ok(0);
913 }
914
915 if self
916 .buf_writable
917 .iter()
918 .all(|w| matches!(w, Writable::Lit(_)))
919 {
920 let mut buf_lit = Buffer::new(0);
921 for s in mem::replace(&mut self.buf_writable, vec![]) {
922 if let Writable::Lit(s) = s {
923 buf_lit.write(s);
924 };
925 }
926 buf.writeln(&format!("writer.write_str({:#?})?;", &buf_lit.buf))?;
927 return Ok(buf_lit.buf.len());
928 }
929
930 let mut size_hint = 0;
931 let mut buf_format = Buffer::new(0);
932 let mut buf_expr = Buffer::new(buf.indent + 1);
933 let mut expr_cache = HashMap::with_capacity(self.buf_writable.len());
934 for s in mem::replace(&mut self.buf_writable, vec![]) {
935 match s {
936 Writable::Lit(s) => {
937 buf_format.write(&s.replace("{", "{{").replace("}", "}}"));
938 size_hint += s.len();
939 }
940 Writable::Expr(s) => {
941 use self::DisplayWrap::*;
942 let mut expr_buf = Buffer::new(0);
943 let wrapped = self.visit_expr(&mut expr_buf, s)?;
944 let expression = match wrapped {
945 Wrapped => expr_buf.buf,
946 Unwrapped => format!(
947 "::askama::MarkupDisplay::new_unsafe(&{}, {})",
948 expr_buf.buf, self.input.escaper
949 ),
950 };
951
952 use std::collections::hash_map::Entry;
953 let id = match expr_cache.entry(expression.clone()) {
954 Entry::Occupied(e) => *e.get(),
955 Entry::Vacant(e) => {
956 let id = self.named;
957 self.named += 1;
958
959 buf_expr.write(&format!("expr{} = ", id));
960 buf_expr.write("&");
961 buf_expr.write(&expression);
962 buf_expr.writeln(",")?;
963
964 e.insert(id);
965 id
966 }
967 };
968
969 buf_format.write(&format!("{{expr{}}}", id));
970 size_hint += 3;
971 }
972 }
973 }
974
975 buf.writeln("write!(")?;
976 buf.indent();
977 buf.writeln("writer,")?;
978 buf.writeln(&format!("{:#?},", &buf_format.buf))?;
979 buf.writeln(buf_expr.buf.trim())?;
980 buf.dedent()?;
981 buf.writeln(")?;")?;
982 Ok(size_hint)
983 }
984
visit_lit(&mut self, lws: &'a str, val: &'a str, rws: &'a str)985 fn visit_lit(&mut self, lws: &'a str, val: &'a str, rws: &'a str) {
986 assert!(self.next_ws.is_none());
987 if !lws.is_empty() {
988 if self.skip_ws {
989 self.skip_ws = false;
990 } else if val.is_empty() {
991 assert!(rws.is_empty());
992 self.next_ws = Some(lws);
993 } else {
994 self.buf_writable.push(Writable::Lit(lws));
995 }
996 }
997
998 if !val.is_empty() {
999 self.buf_writable.push(Writable::Lit(val));
1000 }
1001
1002 if !rws.is_empty() {
1003 self.next_ws = Some(rws);
1004 }
1005 }
1006
write_comment(&mut self, ws: WS)1007 fn write_comment(&mut self, ws: WS) {
1008 self.handle_ws(ws);
1009 }
1010
1011 /* Visitor methods for expression types */
1012
visit_expr_root(&mut self, expr: &Expr) -> Result<String, CompileError>1013 fn visit_expr_root(&mut self, expr: &Expr) -> Result<String, CompileError> {
1014 let mut buf = Buffer::new(0);
1015 self.visit_expr(&mut buf, expr)?;
1016 Ok(buf.buf)
1017 }
1018
visit_expr(&mut self, buf: &mut Buffer, expr: &Expr) -> Result<DisplayWrap, CompileError>1019 fn visit_expr(&mut self, buf: &mut Buffer, expr: &Expr) -> Result<DisplayWrap, CompileError> {
1020 Ok(match *expr {
1021 Expr::BoolLit(s) => self.visit_bool_lit(buf, s),
1022 Expr::NumLit(s) => self.visit_num_lit(buf, s),
1023 Expr::StrLit(s) => self.visit_str_lit(buf, s),
1024 Expr::CharLit(s) => self.visit_char_lit(buf, s),
1025 Expr::Var(s) => self.visit_var(buf, s),
1026 Expr::VarCall(var, ref args) => self.visit_var_call(buf, var, args)?,
1027 Expr::Path(ref path) => self.visit_path(buf, path),
1028 Expr::PathCall(ref path, ref args) => self.visit_path_call(buf, path, args)?,
1029 Expr::Array(ref elements) => self.visit_array(buf, elements)?,
1030 Expr::Attr(ref obj, name) => self.visit_attr(buf, obj, name)?,
1031 Expr::Index(ref obj, ref key) => self.visit_index(buf, obj, key)?,
1032 Expr::Filter(name, ref args) => self.visit_filter(buf, name, args)?,
1033 Expr::Unary(op, ref inner) => self.visit_unary(buf, op, inner)?,
1034 Expr::BinOp(op, ref left, ref right) => self.visit_binop(buf, op, left, right)?,
1035 Expr::Range(op, ref left, ref right) => self.visit_range(buf, op, left, right)?,
1036 Expr::Group(ref inner) => self.visit_group(buf, inner)?,
1037 Expr::MethodCall(ref obj, method, ref args) => {
1038 self.visit_method_call(buf, obj, method, args)?
1039 }
1040 Expr::RustMacro(name, args) => self.visit_rust_macro(buf, name, args),
1041 })
1042 }
1043
visit_rust_macro(&mut self, buf: &mut Buffer, name: &str, args: &str) -> DisplayWrap1044 fn visit_rust_macro(&mut self, buf: &mut Buffer, name: &str, args: &str) -> DisplayWrap {
1045 buf.write(name);
1046 buf.write("!(");
1047 buf.write(args);
1048 buf.write(")");
1049
1050 DisplayWrap::Unwrapped
1051 }
1052
visit_match_variant(&mut self, buf: &mut Buffer, param: &MatchVariant) -> DisplayWrap1053 fn visit_match_variant(&mut self, buf: &mut Buffer, param: &MatchVariant) -> DisplayWrap {
1054 let mut expr_buf = Buffer::new(0);
1055 let wrapped = match *param {
1056 MatchVariant::StrLit(s) => {
1057 expr_buf.write("&");
1058 self.visit_str_lit(&mut expr_buf, s)
1059 }
1060 MatchVariant::CharLit(s) => self.visit_char_lit(&mut expr_buf, s),
1061 MatchVariant::NumLit(s) => self.visit_num_lit(&mut expr_buf, s),
1062 MatchVariant::Name(s) => {
1063 expr_buf.write(s);
1064 DisplayWrap::Unwrapped
1065 }
1066 MatchVariant::Path(ref s) => {
1067 expr_buf.write(&s.join("::"));
1068 DisplayWrap::Unwrapped
1069 }
1070 };
1071 buf.write(&expr_buf.buf);
1072 wrapped
1073 }
1074
visit_match_param(&mut self, buf: &mut Buffer, param: &MatchParameter) -> DisplayWrap1075 fn visit_match_param(&mut self, buf: &mut Buffer, param: &MatchParameter) -> DisplayWrap {
1076 let mut expr_buf = Buffer::new(0);
1077 let wrapped = match *param {
1078 MatchParameter::NumLit(s) => self.visit_num_lit(&mut expr_buf, s),
1079 MatchParameter::StrLit(s) => self.visit_str_lit(&mut expr_buf, s),
1080 MatchParameter::CharLit(s) => self.visit_char_lit(&mut expr_buf, s),
1081 MatchParameter::Name(s) => {
1082 expr_buf.write(s);
1083 DisplayWrap::Unwrapped
1084 }
1085 };
1086 buf.write(&expr_buf.buf);
1087 wrapped
1088 }
1089
visit_filter( &mut self, buf: &mut Buffer, name: &str, args: &[Expr], ) -> Result<DisplayWrap, CompileError>1090 fn visit_filter(
1091 &mut self,
1092 buf: &mut Buffer,
1093 name: &str,
1094 args: &[Expr],
1095 ) -> Result<DisplayWrap, CompileError> {
1096 if name == "format" {
1097 self._visit_format_filter(buf, args)?;
1098 return Ok(DisplayWrap::Unwrapped);
1099 } else if name == "fmt" {
1100 self._visit_fmt_filter(buf, args)?;
1101 return Ok(DisplayWrap::Unwrapped);
1102 } else if name == "join" {
1103 self._visit_join_filter(buf, args)?;
1104 return Ok(DisplayWrap::Unwrapped);
1105 }
1106
1107 if name == "escape" || name == "safe" || name == "e" || name == "json" {
1108 buf.write(&format!(
1109 "::askama::filters::{}({}, ",
1110 name, self.input.escaper
1111 ));
1112 } else if filters::BUILT_IN_FILTERS.contains(&name) {
1113 buf.write(&format!("::askama::filters::{}(", name));
1114 } else {
1115 buf.write(&format!("filters::{}(", name));
1116 }
1117
1118 self._visit_args(buf, args)?;
1119 buf.write(")?");
1120 Ok(
1121 if name == "safe" || name == "escape" || name == "e" || name == "json" {
1122 DisplayWrap::Wrapped
1123 } else {
1124 DisplayWrap::Unwrapped
1125 },
1126 )
1127 }
1128
_visit_format_filter( &mut self, buf: &mut Buffer, args: &[Expr], ) -> Result<(), CompileError>1129 fn _visit_format_filter(
1130 &mut self,
1131 buf: &mut Buffer,
1132 args: &[Expr],
1133 ) -> Result<(), CompileError> {
1134 buf.write("format!(");
1135 if let Some(Expr::StrLit(v)) = args.first() {
1136 self.visit_str_lit(buf, v);
1137 if args.len() > 1 {
1138 buf.write(", ");
1139 }
1140 } else {
1141 return Err("invalid expression type for format filter".into());
1142 }
1143 self._visit_args(buf, &args[1..])?;
1144 buf.write(")");
1145 Ok(())
1146 }
1147
_visit_fmt_filter(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError>1148 fn _visit_fmt_filter(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError> {
1149 buf.write("format!(");
1150 if let Some(Expr::StrLit(v)) = args.get(1) {
1151 self.visit_str_lit(buf, v);
1152 buf.write(", ");
1153 } else {
1154 return Err("invalid expression type for fmt filter".into());
1155 }
1156 self._visit_args(buf, &args[0..1])?;
1157 if args.len() > 2 {
1158 return Err("only two arguments allowed to fmt filter".into());
1159 }
1160 buf.write(")");
1161 Ok(())
1162 }
1163
1164 // Force type coercion on first argument to `join` filter (see #39).
_visit_join_filter(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError>1165 fn _visit_join_filter(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError> {
1166 buf.write("::askama::filters::join((&");
1167 for (i, arg) in args.iter().enumerate() {
1168 if i > 0 {
1169 buf.write(", &");
1170 }
1171 self.visit_expr(buf, arg)?;
1172 if i == 0 {
1173 buf.write(").into_iter()");
1174 }
1175 }
1176 buf.write(")?");
1177 Ok(())
1178 }
1179
_visit_args(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError>1180 fn _visit_args(&mut self, buf: &mut Buffer, args: &[Expr]) -> Result<(), CompileError> {
1181 if args.is_empty() {
1182 return Ok(());
1183 }
1184
1185 for (i, arg) in args.iter().enumerate() {
1186 if i > 0 {
1187 buf.write(", &");
1188 } else {
1189 buf.write("&");
1190 }
1191
1192 let scoped = matches!(arg,
1193 Expr::Filter(_, _)
1194 | Expr::MethodCall(_, _, _)
1195 | Expr::VarCall(_, _)
1196 | Expr::PathCall(_, _));
1197
1198 if scoped {
1199 buf.writeln("{")?;
1200 self.visit_expr(buf, arg)?;
1201 buf.writeln("}")?;
1202 } else {
1203 self.visit_expr(buf, arg)?;
1204 }
1205 }
1206 Ok(())
1207 }
1208
visit_attr( &mut self, buf: &mut Buffer, obj: &Expr, attr: &str, ) -> Result<DisplayWrap, CompileError>1209 fn visit_attr(
1210 &mut self,
1211 buf: &mut Buffer,
1212 obj: &Expr,
1213 attr: &str,
1214 ) -> Result<DisplayWrap, CompileError> {
1215 if let Expr::Var(name) = *obj {
1216 if name == "loop" {
1217 if attr == "index" {
1218 buf.write("(_loop_item.index + 1)");
1219 return Ok(DisplayWrap::Unwrapped);
1220 } else if attr == "index0" {
1221 buf.write("_loop_item.index");
1222 return Ok(DisplayWrap::Unwrapped);
1223 } else if attr == "first" {
1224 buf.write("_loop_item.first");
1225 return Ok(DisplayWrap::Unwrapped);
1226 } else if attr == "last" {
1227 buf.write("_loop_item.last");
1228 return Ok(DisplayWrap::Unwrapped);
1229 } else {
1230 return Err("unknown loop variable".into());
1231 }
1232 }
1233 }
1234 self.visit_expr(buf, obj)?;
1235 buf.write(&format!(".{}", attr));
1236 Ok(DisplayWrap::Unwrapped)
1237 }
1238
visit_index( &mut self, buf: &mut Buffer, obj: &Expr, key: &Expr, ) -> Result<DisplayWrap, CompileError>1239 fn visit_index(
1240 &mut self,
1241 buf: &mut Buffer,
1242 obj: &Expr,
1243 key: &Expr,
1244 ) -> Result<DisplayWrap, CompileError> {
1245 buf.write("&");
1246 self.visit_expr(buf, obj)?;
1247 buf.write("[");
1248 self.visit_expr(buf, key)?;
1249 buf.write("]");
1250 Ok(DisplayWrap::Unwrapped)
1251 }
1252
visit_method_call( &mut self, buf: &mut Buffer, obj: &Expr, method: &str, args: &[Expr], ) -> Result<DisplayWrap, CompileError>1253 fn visit_method_call(
1254 &mut self,
1255 buf: &mut Buffer,
1256 obj: &Expr,
1257 method: &str,
1258 args: &[Expr],
1259 ) -> Result<DisplayWrap, CompileError> {
1260 if let Expr::Var("self") = obj {
1261 buf.write("self");
1262 } else {
1263 self.visit_expr(buf, obj)?;
1264 }
1265
1266 buf.write(&format!(".{}(", method));
1267 self._visit_args(buf, args)?;
1268 buf.write(")");
1269 Ok(DisplayWrap::Unwrapped)
1270 }
1271
visit_unary( &mut self, buf: &mut Buffer, op: &str, inner: &Expr, ) -> Result<DisplayWrap, CompileError>1272 fn visit_unary(
1273 &mut self,
1274 buf: &mut Buffer,
1275 op: &str,
1276 inner: &Expr,
1277 ) -> Result<DisplayWrap, CompileError> {
1278 buf.write(op);
1279 self.visit_expr(buf, inner)?;
1280 Ok(DisplayWrap::Unwrapped)
1281 }
1282
visit_range( &mut self, buf: &mut Buffer, op: &str, left: &Option<Box<Expr>>, right: &Option<Box<Expr>>, ) -> Result<DisplayWrap, CompileError>1283 fn visit_range(
1284 &mut self,
1285 buf: &mut Buffer,
1286 op: &str,
1287 left: &Option<Box<Expr>>,
1288 right: &Option<Box<Expr>>,
1289 ) -> Result<DisplayWrap, CompileError> {
1290 if let Some(left) = left {
1291 self.visit_expr(buf, left)?;
1292 }
1293 buf.write(op);
1294 if let Some(right) = right {
1295 self.visit_expr(buf, right)?;
1296 }
1297 Ok(DisplayWrap::Unwrapped)
1298 }
1299
visit_binop( &mut self, buf: &mut Buffer, op: &str, left: &Expr, right: &Expr, ) -> Result<DisplayWrap, CompileError>1300 fn visit_binop(
1301 &mut self,
1302 buf: &mut Buffer,
1303 op: &str,
1304 left: &Expr,
1305 right: &Expr,
1306 ) -> Result<DisplayWrap, CompileError> {
1307 self.visit_expr(buf, left)?;
1308 buf.write(&format!(" {} ", op));
1309 self.visit_expr(buf, right)?;
1310 Ok(DisplayWrap::Unwrapped)
1311 }
1312
visit_group(&mut self, buf: &mut Buffer, inner: &Expr) -> Result<DisplayWrap, CompileError>1313 fn visit_group(&mut self, buf: &mut Buffer, inner: &Expr) -> Result<DisplayWrap, CompileError> {
1314 buf.write("(");
1315 self.visit_expr(buf, inner)?;
1316 buf.write(")");
1317 Ok(DisplayWrap::Unwrapped)
1318 }
1319
visit_array( &mut self, buf: &mut Buffer, elements: &[Expr], ) -> Result<DisplayWrap, CompileError>1320 fn visit_array(
1321 &mut self,
1322 buf: &mut Buffer,
1323 elements: &[Expr],
1324 ) -> Result<DisplayWrap, CompileError> {
1325 buf.write("[");
1326 for (i, el) in elements.iter().enumerate() {
1327 if i > 0 {
1328 buf.write(", ");
1329 }
1330 self.visit_expr(buf, el)?;
1331 }
1332 buf.write("]");
1333 Ok(DisplayWrap::Unwrapped)
1334 }
1335
visit_path(&mut self, buf: &mut Buffer, path: &[&str]) -> DisplayWrap1336 fn visit_path(&mut self, buf: &mut Buffer, path: &[&str]) -> DisplayWrap {
1337 for (i, part) in path.iter().enumerate() {
1338 if i > 0 {
1339 buf.write("::");
1340 }
1341 buf.write(part);
1342 }
1343 DisplayWrap::Unwrapped
1344 }
1345
visit_path_call( &mut self, buf: &mut Buffer, path: &[&str], args: &[Expr], ) -> Result<DisplayWrap, CompileError>1346 fn visit_path_call(
1347 &mut self,
1348 buf: &mut Buffer,
1349 path: &[&str],
1350 args: &[Expr],
1351 ) -> Result<DisplayWrap, CompileError> {
1352 for (i, part) in path.iter().enumerate() {
1353 if i > 0 {
1354 buf.write("::");
1355 }
1356 buf.write(part);
1357 }
1358 buf.write("(");
1359 self._visit_args(buf, args)?;
1360 buf.write(")");
1361 Ok(DisplayWrap::Unwrapped)
1362 }
1363
visit_var(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap1364 fn visit_var(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
1365 if self.locals.contains(s) || s == "self" {
1366 buf.write(s);
1367 } else {
1368 buf.write("self.");
1369 buf.write(s);
1370 }
1371 DisplayWrap::Unwrapped
1372 }
1373
visit_var_call( &mut self, buf: &mut Buffer, s: &str, args: &[Expr], ) -> Result<DisplayWrap, CompileError>1374 fn visit_var_call(
1375 &mut self,
1376 buf: &mut Buffer,
1377 s: &str,
1378 args: &[Expr],
1379 ) -> Result<DisplayWrap, CompileError> {
1380 buf.write("(");
1381 if self.locals.contains(s) || s == "self" {
1382 buf.write(s);
1383 } else {
1384 buf.write("self.");
1385 buf.write(s);
1386 }
1387 buf.write(")(");
1388 self._visit_args(buf, args)?;
1389 buf.write(")");
1390 Ok(DisplayWrap::Unwrapped)
1391 }
1392
visit_bool_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap1393 fn visit_bool_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
1394 buf.write(s);
1395 DisplayWrap::Unwrapped
1396 }
1397
visit_str_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap1398 fn visit_str_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
1399 buf.write(&format!("\"{}\"", s));
1400 DisplayWrap::Unwrapped
1401 }
1402
visit_char_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap1403 fn visit_char_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
1404 buf.write(&format!("'{}'", s));
1405 DisplayWrap::Unwrapped
1406 }
1407
visit_num_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap1408 fn visit_num_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
1409 buf.write(s);
1410 DisplayWrap::Unwrapped
1411 }
1412
visit_target(&mut self, buf: &mut Buffer, target: &'a Target)1413 fn visit_target(&mut self, buf: &mut Buffer, target: &'a Target) {
1414 match *target {
1415 Target::Name(name) => {
1416 self.locals.insert(name);
1417 buf.write(name);
1418 }
1419 Target::Tuple(ref targets) => {
1420 buf.write("(");
1421 for name in targets {
1422 self.locals.insert(name);
1423 buf.write(name);
1424 buf.write(",");
1425 }
1426 buf.write(")");
1427 }
1428 }
1429 }
1430
1431 /* Helper methods for dealing with whitespace nodes */
1432
1433 // Combines `flush_ws()` and `prepare_ws()` to handle both trailing whitespace from the
1434 // preceding literal and leading whitespace from the succeeding literal.
handle_ws(&mut self, ws: WS)1435 fn handle_ws(&mut self, ws: WS) {
1436 self.flush_ws(ws);
1437 self.prepare_ws(ws);
1438 }
1439
1440 // If the previous literal left some trailing whitespace in `next_ws` and the
1441 // prefix whitespace suppressor from the given argument, flush that whitespace.
1442 // In either case, `next_ws` is reset to `None` (no trailing whitespace).
flush_ws(&mut self, ws: WS)1443 fn flush_ws(&mut self, ws: WS) {
1444 if self.next_ws.is_some() && !ws.0 {
1445 let val = self.next_ws.unwrap();
1446 if !val.is_empty() {
1447 self.buf_writable.push(Writable::Lit(val));
1448 }
1449 }
1450 self.next_ws = None;
1451 }
1452
1453 // Sets `skip_ws` to match the suffix whitespace suppressor from the given
1454 // argument, to determine whether to suppress leading whitespace from the
1455 // next literal.
prepare_ws(&mut self, ws: WS)1456 fn prepare_ws(&mut self, ws: WS) {
1457 self.skip_ws = ws.1;
1458 }
1459 }
1460
1461 struct Buffer {
1462 // The buffer to generate the code into
1463 buf: String,
1464 // The current level of indentation (in spaces)
1465 indent: u8,
1466 // Whether the output buffer is currently at the start of a line
1467 start: bool,
1468 }
1469
1470 impl Buffer {
new(indent: u8) -> Self1471 fn new(indent: u8) -> Self {
1472 Self {
1473 buf: String::new(),
1474 indent,
1475 start: true,
1476 }
1477 }
1478
writeln(&mut self, s: &str) -> Result<(), CompileError>1479 fn writeln(&mut self, s: &str) -> Result<(), CompileError> {
1480 if s == "}" {
1481 self.dedent()?;
1482 }
1483 if !s.is_empty() {
1484 self.write(s);
1485 }
1486 self.buf.push('\n');
1487 if s.ends_with('{') {
1488 self.indent();
1489 }
1490 self.start = true;
1491 Ok(())
1492 }
1493
write(&mut self, s: &str)1494 fn write(&mut self, s: &str) {
1495 if self.start {
1496 for _ in 0..(self.indent * 4) {
1497 self.buf.push(' ');
1498 }
1499 self.start = false;
1500 }
1501 self.buf.push_str(s);
1502 }
1503
indent(&mut self)1504 fn indent(&mut self) {
1505 self.indent += 1;
1506 }
1507
dedent(&mut self) -> Result<(), CompileError>1508 fn dedent(&mut self) -> Result<(), CompileError> {
1509 if self.indent == 0 {
1510 return Err("dedent() called while indentation == 0".into());
1511 }
1512 self.indent -= 1;
1513 Ok(())
1514 }
1515 }
1516
1517 #[derive(Debug)]
1518 struct SetChain<'a, T: 'a>
1519 where
1520 T: cmp::Eq + hash::Hash,
1521 {
1522 parent: Option<&'a SetChain<'a, T>>,
1523 scopes: Vec<HashSet<T>>,
1524 }
1525
1526 impl<'a, T: 'a> SetChain<'a, T>
1527 where
1528 T: cmp::Eq + hash::Hash,
1529 {
new() -> SetChain<'a, T>1530 fn new() -> SetChain<'a, T> {
1531 SetChain {
1532 parent: None,
1533 scopes: vec![HashSet::new()],
1534 }
1535 }
1536
with_parent<'p>(parent: &'p SetChain<T>) -> SetChain<'p, T>1537 fn with_parent<'p>(parent: &'p SetChain<T>) -> SetChain<'p, T> {
1538 SetChain {
1539 parent: Some(parent),
1540 scopes: vec![HashSet::new()],
1541 }
1542 }
1543
contains(&self, val: T) -> bool1544 fn contains(&self, val: T) -> bool {
1545 self.scopes.iter().rev().any(|set| set.contains(&val))
1546 || match self.parent {
1547 Some(set) => set.contains(val),
1548 None => false,
1549 }
1550 }
1551
is_current_empty(&self) -> bool1552 fn is_current_empty(&self) -> bool {
1553 self.scopes.last().unwrap().is_empty()
1554 }
1555
insert(&mut self, val: T)1556 fn insert(&mut self, val: T) {
1557 self.scopes.last_mut().unwrap().insert(val);
1558 }
1559
push(&mut self)1560 fn push(&mut self) {
1561 self.scopes.push(HashSet::new());
1562 }
1563
pop(&mut self)1564 fn pop(&mut self) {
1565 self.scopes.pop().unwrap();
1566 assert!(!self.scopes.is_empty());
1567 }
1568 }
1569
median(sizes: &mut [usize]) -> usize1570 fn median(sizes: &mut [usize]) -> usize {
1571 sizes.sort_unstable();
1572 if sizes.len() % 2 == 1 {
1573 sizes[sizes.len() / 2]
1574 } else {
1575 (sizes[sizes.len() / 2 - 1] + sizes[sizes.len() / 2]) / 2
1576 }
1577 }
1578
1579 #[derive(Clone, PartialEq)]
1580 enum AstLevel {
1581 Top,
1582 Block,
1583 Nested,
1584 }
1585
1586 impl Copy for AstLevel {}
1587
1588 #[derive(Clone)]
1589 enum DisplayWrap {
1590 Wrapped,
1591 Unwrapped,
1592 }
1593
1594 impl Copy for DisplayWrap {}
1595
1596 #[derive(Debug)]
1597 enum Writable<'a> {
1598 Lit(&'a str),
1599 Expr(&'a Expr<'a>),
1600 }
1601