diff --git a/README.md b/README.md index b02c006..ad7c028 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,24 @@ Parser library for SystemVerilog ([IEEE 1800-2017](https://standards.ieee.org/st sv-parser = "0.1.0" ``` +sv-parser provides `parse_sv` function which returns `SyntexTree`. +`SyntaxTree` shows Concrete Syntax Tree. It has the preprocessed string and the parsed tree. + +`RefNode` shows a reference to any node of `SyntaxTree`. +You can get `RefNode` through an iterator of `SyntaxTree`. + +`Locate` shows a position of token. All leaf node of `SyntaxTree` is `Locate`. +You can get string from `Locate` by `SyntaxTree::get_str(self, locate: &Locate)`. + ## Example +The following example parses a SystemVerilog source file and shows module names. + ```rust use std::collections::HashMap; -use std::convert::TryInto; use std::env; use std::path::PathBuf; -use sv_parser::{parse_sv, Locate, RefNode}; +use sv_parser::{parse_sv, unwrap_node, Locate, RefNode}; fn main() { let args: Vec = env::args().collect(); @@ -31,31 +41,27 @@ fn main() { // The list of include paths let includes: Vec = Vec::new(); - // Do parse + // Parse let result = parse_sv(&path, &defines, &includes); if let Ok((syntax_tree, _)) = result { - // SyntexTree is iterable + // &SyntaxTree is iterable for node in &syntax_tree { - // The type of Each node is RefNode + // The type of each node is RefNode match node { RefNode::ModuleDeclarationNonansi(x) => { - // The type of header is ModuleNonansiHeader - let (ref header, _, _, _, _) = x.nodes; - // The type of name is ModuleIdentifier - let (_, _, _, ref name, _, _, _, _) = header.nodes; + // unwrap_node! gets the nearest ModuleIdentifier from x + let id = unwrap_node!(x, ModuleIdentifier).unwrap(); - // Any type included in SyntaxTree can be convert RefNode by into() - let id = get_identifier(name.into()).unwrap(); + let id = get_identifier(id).unwrap(); - // Original string can be got by SyntexTree::get_str(self, locate: &Locate) + // Original string can be got by SyntaxTree::get_str(self, locate: &Locate) let id = syntax_tree.get_str(&id); println!("module: {}", id); } RefNode::ModuleDeclarationAnsi(x) => { - let (ref header, _, _, _, _) = x.nodes; - let (_, _, _, ref name, _, _, _, _) = header.nodes; - let id = get_identifier(name.into()).unwrap(); + let id = unwrap_node!(x, ModuleIdentifier).unwrap(); + let id = get_identifier(id).unwrap(); let id = syntax_tree.get_str(&id); println!("module: {}", id); } @@ -68,19 +74,15 @@ fn main() { } fn get_identifier(node: RefNode) -> Option { - for n in node { - match n { - RefNode::SimpleIdentifier(x) => { - let x: Locate = x.nodes.0.try_into().unwrap(); - return Some(x); - } - RefNode::EscapedIdentifier(x) => { - let x: Locate = x.nodes.0.try_into().unwrap(); - return Some(x); - } - _ => (), + // unwrap_node! can take multiple types + match unwrap_node!(node, SimpleIdentifier, EscapedIdentifier) { + Some(RefNode::SimpleIdentifier(x)) => { + return Some(x.nodes.0); } + Some(RefNode::EscapedIdentifier(x)) => { + return Some(x.nodes.0); + } + _ => None, } - None } ``` diff --git a/sv-parser/examples/module_list.rs b/sv-parser/examples/module_list.rs index b8d16db..e36d6a1 100644 --- a/sv-parser/examples/module_list.rs +++ b/sv-parser/examples/module_list.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use std::convert::TryInto; use std::env; use std::path::PathBuf; -use sv_parser::{parse_sv, Locate, RefNode}; +use sv_parser::{parse_sv, unwrap_node, Locate, RefNode}; fn main() { let args: Vec = env::args().collect(); @@ -14,31 +13,27 @@ fn main() { // The list of include paths let includes: Vec = Vec::new(); - // Do parse + // Parse let result = parse_sv(&path, &defines, &includes); if let Ok((syntax_tree, _)) = result { - // SyntexTree is iterable + // &SyntexTree is iterable for node in &syntax_tree { - // The type of Each node is RefNode + // The type of each node is RefNode match node { RefNode::ModuleDeclarationNonansi(x) => { - // The type of header is ModuleNonansiHeader - let (ref header, _, _, _, _) = x.nodes; - // The type of name is ModuleIdentifier - let (_, _, _, ref name, _, _, _, _) = header.nodes; + // unwrap_node! gets the nearest ModuleIdentifier from x + let id = unwrap_node!(x, ModuleIdentifier).unwrap(); - // Any type included in SyntaxTree can be convert RefNode by into() - let id = get_identifier(name.into()).unwrap(); + let id = get_identifier(id).unwrap(); // Original string can be got by SyntexTree::get_str(self, locate: &Locate) let id = syntax_tree.get_str(&id); println!("module: {}", id); } RefNode::ModuleDeclarationAnsi(x) => { - let (ref header, _, _, _, _) = x.nodes; - let (_, _, _, ref name, _, _, _, _) = header.nodes; - let id = get_identifier(name.into()).unwrap(); + let id = unwrap_node!(x, ModuleIdentifier).unwrap(); + let id = get_identifier(id).unwrap(); let id = syntax_tree.get_str(&id); println!("module: {}", id); } @@ -51,18 +46,14 @@ fn main() { } fn get_identifier(node: RefNode) -> Option { - for n in node { - match n { - RefNode::SimpleIdentifier(x) => { - let x: Locate = x.nodes.0.try_into().unwrap(); - return Some(x); - } - RefNode::EscapedIdentifier(x) => { - let x: Locate = x.nodes.0.try_into().unwrap(); - return Some(x); - } - _ => (), + // unwrap_node! can take multiple types + match unwrap_node!(node, SimpleIdentifier, EscapedIdentifier) { + Some(RefNode::SimpleIdentifier(x)) => { + return Some(x.nodes.0); } + Some(RefNode::EscapedIdentifier(x)) => { + return Some(x.nodes.0); + } + _ => None, } - None } diff --git a/sv-parser/src/lib.rs b/sv-parser/src/lib.rs index 6824725..69fad50 100644 --- a/sv-parser/src/lib.rs +++ b/sv-parser/src/lib.rs @@ -102,3 +102,19 @@ pub fn parse_lib, U: AsRef>( Err(_) => Err(ErrorKind::Parse.into()), } } + +#[macro_export] +macro_rules! unwrap_node { + ($n:expr, $( $ty:tt ),+) => {{ + let unwrap = || { + for x in $n { + match x { + $(RefNode::$ty(x) => return Some(RefNode::$ty(x)),)* + _ => (), + } + } + None + }; + unwrap() + }}; +}