sv-parser icon indicating copy to clipboard operation
sv-parser copied to clipboard

Request: Add an example of how to use this library to rewrite the AST?

Open parker-research opened this issue 10 months ago • 3 comments

I think the following would make a good example:

Create an example function which traverses the SyntaxTree, and renames all signals it encounters to be suffixed with "_visited".

It could even be written in the style of a unit test, with the following input and output:

Example Input

module RefModule (
  input in1,
  input in2,
  output logic out
);

  assign out = in1 & ~in2;

endmodule

Example Output

module RefModule (
  input in1_visited,
  input in2_visited,
  output logic out_visited
);

  assign out_visited = in1_visited & ~in2_visited;

endmodule

Additional context I'd be happy to help finish this in a PR if you can just give a crude example of how this is accomplished.

parker-research avatar Feb 24 '25 20:02 parker-research

Unfortunately, rewriting AST is difficult in the current implementation. This is because all node is based on Locate including only positional information in the source code.

#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Locate {
    pub offset: usize,
    pub line: u32,
    pub len: usize,
}

So modifying output code can be achieved like below, but I think it is different with modifying AST.

        let mut idents = Vec::new();

        // Gather identifier
        for node in &syntax_tree {
            match node {
                RefNode::Identifier(x) => {
                    let locate = unwrap_node!(x, Locate).unwrap();
                    if let RefNode::Locate(x) = locate {
                        idents.push(x);
                    }
                }
                _ => (),
            }
        }

        // Output renamed code
        for node in &syntax_tree {
            match node {
                RefNode::Locate(x) => {
                    let text = if idents.iter().any(|y| *y == x) {
                        format!("{}_visited", syntax_tree.get_str(x).unwrap().to_string())
                    } else {
                        syntax_tree.get_str(x).unwrap().to_string()
                    };
                    print!("{text}");
                }
                _ => (),
            }
        }

dalance avatar Feb 25 '25 05:02 dalance

Any advice on how to create a system that would modify/add/remove syntax nodes, built on top of sv-parser's syntax definitions? I guess it would live in a separate crate. Perhaps one day it would be worthy to be merged into this project

parker-research avatar Mar 03 '25 20:03 parker-research

I have no idea about building new modifiable syntax tree crate on sv-parser. Copying all syntax definition may be required.

Instead of it, extending sv-parser may be reasonable. For example, text field to Locate can be added. The StrId is a unique ID to point the actual String. The String is stored HashMap on thread local storage.

#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Locate {
    pub offset: usize,
    pub line: u32,
    pub len: usize,
    pub text: StrId,
}

And Locate generation code is probably like below: https://github.com/dalance/sv-parser/blob/master/sv-parser-parser/src/utils.rs

pub(crate) fn into_locate(s: Span) -> Locate {
    let text = string_table.insert(s.fragment()); // Insert &str to string_table, and return StrId
    Locate {
        offset: s.location_offset(),
        line: s.location_line(),
        len: s.fragment().len(),
        text,
    }
}

The actual example of such string table is below:

https://github.com/veryl-lang/veryl/blob/master/crates/parser/src/resource_table.rs

dalance avatar Mar 04 '25 01:03 dalance