1use std;
7
8use itertools;
9use liquid_error::{Error, Result, ResultLiquidExt};
10use liquid_interpreter::Expression;
11use liquid_interpreter::Renderable;
12use liquid_interpreter::Variable;
13use liquid_value::Value;
14
15use super::Language;
16use super::Text;
17use super::{Filter, FilterArguments, FilterChain};
18
19use pest::Parser;
20
21mod pest {
22 #[derive(Parser)]
23 #[grammar = "grammar.pest"]
24 pub struct LiquidParser;
25}
26
27use self::pest::*;
28
29type Pair<'a> = ::pest::iterators::Pair<'a, Rule>;
30type Pairs<'a> = ::pest::iterators::Pairs<'a, Rule>;
31
32fn convert_pest_error(err: ::pest::error::Error<Rule>) -> Error {
34 let err = err.renamed_rules(|&rule| match rule {
35 Rule::LesserThan => "\"<\"".to_string(),
36 Rule::GreaterThan => "\">\"".to_string(),
37 Rule::LesserThanEquals => "\"<=\"".to_string(),
38 Rule::GreaterThanEquals => "\">=\"".to_string(),
39 Rule::Equals => "\"==\"".to_string(),
40 Rule::NotEquals => "\"!=\"".to_string(),
41 Rule::LesserThanGreaterThan => "\"<>\"".to_string(),
42 Rule::Assign => "\"=\"".to_string(),
43 Rule::Comma => "\",\"".to_string(),
44 Rule::Colon => "\":\"".to_string(),
45 other => format!("{:?}", other),
46 });
47 Error::with_msg(err.to_string())
48}
49
50fn error_from_pair(pair: Pair, msg: String) -> Error {
53 let pest_error = ::pest::error::Error::new_from_span(
54 ::pest::error::ErrorVariant::CustomError { message: msg },
55 pair.as_span(),
56 );
57 convert_pest_error(pest_error)
58}
59
60pub fn parse(text: &str, options: &Language) -> Result<Vec<Box<Renderable>>> {
62 let mut liquid = LiquidParser::parse(Rule::LaxLiquidFile, text)
63 .expect("Parsing with Rule::LaxLiquidFile should not raise errors, but InvalidLiquid tokens instead.")
64 .next()
65 .expect("Unwrapping LiquidFile to access the elements.")
66 .into_inner();
67
68 let mut renderables = Vec::new();
69
70 while let Some(element) = liquid.next() {
71 if element.as_rule() == Rule::EOI {
72 break;
73 }
74
75 renderables.push(BlockElement::parse_pair(
76 element.into(),
77 &mut liquid,
78 options,
79 )?);
80 }
81 Ok(renderables)
82}
83
84fn parse_literal(literal: Pair) -> Value {
87 if literal.as_rule() != Rule::Literal {
88 panic!("Expected literal.");
89 }
90
91 let literal = literal
92 .into_inner()
93 .next()
94 .expect("Get into the rule inside literal.");
95
96 match literal.as_rule() {
97 Rule::NilLiteral => Value::Nil,
98 Rule::EmptyLiteral => Value::Empty,
99 Rule::BlankLiteral => Value::Blank,
100 Rule::StringLiteral => {
101 let literal = literal.as_str();
102 let trim_quotes = &literal[1..literal.len() - 1];
103
104 Value::scalar(trim_quotes.to_owned())
105 }
106 Rule::IntegerLiteral => Value::scalar(
107 literal
108 .as_str()
109 .parse::<i32>()
110 .expect("Grammar ensures matches are parseable as integers."),
111 ),
112 Rule::FloatLiteral => Value::scalar(
113 literal
114 .as_str()
115 .parse::<f64>()
116 .expect("Grammar ensures matches are parseable as floats."),
117 ),
118 Rule::BooleanLiteral => Value::scalar(
119 literal
120 .as_str()
121 .parse::<bool>()
122 .expect("Grammar ensures matches are parseable as bools."),
123 ),
124 _ => unreachable!(),
125 }
126}
127
128fn parse_variable(variable: Pair) -> Variable {
131 if variable.as_rule() != Rule::Variable {
132 panic!("Expected variable.");
133 }
134
135 let mut indexes = variable.into_inner();
136
137 let first_identifier = indexes
138 .next()
139 .expect("A variable starts with an identifier.")
140 .as_str()
141 .to_owned();
142 let mut variable = Variable::with_literal(first_identifier);
143
144 let indexes = indexes.map(|index| match index.as_rule() {
145 Rule::Identifier => Expression::with_literal(index.as_str().to_owned()),
146 Rule::Value => parse_value(index),
147 _ => unreachable!(),
148 });
149
150 variable.extend(indexes);
151 variable
152}
153
154fn parse_value(value: Pair) -> Expression {
161 if value.as_rule() != Rule::Value {
162 panic!("Expected value.");
163 }
164
165 let value = value.into_inner().next().expect("Get inside the value.");
166
167 match value.as_rule() {
168 Rule::Literal => Expression::Literal(parse_literal(value)),
169 Rule::Variable => Expression::Variable(parse_variable(value)),
170 _ => unreachable!(),
171 }
172}
173
174fn parse_filter(filter: Pair, options: &Language) -> Result<Box<Filter>> {
177 if filter.as_rule() != Rule::Filter {
178 panic!("Expected a filter.");
179 }
180
181 let filter_str = filter.as_str();
182 let mut filter = filter.into_inner();
183 let name = filter.next().expect("A filter always has a name.").as_str();
184
185 let mut keyword_args = Vec::new();
186 let mut positional_args = Vec::new();
187
188 for arg in filter {
189 match arg.as_rule() {
190 Rule::PositionalFilterArgument => {
191 let value = arg.into_inner().next().expect("Rule ensures value.");
192 let value = parse_value(value);
193 positional_args.push(value);
194 }
195 Rule::KeywordFilterArgument => {
196 let mut arg = arg.into_inner();
197 let key = arg.next().expect("Rule ensures identifier.").as_str();
198 let value = arg.next().expect("Rule ensures value.");
199 let value = parse_value(value);
200 keyword_args.push((key, value));
201 }
202 _ => unreachable!(),
203 }
204 }
205
206 let args = FilterArguments {
207 positional: Box::new(positional_args.into_iter()),
208 keyword: Box::new(keyword_args.into_iter()),
209 };
210
211 let f = options.filters.get(name).ok_or_else(|| {
212 let mut available: Vec<_> = options.filters.plugin_names().collect();
213 available.sort_unstable();
214 let available = itertools::join(available, ", ");
215 Error::with_msg("Unknown filter")
216 .context("requested filter", name.to_owned())
217 .context("available filters", available)
218 })?;
219
220 let f = f
221 .parse(args)
222 .trace("Filter parsing error")
223 .context_key("filter")
224 .value_with(|| filter_str.to_string().into())?;
225
226 Ok(f)
227}
228
229fn parse_filter_chain(chain: Pair, options: &Language) -> Result<FilterChain> {
232 if chain.as_rule() != Rule::FilterChain {
233 panic!("Expected an expression with filters.");
234 }
235
236 let mut chain = chain.into_inner();
237 let entry = parse_value(
238 chain
239 .next()
240 .expect("A filterchain always has starts by a value."),
241 );
242 let filters: Result<Vec<_>> = chain.map(|f| parse_filter(f, options)).collect();
243 let filters = filters?;
244
245 let filters = FilterChain::new(entry, filters);
246 Ok(filters)
247}
248
249pub struct TagBlock<'a: 'b, 'b> {
251 name: &'b str,
252 iter: &'b mut Iterator<Item = Pair<'a>>,
253 closed: bool,
254}
255
256impl<'a, 'b> TagBlock<'a, 'b> {
257 fn new(name: &'b str, next_elements: &'b mut Iterator<Item = Pair<'a>>) -> Self {
258 TagBlock {
259 name,
260 iter: next_elements,
261 closed: false,
262 }
263 }
264
265 pub fn next(&mut self) -> Result<Option<BlockElement<'a>>> {
270 if self.closed {
271 return Ok(None);
272 }
273
274 let element = self.iter.next().expect("File shouldn't end before EOI.");
275
276 if element.as_rule() == Rule::EOI {
277 return error_from_pair(
278 element,
279 format!("Unclosed block. {{% end{} %}} tag expected.", self.name),
280 )
281 .into_err();
282 }
283
284 if element.as_rule() == Rule::Tag {
286 let as_str = element.as_str();
287 let mut tag = element
288 .into_inner()
289 .next()
290 .expect("Unwrapping TagInner")
291 .into_inner();
292 let name = tag.next().expect("Tags start by their identifier.");
293 let name_str = name.as_str();
294
295 if name_str.len() > 3 && &name_str[0..3] == "end" && &name_str[3..] == self.name {
297 if let Some(token) = tag.next() {
301 return TagToken::from(token).raise_error().into_err();
302 }
303
304 self.closed = true;
305 return Ok(None);
306 } else {
307 let tokens = TagTokenIter::new(&name, tag);
309 return Ok(Some(BlockElement::Tag(Tag {
310 name,
311 tokens,
312 as_str,
313 })));
314 }
315 }
316 Ok(Some(element.into()))
317 }
318
319 pub fn escape_liquid(&mut self, allow_nesting: bool) -> Result<&'a str> {
334 if self.closed {
335 panic!("`escape_liquid` must be used in an open tag.")
336 }
337
338 let mut nesting_level = 1;
339
340 let mut start_pos = None;
342 let mut end_pos = None;
343
344 while let Some(element) = self.iter.next() {
345 let element_as_span = element.as_span();
346 if start_pos.is_none() {
347 start_pos = Some(element_as_span.start_pos());
348 }
349
350 if element.as_rule() == Rule::EOI {
351 return error_from_pair(
352 element,
353 format!("Unclosed block. {{% end{} %}} tag expected.", self.name),
354 )
355 .into_err();
356 }
357
358 if element.as_rule() == Rule::Tag {
360 let mut tag = element
361 .into_inner()
362 .next()
363 .expect("Unwrapping TagInner")
364 .into_inner();
365 let name = tag.next().expect("Tags start by their identifier.");
366 let name_str = name.as_str();
367
368 if name_str.len() > 3 && &name_str[0..3] == "end" && &name_str[3..] == self.name {
370 if tag.next().is_none() {
373 nesting_level -= 1;
374 if nesting_level == 0 {
375 self.closed = true;
376 let start_pos = start_pos.expect("Will be `Some` inside this loop.");
377 let output = match end_pos {
378 Some(end_pos) => start_pos.span(&end_pos).as_str(),
379 None => "",
380 };
381
382 return Ok(output);
383 }
384 }
385 } else if name_str == self.name && allow_nesting {
386 nesting_level += 1;
388 }
389 }
390
391 end_pos = Some(element_as_span.end_pos());
392 }
393
394 panic!("Function must eventually find either a Rule::EOI or a closing tag.")
395 }
396
397 pub fn parse_all(&mut self, options: &Language) -> Result<Vec<Box<Renderable>>> {
399 let mut renderables = Vec::new();
400 while let Some(r) = self.parse_next(options)? {
401 renderables.push(r);
402 }
403 Ok(renderables)
404 }
405
406 pub fn parse_next(&mut self, options: &Language) -> Result<Option<Box<Renderable>>> {
410 match self.next()? {
411 None => Ok(None),
412 Some(element) => Ok(Some(element.parse(self, options)?)),
413 }
414 }
415
416 pub fn assert_empty(self) {
421 assert!(
422 self.closed,
423 "Block {{% {} %}} doesn't exhaust its iterator of elements.",
424 self.name
425 )
426 }
427}
428
429pub struct Raw<'a> {
431 text: &'a str,
432}
433impl<'a> From<Pair<'a>> for Raw<'a> {
434 fn from(element: Pair<'a>) -> Self {
435 if element.as_rule() != Rule::Raw {
436 panic!("Only rule Raw can be converted to Raw.");
437 }
438 Raw {
439 text: element.as_str(),
440 }
441 }
442}
443impl<'a> Into<&'a str> for Raw<'a> {
444 fn into(self) -> &'a str {
445 self.as_str()
446 }
447}
448impl<'a> Raw<'a> {
449 pub fn to_renderable(self) -> Box<Renderable> {
451 Box::new(Text::new(self.as_str()))
452 }
453
454 pub fn as_str(&self) -> &'a str {
456 self.text
457 }
458}
459
460pub struct Tag<'a> {
462 name: Pair<'a>,
463 tokens: TagTokenIter<'a>,
464 as_str: &'a str,
465}
466
467impl<'a> From<Pair<'a>> for Tag<'a> {
468 fn from(element: Pair<'a>) -> Self {
469 if element.as_rule() != Rule::Tag {
470 panic!("Only rule Tag can be converted to Tag.");
471 }
472 let as_str = element.as_str();
473 let mut tag = element
474 .into_inner()
475 .next()
476 .expect("Unwrapping TagInner.")
477 .into_inner();
478 let name = tag.next().expect("A tag starts with an identifier.");
479 let tokens = TagTokenIter::new(&name, tag);
480
481 Tag {
482 name,
483 tokens,
484 as_str,
485 }
486 }
487}
488
489impl<'a> Tag<'a> {
490 pub fn new(text: &'a str) -> Result<Self> {
494 let tag = LiquidParser::parse(Rule::Tag, text)
495 .map_err(convert_pest_error)?
496 .next()
497 .ok_or_else(|| Error::with_msg("Tried to create a Tag from an invalid string."))?;
498
499 Ok(tag.into())
500 }
501
502 pub fn name(&self) -> &str {
504 self.name.as_str()
505 }
506
507 pub fn tokens(&mut self) -> &mut TagTokenIter<'a> {
509 &mut self.tokens
510 }
511
512 pub fn into_tokens(self) -> TagTokenIter<'a> {
514 self.tokens
515 }
516
517 pub fn as_str(&self) -> &str {
519 self.as_str
520 }
521
522 pub fn parse(self, tag_block: &mut TagBlock, options: &Language) -> Result<Box<Renderable>> {
524 self.parse_pair(&mut tag_block.iter, options)
525 }
526
527 fn parse_pair(
529 self,
530 next_elements: &mut Iterator<Item = Pair>,
531 options: &Language,
532 ) -> Result<Box<Renderable>> {
533 let (name, tokens) = (self.name, self.tokens);
534 let position = name.as_span();
535 let name = name.as_str();
536
537 if let Some(plugin) = options.tags.get(name) {
538 plugin.parse(tokens, options)
539 } else if let Some(plugin) = options.blocks.get(name) {
540 let block = TagBlock::new(name, next_elements);
541 let renderables = plugin.parse(tokens, block, options)?;
542 Ok(renderables)
543 } else {
544 let pest_error = ::pest::error::Error::new_from_span(
545 ::pest::error::ErrorVariant::CustomError {
546 message: "Unknown tag.".to_string(),
547 },
548 position,
549 );
550 let mut all_tags: Vec<_> = options.tags.plugin_names().collect();
551 all_tags.sort_unstable();
552 let all_tags = itertools::join(all_tags, ", ");
553 let mut all_blocks: Vec<_> = options.blocks.plugin_names().collect();
554 all_blocks.sort_unstable();
555 let all_blocks = itertools::join(all_blocks, ", ");
556 let error = convert_pest_error(pest_error)
557 .context("requested", name.to_owned())
558 .context("available tags", all_tags)
559 .context("available blocks", all_blocks);
560 Err(error)
561 }
562 }
563}
564
565pub struct Exp<'a> {
567 element: Pair<'a>,
568}
569
570impl<'a> From<Pair<'a>> for Exp<'a> {
571 fn from(element: Pair<'a>) -> Self {
572 if element.as_rule() != Rule::Expression {
573 panic!("Only rule Expression can be converted to Expression.");
574 }
575 Exp { element }
576 }
577}
578
579impl<'a> Exp<'a> {
580 pub fn parse(self, options: &Language) -> Result<Box<Renderable>> {
582 let filter_chain = self
583 .element
584 .into_inner()
585 .next()
586 .expect("Unwrapping ExpressionInner")
587 .into_inner()
588 .next()
589 .expect("An expression consists of one filterchain.");
590
591 let filter_chain = parse_filter_chain(filter_chain, options)?;
592 Ok(Box::new(filter_chain))
593 }
594
595 pub fn as_str(&self) -> &str {
597 self.element.as_str()
598 }
599}
600
601pub struct InvalidLiquidToken<'a> {
604 element: Pair<'a>,
605}
606impl<'a> InvalidLiquidToken<'a> {
607 pub fn as_str(&self) -> &str {
610 self.element.as_str()
611 }
612
613 pub fn parse(self, tag_block: &mut TagBlock) -> Result<Box<Renderable>> {
616 self.parse_pair(&mut tag_block.iter)
617 }
618
619 fn parse_pair(self, next_elements: &mut Iterator<Item = Pair>) -> Result<Box<Renderable>> {
622 use pest::error::LineColLocation;
623
624 let invalid_token_span = self.element.as_span();
625 let invalid_token_position = invalid_token_span.start_pos();
626 let (offset_l, offset_c) = invalid_token_position.line_col();
627 let offset_l = offset_l - 1;
628 let offset_c = offset_c - 1;
629
630 let end_position = match next_elements.last() {
631 Some(element) => element.as_span().end_pos(),
632 None => invalid_token_span.end_pos(),
633 };
634
635 let mut text = String::from(&invalid_token_position.line_of()[..offset_c]);
636 text.push_str(invalid_token_position.span(&end_position).as_str());
637
638 let mut error = match LiquidParser::parse(Rule::LiquidFile, &text) {
641 Ok(_) => panic!("`LiquidParser::parse` should fail in InvalidLiquidTokens."),
642 Err(error) => error,
643 };
644
645 error.line_col = match error.line_col {
649 LineColLocation::Span((ls, cs), (le, ce)) => {
650 LineColLocation::Span((ls + offset_l, cs), (le + offset_l, ce))
651 }
652 LineColLocation::Pos((ls, cs)) => LineColLocation::Pos((ls + offset_l, cs)),
653 };
654
655 Err(convert_pest_error(error))
656 }
657}
658impl<'a> From<Pair<'a>> for InvalidLiquidToken<'a> {
659 fn from(element: Pair<'a>) -> Self {
660 if element.as_rule() != Rule::InvalidLiquid {
661 panic!("Tried to parse a valid liquid token as invalid.");
662 }
663 InvalidLiquidToken { element }
664 }
665}
666
667pub enum BlockElement<'a> {
671 Raw(Raw<'a>),
672 Tag(Tag<'a>),
673 Expression(Exp<'a>),
674 Invalid(InvalidLiquidToken<'a>),
675}
676impl<'a> From<Pair<'a>> for BlockElement<'a> {
677 fn from(element: Pair<'a>) -> Self {
678 match element.as_rule() {
679 Rule::Raw => BlockElement::Raw(element.into()),
680 Rule::Tag => BlockElement::Tag(element.into()),
681 Rule::Expression => BlockElement::Expression(element.into()),
682 Rule::InvalidLiquid => BlockElement::Invalid(element.into()),
683 _ => panic!(
684 "Only rules Raw | Tag | Expression can be converted to BlockElement. Found {:?}",
685 element.as_rule()
686 ),
687 }
688 }
689}
690
691impl<'a> BlockElement<'a> {
692 pub fn parse(
694 self,
695 block: &mut TagBlock<'a, '_>,
696 options: &Language,
697 ) -> Result<Box<Renderable>> {
698 match self {
699 BlockElement::Raw(raw) => Ok(raw.to_renderable()),
700 BlockElement::Tag(tag) => tag.parse(block, options),
701 BlockElement::Expression(exp) => exp.parse(options),
702 BlockElement::Invalid(invalid) => invalid.parse(block),
703 }
704 }
705
706 fn parse_pair(
708 self,
709 next_elements: &mut Iterator<Item = Pair>,
710 options: &Language,
711 ) -> Result<Box<Renderable>> {
712 match self {
713 BlockElement::Raw(raw) => Ok(raw.to_renderable()),
714 BlockElement::Tag(tag) => tag.parse_pair(next_elements, options),
715 BlockElement::Expression(exp) => exp.parse(options),
716 BlockElement::Invalid(invalid) => invalid.parse_pair(next_elements),
717 }
718 }
719
720 pub fn as_str(&self) -> &str {
722 match self {
723 BlockElement::Raw(raw) => raw.as_str(),
724 BlockElement::Tag(tag) => tag.as_str(),
725 BlockElement::Expression(exp) => exp.as_str(),
726 BlockElement::Invalid(invalid) => invalid.as_str(),
727 }
728 }
729}
730
731pub struct TagTokenIter<'a> {
735 iter: Box<Iterator<Item = TagToken<'a>> + 'a>,
736 position: ::pest::Position<'a>,
737}
738impl<'a> Iterator for TagTokenIter<'a> {
739 type Item = TagToken<'a>;
740 fn next(&mut self) -> Option<Self::Item> {
741 self.iter.next().map(|next| {
742 self.position = next.token.as_span().end_pos();
743 next
744 })
745 }
746}
747impl<'a> TagTokenIter<'a> {
748 fn new(name: &Pair<'a>, tokens: Pairs<'a>) -> Self {
749 TagTokenIter {
750 iter: Box::new(tokens.map(TagToken::from)),
751 position: name.as_span().end_pos(),
752 }
753 }
754
755 pub fn raise_error(&mut self, error_msg: &str) -> Error {
758 let pest_error = ::pest::error::Error::new_from_pos(
759 ::pest::error::ErrorVariant::CustomError {
760 message: error_msg.to_string(),
761 },
762 self.position.clone(),
763 );
764 convert_pest_error(pest_error)
765 }
766
767 pub fn expect_next(&mut self, error_msg: &str) -> Result<TagToken<'a>> {
769 self.next().ok_or_else(|| self.raise_error(error_msg))
770 }
771
772 pub fn expect_nothing(&mut self) -> Result<()> {
774 if let Some(token) = self.next() {
775 Err(token.raise_error())
776 } else {
777 Ok(())
778 }
779 }
780}
781
782pub enum TryMatchToken<'a, T> {
787 Matches(T),
788 Fails(TagToken<'a>),
789}
790
791impl<'a, T> TryMatchToken<'a, T> {
792 pub fn into_result(self) -> Result<T> {
793 match self {
794 TryMatchToken::Matches(t) => Ok(t),
795 TryMatchToken::Fails(t) => Err(t.raise_error()),
796 }
797 }
798
799 pub fn into_result_custom_msg(self, msg: &str) -> Result<T> {
800 match self {
801 TryMatchToken::Matches(t) => Ok(t),
802 TryMatchToken::Fails(t) => Err(t.raise_custom_error(msg)),
803 }
804 }
805}
806
807pub struct TagToken<'a> {
809 token: Pair<'a>,
810 expected: Vec<Rule>,
811}
812
813impl<'a> From<Pair<'a>> for TagToken<'a> {
814 fn from(token: Pair<'a>) -> Self {
815 TagToken {
816 token,
817 expected: Vec::new(),
818 }
819 }
820}
821
822impl<'a> TagToken<'a> {
823 pub fn raise_error(self) -> Error {
833 let pest_error = ::pest::error::Error::new_from_span(
834 ::pest::error::ErrorVariant::ParsingError {
835 positives: self.expected,
836 negatives: vec![self.token.as_rule()],
837 },
838 self.token.as_span(),
839 );
840 convert_pest_error(pest_error)
841 }
842
843 pub fn raise_custom_error(self, msg: &str) -> Error {
847 let pest_error = ::pest::error::Error::new_from_span(
848 ::pest::error::ErrorVariant::CustomError {
849 message: msg.to_string(),
850 },
851 self.token.as_span(),
852 );
853 convert_pest_error(pest_error)
854 }
855
856 fn unwrap_filter_chain(&mut self) -> std::result::Result<Pair<'a>, ()> {
857 let token = self.token.clone();
858
859 if token.as_rule() != Rule::FilterChain {
860 return Err(());
861 }
862
863 Ok(token)
864 }
865
866 fn unwrap_value(&mut self) -> std::result::Result<Pair<'a>, ()> {
867 let filterchain = self.unwrap_filter_chain()?;
868
869 let mut chain = filterchain.into_inner();
870 let value = chain.next().expect("Unwrapping value out of Filterchain.");
871 if chain.next().is_some() {
872 return Err(());
874 }
875
876 Ok(value)
877 }
878
879 fn unwrap_variable(&mut self) -> std::result::Result<Pair<'a>, ()> {
880 let value = self.unwrap_value()?;
881
882 let variable = value
883 .into_inner()
884 .next()
885 .expect("A value is made of one token.");
886
887 if variable.as_rule() != Rule::Variable {
888 return Err(());
889 }
890
891 Ok(variable)
892 }
893
894 fn unwrap_identifier(&mut self) -> std::result::Result<Pair<'a>, ()> {
895 let variable = self.unwrap_variable()?;
896
897 let mut indexes = variable.into_inner();
898 let identifier = indexes
899 .next()
900 .expect("Unwrapping identifier out of variable.");
901 if indexes.next().is_some() {
902 return Err(());
904 }
905
906 Ok(identifier)
907 }
908
909 fn unwrap_literal(&mut self) -> std::result::Result<Pair<'a>, ()> {
910 let value = self.unwrap_value()?;
911
912 let literal = value
913 .into_inner()
914 .next()
915 .expect("A value is made of one token.");
916
917 if literal.as_rule() != Rule::Literal {
918 return Err(());
919 }
920
921 Ok(literal)
922 }
923
924 pub fn expect_filter_chain(mut self, options: &Language) -> TryMatchToken<'a, FilterChain> {
926 match self.expect_filter_chain_err(options) {
927 Ok(t) => TryMatchToken::Matches(t),
928 Err(_) => {
929 self.expected.push(Rule::FilterChain);
930 TryMatchToken::Fails(self)
931 }
932 }
933 }
934
935 fn expect_filter_chain_err(&mut self, options: &Language) -> Result<FilterChain> {
936 let t = self
937 .unwrap_filter_chain()
938 .map_err(|_| Error::with_msg("failed to parse"))?;
939 let f = parse_filter_chain(t, options)?;
940 Ok(f)
941 }
942
943 pub fn expect_value(mut self) -> TryMatchToken<'a, Expression> {
948 match self.unwrap_value() {
949 Ok(t) => TryMatchToken::Matches(parse_value(t)),
950 Err(_) => {
951 self.expected.push(Rule::Value);
952 TryMatchToken::Fails(self)
953 }
954 }
955 }
956
957 pub fn expect_variable(mut self) -> TryMatchToken<'a, Variable> {
959 match self.unwrap_variable() {
960 Ok(t) => TryMatchToken::Matches(parse_variable(t)),
961 Err(_) => {
962 self.expected.push(Rule::Variable);
963 TryMatchToken::Fails(self)
964 }
965 }
966 }
967
968 pub fn expect_identifier(mut self) -> TryMatchToken<'a, &'a str> {
972 match self.unwrap_identifier() {
973 Ok(t) => TryMatchToken::Matches(t.as_str()),
974 Err(_) => {
975 self.expected.push(Rule::Identifier);
976 TryMatchToken::Fails(self)
977 }
978 }
979 }
980
981 pub fn expect_literal(mut self) -> TryMatchToken<'a, Value> {
985 match self.unwrap_literal() {
986 Ok(t) => TryMatchToken::Matches(parse_literal(t)),
987 Err(_) => {
988 self.expected.push(Rule::Literal);
989 TryMatchToken::Fails(self)
990 }
991 }
992 }
993 pub fn expect_range(mut self) -> TryMatchToken<'a, (Expression, Expression)> {
997 let token = self.token.clone();
998
999 if token.as_rule() != Rule::Range {
1000 self.expected.push(Rule::Range);
1001 return TryMatchToken::Fails(self);
1002 }
1003
1004 let mut range = token.into_inner();
1005 TryMatchToken::Matches((
1006 parse_value(range.next().expect("start")),
1007 parse_value(range.next().expect("end")),
1008 ))
1009 }
1010
1011 pub fn expect_str(self, expected: &str) -> TryMatchToken<'a, ()> {
1013 if self.as_str() == expected {
1014 TryMatchToken::Matches(())
1015 } else {
1016 TryMatchToken::Fails(self)
1018 }
1019 }
1020
1021 pub fn as_str(&self) -> &str {
1023 self.token.as_str().trim()
1024 }
1025}
1026
1027#[cfg(test)]
1028mod test {
1029 use super::*;
1030 use liquid_interpreter::{Context, Template};
1031
1032 #[test]
1033 fn test_parse_literal() {
1034 let nil = LiquidParser::parse(Rule::Literal, "nil")
1035 .unwrap()
1036 .next()
1037 .unwrap();
1038 assert_eq!(parse_literal(nil), Value::Nil);
1039 let nil = LiquidParser::parse(Rule::Literal, "null")
1040 .unwrap()
1041 .next()
1042 .unwrap();
1043 assert_eq!(parse_literal(nil), Value::Nil);
1044
1045 let blank = LiquidParser::parse(Rule::Literal, "blank")
1046 .unwrap()
1047 .next()
1048 .unwrap();
1049 assert_eq!(parse_literal(blank), Value::Blank);
1050
1051 let empty = LiquidParser::parse(Rule::Literal, "empty")
1052 .unwrap()
1053 .next()
1054 .unwrap();
1055 assert_eq!(parse_literal(empty), Value::Empty);
1056
1057 let integer = LiquidParser::parse(Rule::Literal, "42")
1058 .unwrap()
1059 .next()
1060 .unwrap();
1061 assert_eq!(parse_literal(integer), Value::scalar(42));
1062
1063 let negative_int = LiquidParser::parse(Rule::Literal, "-42")
1064 .unwrap()
1065 .next()
1066 .unwrap();
1067 assert_eq!(parse_literal(negative_int), Value::scalar(-42));
1068
1069 let float = LiquidParser::parse(Rule::Literal, "4321.032")
1070 .unwrap()
1071 .next()
1072 .unwrap();
1073 assert_eq!(parse_literal(float), Value::scalar(4321.032));
1074
1075 let negative_float = LiquidParser::parse(Rule::Literal, "-4321.032")
1076 .unwrap()
1077 .next()
1078 .unwrap();
1079 assert_eq!(parse_literal(negative_float), Value::scalar(-4321.032));
1080
1081 let boolean = LiquidParser::parse(Rule::Literal, "true")
1082 .unwrap()
1083 .next()
1084 .unwrap();
1085 assert_eq!(parse_literal(boolean), Value::scalar(true));
1086
1087 let string_double_quotes = LiquidParser::parse(Rule::Literal, "\"Hello world!\"")
1088 .unwrap()
1089 .next()
1090 .unwrap();
1091 assert_eq!(
1092 parse_literal(string_double_quotes),
1093 Value::scalar("Hello world!")
1094 );
1095
1096 let string_single_quotes = LiquidParser::parse(Rule::Literal, "'Liquid'")
1097 .unwrap()
1098 .next()
1099 .unwrap();
1100 assert_eq!(parse_literal(string_single_quotes), Value::scalar("Liquid"));
1101 }
1102
1103 #[test]
1104 fn test_parse_variable() {
1105 let variable = LiquidParser::parse(Rule::Variable, "foo[0].bar.baz[foo.bar]")
1106 .unwrap()
1107 .next()
1108 .unwrap();
1109
1110 let indexes = vec![
1111 Expression::Literal(Value::scalar(0)),
1112 Expression::Literal(Value::scalar("bar")),
1113 Expression::Literal(Value::scalar("baz")),
1114 Expression::Variable(Variable::with_literal("foo").push_literal("bar")),
1115 ];
1116
1117 let mut expected = Variable::with_literal("foo");
1118 expected.extend(indexes);
1119
1120 assert_eq!(parse_variable(variable), expected);
1121 }
1122
1123 #[test]
1124 fn test_whitespace_control() {
1125 let options = Language::default();
1126
1127 let mut context = Context::new();
1128 context.stack_mut().set_global("exp", Value::scalar(5));
1129
1130 let text = " \n {{ exp }} \n ";
1131 let template = parse(text, &options).map(Template::new).unwrap();
1132 let output = template.render(&mut context).unwrap();
1133
1134 assert_eq!(output, " \n 5 \n ");
1135
1136 let text = " \n {{- exp }} \n ";
1137 let template = parse(text, &options).map(Template::new).unwrap();
1138 let output = template.render(&mut context).unwrap();
1139
1140 assert_eq!(output, "5 \n ");
1141
1142 let text = " \n {{ exp -}} \n ";
1143 let template = parse(text, &options).map(Template::new).unwrap();
1144 let output = template.render(&mut context).unwrap();
1145
1146 assert_eq!(output, " \n 5");
1147
1148 let text = " \n {{- exp -}} \n ";
1149 let template = parse(text, &options).map(Template::new).unwrap();
1150 let output = template.render(&mut context).unwrap();
1151
1152 assert_eq!(output, "5");
1153 }
1154}