dsl: add io (#28)

This commit is contained in:
Gaufoo 2019-11-29 20:10:57 +08:00 committed by GitHub
parent 0785010acc
commit 3f91cbf6bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 210 additions and 47 deletions

View File

@ -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

View File

@ -1,2 +1,5 @@
class PyHclError(BaseException):
from .. import PyHclError
class CoreError(PyHclError):
pass

View File

@ -1,16 +1,23 @@
from ...core import PyHclError
from .. import CoreError
class ModuleErr(PyHclError):
pass
class ModuleError(CoreError):
@staticmethod
def not_contains_io(msg):
return ModuleError.err('NotContainsIO', msg)
@staticmethod
def duplicate_name(msg):
return ModuleError.err('InheritDuplicateName', msg)
err = {
# Error Name | Error value | Error Code
'NotContainsIO': (ModuleErr('not contains io'), 0),
'DuplicateName': (ModuleErr('duplicate names'), 1),
}
ModuleError.append({
'NotContainsIO': {
'code': 100,
'value': ModuleError('the module lack of io attribute')},
def module_err(name):
return err[name][0]
'InheritDuplicateName': {
'code': 101,
'value': ModuleError('modules with inherited relationships '
'contain duplicate attributes')},
})

View File

@ -1,15 +1,20 @@
from . import module_err
from ...dsl.expression import Expression
from py_hcl.core.module_constructor import ModuleError
from py_hcl.dsl.expr.expression import Expression
def extract(dct):
def extract(dct, name):
res = {}
for k in dct:
if isinstance(dct[k], Expression):
res[k] = dct[k]
for k, v in dct.items():
if isinstance(v, Expression):
res[k] = v
if 'io' not in res:
raise module_err('NotContainsIO')
check_io_exist(res, name)
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))

View File

@ -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_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())
if len(a) > 1:
raise module_err('DuplicateName')
check_dup_mod(dest, src, mod_names)
io_dest = merge_io(io_dest, io_src, mod_names)
res = {**dest, **src, 'io': io_dest}
return res
def merge_io(dest, src):
return dest, src # TODO
def check_dup_mod(dest, src, mod_names):
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

View File

@ -5,5 +5,5 @@ class MetaModule(type):
def __init__(cls, name, bases, dct):
super().__init__(name, bases, dct)
packed = pack(name, bases, dct)
packed = pack(bases, dct, name)
cls.packed_module = packed

View File

@ -3,17 +3,18 @@ from .extractor import extract
from .packed_module import PackedModule
def pack(name, bases, dct):
raw_expr = extract(dct)
def pack(bases, dct, name):
raw_expr = extract(dct, name)
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)
return res
def handle_inherit(bases, named_expression, top_scope):
def handle_inherit(bases, named_expression, top_scope, name):
for b in bases:
if not hasattr(b, 'packed_module'):
continue
@ -22,7 +23,7 @@ def handle_inherit(bases, named_expression, top_scope):
expr = pm.named_expressions
ts = pm.top_scope
named_expression = merge_expr(named_expression, expr)
top_scope = merge_scope(top_scope, ts)
named_expression = merge_expr(named_expression, expr, (name, pm.name))
top_scope = merge_scope(top_scope, ts, (name, pm.name))
return named_expression, top_scope

View File

@ -0,0 +1,5 @@
from py_hcl import PyHclError
class DslError(PyHclError):
pass

View File

@ -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')},
})

34
py_hcl/dsl/expr/io.py Normal file
View File

@ -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

View File

@ -1,8 +1,9 @@
from py_hcl.dsl.expr.io import IO
from ..core.module_constructor.meta_module import MetaModule
from .expression import Expression
from py_hcl.dsl.expr.expression import Expression
class Module(metaclass=MetaModule):
io = Expression() # TODO
io = IO() # TODO
clock = Expression() # TODO
reset = Expression() # TODO

34
tests/test_dsl/test_io.py Normal file
View File

@ -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())

View File

@ -1,13 +1,14 @@
import pytest
from py_hcl.core.module_constructor import ModuleErr
from py_hcl.dsl.expression import Expression
from py_hcl.core.module_constructor import ModuleError
from py_hcl.dsl.expr.expression import Expression
from py_hcl.dsl.expr.io import IO, Input
from py_hcl.dsl.module import Module
def test_module():
class A(Module):
io = Expression()
io = IO()
a = Expression()
assert hasattr(A, "packed_module")
@ -16,18 +17,18 @@ def test_module():
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):
b = Expression()
def test_module_inherit():
class A(Module):
io = Expression()
io = IO()
a = Expression()
class B(A):
io = Expression()
io = IO()
b = Expression()
assert hasattr(B, "packed_module")
@ -36,11 +37,22 @@ def test_module_inherit():
def test_module_duplicate_name():
with pytest.raises(ModuleErr, match='duplicate names'):
with pytest.raises(ModuleError, match='^.*duplicate.*$'):
class A(Module):
io = Expression()
io = IO()
a = Expression()
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()