1use std::fmt::{Display, Formatter};
2
3use crate::error::NodeError;
4use crate::lexer::ItemType;
5use crate::utils::unquote_char;
6
7use gtmpl_value::Value;
8
9macro_rules! nodes {
10 ($($node:ident, $name:ident),*) => {
11 #[derive(Debug)]
12 #[derive(Clone)]
13 #[derive(PartialEq)]
14 pub enum NodeType {
15 $($name,)*
16 }
17
18 #[derive(Clone)]
19 #[derive(Debug)]
20 pub enum Nodes {
21 $($name($node),)*
22 }
23
24 impl Display for Nodes {
25 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
26 match *self {
27 $(Nodes::$name(ref t) => t.fmt(f),)*
28 }
29 }
30 }
31
32 impl Nodes {
33 pub fn typ(&self) -> &NodeType {
34 match *self {
35 $(Nodes::$name(ref t) => t.typ(),)*
36 }
37 }
38 pub fn pos(&self) -> Pos {
39 match *self {
40 $(Nodes::$name(ref t) => t.pos(),)*
41 }
42 }
43 pub fn tree(&self) -> TreeId {
44 match *self {
45 $(Nodes::$name(ref t) => t.tree(),)*
46 }
47 }
48 }
49 }
50}
51
52nodes!(
53 ListNode,
54 List,
55 TextNode,
56 Text,
57 PipeNode,
58 Pipe,
59 ActionNode,
60 Action,
61 CommandNode,
62 Command,
63 IdentifierNode,
64 Identifier,
65 VariableNode,
66 Variable,
67 DotNode,
68 Dot,
69 NilNode,
70 Nil,
71 FieldNode,
72 Field,
73 ChainNode,
74 Chain,
75 BoolNode,
76 Bool,
77 NumberNode,
78 Number,
79 StringNode,
80 String,
81 EndNode,
82 End,
83 ElseNode,
84 Else,
85 IfNode,
86 If,
87 WithNode,
88 With,
89 RangeNode,
90 Range,
91 TemplateNode,
92 Template
93);
94
95pub type Pos = usize;
96
97pub type TreeId = usize;
98
99pub trait Node: Display {
100 fn typ(&self) -> &NodeType;
101 fn pos(&self) -> Pos;
102 fn tree(&self) -> TreeId;
103}
104
105macro_rules! node {
106 ($name:ident {
107 $($field:ident : $typ:ty),* $(,)*
108 }) => {
109 #[derive(Clone)]
110 #[derive(Debug)]
111 pub struct $name {
112 typ: NodeType,
113 pos: Pos,
114 tr: TreeId,
115 $(pub $field: $typ,)*
116 }
117 impl Node for $name {
118 fn typ(&self) -> &NodeType {
119 &self.typ
120 }
121 fn pos(&self) -> Pos {
122 self.pos
123 }
124 fn tree(&self) -> TreeId {
125 self.tr
126 }
127 }
128 }
129}
130
131impl Nodes {
132 pub fn is_empty_tree(&self) -> Result<bool, NodeError> {
133 match *self {
134 Nodes::List(ref n) => n.is_empty_tree(),
135 Nodes::Text(ref n) => Ok(n.text.is_empty()),
136 Nodes::Action(_)
137 | Nodes::If(_)
138 | Nodes::Range(_)
139 | Nodes::Template(_)
140 | Nodes::With(_) => Ok(false),
141 _ => Err(NodeError::NaTN),
142 }
143 }
144}
145
146node!(
147 ListNode {
148 nodes: Vec<Nodes>
149 }
150);
151
152impl ListNode {
153 pub fn append(&mut self, n: Nodes) {
154 self.nodes.push(n);
155 }
156 pub fn new(tr: TreeId, pos: Pos) -> ListNode {
157 ListNode {
158 typ: NodeType::List,
159 pos,
160 tr,
161 nodes: vec![],
162 }
163 }
164 pub fn is_empty_tree(&self) -> Result<bool, NodeError> {
165 for n in &self.nodes {
166 match n.is_empty_tree() {
167 Ok(true) => {}
168 Ok(false) => return Ok(false),
169 Err(s) => return Err(s),
170 }
171 }
172 Ok(true)
173 }
174}
175
176impl Display for ListNode {
177 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
178 for n in &self.nodes {
179 if let Err(e) = n.fmt(f) {
180 return Err(e);
181 }
182 }
183 Ok(())
184 }
185}
186
187node!(TextNode { text: String });
188
189impl TextNode {
190 pub fn new(tr: TreeId, pos: Pos, text: String) -> TextNode {
191 TextNode {
192 typ: NodeType::Text,
193 pos,
194 tr,
195 text,
196 }
197 }
198}
199
200impl Display for TextNode {
201 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
202 write!(f, "{}", self.text)
203 }
204}
205
206node!(
207 PipeNode {
208 decl: Vec<VariableNode>,
209 cmds: Vec<CommandNode>
210 }
211);
212
213impl PipeNode {
214 pub fn new(tr: TreeId, pos: Pos, decl: Vec<VariableNode>) -> PipeNode {
215 PipeNode {
216 typ: NodeType::Pipe,
217 tr,
218 pos,
219 decl,
220 cmds: vec![],
221 }
222 }
223
224 pub fn append(&mut self, cmd: CommandNode) {
225 self.cmds.push(cmd);
226 }
227}
228
229impl Display for PipeNode {
230 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
231 let decl = if self.decl.is_empty() {
232 Ok(())
233 } else {
234 write!(
235 f,
236 "{} := ",
237 self.decl
238 .iter()
239 .map(|n| n.to_string())
240 .collect::<Vec<String>>()
241 .join(", ")
242 )
243 };
244 decl.and_then(|_| {
245 write!(
246 f,
247 "{}",
248 self.cmds
249 .iter()
250 .map(|cmd| cmd.to_string())
251 .collect::<Vec<String>>()
252 .join(" | ")
253 )
254 })
255 }
256}
257
258node!(ActionNode { pipe: PipeNode });
259
260impl ActionNode {
261 pub fn new(tr: TreeId, pos: Pos, pipe: PipeNode) -> ActionNode {
262 ActionNode {
263 typ: NodeType::Action,
264 tr,
265 pos,
266 pipe,
267 }
268 }
269}
270
271impl Display for ActionNode {
272 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
273 write!(f, "{{{{{}}}}}", self.pipe)
274 }
275}
276
277node!(
278 CommandNode {
279 args: Vec<Nodes>
280 }
281);
282
283impl CommandNode {
284 pub fn new(tr: TreeId, pos: Pos) -> CommandNode {
285 CommandNode {
286 typ: NodeType::Command,
287 pos,
288 tr,
289 args: vec![],
290 }
291 }
292
293 pub fn append(&mut self, node: Nodes) {
294 self.args.push(node);
295 }
296}
297
298impl Display for CommandNode {
299 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
300 let s = self
301 .args
302 .iter()
303 .map(|n|
304 n.to_string())
306 .collect::<Vec<String>>()
307 .join(" ");
308 write!(f, "{}", s)
309 }
310}
311
312node!(IdentifierNode { ident: String });
313
314impl IdentifierNode {
315 pub fn new(ident: String) -> IdentifierNode {
316 IdentifierNode {
317 typ: NodeType::Identifier,
318 tr: 0,
319 pos: 0,
320 ident,
321 }
322 }
323
324 pub fn set_pos(&mut self, pos: Pos) -> &IdentifierNode {
325 self.pos = pos;
326 self
327 }
328
329 pub fn set_tree(&mut self, tr: TreeId) -> &IdentifierNode {
330 self.tr = tr;
331 self
332 }
333}
334
335impl Display for IdentifierNode {
336 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
337 write!(f, "{}", self.ident)
338 }
339}
340
341node!(
342 VariableNode {
343 ident: Vec<String>
344 }
345);
346
347impl VariableNode {
348 pub fn new(tr: TreeId, pos: Pos, ident: &str) -> VariableNode {
349 VariableNode {
350 typ: NodeType::Variable,
351 tr,
352 pos,
353 ident: ident.split('.').map(|s| s.to_owned()).collect(),
354 }
355 }
356}
357
358impl Display for VariableNode {
359 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
360 write!(f, "{}", self.ident.join("."))
361 }
362}
363
364node!(DotNode {});
365
366impl DotNode {
367 pub fn new(tr: TreeId, pos: Pos) -> DotNode {
368 DotNode {
369 typ: NodeType::Dot,
370 tr,
371 pos,
372 }
373 }
374}
375
376impl Display for DotNode {
377 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
378 write!(f, ".")
379 }
380}
381
382node!(NilNode {});
383
384impl Display for NilNode {
385 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
386 write!(f, "nil")
387 }
388}
389
390impl NilNode {
391 pub fn new(tr: TreeId, pos: Pos) -> NilNode {
392 NilNode {
393 typ: NodeType::Nil,
394 tr,
395 pos,
396 }
397 }
398}
399
400node!(
401 FieldNode {
402 ident: Vec<String>
403 }
404);
405
406impl FieldNode {
407 pub fn new(tr: TreeId, pos: Pos, ident: &str) -> FieldNode {
408 FieldNode {
409 typ: NodeType::Field,
410 tr,
411 pos,
412 ident: ident[..]
413 .split('.')
414 .filter_map(|s| {
415 if s.is_empty() {
416 None
417 } else {
418 Some(s.to_owned())
419 }
420 })
421 .collect(),
422 }
423 }
424}
425
426impl Display for FieldNode {
427 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
428 write!(f, "{}", self.ident.join("."))
429 }
430}
431
432node!(
433 ChainNode {
434 node: Box<Nodes>,
435 field: Vec<String>
436 }
437);
438
439impl ChainNode {
440 pub fn new(tr: TreeId, pos: Pos, node: Nodes) -> ChainNode {
441 ChainNode {
442 typ: NodeType::Chain,
443 tr,
444 pos,
445 node: Box::new(node),
446 field: vec![],
447 }
448 }
449
450 pub fn add(&mut self, val: &str) {
451 let val = val.trim_start_matches('.').to_owned();
452 self.field.push(val);
453 }
454}
455
456impl Display for ChainNode {
457 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
458 if let Err(e) = {
459 write!(f, "{}", self.node)
461 } {
462 return Err(e);
463 }
464 for field in &self.field {
465 if let Err(e) = write!(f, ".{}", field) {
466 return Err(e);
467 }
468 }
469 Ok(())
470 }
471}
472
473node!(BoolNode { value: Value });
474
475impl BoolNode {
476 pub fn new(tr: TreeId, pos: Pos, val: bool) -> BoolNode {
477 BoolNode {
478 typ: NodeType::Bool,
479 tr,
480 pos,
481 value: Value::from(val),
482 }
483 }
484}
485
486impl Display for BoolNode {
487 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
488 write!(f, "{}", self.value)
489 }
490}
491
492#[derive(Clone, Debug)]
493pub enum NumberType {
494 U64,
495 I64,
496 Float,
497 Char,
498}
499
500node!(NumberNode {
501 is_i64: bool,
502 is_u64: bool,
503 is_f64: bool,
504 text: String,
505 number_typ: NumberType,
506 value: Value,
507});
508
509impl NumberNode {
510 #[cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))]
511 pub fn new(
512 tr: TreeId,
513 pos: Pos,
514 text: String,
515 item_typ: &ItemType,
516 ) -> Result<NumberNode, NodeError> {
517 match *item_typ {
518 ItemType::ItemCharConstant => unquote_char(&text, '\'')
519 .map(|c| NumberNode {
520 typ: NodeType::Number,
521 tr,
522 pos,
523 is_i64: true,
524 is_u64: true,
525 is_f64: true,
526 text,
527 number_typ: NumberType::Char,
528 value: Value::from(c as u64),
529 })
530 .ok_or(NodeError::UnquoteError),
531 _ => {
532 let mut number_typ = NumberType::Float;
533
534 let (mut as_i64, mut is_i64) = text
536 .parse::<i64>()
537 .map(|i| (i, true))
538 .unwrap_or((0i64, false));
539
540 if is_i64 {
541 number_typ = NumberType::I64;
542 }
543
544 let (mut as_u64, mut is_u64) = text
545 .parse::<u64>()
546 .map(|i| (i, true))
547 .unwrap_or((0u64, false));
548
549 if is_u64 {
550 number_typ = NumberType::U64;
551 }
552
553 if is_i64 && as_i64 == 0 {
554 as_u64 = 0;
556 is_u64 = true;
557 }
558
559 let (as_f64, is_f64) = match text.parse::<f64>() {
560 Err(_) => (0.0_f64, false),
561 Ok(f) => {
562 let frac = text.contains(|c| {
563 matches! {
564 c, '.' | 'e' | 'E' }
565 });
566 if frac {
567 (f, true)
568 } else {
569 (f, false)
570 }
571 }
572 };
573 if !is_i64 && ((as_f64 as i64) as f64) == as_f64 {
574 as_i64 = as_f64 as i64;
575 is_i64 = true;
576 }
577 if !is_u64 && ((as_f64 as u64) as f64) == as_f64 {
578 as_u64 = as_f64 as u64;
579 is_u64 = true;
580 }
581 if !is_u64 && !is_i64 && !is_f64 {
582 return Err(NodeError::NaN);
583 }
584
585 let value = if is_u64 {
586 Value::from(as_u64)
587 } else if is_i64 {
588 Value::from(as_i64)
589 } else {
590 Value::from(as_f64)
591 };
592
593 Ok(NumberNode {
594 typ: NodeType::Number,
595 tr,
596 pos,
597 is_i64,
598 is_u64,
599 is_f64,
600 text,
601 number_typ,
602 value,
603 })
604 }
605 }
606 }
607}
608
609impl Display for NumberNode {
610 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
611 write!(f, "{}", self.text)
612 }
613}
614
615node!(StringNode {
616 quoted: String,
617 value: Value,
618});
619
620impl StringNode {
621 pub fn new(tr: TreeId, pos: Pos, orig: String, text: String) -> StringNode {
622 StringNode {
623 typ: NodeType::String,
624 tr,
625 pos,
626 quoted: orig,
627 value: Value::from(text),
628 }
629 }
630}
631
632impl Display for StringNode {
633 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
634 write!(f, "{}", self.quoted)
635 }
636}
637
638node!(EndNode {});
639
640impl EndNode {
641 pub fn new(tr: TreeId, pos: Pos) -> EndNode {
642 EndNode {
643 typ: NodeType::End,
644 tr,
645 pos,
646 }
647 }
648}
649
650impl Display for EndNode {
651 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
652 write!(f, "{{{{end}}}}")
653 }
654}
655
656node!(ElseNode {});
657
658impl ElseNode {
659 pub fn new(tr: TreeId, pos: Pos) -> ElseNode {
660 ElseNode {
661 typ: NodeType::Else,
662 tr,
663 pos,
664 }
665 }
666}
667
668impl Display for ElseNode {
669 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
670 write!(f, "{{{{else}}}}")
671 }
672}
673
674node!(
675 BranchNode {
676 pipe: PipeNode,
677 list: ListNode,
678 else_list: Option<ListNode>
679 }
680);
681
682pub type IfNode = BranchNode;
683pub type WithNode = BranchNode;
684pub type RangeNode = BranchNode;
685
686impl BranchNode {
687 pub fn new_if(
688 tr: TreeId,
689 pos: Pos,
690 pipe: PipeNode,
691 list: ListNode,
692 else_list: Option<ListNode>,
693 ) -> IfNode {
694 IfNode {
695 typ: NodeType::If,
696 tr,
697 pos,
698 pipe,
699 list,
700 else_list,
701 }
702 }
703
704 pub fn new_with(
705 tr: TreeId,
706 pos: Pos,
707 pipe: PipeNode,
708 list: ListNode,
709 else_list: Option<ListNode>,
710 ) -> WithNode {
711 WithNode {
712 typ: NodeType::With,
713 tr,
714 pos,
715 pipe,
716 list,
717 else_list,
718 }
719 }
720
721 pub fn new_range(
722 tr: TreeId,
723 pos: Pos,
724 pipe: PipeNode,
725 list: ListNode,
726 else_list: Option<ListNode>,
727 ) -> RangeNode {
728 RangeNode {
729 typ: NodeType::Range,
730 tr,
731 pos,
732 pipe,
733 list,
734 else_list,
735 }
736 }
737}
738
739impl Display for BranchNode {
740 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
741 let name = match self.typ {
742 NodeType::If => "if",
743 NodeType::Range => "range",
744 NodeType::With => "with",
745 _ => {
746 return Err(std::fmt::Error);
747 }
748 };
749 if let Some(ref else_list) = self.else_list {
750 return write!(
751 f,
752 "{{{{{} {}}}}}{}{{{{else}}}}{}{{{{end}}}}",
753 name, self.pipe, self.list, else_list
754 );
755 }
756 write!(f, "{{{{{} {}}}}}{}{{{{end}}}}", name, self.pipe, self.list)
757 }
758}
759
760node!(
761 TemplateNode {
762 name: PipeOrString,
763 pipe: Option<PipeNode>
764 }
765);
766
767impl TemplateNode {
768 pub fn new(tr: TreeId, pos: Pos, name: PipeOrString, pipe: Option<PipeNode>) -> TemplateNode {
769 TemplateNode {
770 typ: NodeType::Template,
771 tr,
772 pos,
773 name,
774 pipe,
775 }
776 }
777}
778
779impl Display for TemplateNode {
780 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
781 match self.pipe {
782 Some(ref pipe) => write!(f, "{{{{template {} {}}}}}", self.name, pipe),
783 None => write!(f, "{{{{template {}}}}}", self.name),
784 }
785 }
786}
787
788#[derive(Clone, Debug)]
789pub enum PipeOrString {
790 Pipe(PipeNode),
791 String(String),
792}
793
794impl Display for PipeOrString {
795 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
796 match *self {
797 PipeOrString::Pipe(ref pipe_node) => write!(f, "{}", pipe_node),
798 PipeOrString::String(ref s) => write!(f, "{}", s),
799 }
800 }
801}
802
803#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
808 fn test_clone() {
809 let t1 = TextNode::new(1, 0, "foo".to_owned());
810 let mut t2 = t1.clone();
811 t2.text = "bar".to_owned();
812 assert_eq!(t1.to_string(), "foo");
813 assert_eq!(t2.to_string(), "bar");
814 }
815
816 #[test]
817 fn test_end() {
818 let t1 = EndNode::new(1, 0);
819 assert_eq!(t1.to_string(), "{{end}}");
820 }
821}