diff --git a/edg/core/Array.py b/edg/core/Array.py index 85da6a8a6..8a2b0e45b 100644 --- a/edg/core/Array.py +++ b/edg/core/Array.py @@ -24,8 +24,9 @@ def __init__(self, container: Vector, elt: ConstraintExpr): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.container] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: - contained_map = self.container._get_contained_ref_map() + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: + contained_map = self.container._elt_sample._create_ref_map(edgir.LocalPath()) + pb = edgir.ValueExpr() pb.map_extract.container.ref.CopyFrom(ref_map[self.container]) # TODO support arbitrary refs pb.map_extract.path.CopyFrom(contained_map[self.elt]) @@ -40,7 +41,7 @@ def __init__(self, elts: ConstraintExpr): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.elts] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.unary_set.op = edgir.UnarySetExpr.Op.FLATTEN pb.unary_set.vals.CopyFrom(self.elts._expr_to_proto(ref_map)) @@ -178,16 +179,15 @@ def _instance_to_proto(self) -> edgir.PortLike: def _def_to_proto(self) -> edgir.PortTypes: raise RuntimeError() # this doesn't generate into a library element - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath) -> None: + super()._build_ref_map(ref_map, prefix) + ref_map[self._length] = edgir.localpath_concat(prefix, edgir.LENGTH) + ref_map[self._requested] = edgir.localpath_concat(prefix, edgir.ALLOCATED) elts_items = self._elts.items() if self._elts is not None else [] - - return super()._get_ref_map(prefix) + IdentityDict[Refable, edgir.LocalPath]( - [(self._length, edgir.localpath_concat(prefix, edgir.LENGTH)), - (self._requested, edgir.localpath_concat(prefix, edgir.ALLOCATED))], - *[elt._get_ref_map(edgir.localpath_concat(prefix, index)) for (index, elt) in elts_items]) + IdentityDict( - *[elt._get_ref_map(edgir.localpath_concat(prefix, edgir.Allocate(suggested_name))) - for (suggested_name, elt) in self._requests] - ) + for index, elt in elts_items: + elt._build_ref_map(ref_map, edgir.localpath_concat(prefix, index)) + for suggested_name, request in self._requests: + request._build_ref_map(ref_map, edgir.localpath_concat(prefix, edgir.Allocate(suggested_name))) def _get_initializers(self, path_prefix: List[str]) -> List[Tuple[ConstraintExpr, List[str], ConstraintExpr]]: if self._elts is not None: @@ -196,9 +196,6 @@ def _get_initializers(self, path_prefix: List[str]) -> List[Tuple[ConstraintExpr else: return [] - def _get_contained_ref_map(self) -> IdentityDict[Refable, edgir.LocalPath]: - return self._elt_sample._get_ref_map(edgir.LocalPath()) - def defined(self) -> None: """Marks this vector as defined, even if it is empty. Can be called multiple times, and append_elt can continue to be used. diff --git a/edg/core/ArrayExpr.py b/edg/core/ArrayExpr.py index 57bc61e09..26990f371 100644 --- a/edg/core/ArrayExpr.py +++ b/edg/core/ArrayExpr.py @@ -20,7 +20,7 @@ def __init__(self): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: # element should be returned by the containing ConstraintExpr return [] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: raise ValueError # can't be used directly diff --git a/edg/core/Binding.py b/edg/core/Binding.py index fb5513000..19a60e260 100644 --- a/edg/core/Binding.py +++ b/edg/core/Binding.py @@ -73,7 +73,7 @@ def is_bound(self) -> bool: return True @abstractmethod - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: ... + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: ... @abstractmethod def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: ... @@ -100,7 +100,7 @@ def is_bound(self) -> bool: else: return True - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ref.CopyFrom(ref_map[expr]) return pb @@ -128,7 +128,7 @@ def __init__(self, value: bool): super().__init__() self.value = value - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.boolean.val = self.value return pb @@ -141,7 +141,7 @@ def __repr__(self) -> str: def __init__(self, value: int): self.value = value - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.integer.val = self.value return pb @@ -154,7 +154,7 @@ def __repr__(self) -> str: def __init__(self, value: Union[float, int]): self.value: float = float(value) - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.floating.val = self.value return pb @@ -167,7 +167,7 @@ def __repr__(self) -> str: def __init__(self, value: Range): self.value = value - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.range.minimum.floating.val = self.value.lower pb.literal.range.maximum.floating.val = self.value.upper @@ -182,7 +182,7 @@ def __init__(self, value: str): super().__init__() self.value = value - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.text.val = self.value return pb @@ -196,7 +196,7 @@ def __init__(self, values: Sequence[LiteralBinding]): super().__init__() self.values = values - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.literal.array.SetInParent() for value in self.values: @@ -218,7 +218,7 @@ def __init__(self, lower: FloatExpr, upper: FloatExpr): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.lower._get_exprs(), self.lower._get_exprs()) - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.binary.op = edgir.BinaryExpr.RANGE pb.binary.lhs.CopyFrom(self.lower._expr_to_proto(ref_map)) @@ -234,7 +234,7 @@ def __init__(self, values: Sequence[ConstraintExpr]): super().__init__() self.values = values - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.array.SetInParent() for value in self.values: @@ -267,7 +267,7 @@ def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.src._get_exprs()) def expr_to_proto(self, expr: ConstraintExpr, - ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.unary.op = self.op_map[self.op] pb.unary.val.CopyFrom(self.src._expr_to_proto(ref_map)) @@ -303,7 +303,7 @@ def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.src._get_exprs()) def expr_to_proto(self, expr: ConstraintExpr, - ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.unary_set.op = self.op_map[self.op] pb.unary_set.vals.CopyFrom(self.src._expr_to_proto(ref_map)) @@ -352,7 +352,7 @@ def __init__(self, def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.lhs._get_exprs(), self.rhs._get_exprs()) - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.binary.op = self.op_map[self.op] pb.binary.lhs.CopyFrom(self.lhs._expr_to_proto(ref_map)) @@ -381,7 +381,7 @@ def __init__(self, def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.lhset._get_exprs(), self.rhs._get_exprs()) - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.binary_set.op = self.op_map[self.op] pb.binary_set.lhset.CopyFrom(self.lhset._expr_to_proto(ref_map)) @@ -402,7 +402,7 @@ def __init__(self, cond: BoolExpr, then_val: ConstraintExpr, else_val: Constrain def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return chain(self.cond._get_exprs(), self.then_val._get_exprs(), self.else_val._get_exprs()) - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ifThenElse.cond.CopyFrom(self.cond._expr_to_proto(ref_map)) pb.ifThenElse.tru.CopyFrom(self.then_val._expr_to_proto(ref_map)) @@ -421,7 +421,7 @@ def __init__(self, src: Port): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.src] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ref.CopyFrom(ref_map[self.src]) pb.ref.steps.add().reserved_param = edgir.IS_CONNECTED @@ -438,7 +438,7 @@ def __init__(self, src: Union[BaseBlock, BasePort]): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ref.CopyFrom(ref_map[self.src]) pb.ref.steps.add().reserved_param = edgir.NAME @@ -456,7 +456,7 @@ def __init__(self, src: Vector): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.src] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ref.CopyFrom(ref_map[self.src]) pb.ref.steps.add().reserved_param = edgir.LENGTH @@ -474,7 +474,7 @@ def __init__(self, src: Vector): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.src] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.ref.CopyFrom(ref_map[self.src]) pb.ref.steps.add().reserved_param = edgir.ALLOCATED @@ -484,7 +484,7 @@ def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edg class AssignBinding(Binding): # Convenience method to make an assign expr without the rest of this proto infrastructure @staticmethod - def make_assign(target: ConstraintExpr, value: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def make_assign(target: ConstraintExpr, value: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: pb = edgir.ValueExpr() pb.assign.dst.CopyFrom(ref_map[target]) pb.assign.src.CopyFrom(value._expr_to_proto(ref_map)) @@ -501,5 +501,5 @@ def __init__(self, target: ConstraintExpr, value: ConstraintExpr): def get_subexprs(self) -> Iterable[Union[ConstraintExpr, BasePort]]: return [self.value] - def expr_to_proto(self, expr: ConstraintExpr, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def expr_to_proto(self, expr: ConstraintExpr, ref_map: Refable.RefMapType) -> edgir.ValueExpr: return self.make_assign(self.target, self.value, ref_map) diff --git a/edg/core/Blocks.py b/edg/core/Blocks.py index 75f8acbab..dfcfd0445 100644 --- a/edg/core/Blocks.py +++ b/edg/core/Blocks.py @@ -180,9 +180,14 @@ def make_connection(self) -> Optional[Union[ConnectedLink, Export]]: bridged_connects: List[Tuple[BasePort, edgir.LocalPath]] = [] link_connects: List[Tuple[BasePort, edgir.LocalPath]] = [] assert self.link_instance is not None - link_ref_map = self.link_instance._get_ref_map_allocate(edgir.LocalPath()) + link_ref_map = self.link_instance._create_ref_map() for link_port, connected_ports in self.link_connected_ports.items(): link_ref = link_ref_map[link_port] + if isinstance(link_port, BaseVector): + allocate_path = edgir.LocalPath() + allocate_path.CopyFrom(link_ref) + allocate_path.steps.append(edgir.LocalStep(allocate='')) + link_ref = allocate_path for connected_port in connected_ports: bridged_port = self.bridged_ports.get(connected_port, None) if bridged_port is None: # direct connection, no bridge @@ -214,14 +219,13 @@ class DescriptionString(): def __init__(self, *elts: Union[str, DescriptionStringElts]): self.elts = elts - def add_to_proto(self, pb, ref_map): + def add_to_proto(self, pb: edgir.BlockLikeTypes, ref_map: Refable.RefMapType): for elt in self.elts: if isinstance(elt, DescriptionStringElts): elt.set_elt_proto(pb, ref_map) elif isinstance(elt, str): new_phrase = pb.description.add() new_phrase.text = elt - return pb class FormatUnits(DescriptionStringElts): ref: ConstraintExpr @@ -310,7 +314,7 @@ def _elaborated_def_to_proto(self) -> BaseBlockEdgirType: return self._def_to_proto() - def _populate_def_proto_block_base(self, pb: BaseBlockEdgirType) -> BaseBlockEdgirType: + def _populate_def_proto_block_base(self, pb: BaseBlockEdgirType) -> None: """Populates the structural parts of a block proto: parameters, ports, superclasses""" assert self._elaboration_state == BlockElaborationState.post_contents or \ self._elaboration_state == BlockElaborationState.post_generate @@ -343,7 +347,7 @@ def _populate_def_proto_block_base(self, pb: BaseBlockEdgirType) -> BaseBlockEdg for (name, port) in self._ports.items(): edgir.add_pair(pb.ports, name).CopyFrom(port._instance_to_proto()) - ref_map = self._get_ref_map(edgir.LocalPath()) # TODO dedup ref_map + ref_map = self._create_ref_map() for (name, port) in self._ports.items(): if port in self._required_ports: if isinstance(port, Port): @@ -359,58 +363,45 @@ def _populate_def_proto_block_base(self, pb: BaseBlockEdgirType) -> BaseBlockEdg self._constraints.finalize() # needed for source locator generation - ref_map = self._get_ref_map(edgir.LocalPath()) self._populate_metadata(pb.meta, self._metadata, ref_map) - return pb - - def _populate_def_proto_port_init(self, pb: BaseBlockEdgirType) -> BaseBlockEdgirType: - ref_map = self._get_ref_map(edgir.LocalPath()) # TODO dedup ref_map - + def _populate_def_proto_port_init(self, pb: BaseBlockEdgirType, ref_map: Refable.RefMapType) -> None: for (name, port) in self._ports.items(): for (param, path, initializer) in port._get_initializers([name]): edgir.add_pair(pb.constraints, f"(init){'.'.join(path)}").CopyFrom( AssignBinding.make_assign(param, param._to_expr_type(initializer), ref_map) ) - return pb - def _populate_def_proto_param_init(self, pb: BaseBlockEdgirType) -> BaseBlockEdgirType: - ref_map = self._get_ref_map(edgir.LocalPath()) # TODO dedup ref_map + def _populate_def_proto_param_init(self, pb: BaseBlockEdgirType, ref_map: Refable.RefMapType) -> None: for (name, param) in self._parameters.items(): if param.initializer is not None: edgir.add_pair(pb.constraints, f'(init){name}').CopyFrom( AssignBinding.make_assign(param, param.initializer, ref_map) ) - return pb - def _populate_def_proto_block_contents(self, pb: BaseBlockEdgirType) -> BaseBlockEdgirType: + def _populate_def_proto_block_contents(self, pb: BaseBlockEdgirType, ref_map: Refable.RefMapType) -> None: """Populates the contents of a block proto: constraints""" assert self._elaboration_state == BlockElaborationState.post_contents or \ self._elaboration_state == BlockElaborationState.post_generate self._constraints.finalize() - ref_map = self._get_ref_map(edgir.LocalPath()) - for (name, constraint) in self._constraints.items(): edgir.add_pair(pb.constraints, name).CopyFrom(constraint._expr_to_proto(ref_map)) - return pb - - def _populate_def_proto_description(self, pb: BaseBlockEdgirType) -> BaseBlockEdgirType: + def _populate_def_proto_description(self, pb: BaseBlockEdgirType, ref_map: Refable.RefMapType) -> None: description = self.description assert(description is None or isinstance(description, DescriptionString)) if isinstance(description, DescriptionString): - pb = description.add_to_proto(pb, self._get_ref_map(edgir.LocalPath())) - - return pb - - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - return super()._get_ref_map(prefix) + IdentityDict( - [(self.name(), edgir.localpath_concat(prefix, edgir.NAME))], - *[param._get_ref_map(edgir.localpath_concat(prefix, name)) for (name, param) in self._parameters.items()], - *[port._get_ref_map(edgir.localpath_concat(prefix, name)) for (name, port) in self._ports.items()] - ) + description.add_to_proto(pb, ref_map) + + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath) -> None: + super()._build_ref_map(ref_map, prefix) + ref_map[self.name()] = edgir.localpath_concat(prefix, edgir.NAME) + for name, param in self._parameters.items(): + param._build_ref_map(ref_map, edgir.localpath_concat(prefix, name)) + for name, port in self._ports.items(): + port._build_ref_map(ref_map, edgir.localpath_concat(prefix, name)) def _bind_in_place(self, parent: Union[BaseBlock, Port]): self._parent = parent diff --git a/edg/core/ConstraintExpr.py b/edg/core/ConstraintExpr.py index 0a0c75e41..b3b76a5af 100644 --- a/edg/core/ConstraintExpr.py +++ b/edg/core/ConstraintExpr.py @@ -91,7 +91,7 @@ def _bind(self: SelfType, binding: Binding) -> SelfType: def _is_bound(self) -> bool: return self.binding is not None and self.binding.is_bound() - def _expr_to_proto(self, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.ValueExpr: + def _expr_to_proto(self, ref_map: Refable.RefMapType) -> edgir.ValueExpr: assert self.binding is not None return self.binding.expr_to_proto(self, ref_map) diff --git a/edg/core/Core.py b/edg/core/Core.py index 934b648aa..4041b7b15 100644 --- a/edg/core/Core.py +++ b/edg/core/Core.py @@ -144,6 +144,8 @@ def values(self) -> ValuesView[ElementType]: class Refable(): """Object that could be referenced into a edgir.LocalPath""" + RefMapType = IdentityDict['Refable', edgir.LocalPath] + def __repr__(self) -> str: return "%s@%02x" % (self.__class__.__name__, (id(self)//4)&0xff) @@ -154,8 +156,15 @@ def __bool__(self) -> bool: raise ValueError("bool-ing a Refable is almost certainly a mistake. " "Note: 'and' and 'or' do not work on BoolExpr, use '&' or '|' instead.") - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict['Refable', edgir.LocalPath]: - return IdentityDict([(self, prefix)]) + def _create_ref_map(self, prefix: edgir.LocalPath = edgir.LocalPath()) -> RefMapType: + """Wrapper around _build_ref_map for top-level refmap construction.""" + ref_map = IdentityDict[Refable, edgir.LocalPath]() + self._build_ref_map(ref_map, prefix) + return ref_map + + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath) -> None: + """Adds the references contained by this object to the parameter refmap.""" + ref_map[self] = prefix class EltPropertiesBase: @@ -238,7 +247,7 @@ def _def_to_proto(self) -> Union[edgir.PortTypes, edgir.BlockLikeTypes]: ... class StructuredMetadata(): """Base class for metadata that is structured (as a class in Python)""" @abstractmethod - def _to_proto(self, ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.Metadata: + def _to_proto(self, ref_map: Refable.RefMapType) -> edgir.Metadata: raise NotImplementedError @@ -288,7 +297,7 @@ def process_direct_base(bcls: Type[HasMetadata.BaseType]): return ordered_direct_bases, ordered_indirect_bases def _populate_metadata(self, pb: edgir.Metadata, src: Any, - ref_map: IdentityDict[Refable, edgir.LocalPath]) -> edgir.Metadata: + ref_map: Refable.RefMapType) -> None: """Generate metadata from a given object.""" if isinstance(src, StructuredMetadata): pb.CopyFrom(src._to_proto(ref_map)) @@ -307,4 +316,3 @@ def _populate_metadata(self, pb: edgir.Metadata, src: Any, self._populate_metadata(pb.members.node[str(idx)], val, ref_map) else: raise ValueError(f'must overload _metadata_to_proto to handle unknown value {src}') - return pb diff --git a/edg/core/DesignTop.py b/edg/core/DesignTop.py index 740cac7b3..7f492d5e1 100644 --- a/edg/core/DesignTop.py +++ b/edg/core/DesignTop.py @@ -1,5 +1,6 @@ from typing import TypeVar, Union, List, Tuple, Dict, Type +from .Core import Refable from .. import edgir from .Builder import builder from .Ports import Port @@ -65,9 +66,9 @@ def _elaborated_def_to_proto(self) -> edgir.HierarchyBlock: builder.pop_to(prev_element) return self._def_to_proto() - def _populate_def_proto_block_contents(self, pb: edgir.HierarchyBlock) -> edgir.HierarchyBlock: + def _populate_def_proto_block_contents(self, pb: edgir.HierarchyBlock, ref_map: Refable.RefMapType) -> None: """Add multipack constraints""" - pb = super()._populate_def_proto_block_contents(pb) + super()._populate_def_proto_block_contents(pb, ref_map) # Since ConstraintExpr arrays don't have the allocate construct (like connects), # we need to aggregate them into a packed array format (instead of generating a constraint for each element) @@ -88,13 +89,13 @@ def _populate_def_proto_block_contents(self, pb: edgir.HierarchyBlock) -> edgir. multipack_name = self._name_of_child(multipack_block, self) multipack_ref_base = edgir.LocalPath() multipack_ref_base.steps.add().name = multipack_name - multipack_ref_map = multipack_block._get_ref_map(multipack_ref_base) + multipack_ref_map = multipack_block._create_ref_map(multipack_ref_base) packing_rule = multipack_block._get_block_packing_rule(multipack_part) packed_ref_base = edgir.LocalPath() for packed_path_part in packed_path: packed_ref_base.steps.add().name = packed_path_part - packed_ref_map = multipack_part_block._get_ref_map(packed_ref_base) + packed_ref_map = multipack_part_block._create_ref_map(packed_ref_base) if isinstance(multipack_part, Block): part_name = multipack_block._name_of_child(multipack_part, self) @@ -163,10 +164,7 @@ def _populate_def_proto_block_contents(self, pb: edgir.HierarchyBlock) -> edgir. for assign_src in assign_srcs: assign_src_vals.add().ref.CopyFrom(assign_src) - return pb - PackedBlockType = TypeVar('PackedBlockType', bound=MultipackBlock) - def PackedBlock(self, tpe: PackedBlockType) -> PackedBlockType: """Instantiates a multipack block, that can be used to pack constituent blocks arbitrarily deep in the design.""" # TODO: additional checks and enforcement beyond what Block provides - eg disallowing .connect operations diff --git a/edg/core/Generator.py b/edg/core/Generator.py index 100a2f1dd..fb8165c92 100644 --- a/edg/core/Generator.py +++ b/edg/core/Generator.py @@ -12,7 +12,7 @@ from .Binding import InitParamBinding, AllocatedBinding, IsConnectedBinding from .Blocks import BlockElaborationState, AbstractBlockProperty from .ConstraintExpr import ConstraintExpr -from .Core import non_library +from .Core import non_library, Refable from .HdlUserExceptions import * from .HierarchyBlock import Block @@ -84,9 +84,9 @@ def generate(self): # def _def_to_proto(self) -> edgir.HierarchyBlock: if self._elaboration_state != BlockElaborationState.post_generate: # only write generator on the stub definition + ref_map = self._create_ref_map() pb = edgir.HierarchyBlock() - ref_map = self._get_ref_map(edgir.LocalPath()) - pb = self._populate_def_proto_block_base(pb) + self._populate_def_proto_block_base(pb) pb.generator.SetInParent() # even if rest of the fields are empty, make sure to create a record if type(self).generate is not GeneratorBlock.generate: @@ -117,7 +117,7 @@ def _generated_def_to_proto(self, generate_values: Iterable[Tuple[edgir.LocalPat self._elaboration_state = BlockElaborationState.generate # Translate parameter values to function arguments - ref_map = self._get_ref_map(edgir.LocalPath()) + ref_map = self._create_ref_map() generate_values_map = {path.SerializeToString(): value for (path, value) in generate_values} assert (self.__class__, AbstractBlockProperty) not in self._elt_properties # abstract blocks can't generate diff --git a/edg/core/HierarchyBlock.py b/edg/core/HierarchyBlock.py index c6477cedf..c7729059f 100644 --- a/edg/core/HierarchyBlock.py +++ b/edg/core/HierarchyBlock.py @@ -3,7 +3,6 @@ import functools import inspect import warnings -from functools import reduce from typing import * from .. import edgir @@ -308,19 +307,18 @@ def _get_ports_by_tag(self, tags: Set[PortTag]) -> List[BasePort]: out.append(block_port) return out - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - ref_map = super()._get_ref_map(prefix) + IdentityDict( - *[block._get_ref_map(edgir.localpath_concat(prefix, name)) for (name, block) in self._blocks.items()] - ) - mixin_ref_maps = list(map(lambda mixin: mixin._get_ref_map(prefix), self._mixins)) - if mixin_ref_maps: - mixin_ref_map = reduce(lambda a, b: a+b, mixin_ref_maps) - ref_map += mixin_ref_map - - return ref_map + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath, *, + interface_only: bool = False) -> None: + super()._build_ref_map(ref_map, prefix) + for mixin in self._mixins: + mixin._build_ref_map(ref_map, prefix) + if not interface_only: + for name, block in self._blocks.items(): + assert isinstance(block, Block) + block._build_ref_map(ref_map, edgir.localpath_concat(prefix, name), interface_only=True) - def _populate_def_proto_block_base(self, pb: edgir.HierarchyBlock) -> edgir.HierarchyBlock: - pb = super()._populate_def_proto_block_base(pb) + def _populate_def_proto_block_base(self, pb: edgir.HierarchyBlock) -> None: + super()._populate_def_proto_block_base(pb) # generate param defaults for param_name, param in self._parameters.items(): @@ -329,15 +327,11 @@ def _populate_def_proto_block_base(self, pb: edgir.HierarchyBlock) -> edgir.Hier param_typed_value = param._to_expr_type(param.binding.value) pb.param_defaults[param_name].CopyFrom(param_typed_value._expr_to_proto(IdentityDict())) - return pb - - def _populate_def_proto_hierarchy(self, pb: edgir.HierarchyBlock) -> edgir.HierarchyBlock: + def _populate_def_proto_hierarchy(self, pb: edgir.HierarchyBlock, ref_map: Refable.RefMapType) -> None: self._blocks.finalize() self._connects.finalize() self._chains.finalize() - ref_map = self._get_ref_map(edgir.LocalPath()) - for name, block in self._blocks.items(): new_block_lib = edgir.add_pair(pb.blocks, name).lib_elem new_block_lib.base.target.name = block._get_def_name() @@ -438,22 +432,21 @@ def _populate_def_proto_hierarchy(self, pb: edgir.HierarchyBlock) -> edgir.Hiera AssignBinding.make_assign(block_param, param_typed_value, ref_map) ) - return pb - # TODO make this non-overriding? def _def_to_proto(self) -> edgir.HierarchyBlock: assert not self._mixins # blocks with mixins can only be instantiated anonymously + ref_map = self._create_ref_map() pb = edgir.HierarchyBlock() pb.prerefine_class.target.name = self._get_def_name() # TODO integrate with a non-link populate_def_proto_block... - pb = self._populate_def_proto_block_base(pb) - pb = self._populate_def_proto_port_init(pb) + self._populate_def_proto_block_base(pb) + self._populate_def_proto_port_init(pb, ref_map) - pb = self._populate_def_proto_param_init(pb) + self._populate_def_proto_param_init(pb, ref_map) - pb = self._populate_def_proto_hierarchy(pb) - pb = self._populate_def_proto_block_contents(pb) - pb = self._populate_def_proto_description(pb) + self._populate_def_proto_hierarchy(pb, ref_map) + self._populate_def_proto_block_contents(pb, ref_map) + self._populate_def_proto_description(pb, ref_map) return pb diff --git a/edg/core/Link.py b/edg/core/Link.py index 679486b31..b4d3e314b 100644 --- a/edg/core/Link.py +++ b/edg/core/Link.py @@ -37,29 +37,17 @@ def __init__(self) -> None: super().__init__() self.parent: Optional[Port] = None - # Returns the ref_map, but with a trailing ALLOCATE for BaseVector ports - def _get_ref_map_allocate(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - def map_port_allocate(ref: Refable, path: edgir.LocalPath) -> edgir.LocalPath: - if isinstance(ref, BaseVector): - new_path = edgir.LocalPath() - new_path.CopyFrom(path) - new_path.steps.append(edgir.LocalStep(allocate='')) - return new_path - else: - return path - - return IdentityDict([(port, map_port_allocate(port, path)) - for port, path in self._get_ref_map(prefix).items()]) - def _def_to_proto(self) -> edgir.Link: - pb = self._populate_def_proto_block_base(edgir.Link()) - pb = self._populate_def_proto_param_init(pb) - pb = self._populate_def_proto_block_contents(pb) - pb = self._populate_def_proto_description(pb) + ref_map = self._create_ref_map() + + pb = edgir.Link() + self._populate_def_proto_block_base(pb) + self._populate_def_proto_param_init(pb, ref_map) + self._populate_def_proto_block_contents(pb, ref_map) + self._populate_def_proto_description(pb, ref_map) # specifically ignore the port initializers # actually generate the links and connects - ref_map = self._get_ref_map(edgir.LocalPath()) self._connects.finalize() delegated_connects = self._all_delegated_connects() for name, connect in self._connects.items_ordered(): diff --git a/edg/core/PortBlocks.py b/edg/core/PortBlocks.py index f90668603..4047d9446 100644 --- a/edg/core/PortBlocks.py +++ b/edg/core/PortBlocks.py @@ -37,12 +37,6 @@ def Port(self, tpe: T, *args, **kwargs) -> T: assert 'optional' not in kwargs, f"Ports in PortBridge are optional by default, required should be set by enclosing block, in {kwargs}" return super().Port(tpe, *args, optional=True, **kwargs) - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - if self.__class__ == PortBridge: # TODO: hack to allow this to elaborate as abstract class while being invalid - return IdentityDict() - - return super()._get_ref_map(prefix) - AdapterDstType = TypeVar('AdapterDstType', bound=Port) @abstract_block @@ -65,15 +59,3 @@ def __setattr__(self, name: str, value): def Port(self, tpe: T, *args, **kwargs) -> T: assert 'optional' not in kwargs, "Ports in PortBridge are optional by default, required should be set by enclosing block" return super().Port(tpe, *args, optional=True, **kwargs) - - # TODO: dedup w/ BaseBlock - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - if self.__class__ == PortAdapter: # TODO: hack to allow this to elaborate as abstract class while being invalid - return IdentityDict() - - # return super().get_ref_map(prefix) + # TODO: dedup w/ BaseBlock, and does this break anything? - return IdentityDict( - *[param._get_ref_map(edgir.localpath_concat(prefix, name)) for (name, param) in self._parameters.items()], - self.src._get_ref_map(edgir.localpath_concat(prefix, 'src')), - self.dst._get_ref_map(edgir.localpath_concat(prefix, 'dst')) - ) diff --git a/edg/core/Ports.py b/edg/core/Ports.py index fdff6fd6a..5e3f1ac89 100644 --- a/edg/core/Ports.py +++ b/edg/core/Ports.py @@ -231,16 +231,14 @@ def _def_to_proto(self) -> edgir.PortTypes: def _type_of(self) -> Hashable: return type(self) - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath) -> None: + super()._build_ref_map(ref_map, prefix) + ref_map[self.is_connected()] = edgir.localpath_concat(prefix, edgir.IS_CONNECTED) + ref_map[self.name()] = edgir.localpath_concat(prefix, edgir.NAME) + for name, param in self._parameters.items(): + param._build_ref_map(ref_map, edgir.localpath_concat(prefix, name)) if self._link_instance is not None: - link_refs = self._link_instance._get_ref_map(edgir.localpath_concat(prefix, edgir.CONNECTED_LINK)) - else: - link_refs = IdentityDict([]) - return super()._get_ref_map(prefix) + IdentityDict[Refable, edgir.LocalPath]( - [(self.is_connected(), edgir.localpath_concat(prefix, edgir.IS_CONNECTED)), - (self.name(), edgir.localpath_concat(prefix, edgir.NAME))], - *[param._get_ref_map(edgir.localpath_concat(prefix, name)) for name, param in self._parameters.items()] - ) + link_refs + self._link_instance._build_ref_map(ref_map, edgir.localpath_concat(prefix, edgir.CONNECTED_LINK)) def _get_initializers(self, path_prefix: List[str]) -> List[Tuple[ConstraintExpr, List[str], ConstraintExpr]]: self._parameters.finalize() @@ -330,10 +328,10 @@ def _def_to_proto(self) -> edgir.Bundle: return pb - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - return super()._get_ref_map(prefix) + IdentityDict( - *[field._get_ref_map(edgir.localpath_concat(prefix, name)) for (name, field) in self._ports.items()] - ) + def _build_ref_map(self, ref_map: Refable.RefMapType, prefix: edgir.LocalPath) -> None: + super()._build_ref_map(ref_map, prefix) + for name, field in self._ports.items(): + field._build_ref_map(ref_map, edgir.localpath_concat(prefix, name)) def _get_initializers(self, path_prefix: List[str]) -> List[Tuple[ConstraintExpr, List[str], ConstraintExpr]]: self_initializers = super()._get_initializers(path_prefix) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index ab1f9f4e5..89809ff20 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -115,11 +115,6 @@ def contents(self): super().contents() self.net() - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - if self.__class__ == CircuitPortBridge: # TODO: hack to allow this to elaborate as abstract class while being invalid - return IdentityDict() - return super()._get_ref_map(prefix) - AdapterDstType = TypeVar('AdapterDstType', bound='CircuitPort') @abstract_block @@ -132,11 +127,6 @@ def contents(self): super().contents() self.net() - def _get_ref_map(self, prefix: edgir.LocalPath) -> IdentityDict[Refable, edgir.LocalPath]: - if self.__class__ == CircuitPortAdapter: # TODO: hack to allow this to elaborate as abstract class while being invalid - return IdentityDict() - return super()._get_ref_map(prefix) - @non_library # TODO make abstract instead? class CircuitLink(NetBaseBlock, Link): diff --git a/edg/electronics_model/SvgPcbTemplateBlock.py b/edg/electronics_model/SvgPcbTemplateBlock.py index f14727d96..af50ef678 100644 --- a/edg/electronics_model/SvgPcbTemplateBlock.py +++ b/edg/electronics_model/SvgPcbTemplateBlock.py @@ -1,8 +1,8 @@ +from abc import abstractmethod from typing import Optional, Any, List, Tuple -from abc import abstractmethod -from ..core import * from .NetlistGenerator import Netlist +from ..core import * @non_library @@ -27,7 +27,7 @@ def _svgpcb_init(self, pathname: TransformUtil.Path, design: CompiledDesign, net self._svgpcb_pathname_data = pathname self._svgpcb_design = design self._svgpcb_netlist = netlist - self._svgpcb_ref_map = self._get_ref_map(pathname.to_local_path()) + self._svgpcb_ref_map = self._create_ref_map(pathname.to_local_path()) def _svgpcb_pathname(self) -> str: """Infrastructure method, returns the pathname for this Block as a JS-code-friendly string."""