build.{dsl,res}: allow platform-dependent attributes using callables.
Fixes #132.
This commit is contained in:
parent
0ab0a74ec1
commit
7b4fbf8e01
|
@ -127,7 +127,7 @@ class _ModuleBuilder(_Namer, _BufferedBuilder, _AttrBuilder):
|
||||||
self._append(" parameter \\{} {}'{:b}\n",
|
self._append(" parameter \\{} {}'{:b}\n",
|
||||||
param, len(value), value.value)
|
param, len(value), value.value)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False, "Bad parameter {!r}".format(value)
|
||||||
for port, wire in ports.items():
|
for port, wire in ports.items():
|
||||||
self._append(" connect {} {}\n", port, wire)
|
self._append(" connect {} {}\n", port, wire)
|
||||||
self._append(" end\n")
|
self._append(" end\n")
|
||||||
|
|
|
@ -91,10 +91,10 @@ def DiffPairsN(*args, **kwargs):
|
||||||
|
|
||||||
class Attrs(OrderedDict):
|
class Attrs(OrderedDict):
|
||||||
def __init__(self, **attrs):
|
def __init__(self, **attrs):
|
||||||
for attr_key, attr_value in attrs.items():
|
for key, value in attrs.items():
|
||||||
if not (attr_value is None or isinstance(attr_value, str)):
|
if not (value is None or isinstance(value, str) or hasattr(value, "__call__")):
|
||||||
raise TypeError("Attribute value must be None or str, not {!r}"
|
raise TypeError("Value of attribute {} must be None, str, or callable, not {!r}"
|
||||||
.format(attr_value))
|
.format(key, value))
|
||||||
|
|
||||||
super().__init__(**attrs)
|
super().__init__(**attrs)
|
||||||
|
|
||||||
|
@ -103,6 +103,8 @@ class Attrs(OrderedDict):
|
||||||
for key, value in self.items():
|
for key, value in self.items():
|
||||||
if value is None:
|
if value is None:
|
||||||
items.append("!" + key)
|
items.append("!" + key)
|
||||||
|
elif hasattr(value, "__call__"):
|
||||||
|
items.append(key + "=" + repr(value))
|
||||||
else:
|
else:
|
||||||
items.append(key + "=" + value)
|
items.append(key + "=" + value)
|
||||||
return "(attrs {})".format(" ".join(items))
|
return "(attrs {})".format(" ".join(items))
|
||||||
|
|
|
@ -103,13 +103,21 @@ class ResourceManager:
|
||||||
return dir, xdr
|
return dir, xdr
|
||||||
|
|
||||||
def resolve(resource, dir, xdr, name, attrs):
|
def resolve(resource, dir, xdr, name, attrs):
|
||||||
|
for attr_key, attr_value in attrs.items():
|
||||||
|
if hasattr(attr_value, "__call__"):
|
||||||
|
attr_value = attr_value(self)
|
||||||
|
assert attr_value is None or isinstance(attr_value, str)
|
||||||
|
if attr_value is None:
|
||||||
|
del attrs[attr_key]
|
||||||
|
else:
|
||||||
|
attrs[attr_key] = attr_value
|
||||||
|
|
||||||
if isinstance(resource.ios[0], Subsignal):
|
if isinstance(resource.ios[0], Subsignal):
|
||||||
fields = OrderedDict()
|
fields = OrderedDict()
|
||||||
for sub in resource.ios:
|
for sub in resource.ios:
|
||||||
sub_attrs = {k: v for k, v in {**attrs, **sub.attrs}.items() if v is not None}
|
|
||||||
fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name],
|
fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name],
|
||||||
name="{}__{}".format(name, sub.name),
|
name="{}__{}".format(name, sub.name),
|
||||||
attrs=sub_attrs)
|
attrs={**attrs, **sub.attrs})
|
||||||
return Record([
|
return Record([
|
||||||
(f_name, f.layout) for (f_name, f) in fields.items()
|
(f_name, f.layout) for (f_name, f) in fields.items()
|
||||||
], fields=fields, name=name)
|
], fields=fields, name=name)
|
||||||
|
|
|
@ -118,9 +118,15 @@ class AttrsTestCase(FHDLTestCase):
|
||||||
self.assertEqual(a["FOO"], None)
|
self.assertEqual(a["FOO"], None)
|
||||||
self.assertEqual(repr(a), "(attrs !FOO)")
|
self.assertEqual(repr(a), "(attrs !FOO)")
|
||||||
|
|
||||||
|
def test_callable(self):
|
||||||
|
fn = lambda self: "FOO"
|
||||||
|
a = Attrs(FOO=fn)
|
||||||
|
self.assertEqual(a["FOO"], fn)
|
||||||
|
self.assertEqual(repr(a), "(attrs FOO={!r})".format(fn))
|
||||||
|
|
||||||
def test_wrong_value(self):
|
def test_wrong_value(self):
|
||||||
with self.assertRaises(TypeError,
|
with self.assertRaises(TypeError,
|
||||||
msg="Attribute value must be None or str, not 1"):
|
msg="Value of attribute FOO must be None, str, or callable, not 1"):
|
||||||
a = Attrs(FOO=1)
|
a = Attrs(FOO=1)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue