forked from opendacs/PyHCL
dsl: add io (#28)
This commit is contained in:
parent
0785010acc
commit
3f91cbf6bd
|
@ -0,0 +1,19 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(format='%(asctime)s %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
class PyHclError(BaseException):
|
||||||
|
errs = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def append(cls, errs):
|
||||||
|
PyHclError.errs[cls] = errs
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def err(cls, name, msg):
|
||||||
|
e = PyHclError.errs[cls][name]
|
||||||
|
ev = e['value']
|
||||||
|
|
||||||
|
logging.error("[%d]: %s", e['code'], msg)
|
||||||
|
return ev
|
|
@ -1,2 +1,5 @@
|
||||||
class PyHclError(BaseException):
|
from .. import PyHclError
|
||||||
|
|
||||||
|
|
||||||
|
class CoreError(PyHclError):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
from ...core import PyHclError
|
from .. import CoreError
|
||||||
|
|
||||||
|
|
||||||
class ModuleErr(PyHclError):
|
class ModuleError(CoreError):
|
||||||
pass
|
@staticmethod
|
||||||
|
def not_contains_io(msg):
|
||||||
|
return ModuleError.err('NotContainsIO', msg)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def duplicate_name(msg):
|
||||||
|
return ModuleError.err('InheritDuplicateName', msg)
|
||||||
|
|
||||||
|
|
||||||
err = {
|
ModuleError.append({
|
||||||
# Error Name | Error value | Error Code
|
'NotContainsIO': {
|
||||||
'NotContainsIO': (ModuleErr('not contains io'), 0),
|
'code': 100,
|
||||||
'DuplicateName': (ModuleErr('duplicate names'), 1),
|
'value': ModuleError('the module lack of io attribute')},
|
||||||
}
|
|
||||||
|
|
||||||
|
'InheritDuplicateName': {
|
||||||
def module_err(name):
|
'code': 101,
|
||||||
return err[name][0]
|
'value': ModuleError('modules with inherited relationships '
|
||||||
|
'contain duplicate attributes')},
|
||||||
|
})
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
from . import module_err
|
from py_hcl.core.module_constructor import ModuleError
|
||||||
from ...dsl.expression import Expression
|
from py_hcl.dsl.expr.expression import Expression
|
||||||
|
|
||||||
|
|
||||||
def extract(dct):
|
def extract(dct, name):
|
||||||
res = {}
|
res = {}
|
||||||
|
|
||||||
for k in dct:
|
for k, v in dct.items():
|
||||||
if isinstance(dct[k], Expression):
|
if isinstance(v, Expression):
|
||||||
res[k] = dct[k]
|
res[k] = v
|
||||||
|
|
||||||
if 'io' not in res:
|
check_io_exist(res, name)
|
||||||
raise module_err('NotContainsIO')
|
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def check_io_exist(res, name):
|
||||||
|
if 'io' not in res:
|
||||||
|
raise ModuleError.not_contains_io(
|
||||||
|
'module {} lack of io attribute'.format(name))
|
||||||
|
|
|
@ -1,22 +1,50 @@
|
||||||
from ..module_constructor import module_err
|
from py_hcl.core.module_constructor import ModuleError
|
||||||
|
from py_hcl.dsl.expr.io import IO
|
||||||
|
|
||||||
|
|
||||||
def merge_expr(dest, src):
|
def merge_expr(dest, src, mod_names):
|
||||||
io_dest = dest['io']
|
io_dest = dest['io']
|
||||||
io_src = src['io']
|
io_src = src['io']
|
||||||
io_dest = merge_io(io_dest, io_src)
|
assert isinstance(io_dest, IO)
|
||||||
|
assert isinstance(io_src, IO)
|
||||||
|
|
||||||
a = set(dest.keys()) & set(src.keys())
|
check_dup_mod(dest, src, mod_names)
|
||||||
if len(a) > 1:
|
|
||||||
raise module_err('DuplicateName')
|
|
||||||
|
|
||||||
|
io_dest = merge_io(io_dest, io_src, mod_names)
|
||||||
res = {**dest, **src, 'io': io_dest}
|
res = {**dest, **src, 'io': io_dest}
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def merge_io(dest, src):
|
def check_dup_mod(dest, src, mod_names):
|
||||||
return dest, src # TODO
|
a = set(dest.keys()) & set(src.keys())
|
||||||
|
a.discard('io')
|
||||||
|
if len(a) > 0:
|
||||||
|
dest_name = mod_names[0]
|
||||||
|
src_name = mod_names[1]
|
||||||
|
raise ModuleError.duplicate_name(
|
||||||
|
'module {} has duplicates with {} in '
|
||||||
|
'module {}'.format(dest_name, list(a), src_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def merge_scope(dest, src):
|
def merge_io(dest, src, mod_names):
|
||||||
|
check_dup_io(dest, src, mod_names)
|
||||||
|
dest.ports.extend(src.ports)
|
||||||
|
|
||||||
|
return dest
|
||||||
|
|
||||||
|
|
||||||
|
def check_dup_io(dest, src, mod_names):
|
||||||
|
names = set(p['name'] for p in dest.ports)
|
||||||
|
for p in src.ports:
|
||||||
|
if p['name'] in names:
|
||||||
|
dest_name = mod_names[0]
|
||||||
|
src_name = mod_names[1]
|
||||||
|
raise ModuleError.duplicate_name(
|
||||||
|
'module {} has duplicates with {} in '
|
||||||
|
'module {} in io'.format(dest_name, p['name'], src_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def merge_scope(dest, src, mod_names):
|
||||||
return dest, src # TODO
|
return dest, src # TODO
|
||||||
|
|
|
@ -5,5 +5,5 @@ class MetaModule(type):
|
||||||
def __init__(cls, name, bases, dct):
|
def __init__(cls, name, bases, dct):
|
||||||
super().__init__(name, bases, dct)
|
super().__init__(name, bases, dct)
|
||||||
|
|
||||||
packed = pack(name, bases, dct)
|
packed = pack(bases, dct, name)
|
||||||
cls.packed_module = packed
|
cls.packed_module = packed
|
||||||
|
|
|
@ -3,17 +3,18 @@ from .extractor import extract
|
||||||
from .packed_module import PackedModule
|
from .packed_module import PackedModule
|
||||||
|
|
||||||
|
|
||||||
def pack(name, bases, dct):
|
def pack(bases, dct, name):
|
||||||
raw_expr = extract(dct)
|
raw_expr = extract(dct, name)
|
||||||
raw_scope = ... # TODO
|
raw_scope = ... # TODO
|
||||||
|
|
||||||
named_expression, top_scope = handle_inherit(bases, raw_expr, raw_scope)
|
named_expression, top_scope = \
|
||||||
|
handle_inherit(bases, raw_expr, raw_scope, name)
|
||||||
|
|
||||||
res = PackedModule(name, named_expression, top_scope)
|
res = PackedModule(name, named_expression, top_scope)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def handle_inherit(bases, named_expression, top_scope):
|
def handle_inherit(bases, named_expression, top_scope, name):
|
||||||
for b in bases:
|
for b in bases:
|
||||||
if not hasattr(b, 'packed_module'):
|
if not hasattr(b, 'packed_module'):
|
||||||
continue
|
continue
|
||||||
|
@ -22,7 +23,7 @@ def handle_inherit(bases, named_expression, top_scope):
|
||||||
expr = pm.named_expressions
|
expr = pm.named_expressions
|
||||||
ts = pm.top_scope
|
ts = pm.top_scope
|
||||||
|
|
||||||
named_expression = merge_expr(named_expression, expr)
|
named_expression = merge_expr(named_expression, expr, (name, pm.name))
|
||||||
top_scope = merge_scope(top_scope, ts)
|
top_scope = merge_scope(top_scope, ts, (name, pm.name))
|
||||||
|
|
||||||
return named_expression, top_scope
|
return named_expression, top_scope
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
from py_hcl import PyHclError
|
||||||
|
|
||||||
|
|
||||||
|
class DslError(PyHclError):
|
||||||
|
pass
|
|
@ -0,0 +1,14 @@
|
||||||
|
from .. import DslError
|
||||||
|
|
||||||
|
|
||||||
|
class ExprError(DslError):
|
||||||
|
@staticmethod
|
||||||
|
def io_value(msg):
|
||||||
|
return ExprError.err('IOValueError', msg)
|
||||||
|
|
||||||
|
|
||||||
|
ExprError.append({
|
||||||
|
'IOValueError': {
|
||||||
|
'code': 200,
|
||||||
|
'value': ExprError('io items should wrap with Input or Output')},
|
||||||
|
})
|
|
@ -0,0 +1,34 @@
|
||||||
|
from py_hcl.dsl.expr import ExprError
|
||||||
|
from py_hcl.dsl.expr.expression import Expression
|
||||||
|
|
||||||
|
|
||||||
|
class IO(Expression):
|
||||||
|
def __init__(self, **named_ports):
|
||||||
|
self.ports = IO.handle_args(named_ports)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def handle_args(named_ports):
|
||||||
|
res = []
|
||||||
|
for k, v in named_ports.items():
|
||||||
|
if isinstance(v, Input):
|
||||||
|
res.append({'name': k, 'direct': 'in', 'tpe': v.tpe})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(v, Output):
|
||||||
|
res.append({'name': k, 'direct': 'out', 'tpe': v.tpe})
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise ExprError.io_value(
|
||||||
|
"type of '{}' is {}, not Input or Output".format(k, type(v)))
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class Input(Exception):
|
||||||
|
def __init__(self, tpe):
|
||||||
|
self.tpe = tpe
|
||||||
|
|
||||||
|
|
||||||
|
class Output(Exception):
|
||||||
|
def __init__(self, tpe):
|
||||||
|
self.tpe = tpe
|
|
@ -1,8 +1,9 @@
|
||||||
|
from py_hcl.dsl.expr.io import IO
|
||||||
from ..core.module_constructor.meta_module import MetaModule
|
from ..core.module_constructor.meta_module import MetaModule
|
||||||
from .expression import Expression
|
from py_hcl.dsl.expr.expression import Expression
|
||||||
|
|
||||||
|
|
||||||
class Module(metaclass=MetaModule):
|
class Module(metaclass=MetaModule):
|
||||||
io = Expression() # TODO
|
io = IO() # TODO
|
||||||
clock = Expression() # TODO
|
clock = Expression() # TODO
|
||||||
reset = Expression() # TODO
|
reset = Expression() # TODO
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from py_hcl.dsl.expr import ExprError
|
||||||
|
from py_hcl.dsl.expr.io import IO, Input, Output
|
||||||
|
from py_hcl.dsl.module import Module
|
||||||
|
from py_hcl.firrtl_ir.expr import Expression
|
||||||
|
|
||||||
|
|
||||||
|
def test_io():
|
||||||
|
class A(Module):
|
||||||
|
io = IO(
|
||||||
|
i=Input(Expression()),
|
||||||
|
o=Output(Expression()))
|
||||||
|
|
||||||
|
ps = A.packed_module.named_expressions['io'].ports
|
||||||
|
assert len(ps) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_io_no_wrap_io():
|
||||||
|
with pytest.raises(ExprError, match='^.*Input.*Output.*$'):
|
||||||
|
class A(Module):
|
||||||
|
io = IO(i=Expression())
|
||||||
|
|
||||||
|
with pytest.raises(ExprError, match='^.*Input.*Output.*$'):
|
||||||
|
class A(Module): # noqa: F811
|
||||||
|
io = IO(
|
||||||
|
i=Expression(),
|
||||||
|
o=Output(Expression()))
|
||||||
|
|
||||||
|
with pytest.raises(ExprError, match='^.*Input.*Output.*$'):
|
||||||
|
class A(Module): # noqa: F811
|
||||||
|
io = IO(
|
||||||
|
i=Input(Expression()),
|
||||||
|
o=Expression())
|
|
@ -1,13 +1,14 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from py_hcl.core.module_constructor import ModuleErr
|
from py_hcl.core.module_constructor import ModuleError
|
||||||
from py_hcl.dsl.expression import Expression
|
from py_hcl.dsl.expr.expression import Expression
|
||||||
|
from py_hcl.dsl.expr.io import IO, Input
|
||||||
from py_hcl.dsl.module import Module
|
from py_hcl.dsl.module import Module
|
||||||
|
|
||||||
|
|
||||||
def test_module():
|
def test_module():
|
||||||
class A(Module):
|
class A(Module):
|
||||||
io = Expression()
|
io = IO()
|
||||||
a = Expression()
|
a = Expression()
|
||||||
|
|
||||||
assert hasattr(A, "packed_module")
|
assert hasattr(A, "packed_module")
|
||||||
|
@ -16,18 +17,18 @@ def test_module():
|
||||||
|
|
||||||
|
|
||||||
def test_module_not_contains_io():
|
def test_module_not_contains_io():
|
||||||
with pytest.raises(ModuleErr, match='not contains io'):
|
with pytest.raises(ModuleError, match='^.*lack of io.*$'):
|
||||||
class A(Module):
|
class A(Module):
|
||||||
b = Expression()
|
b = Expression()
|
||||||
|
|
||||||
|
|
||||||
def test_module_inherit():
|
def test_module_inherit():
|
||||||
class A(Module):
|
class A(Module):
|
||||||
io = Expression()
|
io = IO()
|
||||||
a = Expression()
|
a = Expression()
|
||||||
|
|
||||||
class B(A):
|
class B(A):
|
||||||
io = Expression()
|
io = IO()
|
||||||
b = Expression()
|
b = Expression()
|
||||||
|
|
||||||
assert hasattr(B, "packed_module")
|
assert hasattr(B, "packed_module")
|
||||||
|
@ -36,11 +37,22 @@ def test_module_inherit():
|
||||||
|
|
||||||
|
|
||||||
def test_module_duplicate_name():
|
def test_module_duplicate_name():
|
||||||
with pytest.raises(ModuleErr, match='duplicate names'):
|
with pytest.raises(ModuleError, match='^.*duplicate.*$'):
|
||||||
class A(Module):
|
class A(Module):
|
||||||
io = Expression()
|
io = IO()
|
||||||
a = Expression()
|
a = Expression()
|
||||||
|
|
||||||
class B(A):
|
class B(A):
|
||||||
io = Expression()
|
io = IO()
|
||||||
|
a = Expression()
|
||||||
|
|
||||||
|
|
||||||
|
def test_module_io_duplicate_name():
|
||||||
|
with pytest.raises(ModuleError, match='^.*duplicate.*$'):
|
||||||
|
class A(Module):
|
||||||
|
io = IO(i=Input(Expression()))
|
||||||
|
a = Expression()
|
||||||
|
|
||||||
|
class B(A):
|
||||||
|
io = IO(i=Input(Expression()))
|
||||||
a = Expression()
|
a = Expression()
|
||||||
|
|
Loading…
Reference in New Issue