mpc/
ast.rs

1//! Contains an AST type to which `mpc_ast_t` is mapped
2#![allow(dead_code)]
3
4use colors::*;
5use mpc_c_types::*;
6use std::slice;
7
8/// The Ast type
9#[derive(Clone, Eq, PartialEq)]
10pub struct Ast
11{
12	/// Pointer to the underlying Ast
13	/// It is not recommended to modify it
14	pub raw_ast: *mut mpc_ast_t,
15	/// Tag of this node. Folded tags are connected with
16	/// the pipe character `|`, tags of nodes with children
17	/// end with `|>`.
18	pub tag: String,
19	/// Contents of this node
20	pub contents: String,
21	/// A vector containing children of this node
22	pub children: Vec<Ast>,
23	/// Number of the row where this node is located, only valid
24	/// for nodes without children
25	pub row: usize,
26	/// Number of the column where this node is located, only valid
27	/// for nodes without children
28	pub column: usize,
29	/// Total position in the file, only valid for nodes with no children
30	pub position: usize,
31}
32
33/// A temporary type to represent a node returned
34/// by one of the searching functions
35#[derive(Clone, Eq, PartialEq)]
36pub struct Child<'a>
37{
38	/// The parent node
39	pub parent: &'a Ast,
40	/// Ast of the current node
41	pub ast: &'a Ast,
42	/// Index of this node in the parent node
43	pub index: usize,
44}
45
46
47impl Ast
48{
49	/// Create a new Ast from a raw `mpc_ast_t`
50	pub fn new(ast_ptr: *mut mpc_ast_t) -> Ast
51	{
52		unsafe
53		{
54			let mut children: Vec<Ast> = Vec::new();
55
56			for node in
57				slice::from_raw_parts((*ast_ptr).children, (*ast_ptr).children_num as usize)
58			{
59				children.push(Ast::new(*node));
60			}
61
62			Ast
63			{
64				raw_ast: ast_ptr,
65				tag: dfs!(ast_ptr, tag),
66				contents: dfs!(ast_ptr, contents),
67				children: children,
68				row: dfu!(ast_ptr, state.row),
69				column: dfu!(ast_ptr, state.col),
70				position: dfu!(ast_ptr, state.pos),
71			}
72		}
73	}
74
75	/// Find a child by index
76	pub fn by_index(&self, index: usize) -> Option<Child>
77	{
78		if index < self.children.len()
79		{
80			Some(Child
81			{
82				parent: self,
83				ast: &self.children[index],
84				index: index,
85			})
86		}
87		else { None }
88	}
89
90	/// Find a child by tag
91	pub fn by_tag(&self, tag: &str) -> Option<Child>
92	{
93		let children = self.children.clone().into_iter();
94		let index: i32 =
95			if let Some(_) =
96				children.clone().filter(|x| x.tag == tag).next()
97					{ children.count() as i32 }
98			else { -1 };
99
100		if index > -1
101		{
102			Some(Child
103			{
104				parent: self,
105				ast: &self.children[index as usize],
106				index: index as usize
107			})
108		}
109		else { None }
110	}
111
112	/// Find a child by contents
113	pub fn by_contents(&self, contents: &str) -> Option<Child>
114	{
115		let children = self.children.clone().into_iter();
116		let index: i32 =
117			if let Some(_) =
118				children.clone().filter(|x| x.contents == contents).next()
119					{ children.count() as i32 }
120			else { -1 };
121
122		if index > -1
123		{
124			Some(Child
125			{
126				parent: self,
127				ast: &self.children[index as usize],
128				index: index as usize
129			})
130		}
131		else { None }
132	}
133
134	/// Print the Ast
135	pub fn print(&self)
136	{
137		self.print_level(0);
138	}
139
140	/// Print the Ast with starting depth (indentation) `level`
141	pub fn print_level(&self, level: usize)
142	{
143		for _ in 0..level {trace!("  ");}
144		if self.children.is_empty()
145		{
146			trace!(
147				RED self.tag
148				RESET ':'
149				GREEN self.row
150				RESET ':'
151				YELLOW self.column " "
152				RESET '\''
153				self.contents "'\n"
154			);
155		}
156		else
157		{
158			trace!(
159				MAGENTA self.tag
160				RESET "\n"
161			);
162			for child in &self.children
163			{
164				child.print_level(level+1);
165			}
166		}
167	}
168}