Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
parker-research opened this issue Feb 24, 2025 · 3 comments

Comments

@parker-research
Copy link
Contributor

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.

@dalance
Copy link
Owner

dalance commented Feb 25, 2025

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}");
                }
                _ => (),
            }
        }

@parker-research
Copy link
Contributor Author

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

@dalance
Copy link
Owner

dalance commented Mar 4, 2025

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants