Skip to content

Commit

Permalink
add doc for module_inherit_mro
Browse files Browse the repository at this point in the history
Signed-off-by: zhongzc <zhongzc_arch@outlook.com>
  • Loading branch information
zhongzc committed Nov 23, 2020
1 parent 72f6456 commit 12fa544
Show file tree
Hide file tree
Showing 16 changed files with 137 additions and 66 deletions.
7 changes: 5 additions & 2 deletions py_hcl/core/expr/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from py_hcl.core.hcl_ops import op_register
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.core.type.sint import SIntT
from py_hcl.core.type.uint import UIntT
from py_hcl.core.type.vector import VectorT
Expand Down Expand Up @@ -99,7 +99,10 @@ def _(lf, rt):
bd_values = {}
for k in lf.hcl_type.fields.keys():
res = getattr(lf, k) + getattr(rt, k)
bd_type_fields[k] = {"dir": Dir.SRC, "hcl_type": res.hcl_type}
bd_type_fields[k] = {
"dir": BundleDirection.SOURCE,
"hcl_type": res.hcl_type
}
bd_values[k] = res

return BundleHolder(BundleT(bd_type_fields), VariableType.VALUE, bd_values)
Expand Down
7 changes: 5 additions & 2 deletions py_hcl/core/expr/ands.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from py_hcl.core.hcl_ops import op_register
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.core.type.sint import SIntT
from py_hcl.core.type.uint import UIntT
from py_hcl.core.type.vector import VectorT
Expand Down Expand Up @@ -102,7 +102,10 @@ def _(lf, rt):
bd_values = {}
for k in lf.hcl_type.fields.keys():
res = getattr(lf, k) & getattr(rt, k)
bd_type_fields[k] = {"dir": Dir.SRC, "hcl_type": res.hcl_type}
bd_type_fields[k] = {
"dir": BundleDirection.SOURCE,
"hcl_type": res.hcl_type
}
bd_values[k] = res

return BundleHolder(BundleT(bd_type_fields), VariableType.VALUE, bd_values)
Expand Down
7 changes: 4 additions & 3 deletions py_hcl/core/expr/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from py_hcl.core.hcl_ops import op_register
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.utils.serialization import json_serialize

field_accessor = op_register('.')
Expand Down Expand Up @@ -39,11 +39,12 @@ def _(o, *_):
raise ExprError.op_type_err('field_accessor', o)


def build_new_var_type(var_type: VariableType, dr: Dir) -> VariableType:
def build_new_var_type(var_type: VariableType,
dr: BundleDirection) -> VariableType:
if var_type == VariableType.ASSIGNABLE_VALUE:
return VariableType.ASSIGNABLE_VALUE
if var_type == VariableType.VALUE and dr == dr.SINK:
return VariableType.LOCATION
if var_type == VariableType.LOCATION and dr == dr.SRC:
if var_type == VariableType.LOCATION and dr == dr.SOURCE:
return VariableType.LOCATION
return VariableType.VALUE
44 changes: 21 additions & 23 deletions py_hcl/core/expr/io.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Dict, Union, Optional, Tuple
from typing import Dict, Union, Optional, Tuple, List

from py_hcl.core.expr import HclExpr
from py_hcl.core.expr.error import ExprError
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import Dir, BundleT
from py_hcl.core.type.bundle import BundleDirection, BundleT
from py_hcl.core.utils import module_inherit_mro
from py_hcl.utils.serialization import json_serialize

Expand Down Expand Up @@ -32,54 +32,52 @@ def __init__(self,
self.module_name = module_name


@json_serialize
class IONode(object):
def __init__(self, io_holder: IOHolder, next_node: Optional["IOHolder"]):
self.io_holder = io_holder
if next_node is not None:
self.next_node = next_node


@json_serialize(
json_fields=["id", "type", "hcl_type", "variable_type", "io_chain_head"])
json_fields=["id", "type", "hcl_type", "variable_type", "io_chain"])
class IO(HclExpr):
def __init__(self, hcl_type: HclType, io_chain_head: IONode):
def __init__(self, hcl_type: HclType, io_chain: List[IOHolder]):
self.type = 'io'
self.hcl_type = hcl_type
self.variable_type = VariableType.VALUE
self.io_chain_head = io_chain_head
self.io_chain = io_chain


def io_extend(modules: Tuple[type]):
"""
"""

modules = module_inherit_mro(modules)

current_ports = {}
io_chain = None
io_chain = []
for m in modules[::-1]:
h = m.io.io_chain_head.io_holder
h = m.io.io_chain[0]
current_ports.update(h.named_ports)
io_chain = IONode(h, io_chain)
io_chain.insert(0, h)

