From 62b09da42877ebf529b5956aa54fd07551c56555 Mon Sep 17 00:00:00 2001 From: Gaufoo Date: Thu, 2 Jan 2020 16:42:19 +0800 Subject: [PATCH] core: add json serialize (#39) --- py_hcl/core/expr/__init__.py | 40 +++++++++++++++--- py_hcl/core/expr/add.py | 13 +++--- py_hcl/core/expr/convert.py | 14 ++++--- py_hcl/core/expr/field.py | 31 +++++++------- py_hcl/core/expr/index.py | 7 ++-- py_hcl/core/expr/io.py | 20 +++++---- py_hcl/core/expr/mod_inst.py | 5 ++- py_hcl/core/expr/slice.py | 16 ++++---- py_hcl/core/expr/wire.py | 4 +- py_hcl/core/module/packed_module.py | 10 ++--- py_hcl/core/module_factory/extractor.py | 2 +- .../module_factory/inherit_list/named_expr.py | 17 ++++---- .../inherit_list/stmt_holder.py | 21 +++++----- py_hcl/core/module_factory/merger.py | 20 ++++----- py_hcl/core/module_factory/packer.py | 14 +++---- py_hcl/core/stmt/__init__.py | 10 +++-- py_hcl/core/stmt/branch.py | 30 ++++++-------- py_hcl/core/stmt/connect.py | 15 +++---- py_hcl/core/stmt_factory/scope.py | 41 ++++++++++++------- py_hcl/core/stmt_factory/trapper.py | 6 +-- py_hcl/core/type/__init__.py | 4 +- py_hcl/core/type/bundle.py | 19 +++++---- py_hcl/core/type/clock.py | 3 +- py_hcl/core/type/sint.py | 1 + py_hcl/core/type/uint.py | 1 + py_hcl/core/type/vector.py | 1 + py_hcl/dsl/tpe/bundle.py | 6 +-- py_hcl/utils.py | 38 ++++++++++++----- tests/test_dsl/test_branch.py | 26 ++++++------ tests/test_dsl/test_io.py | 8 ++-- tests/test_dsl/test_module.py | 2 +- tests/test_dsl/test_statement.py | 4 +- 32 files changed, 263 insertions(+), 186 deletions(-) diff --git a/py_hcl/core/expr/__init__.py b/py_hcl/core/expr/__init__.py index 547b8c6..08a578b 100644 --- a/py_hcl/core/expr/__init__.py +++ b/py_hcl/core/expr/__init__.py @@ -3,14 +3,43 @@ from multipledispatch.dispatcher import MethodDispatcher from py_hcl.core.hcl_ops import op_apply from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import UnknownType, HclType -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +class ExprIdGen: + id = -1 + + @classmethod + def next_id(cls): + cls.id += 1 + return cls.id + + +class ExprPool: + pool = {} + + @classmethod + def add(cls, i, obj): + cls.pool[i] = obj + + @classmethod + def fetch_all(cls): + p = cls.pool + cls.pool = {} + return p + + +@json_serialize class HclExpr(object): hcl_type = UnknownType() conn_side = ConnSide.UNKNOWN + def __new__(cls, *args): + obj = super().__new__(cls) + obj.id = ExprIdGen.next_id() + ExprPool.add(obj.id, obj) + return obj + def __ilshift__(self, other): return op_apply('<<=')(self, other) @@ -58,9 +87,10 @@ class HclExpr(object): return op_apply('to_bool')(self) -@auto_repr(repr_fields=['hcl_type', 'conn_side', 'assoc_value']) +@json_serialize(json_fields=['id', 'type', 'hcl_type', 'conn_side', 'op_node']) class ExprHolder(HclExpr): - def __init__(self, hcl_type: HclType, conn_side: ConnSide, assoc_value): + def __init__(self, hcl_type: HclType, conn_side: ConnSide, op_node): + self.type = 'expr_holder' self.hcl_type = hcl_type self.conn_side = conn_side - self.assoc_value = assoc_value + self.op_node = op_node diff --git a/py_hcl/core/expr/add.py b/py_hcl/core/expr/add.py index 97a4801..8232b9e 100644 --- a/py_hcl/core/expr/add.py +++ b/py_hcl/core/expr/add.py @@ -1,21 +1,22 @@ -from py_hcl.core.expr.error import ExprError from py_hcl.core.expr import ExprHolder +from py_hcl.core.expr.error import ExprError from py_hcl.core.expr.utils import assert_right_side from py_hcl.core.expr.vec_holder import VecHolder -from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.hcl_ops import op_register +from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType from py_hcl.core.type.sint import SIntT from py_hcl.core.type.uint import UIntT from py_hcl.core.type.vector import VectorT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class Add(object): def __init__(self, left, right): - self.left = left - self.right = right + self.operation = 'add' + self.left_expr_id = left.id + self.right_expr_id = right.id adder = op_register('+') diff --git a/py_hcl/core/expr/convert.py b/py_hcl/core/expr/convert.py index 5e5584d..7015df0 100644 --- a/py_hcl/core/expr/convert.py +++ b/py_hcl/core/expr/convert.py @@ -1,28 +1,30 @@ from py_hcl.core.expr import ExprHolder from py_hcl.core.expr.error import ExprError from py_hcl.core.expr.utils import assert_right_side -from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.hcl_ops import op_register +from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType from py_hcl.core.type.sint import SIntT from py_hcl.core.type.uint import UIntT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize to_bool = op_register('to_bool') to_uint = op_register('to_uint') to_sint = op_register('to_sint') -@auto_repr +@json_serialize class ToSInt(object): def __init__(self, expr): - self.expr = expr + self.operation = "to_sint" + self.ref_expr_id = expr.id -@auto_repr +@json_serialize class ToUInt(object): def __init__(self, expr): - self.expr = expr + self.operation = "to_uint" + self.ref_expr_id = expr.id @to_bool(UIntT) diff --git a/py_hcl/core/expr/field.py b/py_hcl/core/expr/field.py index 0a43dec..3353c12 100644 --- a/py_hcl/core/expr/field.py +++ b/py_hcl/core/expr/field.py @@ -1,35 +1,36 @@ from py_hcl.core.expr import ExprHolder from py_hcl.core.expr.error import ExprError -from py_hcl.core.expr.io import IO, IOHolder from py_hcl.core.hcl_ops import op_register from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType from py_hcl.core.type.bundle import BundleT, Dir -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize field_accessor = op_register('.') -@auto_repr +@json_serialize class FieldAccess(object): def __init__(self, expr, item): + self.operation = "field_access" self.item = item - self.expr = expr + self.ref_expr_id = expr.id @field_accessor(BundleT) def _(bd, item): # TODO: Accurate Error Message - assert item in bd.hcl_type.types + assert item in bd.hcl_type.fields # build connect side sd = bd.conn_side - dr, tpe = bd.hcl_type.types[item] + f = bd.hcl_type.fields[item] + dr, tpe = f["dir"], f["hcl_type"] new_sd = build_new_sd(sd, dr) - # for io - if isinstance(bd, IO): - bd = fetch_inner_io_holder(bd, item) + # # for io + # if isinstance(bd, IO): + # bd = fetch_inner_io_holder(bd, item) return ExprHolder(tpe, new_sd, FieldAccess(bd, item)) @@ -49,9 +50,9 @@ def build_new_sd(sd: ConnSide, dr: Dir) -> ConnSide: return ConnSide.RT -def fetch_inner_io_holder(io, name) -> IOHolder: - current_node = io.io_chain_head - while True: - if name in current_node.io_holder.named_ports: - return current_node.io_holder - current_node = current_node.next_node +# def fetch_inner_io_holder(io, name) -> IOHolder: +# current_node = io.io_chain_head +# while True: +# if name in current_node.io_holder.named_ports: +# return current_node.io_holder +# current_node = current_node.next_node diff --git a/py_hcl/core/expr/index.py b/py_hcl/core/expr/index.py index 65f3187..a467f56 100644 --- a/py_hcl/core/expr/index.py +++ b/py_hcl/core/expr/index.py @@ -7,16 +7,17 @@ from py_hcl.core.type import HclType from py_hcl.core.type.sint import SIntT from py_hcl.core.type.uint import UIntT from py_hcl.core.type.vector import VectorT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize index = op_register('[i]') -@auto_repr +@json_serialize class VecIndex(object): def __init__(self, expr, idx: int): + self.operation = "vec_index" self.index = idx - self.expr = expr + self.ref_expr_id = expr.id @index(UIntT) diff --git a/py_hcl/core/expr/io.py b/py_hcl/core/expr/io.py index 13192de..d3967e1 100644 --- a/py_hcl/core/expr/io.py +++ b/py_hcl/core/expr/io.py @@ -6,22 +6,24 @@ from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType from py_hcl.core.type.bundle import Dir, BundleT from py_hcl.core.utils import module_inherit_mro -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class Input(object): def __init__(self, hcl_type: HclType): + self.port_dir = 'input' self.hcl_type = hcl_type -@auto_repr +@json_serialize class Output(object): def __init__(self, hcl_type: HclType): + self.port_dir = 'output' self.hcl_type = hcl_type -@auto_repr +@json_serialize class IOHolder(object): def __init__(self, named_ports: Dict[str, Union[Input, Output]], module_name: Optional[str] = None): @@ -29,7 +31,7 @@ class IOHolder(object): self.module_name = module_name -@auto_repr +@json_serialize class IONode(object): def __init__(self, io_holder: IOHolder, next_node: Optional["IOHolder"]): @@ -37,9 +39,11 @@ class IONode(object): self.next_node = next_node -@auto_repr(repr_fields=["hcl_type", "conn_side", "io_chain_head"]) +@json_serialize(json_fields=["id", "type", "hcl_type", + "conn_side", "io_chain_head"]) class IO(HclExpr): def __init__(self, hcl_type: HclType, io_chain_head: IONode): + self.type = 'io' self.hcl_type = hcl_type self.conn_side = ConnSide.RT self.io_chain_head = io_chain_head @@ -67,11 +71,11 @@ def calc_type_from_ports(named_ports: Dict[str, Union[Input, Output]]): types = {} for k, v in named_ports.items(): if isinstance(v, Input): - types[k] = (Dir.SRC, v.hcl_type) + types[k] = {"dir": Dir.SRC, "hcl_type": v.hcl_type} continue if isinstance(v, Output): - types[k] = (Dir.SINK, v.hcl_type) + types[k] = {"dir": Dir.SINK, "hcl_type": v.hcl_type} continue raise ExprError.io_value( diff --git a/py_hcl/core/expr/mod_inst.py b/py_hcl/core/expr/mod_inst.py index e35392e..9e14b09 100644 --- a/py_hcl/core/expr/mod_inst.py +++ b/py_hcl/core/expr/mod_inst.py @@ -1,11 +1,12 @@ from py_hcl.core.expr import ExprHolder from py_hcl.core.stmt.connect import ConnSide -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr(repr_fields=['module_name']) +@json_serialize(json_fields=['operation', 'module_name']) class ModuleInst(object): def __init__(self, module_cls): + self.operation = 'module_inst' self.packed_module = module_cls.packed_module self.module_name = module_cls.packed_module.name diff --git a/py_hcl/core/expr/slice.py b/py_hcl/core/expr/slice.py index 28494b9..41e36a2 100644 --- a/py_hcl/core/expr/slice.py +++ b/py_hcl/core/expr/slice.py @@ -1,32 +1,34 @@ from py_hcl.core.expr import ExprHolder +from py_hcl.core.expr.error import ExprError from py_hcl.core.expr.utils import assert_right_side from py_hcl.core.expr.vec_holder import VecHolder -from py_hcl.core.stmt.connect import ConnSide -from py_hcl.core.expr.error import ExprError from py_hcl.core.hcl_ops import op_register +from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType from py_hcl.core.type.sint import SIntT from py_hcl.core.type.uint import UIntT from py_hcl.core.type.vector import VectorT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize slice_ = op_register('[i:j]') -@auto_repr +@json_serialize class Bits(object): def __init__(self, expr, high, low): + self.operation = 'bits' self.high = high self.low = low - self.expr = expr + self.ref_expr_id = expr.id -@auto_repr +@json_serialize class VecSlice(object): def __init__(self, expr, low, high): + self.operation = 'vec_slice' self.low = low self.high = high - self.expr = expr + self.ref_expr_id = expr.id @slice_(UIntT) diff --git a/py_hcl/core/expr/wire.py b/py_hcl/core/expr/wire.py index 5c980f3..a90eff8 100644 --- a/py_hcl/core/expr/wire.py +++ b/py_hcl/core/expr/wire.py @@ -1,10 +1,10 @@ from py_hcl.core.expr import HclExpr from py_hcl.core.stmt.connect import ConnSide from py_hcl.core.type import HclType -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr(repr_fields=['hcl_type', 'conn_side']) +@json_serialize(json_fields=['hcl_type', 'conn_side']) class Wire(HclExpr): def __init__(self, hcl_type: HclType): self.hcl_type = hcl_type diff --git a/py_hcl/core/module/packed_module.py b/py_hcl/core/module/packed_module.py index 864be5f..ed06ac3 100644 --- a/py_hcl/core/module/packed_module.py +++ b/py_hcl/core/module/packed_module.py @@ -1,9 +1,9 @@ -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class PackedModule(object): - def __init__(self, name, named_expr_list, statement_list): + def __init__(self, name, named_expr_chain, statement_chain): self.name = name - self.named_expr_list = named_expr_list - self.statement_list = statement_list + self.named_expr_chain = named_expr_chain + self.statement_chain = statement_chain diff --git a/py_hcl/core/module_factory/extractor.py b/py_hcl/core/module_factory/extractor.py index 58b9b3b..1269ac0 100644 --- a/py_hcl/core/module_factory/extractor.py +++ b/py_hcl/core/module_factory/extractor.py @@ -7,6 +7,6 @@ def extract(dct): for k, v in dct.items(): # TODO: check if is source not composed expression if isinstance(v, HclExpr): - res[k] = v + res[k] = {"expr_id": v.id} return res diff --git a/py_hcl/core/module_factory/inherit_list/named_expr.py b/py_hcl/core/module_factory/inherit_list/named_expr.py index f67a21a..5f45e1b 100644 --- a/py_hcl/core/module_factory/inherit_list/named_expr.py +++ b/py_hcl/core/module_factory/inherit_list/named_expr.py @@ -1,10 +1,10 @@ from typing import Optional, Dict from py_hcl.core.expr import HclExpr -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class NamedExprHolder(object): def __init__(self, module_name: str, named_expressions: Dict[str, HclExpr]): @@ -12,16 +12,17 @@ class NamedExprHolder(object): self.named_expressions = named_expressions -@auto_repr +@json_serialize class NamedExprNode(object): def __init__(self, named_expr_holder: NamedExprHolder, next_node: Optional["NamedExprNode"]): self.named_expr_holder = named_expr_holder - self.next_node = next_node + if next_node: + self.next_node = next_node -@auto_repr -class NamedExprList(object): - def __init__(self, named_expr_list_head: NamedExprNode): - self.named_expr_list_head = named_expr_list_head +@json_serialize +class NamedExprChain(object): + def __init__(self, named_expr_chain_head: NamedExprNode): + self.named_expr_chain_head = named_expr_chain_head diff --git a/py_hcl/core/module_factory/inherit_list/stmt_holder.py b/py_hcl/core/module_factory/inherit_list/stmt_holder.py index 2aafed0..3d248bc 100644 --- a/py_hcl/core/module_factory/inherit_list/stmt_holder.py +++ b/py_hcl/core/module_factory/inherit_list/stmt_holder.py @@ -1,25 +1,26 @@ from typing import Optional -from py_hcl.core.stmt import BlockStatement -from py_hcl.utils import auto_repr +from py_hcl.core.stmt import ClusterStatement +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class StmtHolder(object): - def __init__(self, module_name: str, top_statement: BlockStatement): + def __init__(self, module_name: str, top_statement: ClusterStatement): self.module_name = module_name self.top_statement = top_statement -@auto_repr +@json_serialize class StmtNode(object): def __init__(self, stmt_holder: StmtHolder, next_node: Optional["StmtNode"]): self.stmt_holder = stmt_holder - self.next_node = next_node + if next_node: + self.next_node = next_node -@auto_repr -class StmtList(object): - def __init__(self, stmt_list_head: StmtNode): - self.stmt_list_head = stmt_list_head +@json_serialize +class StmtChain(object): + def __init__(self, stmt_chain_head: StmtNode): + self.stmt_chain_head = stmt_chain_head diff --git a/py_hcl/core/module_factory/merger.py b/py_hcl/core/module_factory/merger.py index 1865128..4701239 100644 --- a/py_hcl/core/module_factory/merger.py +++ b/py_hcl/core/module_factory/merger.py @@ -1,30 +1,30 @@ from typing import List -from py_hcl.core.module_factory.inherit_list.named_expr import NamedExprList, \ +from .inherit_list.named_expr import NamedExprChain, \ NamedExprNode, NamedExprHolder -from py_hcl.core.module_factory.inherit_list.stmt_holder import StmtList, \ +from .inherit_list.stmt_holder import StmtChain, \ StmtHolder, StmtNode def merge_expr(modules: List[type], - expr_holder: NamedExprHolder) -> NamedExprList: + expr_holder: NamedExprHolder) -> NamedExprChain: expr_list = None for m in modules[::-1]: - h = m.packed_module.named_expr_list \ - .named_expr_list_head.named_expr_holder + h = m.packed_module.named_expr_chain \ + .named_expr_chain_head.named_expr_holder expr_list = NamedExprNode(h, expr_list) expr_list = NamedExprNode(expr_holder, expr_list) - return NamedExprList(expr_list) + return NamedExprChain(expr_list) def merge_statement(modules: List[type], - stmt_holder: StmtHolder) -> StmtList: + stmt_holder: StmtHolder) -> StmtChain: stmt_list = None for m in modules[::-1]: - h = m.packed_module.statement_list \ - .stmt_list_head.stmt_holder + h = m.packed_module.statement_chain \ + .stmt_chain_head.stmt_holder stmt_list = StmtNode(h, stmt_list) stmt_list = StmtNode(stmt_holder, stmt_list) - return StmtList(stmt_list) + return StmtChain(stmt_list) diff --git a/py_hcl/core/module_factory/packer.py b/py_hcl/core/module_factory/packer.py index e706429..1739ef6 100644 --- a/py_hcl/core/module_factory/packer.py +++ b/py_hcl/core/module_factory/packer.py @@ -1,30 +1,30 @@ +from py_hcl.core.module.packed_module import PackedModule from py_hcl.core.module_factory.inherit_list.named_expr import NamedExprHolder from py_hcl.core.module_factory.inherit_list.stmt_holder import StmtHolder from py_hcl.core.stmt_factory.trapper import StatementTrapper from py_hcl.core.utils import module_inherit_mro -from . import merger from . import extractor -from py_hcl.core.module.packed_module import PackedModule +from . import merger def pack(bases, dct, name) -> PackedModule: raw_expr = extractor.extract(dct) raw_scope = StatementTrapper.trap() - named_expr_list, statement_list = \ + named_expr_chain, statement_chain = \ handle_inherit(bases, raw_expr, raw_scope, name) - res = PackedModule(name, named_expr_list, statement_list) + res = PackedModule(name, named_expr_chain, statement_chain) return res def handle_inherit(bases, named_expression, top_statement, name): modules = module_inherit_mro(bases) - named_expr_list = \ + named_expr_chain = \ merger.merge_expr(modules, NamedExprHolder(name, named_expression)) - statement_list = \ + statement_chain = \ merger.merge_statement(modules, StmtHolder(name, top_statement)) - return named_expr_list, statement_list + return named_expr_chain, statement_chain diff --git a/py_hcl/core/stmt/__init__.py b/py_hcl/core/stmt/__init__.py index fac91d0..5ebb6d9 100644 --- a/py_hcl/core/stmt/__init__.py +++ b/py_hcl/core/stmt/__init__.py @@ -1,15 +1,17 @@ -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class LineStatement(object): def __init__(self, scope_id, statement): + self.stmt_class = 'line' self.scope_id = scope_id self.statement = statement -@auto_repr -class BlockStatement(object): +@json_serialize +class ClusterStatement(object): def __init__(self, scope_info, stmts): + self.stmt_class = 'cluster' self.scope_info = scope_info self.statements = stmts diff --git a/py_hcl/core/stmt/branch.py b/py_hcl/core/stmt/branch.py index 891753c..d49c8be 100644 --- a/py_hcl/core/stmt/branch.py +++ b/py_hcl/core/stmt/branch.py @@ -1,27 +1,22 @@ from py_hcl.core.expr import HclExpr +from py_hcl.core.stmt import ClusterStatement from py_hcl.core.stmt.error import StatementError from py_hcl.core.stmt_factory.scope import ScopeManager, ScopeType -from py_hcl.core.stmt import BlockStatement from py_hcl.core.stmt_factory.trapper import StatementTrapper from py_hcl.core.type.uint import UIntT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class When(object): def __init__(self, cond: HclExpr): - self.cond = cond + self.cond_expr_id = cond.id -@auto_repr +@json_serialize class ElseWhen(object): def __init__(self, cond: HclExpr): - self.cond = cond - - -@auto_repr -class Otherwise(object): - pass + self.cond_expr_id = cond.id def do_when_enter(cond_expr: HclExpr): @@ -50,8 +45,7 @@ def do_else_when_exit(): def do_otherwise_enter(): check_branch_syntax() - o = Otherwise() - ScopeManager.expand_scope(ScopeType.OTHERWISE, o) + ScopeManager.expand_scope(ScopeType.OTHERWISE) def do_otherwise_exit(): @@ -82,9 +76,9 @@ def check_exists_pre_stmts(): def check_exists_pre_when_block(): last_stmt = StatementTrapper.trapped_stmts[-1][-1] - if isinstance(last_stmt, BlockStatement): + if isinstance(last_stmt, ClusterStatement): last_scope = last_stmt.scope_info - last_scope_type = last_scope['scope_type'] + last_scope_type = last_scope.scope_type when = last_scope_type == ScopeType.WHEN else_when = last_scope_type == ScopeType.ELSE_WHEN @@ -100,11 +94,11 @@ def check_exists_pre_when_block(): def check_correct_block_level(): last_stmt = StatementTrapper.trapped_stmts[-1][-1] - if isinstance(last_stmt, BlockStatement): + if isinstance(last_stmt, ClusterStatement): last_scope = last_stmt.scope_info current_scope = ScopeManager.current_scope() - last_scope_level = last_scope['scope_level'] - current_scope_level = current_scope['scope_level'] + last_scope_level = last_scope.scope_level + current_scope_level = current_scope.scope_level if last_scope_level == current_scope_level + 1: return diff --git a/py_hcl/core/stmt/connect.py b/py_hcl/core/stmt/connect.py index 00083a3..4dcbb4e 100644 --- a/py_hcl/core/stmt/connect.py +++ b/py_hcl/core/stmt/connect.py @@ -9,7 +9,7 @@ from py_hcl.core.type.bundle import BundleT, Dir from py_hcl.core.type.sint import SIntT from py_hcl.core.type.uint import UIntT from py_hcl.core.type.vector import VectorT -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize class ConnSide(Enum): @@ -19,11 +19,12 @@ class ConnSide(Enum): BOTH = 3 -@auto_repr +@json_serialize class Connect(object): def __init__(self, left, right): - self.left = left - self.right = right + self.stmt_type = 'connect' + self.left_expr_id = left.id + self.right_expr_id = right.id connector = op_register('<<=') @@ -78,14 +79,14 @@ def _(left, right): check_connect_dir(left, right) # TODO: Accurate Error Message - dir_and_types = right.hcl_type.types + dir_and_types = right.hcl_type.fields keys = dir_and_types.keys() - assert keys == left.hcl_type.types.keys() + assert keys == left.hcl_type.fields.keys() for k in keys: lf = op_apply('.')(left, k) rt = op_apply('.')(right, k) - if dir_and_types[k][0] == Dir.SRC: + if dir_and_types[k]['dir'] == Dir.SRC: op_apply('<<=')(lf, rt) else: op_apply('<<=')(rt, lf) diff --git a/py_hcl/core/stmt_factory/scope.py b/py_hcl/core/stmt_factory/scope.py index 41b74f9..889eba2 100644 --- a/py_hcl/core/stmt_factory/scope.py +++ b/py_hcl/core/stmt_factory/scope.py @@ -1,5 +1,7 @@ from enum import Enum +from py_hcl.utils import json_serialize + class ScopeType(Enum): TOP = 0 @@ -9,6 +11,16 @@ class ScopeType(Enum): OTHERWISE = 4 +@json_serialize +class ScopeInfo(object): + def __init__(self, scope_id, scope_level, scope_type, tag_object=None): + self.scope_id = scope_id + self.scope_level = scope_level + self.scope_type = scope_type + if tag_object: + self.tag_object = tag_object + + class ScopeLevelManager(object): _next_scope_level = 0 @@ -36,15 +48,16 @@ class ScopeIdManager(object): class ScopeManager(object): - scope_list = [{ - # TOP SCOPE which contains all modules - 'scope_id': ScopeIdManager.next_id(), - 'scope_level': ScopeLevelManager.current_level(), - 'scope_type': ScopeType.TOP, - 'tag_object': None - }] + scope_list = [ + ScopeInfo( + # TOP SCOPE which contains all modules + scope_id=ScopeIdManager.next_id(), + scope_level=ScopeLevelManager.current_level(), + scope_type=ScopeType.TOP, + ) + ] scope_id_map = { - scope_list[0]['scope_id']: scope_list[0] + scope_list[0].scope_id: scope_list[0] } scope_expanding_hooks = [] scope_shrinking_hooks = [] @@ -55,12 +68,12 @@ class ScopeManager(object): current_scope = cls.current_scope() next_id = ScopeIdManager.next_id() - next_scope = { - 'scope_id': next_id, - 'scope_level': ScopeLevelManager.current_level(), - 'scope_type': scope_type, - 'tag_object': tag_object - } + next_scope = ScopeInfo( + scope_id=next_id, + scope_level=ScopeLevelManager.current_level(), + scope_type=scope_type, + tag_object=tag_object, + ) cls.scope_id_map[next_id] = next_scope cls.scope_list.append(next_scope) diff --git a/py_hcl/core/stmt_factory/trapper.py b/py_hcl/core/stmt_factory/trapper.py index 32cad03..1de18fd 100644 --- a/py_hcl/core/stmt_factory/trapper.py +++ b/py_hcl/core/stmt_factory/trapper.py @@ -1,4 +1,4 @@ -from py_hcl.core.stmt import LineStatement, BlockStatement +from py_hcl.core.stmt import LineStatement, ClusterStatement from .scope import ScopeManager, ScopeType @@ -29,7 +29,7 @@ class StatementTrapper(object): @classmethod def track(cls, statement): statement = LineStatement( - ScopeManager.current_scope()['scope_id'], + ScopeManager.current_scope().scope_id, statement ) cls.trapped_stmts[-1].append(statement) @@ -41,7 +41,7 @@ class StatementTrapper(object): @classmethod def on_scope_shrinking(cls, current_scope, next_scope): stmts = cls.trapped_stmts.pop() - cls.trapped_stmts[-1].append(BlockStatement(current_scope, stmts)) + cls.trapped_stmts[-1].append(ClusterStatement(current_scope, stmts)) set_up() diff --git a/py_hcl/core/type/__init__.py b/py_hcl/core/type/__init__.py index 1522d89..029f12b 100644 --- a/py_hcl/core/type/__init__.py +++ b/py_hcl/core/type/__init__.py @@ -1,7 +1,7 @@ -from py_hcl.utils import auto_repr +from py_hcl.utils import json_serialize -@auto_repr +@json_serialize class HclType(object): pass diff --git a/py_hcl/core/type/bundle.py b/py_hcl/core/type/bundle.py index c42c3f6..19db993 100644 --- a/py_hcl/core/type/bundle.py +++ b/py_hcl/core/type/bundle.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Dict, Tuple +from typing import Dict from py_hcl.core.type import HclType from py_hcl.core.type.wrapper import vec_wrap, bd_fld_wrap @@ -13,12 +13,13 @@ class Dir(Enum): @bd_fld_wrap @vec_wrap class BundleT(HclType): - def __init__(self, types: Dict[str, Tuple[Dir, HclType]]): - self.types = types + def __init__(self, fields: Dict[str, dict]): + self.type = "bundle" + self.fields = fields - def rev(self): - types = {} - for k, v in self.types.items(): - d = Dir.SINK if v[0] == Dir.SRC else Dir.SRC - types[k] = (d, v[1]) - return BundleT(types) + # def rev(self): + # types = {} + # for k, v in self.fields.items(): + # d = Dir.SINK if v[0] == Dir.SRC else Dir.SRC + # types[k] = {dir: d, type: v[1]} + # return BundleT(types) diff --git a/py_hcl/core/type/clock.py b/py_hcl/core/type/clock.py index 80c4219..5ab243f 100644 --- a/py_hcl/core/type/clock.py +++ b/py_hcl/core/type/clock.py @@ -2,4 +2,5 @@ from py_hcl.core.type import HclType class ClockT(HclType): - pass + def __init__(self): + self.type = "clock" diff --git a/py_hcl/core/type/sint.py b/py_hcl/core/type/sint.py index dbaa30a..2fb0ea3 100644 --- a/py_hcl/core/type/sint.py +++ b/py_hcl/core/type/sint.py @@ -7,6 +7,7 @@ from py_hcl.utils import signed_num_bin_len @vec_wrap class SIntT(HclType): def __init__(self, width): + self.type = "sint" self.width = width def __call__(self, value: int): diff --git a/py_hcl/core/type/uint.py b/py_hcl/core/type/uint.py index 3af6b10..1d691fb 100644 --- a/py_hcl/core/type/uint.py +++ b/py_hcl/core/type/uint.py @@ -7,6 +7,7 @@ from py_hcl.utils import unsigned_num_bin_len @vec_wrap class UIntT(HclType): def __init__(self, width): + self.type = "uint" self.width = width def __call__(self, value: int): diff --git a/py_hcl/core/type/vector.py b/py_hcl/core/type/vector.py index 8dc6332..a840537 100644 --- a/py_hcl/core/type/vector.py +++ b/py_hcl/core/type/vector.py @@ -7,5 +7,6 @@ class VectorT(HclType): def __init__(self, inner_type: HclType, size: int): # TODO: Accurate Error Message assert size > 0 + self.type = "vector" self.size = size self.inner_type = inner_type diff --git a/py_hcl/dsl/tpe/bundle.py b/py_hcl/dsl/tpe/bundle.py index 4f6f8e4..b6fafca 100644 --- a/py_hcl/dsl/tpe/bundle.py +++ b/py_hcl/dsl/tpe/bundle.py @@ -1,11 +1,11 @@ -from typing import Tuple, Union +from typing import Union from py_hcl.core.type import HclType from py_hcl.core.type.bundle import BundleT, Dir -def Bundle(**named_ports: Union[HclType, Tuple[Dir, HclType]]) -> BundleT: - t = {k: ((Dir.SRC, v) if isinstance(v, HclType) else v) +def Bundle(**named_ports: Union[HclType, dict]) -> BundleT: + t = {k: ({dir: Dir.SRC, type: v} if isinstance(v, HclType) else v) for k, v in named_ports.items()} return BundleT(t) diff --git a/py_hcl/utils.py b/py_hcl/utils.py index 11245c2..8dc5697 100644 --- a/py_hcl/utils.py +++ b/py_hcl/utils.py @@ -1,3 +1,5 @@ +import json +from enum import Enum from functools import partial from multipledispatch import dispatch @@ -11,24 +13,38 @@ def unsigned_num_bin_len(num): return len("{:b}".format(num)) -def auto_repr(cls=None, repr_fields=()): - def _(_cls, _repr_fields): - def __repr__(self): - if len(_repr_fields) == 0: +def json_serialize(cls=None, json_fields=()): + def rec(v): + if hasattr(v, "json_obj"): + return v.json_obj() + elif isinstance(v, dict): + return {k: rec(v) for k, v in v.items()} + elif isinstance(v, (list, tuple)): + return [rec(v) for v in v] + elif isinstance(v, Enum): + return v.name + return v + + def serialize(self): + return json.dumps(self.json_obj(), indent=2) + + def _(_cls, _json_fields): + def js(self): + if len(_json_fields) == 0: kv = vars(self) else: - kv = {f: vars(self)[f] for f in _repr_fields} - ls = ['{}={}'.format(k, _fm(v)) for k, v in kv.items()] - fs = _iter_repr(ls) - return '%s {%s}' % (type(self).__name__, ''.join(fs)) + kv = {f: vars(self)[f] for f in _json_fields} - _cls.__repr__ = __repr__ + return {k: rec(v) for k, v in kv.items()} + + _cls.json_obj = js + _cls.__str__ = serialize return _cls if cls: - return _(cls, repr_fields) + return _(cls, json_fields) - return partial(_, _repr_fields=repr_fields) + return partial(_, _json_fields=json_fields) @dispatch() diff --git a/tests/test_dsl/test_branch.py b/tests/test_dsl/test_branch.py index 514b847..41ea88a 100644 --- a/tests/test_dsl/test_branch.py +++ b/tests/test_dsl/test_branch.py @@ -30,35 +30,35 @@ def test_branch(): with otherwise(): c <<= a + b - s = A.packed_module.statement_list \ - .stmt_list_head.stmt_holder.top_statement.statements + s = A.packed_module.statement_chain \ + .stmt_chain_head.stmt_holder.top_statement.statements assert len(s) == 4 si = ScopeManager.get_scope_info(s[0].scope_id) - assert si['scope_type'] == ScopeType.GROUND + assert si.scope_type == ScopeType.GROUND assert isinstance(s[0].statement, Connect) si = s[1].scope_info - assert si['scope_type'] == ScopeType.WHEN - assert si['scope_level'] == 2 + assert si.scope_type == ScopeType.WHEN + assert si.scope_level == 2 assert len(s[1].statements) == 2 si = s[2].scope_info - assert si['scope_type'] == ScopeType.ELSE_WHEN - assert si['scope_level'] == 2 + assert si.scope_type == ScopeType.ELSE_WHEN + assert si.scope_level == 2 assert len(s[2].statements) == 3 si = s[2].statements[1].scope_info - assert si['scope_type'] == ScopeType.WHEN - assert si['scope_level'] == 3 + assert si.scope_type == ScopeType.WHEN + assert si.scope_level == 3 si = s[2].statements[2].scope_info - assert si['scope_type'] == ScopeType.OTHERWISE - assert si['scope_level'] == 3 + assert si.scope_type == ScopeType.OTHERWISE + assert si.scope_level == 3 si = s[3].scope_info - assert si['scope_type'] == ScopeType.OTHERWISE - assert si['scope_level'] == 2 + assert si.scope_type == ScopeType.OTHERWISE + assert si.scope_level == 2 assert len(s[3].statements) == 1 diff --git a/tests/test_dsl/test_io.py b/tests/test_dsl/test_io.py index 15de933..802a64b 100644 --- a/tests/test_dsl/test_io.py +++ b/tests/test_dsl/test_io.py @@ -1,5 +1,6 @@ import pytest +from py_hcl.core.expr import ExprPool from py_hcl.core.expr.error import ExprError from py_hcl.core.type.bundle import BundleT from py_hcl.dsl.expr.io import IO, Input, Output @@ -16,10 +17,11 @@ def test_io(): io.o <<= io.i - t = A.packed_module.named_expr_list.named_expr_list_head \ - .named_expr_holder.named_expressions['io'].hcl_type + t = A.packed_module.named_expr_chain.named_expr_chain_head \ + .named_expr_holder.named_expressions['io'] + t = ExprPool.pool[t['expr_id']].hcl_type assert isinstance(t, BundleT) - assert len(t.types) == 2 + assert len(t.fields) == 2 def test_io_no_wrap_io(): diff --git a/tests/test_dsl/test_module.py b/tests/test_dsl/test_module.py index 0b89fa2..fe0163a 100644 --- a/tests/test_dsl/test_module.py +++ b/tests/test_dsl/test_module.py @@ -12,7 +12,7 @@ def test_module(): a = HclExpr() assert hasattr(A, "packed_module") - assert len(A.packed_module.named_expr_list.named_expr_list_head + assert len(A.packed_module.named_expr_chain.named_expr_chain_head .named_expr_holder.named_expressions) == 2 diff --git a/tests/test_dsl/test_statement.py b/tests/test_dsl/test_statement.py index 83b3b76..d3d7b6d 100644 --- a/tests/test_dsl/test_statement.py +++ b/tests/test_dsl/test_statement.py @@ -15,7 +15,7 @@ def test_statement(): c <<= a + b - s = A.packed_module.statement_list \ - .stmt_list_head.stmt_holder.top_statement.statements + s = A.packed_module.statement_chain \ + .stmt_chain_head.stmt_holder.top_statement.statements assert len(s) == 1 assert isinstance(s[0].statement, Connect)