Add Tree/TreeView and allow Builder to ingest them
This commit is contained in:
parent
b4d31903c1
commit
9a7a5583ed
@ -101,7 +101,7 @@ References are accomplished by listing the target's name, not its `Pattern` obje
|
||||
|
||||
## Glossary
|
||||
- `Library`: A collection of named cells. OASIS or GDS "library" or file.
|
||||
- "tree": Any Library which has only one topcell.
|
||||
- `Tree`: Any `{name: pattern}` mapping which has only one topcell.
|
||||
- `Pattern`: A collection of geometry, text labels, and reference to other patterns.
|
||||
OASIS or GDS "Cell", DXF "Block".
|
||||
- `Ref`: A reference to another pattern. GDS "AREF/SREF", OASIS "Placement".
|
||||
@ -142,6 +142,11 @@ my_pattern.ref(new_name, ...) # instantiate the cell
|
||||
|
||||
# In practice, you may do lots of
|
||||
my_pattern.ref(lib << make_tree(...), ...)
|
||||
|
||||
# With a `Builder` and `place()`/`plug()` the `lib <<` portion can be implicit:
|
||||
my_builder = Builder(library=lib, ...)
|
||||
...
|
||||
my_builder.place(make_tree(...))
|
||||
```
|
||||
|
||||
We can also use this shorthand to quickly add and reference a single flat (as yet un-named) pattern:
|
||||
|
@ -38,7 +38,7 @@ from .pattern import Pattern, map_layers, map_targets, chain_elements
|
||||
from .library import (
|
||||
ILibraryView, ILibrary,
|
||||
LibraryView, Library, LazyLibrary,
|
||||
AbstractView,
|
||||
AbstractView, TreeView, Tree,
|
||||
)
|
||||
from .ports import Port, PortList
|
||||
from .abstract import Abstract
|
||||
|
@ -8,7 +8,7 @@ import logging
|
||||
from numpy.typing import ArrayLike
|
||||
|
||||
from ..pattern import Pattern
|
||||
from ..library import ILibrary
|
||||
from ..library import ILibrary, TreeView
|
||||
from ..error import BuildError
|
||||
from ..ports import PortList, Port
|
||||
from ..abstract import Abstract
|
||||
@ -190,7 +190,7 @@ class Builder(PortList):
|
||||
|
||||
def plug(
|
||||
self,
|
||||
other: Abstract | str | Pattern,
|
||||
other: Abstract | str | Pattern | TreeView,
|
||||
map_in: dict[str, str],
|
||||
map_out: dict[str, str | None] | None = None,
|
||||
*,
|
||||
@ -201,11 +201,16 @@ class Builder(PortList):
|
||||
) -> Self:
|
||||
"""
|
||||
Wrapper around `Pattern.plug` which allows a string for `other`.
|
||||
|
||||
The `Builder`'s library is used to dereference the string (or `Abstract`, if
|
||||
one is passed with `append=True`).
|
||||
one is passed with `append=True`). If a `TreeView` is passed, it is first
|
||||
added into `self.library`.
|
||||
|
||||
Args:
|
||||
other: An `Abstract`, string, or `Pattern` describing the device to be instatiated.
|
||||
other: An `Abstract`, string, `Pattern`, or `TreeView` describing the
|
||||
device to be instatiated. If it is a `TreeView`, it is first
|
||||
added into `self.library`, after which the topcell is plugged;
|
||||
an equivalent statement is `self.plug(self.library << other, ...)`.
|
||||
map_in: dict of `{'self_port': 'other_port'}` mappings, specifying
|
||||
port connections between the two devices.
|
||||
map_out: dict of `{'old_name': 'new_name'}` mappings, specifying
|
||||
@ -243,6 +248,10 @@ class Builder(PortList):
|
||||
logger.error('Skipping plug() since device is dead')
|
||||
return self
|
||||
|
||||
if not isinstance(other, (str, Abstract, Pattern)):
|
||||
# We got a Tree; add it into self.library and grab an Abstract for it
|
||||
other = self.library << other
|
||||
|
||||
if isinstance(other, str):
|
||||
other = self.library.abstract(other)
|
||||
if append and isinstance(other, Abstract):
|
||||
@ -261,7 +270,7 @@ class Builder(PortList):
|
||||
|
||||
def place(
|
||||
self,
|
||||
other: Abstract | str | Pattern,
|
||||
other: Abstract | str | Pattern | TreeView,
|
||||
*,
|
||||
offset: ArrayLike = (0, 0),
|
||||
rotation: float = 0,
|
||||
@ -272,12 +281,17 @@ class Builder(PortList):
|
||||
append: bool = False,
|
||||
) -> Self:
|
||||
"""
|
||||
Wrapper around `Pattern.place` which allows a string for `other`.
|
||||
Wrapper around `Pattern.place` which allows a string or `TreeView` for `other`.
|
||||
|
||||
The `Builder`'s library is used to dereference the string (or `Abstract`, if
|
||||
one is passed with `append=True`).
|
||||
one is passed with `append=True`). If a `TreeView` is passed, it is first
|
||||
added into `self.library`.
|
||||
|
||||
Args:
|
||||
other: An `Abstract`, string, or `Pattern` describing the device to be instatiated.
|
||||
other: An `Abstract`, string, `Pattern`, or `TreeView` describing the
|
||||
device to be instatiated. If it is a `TreeView`, it is first
|
||||
added into `self.library`, after which the topcell is plugged;
|
||||
an equivalent statement is `self.plug(self.library << other, ...)`.
|
||||
offset: Offset at which to place the instance. Default (0, 0).
|
||||
rotation: Rotation applied to the instance before placement. Default 0.
|
||||
pivot: Rotation is applied around this pivot point (default (0, 0)).
|
||||
@ -306,6 +320,10 @@ class Builder(PortList):
|
||||
logger.error('Skipping place() since device is dead')
|
||||
return self
|
||||
|
||||
if not isinstance(other, (str, Abstract, Pattern)):
|
||||
# We got a Tree; add it into self.library and grab an Abstract for it
|
||||
other = self.library << other
|
||||
|
||||
if isinstance(other, str):
|
||||
other = self.library.abstract(other)
|
||||
if append and isinstance(other, Abstract):
|
||||
|
@ -14,7 +14,7 @@ Classes include:
|
||||
- `AbstractView`: Provides a way to use []-indexing to generate abstracts for patterns in the linked
|
||||
library. Generated with `ILibraryView.abstract_view()`.
|
||||
"""
|
||||
from typing import Callable, Self, Type, TYPE_CHECKING, cast
|
||||
from typing import Callable, Self, Type, TYPE_CHECKING, cast, TypeAlias, Protocol, Literal
|
||||
from typing import Iterator, Mapping, MutableMapping, Sequence
|
||||
import logging
|
||||
import base64
|
||||
@ -44,6 +44,14 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
visitor_function_t = Callable[..., 'Pattern']
|
||||
|
||||
|
||||
TreeView: TypeAlias = Mapping[str, 'Pattern']
|
||||
""" A name-to-`Pattern` mapping which is expected to have only one top-level cell """
|
||||
|
||||
Tree: TypeAlias = MutableMapping[str, 'Pattern']
|
||||
""" A mutable name-to-`Pattern` mapping which is expected to have only one top-level cell """
|
||||
|
||||
|
||||
SINGLE_USE_PREFIX = '_'
|
||||
"""
|
||||
Names starting with this prefix are assumed to refer to single-use patterns,
|
||||
@ -674,7 +682,7 @@ class ILibrary(ILibraryView, MutableMapping[str, 'Pattern'], metaclass=ABCMeta):
|
||||
|
||||
return rename_map
|
||||
|
||||
def __lshift__(self, other: Mapping[str, 'Pattern']) -> str:
|
||||
def __lshift__(self, other: TreeView) -> str:
|
||||
if len(other) == 1:
|
||||
name = next(iter(other))
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user