def _(named_ports: Dict[str, Union[Input, Output]]):
current_ports.update(named_ports)
io_chain_head = IONode(IOHolder(named_ports), io_chain)
return IO(calc_type_from_ports(current_ports), io_chain_head)
io_chain.insert(0, IOHolder(named_ports))
return IO(__build_bundle_type_from_ports(current_ports), io_chain)

return _


def calc_type_from_ports(named_ports: Dict[str, Union[Input, Output]]):
types = {}
def __build_bundle_type_from_ports(
named_ports: Dict[str, Union[Input, Output]]) -> BundleT:
fields = {}
for k, v in named_ports.items():
if isinstance(v, Input):
types[k] = {"dir": Dir.SRC, "hcl_type": v.hcl_type}
fields[k] = {"dir": BundleDirection.SOURCE, "hcl_type": v.hcl_type}
continue

if isinstance(v, Output):
types[k] = {"dir": Dir.SINK, "hcl_type": v.hcl_type}
fields[k] = {"dir": BundleDirection.SINK, "hcl_type": v.hcl_type}
continue

raise ExprError.io_value_err(
"type of '{}' is {}, not Input or Output".format(k, type(v)))

return BundleT(types)
return BundleT(fields)
7 changes: 5 additions & 2 deletions py_hcl/core/expr/ors.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from py_hcl.core.hcl_ops import op_register
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.core.type.sint import SIntT
from py_hcl.core.type.uint import UIntT
from py_hcl.core.type.vector import VectorT
Expand Down Expand Up @@ -102,7 +102,10 @@ def _(lf, rt):
bd_values = {}
for k in lf.hcl_type.fields.keys():
res = getattr(lf, k) | getattr(rt, k)
bd_type_fields[k] = {"dir": Dir.SRC, "hcl_type": res.hcl_type}
bd_type_fields[k] = {
"dir": BundleDirection.SOURCE,
"hcl_type": res.hcl_type
}
bd_values[k] = res

