#!/usr/bin/env python3 # DESCRIPTION: Verilator: Primitive C++ style checker # # Copyright 2024 by Wilson Snyder. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 import vltest_bootstrap test.scenarios('dist') root = ".." Waivers = [ '+verilator+prof+threads+file+', # Deprecated '+verilator+prof+threads+start+', # Deprecated '+verilator+prof+threads+window+', # Deprecated '-fno-', # Documented differently '-no-lineno', # Deprecated '-no-order-clock-delay', # Deprecated '-prof-threads', # Deprecated) ] def get_summary_opts(root): args = {} for filename in test.glob_some(root + "/bin/*"): with open(filename, "r", encoding="latin-1") as fh: on = False lineno = 0 for line in fh: lineno += 1 line = line.rstrip() m1 = re.search(r'^\s+((-|\+)+[^ ]+)', line) m2 = re.search(r"parser.add_argument\('((-|\+)[^']+)'", line) if re.search(r'ARGUMENT SUMMARY', line): on = True elif re.search(r'=head1', line): on = False elif on and m1: opt = opt_clean(m1.group(1)) if test.verbose: print("S '" + opt + "' " + line) args[opt] = filename + ":" + str(lineno) elif m2: opt = opt_clean(m2.group(1)) if test.verbose: print("S '" + opt + "' " + line) args[opt] = filename + ":" + str(lineno) return args def get_docs_opts(root): args = {} for filename in test.glob_some(root + "/docs/guide/*.rst"): with open(filename, "r", encoding="latin-1") as fh: lineno = 0 for line in fh: lineno += 1 line = line.rstrip() m = re.search(r'option:: ((-|\+)+[^ `]+)', line) if not m: m = re.search(r':vlopt:`[^`]+ <([^>]+)>', line) if not m: m = re.search(r':vlopt:`((-|\+)+[^ `]+)', line) if m: opt = opt_clean(m.group(1)) if test.verbose: print("D '" + opt + "' " + line) args[opt] = filename + ":" + str(lineno) return args def opt_clean(opt): opt = re.sub(r'--', '-', opt) opt = re.sub(r'<.*', '', opt) opt = re.sub(r'\\', '', opt) return opt def alt_names(opt): opts = [opt] if re.search(r'^-', opt): opts.append("-no" + opt) m = re.search(r'^-no(-.*)', opt) if m: opts.append(m.group(1)) return opts if not os.path.exists(root + "/.git"): test.skip("Not in a git repository") sums = get_summary_opts(root) docs = get_docs_opts(root) both = {} both.update(sums) both.update(docs) waiver = {k: 1 for k in Waivers} for opt in sorted(both.keys()): if opt in waiver: continue sum_ok = False docs_ok = False for alt in alt_names(opt): if alt in sums: sum_ok = True if test.verbose: print(str(sum_ok) + " SAC '" + opt + "' -> '" + alt + "'") if re.search(r'-fno-', opt): # Minimal-documented optimization option sum_ok = True for alt in alt_names(opt): if alt in docs: docs_ok = True if test.verbose: print(str(docs_ok) + " DAC '" + opt + "' -> '" + alt + "'") if not sum_ok: test.error(docs[opt] + ": Option documented in docs/guide '" + opt + "' not found in bin/* ARGUMENT SUMMARY documentation") elif not docs_ok: test.error(sums[opt] + ": Option documented in bin/ ARGUMENT SUMMARY '" + opt + "' not found in docs/guide documentation") elif test.verbose: print(": ok '" + opt) test.passes()