1#![recursion_limit = "256"]
2
3use nom_greedyerror::error_position;
4use std::fmt;
5use std::hash::BuildHasher;
6use std::path::{Path, PathBuf};
7pub use sv_parser_error::Error;
8use sv_parser_parser::{
9 lib_parser, lib_parser_incomplete, sv_parser, sv_parser_incomplete, Span, SpanInfo,
10};
11pub use sv_parser_pp::preprocess::{
12 preprocess, preprocess_str, Define, DefineText, Defines, PreprocessedText,
13};
14pub use sv_parser_syntaxtree::*;
15
16pub struct SyntaxTree {
17 node: AnyNode,
18 text: PreprocessedText,
19}
20
21impl SyntaxTree {
22 pub fn get_str<'a, T: Into<RefNodes<'a>>>(&self, nodes: T) -> Option<&str> {
24 let mut beg = None;
25 let mut end = 0;
26 for n in Iter::new(nodes.into()) {
27 if let RefNode::Locate(x) = n {
28 if beg.is_none() {
29 beg = Some(x.offset);
30 }
31 end = x.offset + x.len;
32 }
33 }
34 if let Some(beg) = beg {
35 let ret = unsafe { self.text.text().get_unchecked(beg..end) };
36 Some(ret)
37 } else {
38 None
39 }
40 }
41
42 pub fn get_str_trim<'a, T: Into<RefNodes<'a>>>(&self, nodes: T) -> Option<&str> {
44 let mut beg = None;
45 let mut end = 0;
46 let mut skip = false;
47 for n in Iter::new(nodes.into()).event() {
48 match n {
49 NodeEvent::Enter(RefNode::WhiteSpace(_)) => {
50 skip = true;
51 }
52 NodeEvent::Leave(RefNode::WhiteSpace(_)) => {
53 skip = false;
54 }
55 NodeEvent::Enter(RefNode::Locate(x)) if !skip => {
56 if beg.is_none() {
57 beg = Some(x.offset);
58 }
59 end = x.offset + x.len;
60 }
61 _ => (),
62 }
63 }
64 if let Some(beg) = beg {
65 let ret = unsafe { self.text.text().get_unchecked(beg..end) };
66 Some(ret)
67 } else {
68 None
69 }
70 }
71
72 pub fn get_origin(&self, locate: &Locate) -> Option<(&PathBuf, usize)> {
74 self.text.origin(locate.offset)
75 }
76}
77
78impl fmt::Display for SyntaxTree {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 let mut ret = String::from("");
81 let mut skip = false;
82 let mut depth = 0;
83 for node in self.into_iter().event() {
84 match node {
85 NodeEvent::Enter(RefNode::Locate(locate)) => {
86 if !skip {
87 ret.push_str(&format!(
88 "{}Token: '{}' @ line:{}\n",
89 " ".repeat(depth),
90 self.get_str(locate).unwrap(),
91 locate.line,
92 ));
93 }
94 depth += 1;
95 }
96 NodeEvent::Enter(RefNode::WhiteSpace(_)) => {
97 skip = true;
98 }
99 NodeEvent::Leave(RefNode::WhiteSpace(_)) => {
100 skip = false;
101 }
102 NodeEvent::Enter(x) => {
103 if !skip {
104 ret.push_str(&format!("{}{}\n", " ".repeat(depth), x));
105 }
106 depth += 1;
107 }
108 NodeEvent::Leave(_) => {
109 depth -= 1;
110 }
111 }
112 }
113 write!(f, "{}", ret)
114 }
115}
116
117impl fmt::Debug for SyntaxTree {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 enum WS {
120 NotWhitespace,
121 Newline,
122 Space,
123 Comment,
124 CompilerDirective,
125 }
126
127 let mut ws: WS = WS::NotWhitespace;
128 let mut depth = 0;
129 let mut ret = String::from("");
130 for node in self.into_iter().event() {
131 match node {
132 NodeEvent::Enter(RefNode::Locate(locate)) => {
133 let (pre, t, post) = match ws {
134 WS::Newline => ("<<<<<", "NewlineToken", ">>>>>"),
135 WS::Space => ("<<<<<", "SpaceToken", ">>>>>"),
136 WS::Comment => ("<<<<<", "CommentToken", ">>>>>"),
137 _ => ("", "Token", ""),
138 };
139 ret.push_str(&format!(
140 "{}{} @line:{}: {}{}{}\n",
141 " ".repeat(depth),
142 t,
143 locate.line,
144 pre,
145 self.get_str(locate).unwrap(),
146 post,
147 ));
148 depth += 1;
149 }
150 NodeEvent::Enter(x) => {
151 match x {
152 RefNode::WhiteSpace(WhiteSpace::Newline(_)) => { ws = WS::Newline; }
153 RefNode::WhiteSpace(WhiteSpace::Space(_)) => { ws = WS::Space; }
154 RefNode::WhiteSpace(WhiteSpace::Comment(_)) => { ws = WS::Comment; }
155 RefNode::WhiteSpace(WhiteSpace::CompilerDirective(_)) => { ws = WS::CompilerDirective; }
156 _ => {}
157 }
158 ret.push_str(&format!("{}{}\n", " ".repeat(depth), x));
159 depth += 1;
160 }
161 NodeEvent::Leave(x) => {
162 match x {
163 RefNode::WhiteSpace(_) => {}
164 _ => { ws = WS::NotWhitespace; }
165 }
166 depth -= 1;
167 }
168 }
169 }
170 write!(f, "{}", ret)
171 }
172}
173
174impl<'a> IntoIterator for &'a SyntaxTree {
175 type Item = RefNode<'a>;
176 type IntoIter = Iter<'a>;
177
178 fn into_iter(self) -> Self::IntoIter {
179 let ref_node: RefNode = (&self.node).into();
180 ref_node.into_iter()
181 }
182}
183
184pub fn parse_sv<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
185 path: T,
186 pre_defines: &Defines<V>,
187 include_paths: &[U],
188 ignore_include: bool,
189 allow_incomplete: bool,
190) -> Result<(SyntaxTree, Defines), Error> {
191 let (text, defines) = preprocess(
192 path,
193 pre_defines,
194 include_paths,
195 false, ignore_include,
197 )?;
198 parse_sv_pp(text, defines, allow_incomplete)
199}
200
201pub fn parse_sv_pp(
202 text: PreprocessedText,
203 defines: Defines,
204 allow_incomplete: bool,
205) -> Result<(SyntaxTree, Defines), Error> {
206 let span = Span::new_extra(text.text(), SpanInfo::default());
207 let result = if allow_incomplete {
208 sv_parser_incomplete(span)
209 } else {
210 sv_parser(span)
211 };
212 match result {
213 Ok((_, x)) => Ok((
214 SyntaxTree {
215 node: x.into(),
216 text,
217 },
218 defines,
219 )),
220 Err(x) => {
221 let pos = match x {
222 nom::Err::Incomplete(_) => None,
223 nom::Err::Error(e) => error_position(&e),
224 nom::Err::Failure(e) => error_position(&e),
225 };
226 let origin = if let Some(pos) = pos {
227 if let Some(origin) = text.origin(pos) {
228 Some((origin.0.clone(), origin.1))
229 } else {
230 None
231 }
232 } else {
233 None
234 };
235 Err(Error::Parse(origin))
236 }
237 }
238}
239
240pub fn parse_sv_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
241 s: &str,
242 path: T,
243 pre_defines: &Defines<V>,
244 include_paths: &[U],
245 ignore_include: bool,
246 allow_incomplete: bool,
247) -> Result<(SyntaxTree, Defines), Error> {
248 let (text, defines) = preprocess_str(
249 s,
250 path,
251 pre_defines,
252 include_paths,
253 ignore_include,
254 false, 0, 0, )?;
258 parse_sv_pp(text, defines, allow_incomplete)
259}
260
261pub fn parse_lib<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
262 path: T,
263 pre_defines: &Defines<V>,
264 include_paths: &[U],
265 ignore_include: bool,
266 allow_incomplete: bool,
267) -> Result<(SyntaxTree, Defines), Error> {
268 let (text, defines) = preprocess(
269 path,
270 pre_defines,
271 include_paths,
272 false, ignore_include,
274 )?;
275 parse_lib_pp(text, defines, allow_incomplete)
276}
277
278pub fn parse_lib_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
279 s: &str,
280 path: T,
281 pre_defines: &Defines<V>,
282 include_paths: &[U],
283 ignore_include: bool,
284 allow_incomplete: bool,
285) -> Result<(SyntaxTree, Defines), Error> {
286 let (text, defines) = preprocess_str(
287 s,
288 path,
289 pre_defines,
290 include_paths,
291 ignore_include,
292 false, 0, 0, )?;
296 parse_lib_pp(text, defines, allow_incomplete)
297}
298
299pub fn parse_lib_pp(
300 text: PreprocessedText,
301 defines: Defines,
302 allow_incomplete: bool,
303) -> Result<(SyntaxTree, Defines), Error> {
304 let span = Span::new_extra(text.text(), SpanInfo::default());
305 let result = if allow_incomplete {
306 lib_parser_incomplete(span)
307 } else {
308 lib_parser(span)
309 };
310 match result {
311 Ok((_, x)) => Ok((
312 SyntaxTree {
313 node: x.into(),
314 text,
315 },
316 defines,
317 )),
318 Err(x) => {
319 let pos = match x {
320 nom::Err::Incomplete(_) => None,
321 nom::Err::Error(e) => error_position(&e),
322 nom::Err::Failure(e) => error_position(&e),
323 };
324 let origin = if let Some(pos) = pos {
325 if let Some(origin) = text.origin(pos) {
326 Some((origin.0.clone(), origin.1))
327 } else {
328 None
329 }
330 } else {
331 None
332 };
333 Err(Error::Parse(origin))
334 }
335 }
336}
337
338#[macro_export]
339macro_rules! unwrap_node {
340 ($n:expr, $( $ty:tt ),+) => {{
341 let unwrap = || {
342 for x in $n {
343 match x {
344 $($crate::RefNode::$ty(x) => return Some($crate::RefNode::$ty(x)),)*
345 _ => (),
346 }
347 }
348 None
349 };
350 unwrap()
351 }};
352}
353
354#[macro_export]
355macro_rules! unwrap_locate {
356 ($n:expr) => {{
357 let unwrap = || {
358 for x in $n {
359 match x {
360 $crate::RefNode::Locate(x) => return Some(x),
361 _ => (),
362 }
363 }
364 None
365 };
366 unwrap()
367 }};
368}
369
370#[cfg(test)]
371mod test {
372 use super::*;
373 use std::collections::HashMap;
374
375 #[test]
376 fn test() {
377 let src = "/* comment */";
378 let (syntax_tree, _) =
379 parse_sv_str(src, PathBuf::from(""), &HashMap::new(), &[""], false, false).unwrap();
380 let comment = unwrap_node!(&syntax_tree, Comment);
381 assert!(comment.is_some());
382 }
383
384 #[test]
385 fn test_continuous() {
386 let src = r##"`ifdef A
387`endif
388
389module FetchStage();
390 always_comb begin
391 for (int j = i + 1; j < FETCH_WIDTH; j++) begin
392 end
393 break;
394 end
395
396 AddrPath fetchAddrOut;
397endmodule"##;
398
399 let src_broken = r##"`ifdef A
400endif
401
402module FetchStage();
403 always_comb begin
404 for (int j = i + 1; j < FETCH_WIDTH; j++) begin
405 end
406 break;
407 end
408
409 AddrPath fetchAddrOut;
410endmodule"##;
411
412 let path = PathBuf::from("");
413 let defines = HashMap::new();
414 let ret = parse_sv_str(src, &path, &defines, &[""], false, false);
415 assert!(ret.is_ok());
416 let ret = parse_sv_str(src_broken, &path, &defines, &[""], false, false);
417 assert!(ret.is_err());
418 let ret = parse_sv_str(src, &path, &defines, &[""], false, false);
419 assert!(ret.is_ok());
420 let ret = parse_sv_str(src_broken, &path, &defines, &[""], false, false);
421 assert!(ret.is_err());
422 let ret = parse_sv_str(src, &path, &defines, &[""], false, false);
423 assert!(ret.is_ok());
424 }
425}