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 is_assign : bool,
211 }
212);
213
214impl PipeNode {
215 pub fn new(tr: TreeId, pos: Pos, decl: Vec<VariableNode>, is_assign: bool) -> PipeNode {
216 PipeNode {
217 typ: NodeType::Pipe,
218 tr,
219 pos,
220 decl,
221 is_assign: is_assign,
222 cmds: vec![],
223 }
224 }
225
226 pub fn append(&mut self, cmd: CommandNode) {
227 self.cmds.push(cmd);
228 }
229}
230
231impl Display for PipeNode {
232 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
233 let decl = if self.decl.is_empty() {
234 Ok(())
235 } else {
236 write!(
237 f,
238 "{} := ",
239 self.decl
240 .iter()
241 .map(|n| n.to_string())
242 .collect::<Vec<String>>()
243 .join(", ")
244 )
245 };
246 decl.and_then(|_| {
247 write!(
248 f,
249 "{}",
250 self.cmds
251 .iter()
252 .map(|cmd| cmd.to_string())
253 .collect::<Vec<String>>()
254 .join(" | ")
255 )
256 })
257 }
258}
259
260node!(ActionNode { pipe: PipeNode });
261
262impl ActionNode {
263 pub fn new(tr: TreeId, pos: Pos, pipe: PipeNode) -> ActionNode {
264 ActionNode {
265 typ: NodeType::Action,
266 tr,
267 pos,
268 pipe,
269 }
270 }
271}
272
273impl Display for ActionNode {
274 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
275 write!(f, "{{{{{}}}}}", self.pipe)
276 }
277}
278
279node!(
280 CommandNode {
281 args: Vec<Nodes>
282 }
283);
284
285impl CommandNode {
286 pub fn new(tr: TreeId, pos: Pos) -> CommandNode {
287 CommandNode {
288 typ: NodeType::Command,
289 pos,
290 tr,
291 args: vec![],
292 }
293 }
294
295 pub fn append(&mut self, node: Nodes) {
296 self.args.push(node);
297 }
298}
299
300impl Display for CommandNode {
301 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
302 let s = self
303 .args
304 .iter()
305 .map(|n|
306 n.to_string())
308 .collect::<Vec<String>>()
309 .join(" ");
310 write!(f, "{}", s)
311 }
312}
313
314node!(IdentifierNode { ident: String });
315
316impl IdentifierNode {
317 pub fn new(ident: String) -> IdentifierNode {
318 IdentifierNode {
319 typ: NodeType::Identifier,
320 tr: 0,
321 pos: 0,
322 ident,
323 }
324 }
325
326 pub fn set_pos(&mut self, pos: Pos) -> &IdentifierNode {
327 self.pos = pos;
328 self
329 }
330
331 pub fn set_tree(&mut self, tr: TreeId) -> &IdentifierNode {
332 self.tr = tr;
333 self
334 }
335}
336
337impl Display for IdentifierNode {
338 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
339 write!(f, "{}", self.ident)
340 }
341}
342
343node!(
344 VariableNode {
345 ident: Vec<String>
346 }
347);
348
349impl VariableNode {
350 pub fn new(tr: TreeId, pos: Pos, ident: &str) -> VariableNode {
351 VariableNode {
352 typ: NodeType::Variable,
353 tr,
354 pos,
355 ident: ident.split('.').map(|s| s.to_owned()).collect(),
356 }
357 }
358}
359
360impl Display for VariableNode {
361 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
362 write!(f, "{}", self.ident.join("."))
363 }
364}
365
366node!(DotNode {});
367
368impl DotNode {
369 pub fn new(tr: TreeId, pos: Pos) -> DotNode {
370 DotNode {
371 typ: NodeType::Dot,
372 tr,
373 pos,
374 }
375 }
376}
377
378impl Display for DotNode {
379 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
380 write!(f, ".")
381 }
382}
383
384node!(NilNode {});
385
386impl Display for NilNode {
387 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
388 write!(f, "nil")
389 }
390}
391
392impl NilNode {
393 pub fn new(tr: TreeId, pos: Pos) -> NilNode {
394 NilNode {
395 typ: NodeType::Nil,
396 tr,
397 pos,
398 }
399 }
400}
401
402node!(
403 FieldNode {
404 ident: Vec<String>
405 }
406);
407
408impl FieldNode {
409 pub fn new(tr: TreeId, pos: Pos, ident: &str) -> FieldNode {
410 FieldNode {
411 typ: NodeType::Field,
412 tr,
413 pos,
414 ident: ident[..]
415 .split('.')
416 .filter_map(|s| {
417 if s.is_empty() {
418 None
419 } else {
420 Some(s.to_owned())
421 }
422 })
423 .collect(),
424 }
425 }
426}
427
428impl Display for FieldNode {
429 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
430 write!(f, "{}", self.ident.join("."))
431 }
432}
433
434node!(
435 ChainNode {
436 node: Box<Nodes>,
437 field: Vec<String>
438 }
439);
440
441impl ChainNode {
442 pub fn new(tr: TreeId, pos: Pos, node: Nodes) -> ChainNode {
443 ChainNode {
444 typ: NodeType::Chain,
445 tr,
446 pos,
447 node: Box::new(node),
448 field: vec![],
449 }
450 }
451
452 pub fn add(&mut self, val: &str) {
453 let val = val.trim_start_matches('.').to_owned();
454 self.field.push(val);
455 }
456}
457
458impl Display for ChainNode {
459 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
460 if let Err(e) = {
461 write!(f, "{}", self.node)
463 } {
464 return Err(e);
465 }
466 for field in &self.field {
467 if let Err(e) = write!(f, ".{}", field) {
468 return Err(e);
469 }
470 }
471 Ok(())
472 }
473}
474
475node!(BoolNode { value: Value });
476
477impl BoolNode {
478 pub fn new(tr: TreeId, pos: Pos, val: bool) -> BoolNode {
479 BoolNode {
480 typ: NodeType::Bool,
481 tr,
482 pos,
483 value: Value::from(val),
484 }
485 }
486}
487
488impl Display for BoolNode {
489 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
490 write!(f, "{}", self.value)
491 }
492}
493
494#[derive(Clone, Debug)]
495pub enum NumberType {
496 U64,
497 I64,
498 Float,
499 Char,
500}
501
502node!(NumberNode {
503 is_i64: bool,
504 is_u64: bool,
505 is_f64: bool,
506 text: String,
507 number_typ: NumberType,
508 value: Value,
509});
510
511impl NumberNode {
512 #[cfg_attr(feature = "cargo-clippy", allow(clippy::float_cmp))]
513 pub fn new(
514 tr: TreeId,
515 pos: Pos,
516 text: String,
517 item_typ: &ItemType,
518 ) -> Result<NumberNode, NodeError> {
519 match *item_typ {
520 ItemType::ItemCharConstant => unquote_char(&text, '\'')
521 .map(|c| NumberNode {
522 typ: NodeType::Number,
523 tr,
524 pos,
525 is_i64: true,
526 is_u64: true,
527 is_f64: true,
528 text,
529 number_typ: NumberType::Char,
530 value: Value::from(c as u64),
531 })
532 .ok_or(NodeError::UnquoteError),
533 _ => {
534 let mut number_typ = NumberType::Float;
535
536 let (mut as_i64, mut is_i64) = text
538 .parse::<i64>()
539 .map(|i| (i, true))
540 .unwrap_or((0i64, false));
541
542 if is_i64 {
543 number_typ = NumberType::I64;
544 }
545
546 let (mut as_u64, mut is_u64) = text
547 .parse::<u64>()
548 .map(|i| (i, true))
549 .unwrap_or((0u64, false));
550
551 if is_u64 {
552 number_typ = NumberType::U64;
553 }
554
555 if is_i64 && as_i64 == 0 {
556 as_u64 = 0;
558 is_u64 = true;
559 }
560
561 let (as_f64, is_f64) = match text.parse::<f64>() {
562 Err(_) => (0.0_f64, false),
563 Ok(f) => {
564 let frac = text.contains(|c| match c {
565 '.' | 'e' | 'E' => true,
566 _ => false,
567 });
568 if frac {
569 (f, true)
570 } else {
571 (f, false)
572 }
573 }
574 };
575 if !is_i64 && ((as_f64 as i64) as f64) == as_f64 {
576 as_i64 = as_f64 as i64;
577 is_i64 = true;
578 }
579 if !is_u64 && ((as_f64 as u64) as f64) == as_f64 {
580 as_u64 = as_f64 as u64;
581 is_u64 = true;
582 }
583 if !is_u64 && !is_i64 && !is_f64 {
584 return Err(NodeError::NaN);
585 }
586
587 let value = if is_u64 {
588 Value::from(as_u64)
589 } else if is_i64 {
590 Value::from(as_i64)
591 } else {
592 Value::from(as_f64)
593 };
594
595 Ok(NumberNode {
596 typ: NodeType::Number,
597 tr,
598 pos,
599 is_i64,
600 is_u64,
601 is_f64,
602 text,
603 number_typ,
604 value,
605 })
606 }
607 }
608 }
609}
610
611impl Display for NumberNode {
612 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
613 write!(f, "{}", self.text)
614 }
615}
616
617node!(StringNode {
618 quoted: String,
619 value: Value,
620});
621
622impl StringNode {
623 pub fn new(tr: TreeId, pos: Pos, orig: String, text: String) -> StringNode {
624 StringNode {
625 typ: NodeType::String,
626 tr,
627 pos,
628 quoted: orig,
629 value: Value::from(text),
630 }
631 }
632}
633
634impl Display for StringNode {
635 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
636 write!(f, "{}", self.quoted)
637 }
638}
639
640node!(EndNode {});
641
642impl EndNode {
643 pub fn new(tr: TreeId, pos: Pos) -> EndNode {
644 EndNode {
645 typ: NodeType::End,
646 tr,
647 pos,
648 }
649 }
650}
651
652impl Display for EndNode {
653 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
654 write!(f, "{{{{end}}}}")
655 }
656}
657
658node!(ElseNode {});
659
660impl ElseNode {
661 pub fn new(tr: TreeId, pos: Pos) -> ElseNode {
662 ElseNode {
663 typ: NodeType::Else,
664 tr,
665 pos,
666 }
667 }
668}
669
670impl Display for ElseNode {
671 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
672 write!(f, "{{{{else}}}}")
673 }
674}
675
676node!(
677 BranchNode {
678 pipe: PipeNode,
679 list: ListNode,
680 else_list: Option<ListNode>
681 }
682);
683
684pub type IfNode = BranchNode;
685pub type WithNode = BranchNode;
686pub type RangeNode = BranchNode;
687
688impl BranchNode {
689 pub fn new_if(
690 tr: TreeId,
691 pos: Pos,
692 pipe: PipeNode,
693 list: ListNode,
694 else_list: Option<ListNode>,
695 ) -> IfNode {
696 IfNode {
697 typ: NodeType::If,
698 tr,
699 pos,
700 pipe,
701 list,
702 else_list,
703 }
704 }
705
706 pub fn new_with(
707 tr: TreeId,
708 pos: Pos,
709 pipe: PipeNode,
710 list: ListNode,
711 else_list: Option<ListNode>,
712 ) -> WithNode {
713 WithNode {
714 typ: NodeType::With,
715 tr,
716 pos,
717 pipe,
718 list,
719 else_list,
720 }
721 }
722
723 pub fn new_range(
724 tr: TreeId,
725 pos: Pos,
726 pipe: PipeNode,
727 list: ListNode,
728 else_list: Option<ListNode>,
729 ) -> RangeNode {
730 RangeNode {
731 typ: NodeType::Range,
732 tr,
733 pos,
734 pipe,
735 list,
736 else_list,
737 }
738 }
739}
740
741impl Display for BranchNode {
742 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
743 let name = match self.typ {
744 NodeType::If => "if",
745 NodeType::Range => "range",
746 NodeType::With => "with",
747 _ => {
748 return Err(std::fmt::Error);
749 }
750 };
751 if let Some(ref else_list) = self.else_list {
752 return write!(
753 f,
754 "{{{{{} {}}}}}{}{{{{else}}}}{}{{{{end}}}}",
755 name, self.pipe, self.list, else_list
756 );
757 }
758 write!(f, "{{{{{} {}}}}}{}{{{{end}}}}", name, self.pipe, self.list)
759 }
760}
761
762node!(
763 TemplateNode {
764 name: PipeOrString,
765 pipe: Option<PipeNode>
766 }
767);
768
769impl TemplateNode {
770 pub fn new(tr: TreeId, pos: Pos, name: PipeOrString, pipe: Option<PipeNode>) -> TemplateNode {
771 TemplateNode {
772 typ: NodeType::Template,
773 tr,
774 pos,
775 name,
776 pipe,
777 }
778 }
779}
780
781impl Display for TemplateNode {
782 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
783 match self.pipe {
784 Some(ref pipe) => write!(f, "{{{{template {} {}}}}}", self.name, pipe),
785 None => write!(f, "{{{{template {}}}}}", self.name),
786 }
787 }
788}
789
790#[derive(Clone, Debug)]
791pub enum PipeOrString {
792 Pipe(PipeNode),
793 String(String),
794}
795
796impl Display for PipeOrString {
797 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
798 match *self {
799 PipeOrString::Pipe(ref pipe_node) => write!(f, "{}", pipe_node),
800 PipeOrString::String(ref s) => write!(f, "{}", s),
801 }
802 }
803}
804
805#[cfg(test)]
806mod tests {
807 use super::*;
808
809 #[test]
810 fn test_clone() {
811 let t1 = TextNode::new(1, 0, "foo".to_owned());
812 let mut t2 = t1.clone();
813 t2.text = "bar".to_owned();
814 assert_eq!(t1.to_string(), "foo");
815 assert_eq!(t2.to_string(), "bar");
816 }
817
818 #[test]
819 fn test_end() {
820 let t1 = EndNode::new(1, 0);
821 assert_eq!(t1.to_string(), "{{end}}");
822 }
823}