3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-06 14:13:23 +00:00

Docs: Preliminary autocellgroup usage

Remove `/source/cell` from .gitignore.
Add a few initial cell pages.
Add YosysCellGroup documenter and cell:group directive.
Update Documenters to use nested json.
Better nested tocs for group.module.source layout.
This commit is contained in:
Krystine Sherwin 2024-05-21 18:10:20 +12:00
parent 5a4a4191af
commit b127ac07f8
No known key found for this signature in database
9 changed files with 331 additions and 130 deletions

View file

@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
# cell signature
cell_ext_sig_re = re.compile(
r'''^ (?:([^:\s]+):)? # explicit file name
r'''^ ([^:\s]+::)? # optional group or file name
([\w$._]+?) # module name
(?:\.([\w_]+))? # optional: thing name
(::[\w_]+)? # attribute
@ -25,7 +25,7 @@ cell_ext_sig_re = re.compile(
@dataclass
class YosysCell:
cell: str
name: str
title: str
ports: str
source: str
@ -34,22 +34,26 @@ class YosysCell:
inputs: list[str]
outputs: list[str]
properties: dict[str, bool]
class YosysCellDocumenter(Documenter):
objtype = 'cell'
object: YosysCell
class YosysCellGroupDocumenter(Documenter):
objtype = 'cellgroup'
priority = 10
object: tuple[str, list[str]]
lib_key = 'groups'
option_spec = {
'caption': autodoc.annotation_option,
'members': autodoc.members_option,
'source': autodoc.bool_option,
'linenos': autodoc.bool_option,
}
__cell_lib: dict[str, YosysCell] | None = None
__cell_lib: dict[str, list[str] | dict[str]] | None = None
@property
def cell_lib(self) -> dict[str, YosysCell]:
def cell_lib(self) -> dict[str, list[str] | dict[str]]:
if not self.__cell_lib:
self.__cell_lib = {}
cells_obj: dict[str, list[dict[str, list[dict[str]]]]]
cells_obj: dict[str, dict[str, list[str] | dict[str]]]
try:
with open(self.config.cells_json, "r") as f:
cells_obj = json.loads(f.read())
@ -60,12 +64,10 @@ class YosysCellDocumenter(Documenter):
subtype = 'cell_lib'
)
else:
for group in cells_obj.get("groups", []):
for cell in group.get("cells", []):
yosysCell = YosysCell(**cell)
self.__cell_lib[yosysCell.cell] = yosysCell
for (name, obj) in cells_obj.get(self.lib_key, {}).items():
self.__cell_lib[name] = obj
return self.__cell_lib
@classmethod
def can_document_member(
cls,
@ -74,75 +76,51 @@ class YosysCellDocumenter(Documenter):
isattr: bool,
parent: Any
) -> bool:
sourcename = str(member).split(":")[0]
if not sourcename.endswith(".v"):
return False
if membername == "__source":
return False
return False
def parse_name(self) -> bool:
try:
matched = cell_ext_sig_re.match(self.name)
path, modname, thing, attribute = matched.groups()
except AttributeError:
logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name),
type='cellref')
return False
self.modname = modname
self.objpath = [path]
self.attribute = attribute
self.fullname = ((self.modname) + (thing or ''))
if not self.options.caption:
self.content_indent = ''
self.fullname = self.modname = self.name
return True
def import_object(self, raiseerror: bool = False) -> bool:
# get cell
try:
self.object = self.cell_lib[self.modname]
self.object = (self.modname, self.cell_lib[self.modname])
except KeyError:
if raiseerror:
raise
return False
self.real_modname = self.modname or ''
self.real_modname = self.modname
return True
def get_sourcename(self) -> str:
return self.object.source.split(":")[0]
return self.env.doc2path(self.env.docname)
def format_name(self) -> str:
return self.object.cell
return self.options.caption or ''
def format_signature(self, **kwargs: Any) -> str:
return f"{self.object.cell} {self.object.ports}"
return self.modname
def add_directive_header(self, sig: str) -> None:
domain = getattr(self, 'domain', self.objtype)
directive = getattr(self, 'directivetype', 'def')
domain = getattr(self, 'domain', 'cell')
directive = getattr(self, 'directivetype', 'group')
name = self.format_name()
sourcename = self.get_sourcename()
cell = self.object
cell_list = self.object
# cell definition
self.add_line(f'.. {domain}:{directive}:: {name}', sourcename)
# options
opt_attrs = ["title", ]
for attr in opt_attrs:
val = getattr(cell, attr, None)
if val:
self.add_line(f' :{attr}: {val}', sourcename)
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
self.add_line(f' :caption: {name}', sourcename)
if self.options.noindex:
self.add_line(' :noindex:', sourcename)
def add_content(self, more_content: Any | None) -> None:
# set sourcename and add content from attribute documentation
sourcename = self.get_sourcename()
startline = int(self.object.source.split(":")[1])
for i, line in enumerate(self.object.desc.splitlines(), startline):
self.add_line(line, sourcename, i)
# groups have no native content
# add additional content (e.g. from document), if present
if more_content:
for line, src in zip(more_content.data, more_content.items):
@ -161,14 +139,25 @@ class YosysCellDocumenter(Documenter):
) -> tuple[bool, list[tuple[str, Any]]]:
ret: list[tuple[str, str]] = []
if self.options.source:
ret.append(('__source', self.real_modname))
if want_all:
for member in self.object[1]:
ret.append((member, self.modname))
else:
memberlist = self.options.members or []
for name in memberlist:
if name in self.object:
ret.append((name, self.modname))
else:
logger.warning(('unknown module mentioned in :members: option: '
f'group {self.modname}, module {name}'),
type='cellref')
return False, ret
def document_members(self, all_members: bool = False) -> None:
want_all = (all_members or
self.options.inherited_members)
self.options.inherited_members or
self.options.members is autodoc.ALL)
# find out which members are documentable
members_check_module, members = self.get_object_members(want_all)
@ -184,7 +173,7 @@ class YosysCellDocumenter(Documenter):
classes.sort(key=lambda cls: cls.priority)
# give explicitly separated module name, so that members
# of inner classes can be documented
full_mname = self.real_modname + '::' + mname
full_mname = self.format_signature() + '::' + mname
documenter = classes[-1](self.directive, full_mname, self.indent)
memberdocumenters.append((documenter, isattr))
@ -247,6 +236,101 @@ class YosysCellDocumenter(Documenter):
# document members, if possible
self.document_members(all_members)
class YosysCellDocumenter(YosysCellGroupDocumenter):
objtype = 'cell'
priority = 15
object: YosysCell
lib_key = 'cells'
@classmethod
def can_document_member(
cls,
member: Any,
membername: str,
isattr: bool,
parent: Any
) -> bool:
if membername == "__source":
return False
if not membername.startswith('$'):
return False
return isinstance(parent, YosysCellGroupDocumenter)
def parse_name(self) -> bool:
try:
matched = cell_ext_sig_re.match(self.name)
group, modname, thing, attribute = matched.groups()
except AttributeError:
logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name),
type='cellref')
return False
self.modname = modname
self.groupname = group or ''
self.attribute = attribute or ''
self.fullname = ((self.modname) + (thing or ''))
return True
def import_object(self, raiseerror: bool = False) -> bool:
if super().import_object(raiseerror):
self.object = YosysCell(self.modname, **self.object[1])
return True
return False
def get_sourcename(self) -> str:
return self.object.source.split(":")[0]
def format_name(self) -> str:
return self.object.name
def format_signature(self, **kwargs: Any) -> str:
return self.groupname + self.fullname + self.attribute
def add_directive_header(self, sig: str) -> None:
domain = getattr(self, 'domain', self.objtype)
directive = getattr(self, 'directivetype', 'def')
name = self.format_name()
sourcename = self.get_sourcename()
cell = self.object
# cell definition
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
# options
opt_attrs = ["title", ]
for attr in opt_attrs:
val = getattr(cell, attr, None)
if val:
self.add_line(f' :{attr}: {val}', sourcename)
if self.options.noindex:
self.add_line(' :noindex:', sourcename)
def add_content(self, more_content: Any | None) -> None:
# set sourcename and add content from attribute documentation
sourcename = self.get_sourcename()
startline = int(self.object.source.split(":")[1])
for i, line in enumerate(self.object.desc.splitlines(), startline):
self.add_line(line, sourcename, i)
# add additional content (e.g. from document), if present
if more_content:
for line, src in zip(more_content.data, more_content.items):
self.add_line(line, src[0], src[1])
def get_object_members(
self,
want_all: bool
) -> tuple[bool, list[tuple[str, Any]]]:
ret: list[tuple[str, str]] = []
if self.options.source:
ret.append(('__source', self.real_modname))
return False, ret
class YosysCellSourceDocumenter(YosysCellDocumenter):
objtype = 'cellsource'
priority = 20
@ -273,7 +357,7 @@ class YosysCellSourceDocumenter(YosysCellDocumenter):
cell = self.object
# cell definition
self.add_line(f'.. {domain}:{directive}:: {name}', sourcename)
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
if self.options.linenos:
self.add_line(f' :source: {cell.source.split(":")[0]}', sourcename)
@ -312,6 +396,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
app.setup_extension('sphinx.ext.autodoc')
app.add_autodocumenter(YosysCellDocumenter)
app.add_autodocumenter(YosysCellSourceDocumenter)
app.add_autodocumenter(YosysCellGroupDocumenter)
return {
'version': '1',
'parallel_read_safe': True,