mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
Enhanced Enhanced VHDL Keyword Collision Check (#285)
* added clearing of _usednames list at start of conversion * [ENH] Added tests for checking the VHDL code for picking up invalid names * added check for double underscore in VHDL names * corrected (with Henry's help) to run with Python 3.x * added category=ToVHDLWarning in _nameValid() check * move test for used VHDL name one level up added a main i test_keywords.py to run the tests manually (and debug them with print() statements ...) * corrected invalid_function_underscore to call on invalid_signal_underscore to solicit for a double underscore
This commit is contained in:
parent
fd286a5b5f
commit
e18557760f
@ -1,6 +1,7 @@
|
||||
import warnings
|
||||
# from myhdl import *
|
||||
# from myhdl import ToVHDLWarning
|
||||
|
||||
from myhdl import ToVHDLWarning
|
||||
|
||||
# A list of all reserved words within VHDL which should not be used for
|
||||
# anything other than their own specific purpose
|
||||
@ -33,16 +34,19 @@ _usedNames = [];
|
||||
# ensure reserved words are not being used for the wrong purpose
|
||||
def _nameValid(name):
|
||||
if name.lower() in _vhdl_keywords:
|
||||
warnings.warn("VHDL keyword used: %s" % (name))
|
||||
warnings.warn("VHDL keyword used: {}".format(name), category=ToVHDLWarning)
|
||||
|
||||
if name.startswith('_'):
|
||||
warnings.warn("VHDL variable names cannot start with '_': %s" % (name))
|
||||
warnings.warn("VHDL variable names cannot start with '_': {}".format(name), category=ToVHDLWarning)
|
||||
|
||||
if '-' in name:
|
||||
warnings.warn("VHDL variable names cannot contain '-': %s" % (name))
|
||||
warnings.warn("VHDL variable names cannot contain '-': {}".format(name), category=ToVHDLWarning)
|
||||
|
||||
if '__' in name:
|
||||
warnings.warn("VHDL variable names cannot contain double underscores '__': {}".format(name), category=ToVHDLWarning)
|
||||
|
||||
if name.lower() in _usedNames:
|
||||
warnings.warn("Previously used name being reused: %s" % (name))
|
||||
warnings.warn("Previously used name being reused: {}".format(name), category=ToVHDLWarning)
|
||||
|
||||
_usedNames.append(name.lower())
|
||||
|
||||
|
@ -63,7 +63,7 @@ from myhdl.conversion._misc import (_error, _kind, _context,
|
||||
from myhdl.conversion._analyze import (_analyzeSigs, _analyzeGens, _analyzeTopFunc,
|
||||
_Ram, _Rom, _enumTypeSet)
|
||||
from myhdl.conversion._toVHDLPackage import _package
|
||||
from myhdl.conversion._VHDLNameValidation import _nameValid
|
||||
from myhdl.conversion._VHDLNameValidation import _nameValid, _usedNames
|
||||
|
||||
from myhdl import bin as tobin
|
||||
|
||||
@ -151,6 +151,9 @@ class _ToVHDLConvertor(object):
|
||||
if not callable(func):
|
||||
raise ToVHDLError(_error.FirstArgType, "got %s" % type(func))
|
||||
|
||||
# clear out the list of user declared Signal (and other?) names
|
||||
del _usedNames[:]
|
||||
|
||||
_converting = 1
|
||||
if self.name is None:
|
||||
name = func.__name__
|
||||
@ -456,6 +459,8 @@ def _writeSigDecls(f, intf, siglist, memlist):
|
||||
continue
|
||||
r = _getRangeString(s)
|
||||
p = _getTypeString(s)
|
||||
# Check if VHDL keyword or reused name
|
||||
_nameValid(s._name)
|
||||
if s._driven:
|
||||
if not s._read and not isinstance(s, _TristateDriver):
|
||||
warnings.warn("%s: %s" % (_error.UnreadSignal, s._name),
|
||||
@ -488,8 +493,6 @@ def _writeSigDecls(f, intf, siglist, memlist):
|
||||
print("signal %s: %s%s%s;" % (s._name, p, r, val_str), file=f)
|
||||
|
||||
elif s._read:
|
||||
# Check if VHDL keyword or reused name
|
||||
_nameValid(s._name)
|
||||
# the original exception
|
||||
# raise ToVHDLError(_error.UndrivenSignal, s._name)
|
||||
# changed to a warning and a continuous assignment to a wire
|
||||
|
177
myhdl/test/conversion/toVHDL/test_keywords.py
Normal file
177
myhdl/test/conversion/toVHDL/test_keywords.py
Normal file
@ -0,0 +1,177 @@
|
||||
from __future__ import absolute_import
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from myhdl import ToVHDLWarning
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import shutil
|
||||
import sys
|
||||
import string
|
||||
import importlib
|
||||
import os
|
||||
from keyword import kwlist as python_kwlist
|
||||
|
||||
import warnings
|
||||
|
||||
_vhdl_keywords = ["abs", "access", "after", "alias", "all",
|
||||
"and", "architecture", "array", "assert",
|
||||
"attribute", "begin", "block", "body", "buffer",
|
||||
"bus", "case", "component", "configuration",
|
||||
"constant", "disconnect", "downto", "else",
|
||||
"elseif", "end", "entity", "exit", "file", "for",
|
||||
"function", "generate", "generic", "group",
|
||||
"guarded", "if", "impure", "in", "inertial",
|
||||
"inout", "is", "label", "library", "linkage",
|
||||
"literal", "loop", "map", "mod", "nand", "new",
|
||||
"next", "nor", "not", "null", "of", "on", "open",
|
||||
"or", "others", "out", "package", "port",
|
||||
"postponed", "procedure", "process", "pure",
|
||||
"range", "record", "register", "reject", "rem",
|
||||
"report", "return", "rol", "ror", "select",
|
||||
"severity", "signal", "shared", "sla", "sll", "sra",
|
||||
"srl", "subtype", "then", "to", "transport", "type",
|
||||
"unaffected", "units", "until", "use", "variable",
|
||||
"wait", "when", "while", "with", "xnor", "xor"];
|
||||
|
||||
keyword_code = """
|
||||
from myhdl import *
|
||||
|
||||
@block
|
||||
def invalid_import_keyword(input_sig, output_sig):
|
||||
${keyword} = Signal(False)
|
||||
|
||||
@always_comb
|
||||
def do_something():
|
||||
${keyword}.next = input_sig and input_sig
|
||||
|
||||
@always_comb
|
||||
def something_else():
|
||||
output_sig.next = ${keyword}
|
||||
|
||||
return do_something, something_else
|
||||
"""
|
||||
|
||||
|
||||
@block
|
||||
def invalid_signal_underscore(input_sig, output_sig):
|
||||
_foo = Signal(bool(0))
|
||||
|
||||
@always_comb
|
||||
def do_something():
|
||||
_foo.next = input_sig and input_sig
|
||||
|
||||
@always_comb
|
||||
def something_else():
|
||||
output_sig.next = _foo
|
||||
|
||||
return do_something, something_else
|
||||
|
||||
|
||||
@block
|
||||
def invalid_function_underscore(clock, input_sig, output_sig):
|
||||
|
||||
ttt = Signal(bool(0))
|
||||
|
||||
block1 = invalid_signal_underscore(input_sig, ttt)
|
||||
|
||||
@always(clock.posedge)
|
||||
def do_something():
|
||||
output_sig.next = ttt
|
||||
|
||||
return block1, do_something
|
||||
|
||||
|
||||
@block
|
||||
def valid(input_sig, output_sig):
|
||||
|
||||
@always_comb
|
||||
def do_something():
|
||||
output_sig.next = input_sig
|
||||
|
||||
return do_something
|
||||
|
||||
|
||||
def test_multiple_conversion():
|
||||
sig_1 = Signal(True)
|
||||
sig_2 = Signal(True)
|
||||
|
||||
a_block = valid(sig_1, sig_2)
|
||||
|
||||
# conversions with keyword should fail
|
||||
with warnings.catch_warnings() as w:
|
||||
warnings.simplefilter('error')
|
||||
|
||||
a_block.convert(hdl='VHDL')
|
||||
a_block.convert(hdl='VHDL')
|
||||
|
||||
|
||||
def test_invalid_keyword_name():
|
||||
sig_1 = Signal(True)
|
||||
sig_2 = Signal(True)
|
||||
|
||||
temp_directory = tempfile.mkdtemp()
|
||||
sys.path.append(temp_directory)
|
||||
|
||||
keyword_template = string.Template(keyword_code)
|
||||
|
||||
try:
|
||||
for keyword in _vhdl_keywords:
|
||||
if keyword in python_kwlist:
|
||||
continue
|
||||
|
||||
fd, full_filename = tempfile.mkstemp(
|
||||
suffix='.py', dir=temp_directory)
|
||||
|
||||
os.write(fd, keyword_template.substitute(keyword=keyword).encode('utf-8'))
|
||||
os.close(fd)
|
||||
|
||||
module_name = os.path.basename(full_filename)[:-3] # chop off .py
|
||||
keyword_import = importlib.import_module(module_name)
|
||||
|
||||
a_block = keyword_import.invalid_import_keyword(sig_1, sig_2)
|
||||
|
||||
with pytest.warns(ToVHDLWarning):
|
||||
a_block.convert(hdl='VHDL')
|
||||
|
||||
finally:
|
||||
sys.path.pop()
|
||||
shutil.rmtree(temp_directory)
|
||||
|
||||
|
||||
def test_invalid_signal_underscore_name():
|
||||
sig_1 = Signal(True)
|
||||
sig_2 = Signal(True)
|
||||
|
||||
a_block = invalid_signal_underscore(sig_1, sig_2)
|
||||
|
||||
# Multiple conversions of a valid block should pass without warning
|
||||
with pytest.warns(ToVHDLWarning):
|
||||
a_block.convert(hdl='VHDL')
|
||||
|
||||
|
||||
def test_invalid_function_underscore_name():
|
||||
sig_1 = Signal(True)
|
||||
sig_2 = Signal(True)
|
||||
clock = Signal(True)
|
||||
|
||||
a_block = invalid_function_underscore(clock, sig_1, sig_2)
|
||||
|
||||
# Multiple conversions of a valid block should pass without warning
|
||||
with pytest.warns(ToVHDLWarning):
|
||||
a_block.convert(hdl='VHDL')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sig_1 = Signal(True)
|
||||
sig_2 = Signal(True)
|
||||
|
||||
a_block = invalid_signal_underscore(sig_1, sig_2)
|
||||
a_block.convert(hdl='VHDL')
|
||||
|
||||
clock = Signal(True)
|
||||
|
||||
a_block = invalid_function_underscore(clock, sig_1, sig_2)
|
||||
|
||||
# Multiple conversions of a valid block should pass without warning
|
||||
a_block.convert(hdl='VHDL')
|
Loading…
x
Reference in New Issue
Block a user