return BundleHolder(BundleT(bd_type_fields), VariableType.VALUE, bd_values)
Expand Down
1 change: 0 additions & 1 deletion py_hcl/core/expr/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def ensure_all_args_are_values(f):
py_hcl.core.expr.error.ExprError: Specified expresion has an invalid
variable type
"""

def _(*args):
check_lists = [a for a in args if hasattr(a, 'variable_type')]
sides = [VariableType.VALUE, VariableType.ASSIGNABLE_VALUE]
Expand Down
7 changes: 5 additions & 2 deletions py_hcl/core/expr/xor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from py_hcl.core.hcl_ops import op_register
from py_hcl.core.stmt.connect import VariableType
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.core.type.sint import SIntT
from py_hcl.core.type.uint import UIntT
from py_hcl.core.type.vector import VectorT
Expand Down Expand Up @@ -99,7 +99,10 @@ def _(lf, rt):
bd_values = {}
for k in lf.hcl_type.fields.keys():
res = getattr(lf, k) ^ getattr(rt, k)
bd_type_fields[k] = {"dir": Dir.SRC, "hcl_type": res.hcl_type}
bd_type_fields[k] = {
"dir": BundleDirection.SOURCE,
"hcl_type": res.hcl_type
}
bd_values[k] = res

return BundleHolder(BundleT(bd_type_fields), VariableType.VALUE, bd_values)
Expand Down
2 changes: 1 addition & 1 deletion py_hcl/core/module/meta_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(cls, name, bases, dct):
name = fetch_module_name(name)

check_io_exist(dct, name)
dct["io"].io_chain_head.io_holder.module_name = name
dct["io"].io_chain[0].module_name = name

packed = packer.pack(bases, dct, name)
cls.packed_module = packed
Expand Down
4 changes: 2 additions & 2 deletions py_hcl/core/stmt/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from py_hcl.core.stmt.error import StatementError
from py_hcl.core.stmt_factory.trapper import StatementTrapper
from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection
from py_hcl.core.type.sint import SIntT
from py_hcl.core.type.uint import UIntT
from py_hcl.core.type.vector import VectorT
Expand Down Expand Up @@ -166,7 +166,7 @@ def _(left, right):
for k in keys:
lf = op_apply('.')(left, k)
rt = op_apply('.')(right, k)
if dir_and_types[k]['dir'] == Dir.SRC:
if dir_and_types[k]['dir'] == BundleDirection.SOURCE:
op_apply('<<=')(lf, rt)
else:
op_apply('<<=')(rt, lf)
Expand Down
4 changes: 2 additions & 2 deletions py_hcl/core/type/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from py_hcl.core.type.wrapper import vec_wrap, bd_fld_wrap


class Dir(Enum):
SRC = 1
class BundleDirection(Enum):
SOURCE = 1
SINK = 2


Expand Down
4 changes: 2 additions & 2 deletions py_hcl/core/type/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

@dispatch()
def invert_exp(self: HclType):
from py_hcl.core.type.bundle import Dir
return {'dir': Dir.SINK, 'hcl_type': self}
from py_hcl.core.type.bundle import BundleDirection
return {'dir': BundleDirection.SINK, 'hcl_type': self}


def bd_fld_wrap(cls):
Expand Down
76 changes: 73 additions & 3 deletions py_hcl/core/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,79 @@
from typing import Tuple, List


def module_inherit_mro(modules: Tuple[type]) -> List[type]:
def module_inherit_mro(bases: Tuple[type]) -> List[type]:
"""
Returns modules in method resolution order.
As we want to handle inherit stuff, the mro is a very basic entry to travel
the inherit graph.
Examples
--------
>>> from py_hcl import *
A normal PyHCL module `V`:
>>> class V(Module):
... io = IO()
A PyHCL module `W` inheriting `V`:
>>> class W(V):
... io = io_extend(V)()
Let's see the bases of `W`:
>>> W.__bases__
(<class 'py_hcl.core.utils.V'>,)
So we can get the mro of its bases via `module_inherit_mro`:
>>> module_inherit_mro(W.__bases__)
[<class 'py_hcl.core.utils.V'>,
<class 'py_hcl.core.module.base_module.BaseModule'>]
A more complicated case:
>>> class X(W):
... io = io_extend(W)()
>>> class Y(V):
... io = io_extend(V)()
>>> class Z(X, Y):
... io = io_extend(X, Y)()
To handle expression inheritance or statement inheritance of the module
`Z`, we can first get the mro of `Z`'s bases:
>>> module_inherit_mro(Z.__bases__)
[<class 'py_hcl.core.utils.X'>,
<class 'py_hcl.core.utils.W'>,
<class 'py_hcl.core.utils.Y'>,
<class 'py_hcl.core.utils.V'>,
<class 'py_hcl.core.module.base_module.BaseModule'>]
"""

from py_hcl.core.module.meta_module import MetaModule

modules = type("_hcl_fake_module", modules, {}).mro()
modules = [m for m in modules[1:] if isinstance(m, MetaModule)]
# Step 1: Build a fake Python class extending bases.
#
# Since `Module`s inherit from `MetaModule`, class construction here will
# trigger `MetaModule.__init__`. We get around the side effect by adding a
# conditional early return at the beginning of `MetaModule.__init__`.
fake_type = type("_hcl_fake_module", bases, {})

# Step 2: Get the method resolution order of the fake class.
# Step 3: Filter useless types in the mro.
modules = [m for m in fake_type.mro()[1:] if isinstance(m, MetaModule)]

return modules
4 changes: 2 additions & 2 deletions py_hcl/dsl/type/bundle.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import Union

from py_hcl.core.type import HclType
from py_hcl.core.type.bundle import BundleT, Dir
from py_hcl.core.type.bundle import BundleT, BundleDirection


def Bundle(**named_ports: Union[HclType, dict]) -> BundleT:
t = {
k: ({
'dir': Dir.SRC,
'dir': BundleDirection.SOURCE,
'hcl_type': v
} if isinstance(v, HclType) else v)
for k, v in named_ports.items()
Expand Down
8 changes: 3 additions & 5 deletions py_hcl/transformer/pyhcl_to_firrtl/conv_expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,9 @@ def convert_expr_op(expr_holder: ExprHolder, fa: FieldAccess):
obj = GlobalContext.expr_table[fa.ref_expr_id]

def fetch_current_io_holder(obj):
current_node = obj.io_chain_head
while True:
if fa.item in current_node.io_holder.named_ports:
return current_node.io_holder
current_node = current_node.next_node
for io_holder in obj.io_chain:
if fa.item in io_holder.named_ports:
return io_holder

if isinstance(obj, IO):
io_holder = fetch_current_io_holder(obj)
Expand Down
16 changes: 4 additions & 12 deletions py_hcl/transformer/pyhcl_to_firrtl/conv_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,9 @@ def flatten_statement_chain(statement_chain: StmtChain):

def flatten_io_chain(io: IO):
ports = {}
node = io.io_chain_head

while True:
holder = node.io_holder
# reverse the dict order
for k in list(holder.named_ports.keys())[::-1]:
v = holder.named_ports[k]
ports[build_io_name(holder.module_name, k)] = v

if not hasattr(node, "next_node"):
break
node = node.next_node
for io_holder in io.io_chain:
for k, v in io_holder.named_ports.items():
ports[build_io_name(io_holder.module_name, k)] = v

return {k: ports[k] for k in list(ports.keys())[::-1]}
return ports
Loading

0 comments on commit 12fa544

Please sign in to comment.