Closed philipaxer closed 1 year ago
Actually the specific issue i have is to get notified about compiler directives (specifically timescale). I have seen that Complier Directives are inside a Whitespace enum.
So essentially I am not so sure how to handle compiler directives while descending the AST. The whitespaces can happen anywhere and it feels weird to have a match statement for each possible symbol/keyword etc. I am also relatively new to rust, so perhaps i am just seeing the obvious.
I am trying to elaborate the entire design and the way how i currently descent the AST is to look at a specific Node and then match all possible insides . The reason to do so is to bail out when i see unssupported features. Example below:
fn elaborate_module(&mut self, syntax_tree: &SyntaxTree, node : &ModuleDeclaration) -> Result<Module> {
let module_loc = unwrap_locate!(node).unwrap();
match node {
ModuleDeclaration::Ansi(module_node) => {return elaborate_module_ansi(syntax_tree, module_node);}
ModuleDeclaration::Nonansi(module_node) => {return elaborate_module_nonansi(syntax_tree, module_node);}
_ => {unimplemented!("Module declaration {:?} is not implemented", node);}
}
Err(ElaborationError::IllegalModuleDefinition)
}
It's not obvious :p
The function parse_sv_str
operates in three main stages:
pp_text
.pp_text
into a PreprocessedText
structure which is a string with some metadata about ranges.syntax_tree
you're working with.The specification of the preprocessor is a bit fuzzy but, essentially, the LRM specifies two languages (preprocessor, everything else), and the compiler directives are lumped in with the preprocesor, see IEEE1800-2017 clause 22.
Sv-parser approaches this by keeping all preprocessor and compiler directives in WhiteSpace
nodes.
Directives are not included in the BNF (IEEE1800-2017 Annex A), and the rules about where they can be placed are not entirely formalised, so sv-parser just keeps them all together for "later" processing.
It's not ideal, but good enough IMO.
To print every node (including WhiteSpace
nodes), you can use the Debug trait like this, which is implemented here.
To handle compiler directives like timescale, you can match RefNode::WhiteSpace(WhiteSpace::CompilerDirective(d))
like this and use string comparison to find the keyword "timescale" or whatever.
There are not many directives to consider, so your code (hopefully) shouldn't be too massive:
pragma
timescale
default_nettype
celldefine
, endcelldefine
unconnected_drive
, nounconnected_drive
begin_keywords
and end_keywords
, I'm not sure.I wouldn't be too worried about performance around that processing, because so sane codebase is going to be using large numbers of directives... I may be wrong :p
Is that helpful?
That makes sense
It looks as if the compiler directives are implemented as whitespaces in the parser. That seems to prevent them from getting printed.
This code
yields the following print out, which forgets about the compiler directive: