From b459c8b71403d64e37a148ec3bbfbed3635c0a30 Mon Sep 17 00:00:00 2001 From: umarcor Date: Fri, 24 Sep 2021 01:29:25 +0200 Subject: [PATCH 1/2] doc: use BuildTheDocs, add CI workflow --- .btd.yml | 5 + .github/workflows/Test.yml | 28 ++++ .gitignore | 2 + README.rst | 44 +++-- doc/.nojekyll | 0 doc/Makefile | 35 +++- doc/_static/Kreon-Bold.woff2 | Bin 13808 -> 0 bytes doc/_static/Kreon-Light.woff2 | Bin 12932 -> 0 bytes doc/_static/Kreon-Regular.woff2 | Bin 13616 -> 0 bytes doc/_static/project.css | 143 ---------------- doc/_templates/download.html | 10 -- doc/_templates/layout.html | 21 --- doc/_templates/page.html | 5 - doc/_templates/projects.html | 77 --------- doc/about.rst | 20 +++ doc/apidoc/hdlparse.rst | 38 ----- doc/apidoc/modules.rst | 7 - doc/conf.py | 212 +++++++----------------- doc/genindex.rst | 4 + doc/getting.rst | 65 ++++++++ doc/index.rst | 280 ++------------------------------ doc/usage.rst | 241 +++++++++++++++++++++++++++ 22 files changed, 492 insertions(+), 745 deletions(-) create mode 100644 .btd.yml create mode 100644 .github/workflows/Test.yml delete mode 100644 doc/.nojekyll delete mode 100644 doc/_static/Kreon-Bold.woff2 delete mode 100644 doc/_static/Kreon-Light.woff2 delete mode 100644 doc/_static/Kreon-Regular.woff2 delete mode 100644 doc/_static/project.css delete mode 100644 doc/_templates/download.html delete mode 100644 doc/_templates/layout.html delete mode 100644 doc/_templates/page.html delete mode 100644 doc/_templates/projects.html create mode 100644 doc/about.rst delete mode 100644 doc/apidoc/hdlparse.rst delete mode 100644 doc/apidoc/modules.rst create mode 100644 doc/genindex.rst create mode 100644 doc/getting.rst create mode 100644 doc/usage.rst diff --git a/.btd.yml b/.btd.yml new file mode 100644 index 0000000..0f45bcf --- /dev/null +++ b/.btd.yml @@ -0,0 +1,5 @@ +input: doc +output: _build +target: gh-pages +formats: [ html ] +theme: https://codeload.github.com/buildthedocs/sphinx.theme/tar.gz/v1 diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml new file mode 100644 index 0000000..6243c01 --- /dev/null +++ b/.github/workflows/Test.yml @@ -0,0 +1,28 @@ +name: Doc + +on: + push: + schedule: + - cron: '0 0 * * 5' + workflow_dispatch: + +jobs: + + BTD: + name: '📓 Docs' + runs-on: ubuntu-latest + steps: + + - name: '🧰 Checkout' + uses: actions/checkout@v2 + + - name: '📓 BuildTheDocs (BTD)' + uses: buildthedocs/btd@v0 + with: + token: ${{ github.token }} + + - name: '📤 Upload artifact: HTML' + uses: actions/upload-artifact@master + with: + name: doc + path: doc/_build/html diff --git a/.gitignore b/.gitignore index 10e04b3..fe021b6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ build/ .idea/ +/doc/_build +/doc/_theme diff --git a/README.rst b/README.rst index 58dccfe..bc07969 100644 --- a/README.rst +++ b/README.rst @@ -1,34 +1,43 @@ - -======== Hdlparse -======== +######## -Hdlparse is a simple package implementing a rudimentary parser for VHDL and Verilog. It is not capable of fully parsing the entire language. Rather, it is meant to extract enough key information from a source file to create generated documentation. +Hdlparse is a simple package implementing a rudimentary parser for VHDL and Verilog. +It is not capable of fully parsing the entire language. +Rather, it is meant to extract enough key information from a source file to create generated documentation. -This library is forked from `kevinpt `_ via `zhelnio `_. The aim of this fork is to provide some bug fixes and additional features to zhelnio's version of Hdlparse. A list of changes is included at the bottom of this README. +This library is used by the `Symbolator `_ diagram generator. -For VHDL this library can extract component, subprogram, type, subtype, and constant declarations from a package. For Verilog it can extract module declarations (both 1995 and 2001 syntax). +For VHDL this library can extract component, subprogram, type, subtype, and constant declarations from a package. +For Verilog it can extract module declarations (both 1995 and 2001 syntax). Requirements ------------ -Hdlparse requires Python 3.x and no additional libraries. This version of Hdlparse is not compatible with Python2. +Hdlparse requires Python3 and no additional libraries. This version of Hdlparse is not compatible with Python2. Download -------- -You can access the Hdlparse Git repository from `Github -`_. You can install direct from PyPI with the "pip" -command if you have it available. +You can access the Hdlparse Git repository from `Github `_. +You can install direct from PyPI with the "pip" command if you have it available. + Installation ------------ -Hdlparse is a Python library. You must have Python installed first to use it. Most modern Linux distributions and OS/X have it available by default. There are a number of options available for Windows. If you don't already have a favorite, I recommend getting one of the `"full-stack" Python distros `_ that are geared toward scientific computing such as Anaconda or Python(x,y). +Hdlparse is a Python library. +You must have Python installed first to use it. +Most modern Linux distributions and OS/X have it available by default. +There are a number of options available for Windows. +If you don't already have a favorite, I recommend getting one of the +`"full-stack" Python distros `_ +that are geared toward scientific computing such as Anaconda or Python(x,y). -You need to have the Python setuptools installed first. If your OS has a package manager, it may be preferable to install setuptools through that tool. Otherwise you can use Pip: +You need to have the Python setuptools installed first. +If your OS has a package manager, it may be preferable to install setuptools through that tool. +Otherwise you can use Pip: .. code-block:: sh @@ -40,7 +49,9 @@ The easiest way to install Hdlparse is from `PyPI pip install --upgrade hdlparse -This will download and install the latest release, upgrading if you already have it installed. If you don't have ``pip`` you may have the ``easy_install`` command available which can be used to install ``pip`` on your system: +This will download and install the latest release, upgrading if you already have it installed. +If you don't have ``pip`` you may have the ``easy_install`` command available which can be used to install ``pip`` on +your system: .. code-block:: sh @@ -51,9 +62,10 @@ You can also use ``pip`` to get the latest development code from Github: .. code-block:: sh - > pip install --upgrade https://github.com/vvvverre/hdlparse/tarball/master + > pip install --upgrade https://github.com/hdl/pyHDLParser/tarball/main -If you manually downloaded a source package or created a clone with Git you can install with the following command run from the base Hdlparse directory: +If you manually downloaded a source package or created a clone with Git you can install with the following command run +from the base Hdlparse directory: .. code-block:: sh @@ -68,7 +80,7 @@ Documentation ------------- The full documentation is available online at the `main Hdlparse site -`_. +`_. Changes diff --git a/doc/.nojekyll b/doc/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/doc/Makefile b/doc/Makefile index e8dd567..9488e57 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,20 +1,37 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. +# Sphinx options. SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = HdlParse -SOURCEDIR = . +SPHINXBUILD = sphinx-build +SPHINXPROJ = pyHDLParser +PAPER = BUILDDIR = _build -# Put it first so that "make" without argument is like "make help". +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees -T -D language=en $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +#--- + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + +#--- + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + +#--- + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + +#--- + .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/_static/Kreon-Bold.woff2 b/doc/_static/Kreon-Bold.woff2 deleted file mode 100644 index 40c6702bd63bb009c86090e9584ea5e40f21853a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13808 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 diff --git a/doc/_static/Kreon-Regular.woff2 b/doc/_static/Kreon-Regular.woff2 deleted file mode 100644 index ff2a7dd90f53cd030e4bed9150ed18f6c174e393..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13616 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 -
- Git clone URL: -
- -
-
-
- diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html deleted file mode 100644 index 56d9ec7..0000000 --- a/doc/_templates/layout.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "!layout.html" %} - -{% block extrahead %} -{{ super() }} - - - - - - -{% endblock %} - - diff --git a/doc/_templates/page.html b/doc/_templates/page.html deleted file mode 100644 index 1823180..0000000 --- a/doc/_templates/page.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "!page.html" %} - -{% set css_files = css_files + ["_static/project.css", "_static/tty/tty-player.min.css"] %} - - diff --git a/doc/_templates/projects.html b/doc/_templates/projects.html deleted file mode 100644 index 5e35866..0000000 --- a/doc/_templates/projects.html +++ /dev/null @@ -1,77 +0,0 @@ -

Other projects

- -
-

-{% if project|lower != "opbasm" %}Opbasm
{% endif %} -{% if project|lower != "ripyl" %}Ripyl
{% endif %} -{% if project|lower != "vertcl" %}Vertcl
{% endif %} -{% if project|lower != "vhdl-extras" %}Vhdl-extras
{% endif %} -{% if project|lower != "lecroy colorizer" %}Lecroy-colorizer{% endif %} -

-
- - diff --git a/doc/about.rst b/doc/about.rst new file mode 100644 index 0000000..f175b42 --- /dev/null +++ b/doc/about.rst @@ -0,0 +1,20 @@ +About +##### + +Licensing +--------- + +pyHDLParser is distributed under the terms of the MIT license. + +Other projects +-------------- + +* `Evfs `__ +* `Guidoc `__ +* `LeCroy-colorizer `__ +* `Opbasm `__ +* `Ripyl `__ +* `Symbolator `__ +* `Syntrax `__ +* `VerTcl `__ +* `VHDL-extras `__ diff --git a/doc/apidoc/hdlparse.rst b/doc/apidoc/hdlparse.rst deleted file mode 100644 index 2b9e1d4..0000000 --- a/doc/apidoc/hdlparse.rst +++ /dev/null @@ -1,38 +0,0 @@ -hdlparse package -================ - -Submodules ----------- - -hdlparse\.minilexer module --------------------------- - -.. automodule:: hdlparse.minilexer - :members: - :undoc-members: - :show-inheritance: - -hdlparse\.verilog\_parser module --------------------------------- - -.. automodule:: hdlparse.verilog_parser - :members: - :undoc-members: - :show-inheritance: - -hdlparse\.vhdl\_parser module ------------------------------ - -.. automodule:: hdlparse.vhdl_parser - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: hdlparse - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/apidoc/modules.rst b/doc/apidoc/modules.rst deleted file mode 100644 index 47adae8..0000000 --- a/doc/apidoc/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -hdlparse -======== - -.. toctree:: - :maxdepth: 4 - - hdlparse diff --git a/doc/conf.py b/doc/conf.py index 10af14c..b85700b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,201 +1,111 @@ # -*- coding: utf-8 -*- -# -# HdlParse documentation build configuration file, created by -# sphinx-quickstart on Sun Oct 15 14:19:42 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# + +from json import loads +from pathlib import Path + import os import sys -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath("..")) -# -- General configuration ------------------------------------------------ -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' +# -- General configuration ------------------------------------------------ -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.githubpages', 'sphinx.ext.autodoc', 'sphinx.ext.napoleon'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon"] -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = [".rst"] -# The master toctree document. -master_doc = 'index' +master_doc = "index" -# General information about the project. -project = u'Hdlparse' -copyright = u'2017, Kevin Thibedeau' -author = u'Kevin Thibedeau' +project = u"pyHDLParser" +copyright = u"2017, Kevin Thibedeau and contributors" +author = u"Kevin Thibedeau" -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# def get_package_version(verfile): - '''Scan the script for the version string''' - version = None - with open(verfile) as fh: - try: - version = [line.split('=')[1].strip().strip("'") for line in fh if \ - line.startswith('__version__')][0] - except IndexError: - pass - return version - -# The short X.Y version. -version = get_package_version('../hdlparse/minilexer.py') -# The full version, including alpha/beta/rc tags. + """Scan the script for the version string""" + version = None + with open(verfile) as fh: + try: + version = [ + line.split("=")[1].strip().strip("'") + for line in fh + if line.startswith("__version__") + ][0] + except IndexError: + pass + return version + + +version = get_package_version("../hdlparse/minilexer.py") release = version -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. language = None -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "_theme", "Thumbs.db", ".DS_Store"] -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "stata-dark" -# If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' +html_theme_path = ["."] +html_theme = "_theme" -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} html_theme_options = { - 'description': 'HDL parsing library', - 'show_powered_by': False, - 'logo_text_align': 'center', - 'font_family': 'Verdana, Geneva, sans-serif', - 'github_user': 'kevinpt', - 'github_repo': 'hdlparse', - 'github_button': True -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'about.html', - 'relations.html', # needs 'show_related': True theme option to display - 'localtoc.html', - 'projects.html', - 'searchbox.html' - ], - - 'index': [ - 'about.html', - 'download.html', - 'relations.html', - 'localtoc.html', - 'projects.html', - 'searchbox.html' - ] + "logo_only": False, + "home_breadcrumbs": True, + "vcs_pageview_mode": "blob", } +html_context = {} -# -- Options for HTMLHelp output ------------------------------------------ +ctx = Path(__file__).resolve().parent / "context.json" +if ctx.is_file(): + html_context.update(loads(ctx.open("r").read())) -# Output file base name for HTML help builder. -htmlhelp_basename = 'HdlParsedoc' +#html_static_path = ["_static"] -# -- Options for LaTeX output --------------------------------------------- +# -- Options for HTMLHelp output ------------------------------------------ -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', +htmlhelp_basename = "pyHDLParserDoc" - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', +# -- Options for LaTeX output --------------------------------------------- - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} +latex_elements = {} -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'HdlParse.tex', u'HdlParse Documentation', - u'Kevin Thibedeau', 'manual'), + ( + master_doc, + "pyHDLParser.tex", + u"pyHDLParser Documentation", + u"Kevin Thibedeau", + "manual", + ), ] # -- Options for manual page output --------------------------------------- -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'hdlparse', u'HdlParse Documentation', - [author], 1) -] +man_pages = [(master_doc, "hdlparse", u"pyHDLParser Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'HdlParse', u'HdlParse Documentation', - author, 'HdlParse', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "pyHDLParser", + u"pyHDLParser Documentation", + author, + "pyHDLParser", + "One line description of project.", + "Miscellaneous", + ), ] - - - diff --git a/doc/genindex.rst b/doc/genindex.rst new file mode 100644 index 0000000..d4fc2f4 --- /dev/null +++ b/doc/genindex.rst @@ -0,0 +1,4 @@ +.. # This file is a placeholder and will be replaced + +Index +##### diff --git a/doc/getting.rst b/doc/getting.rst new file mode 100644 index 0000000..53149d5 --- /dev/null +++ b/doc/getting.rst @@ -0,0 +1,65 @@ +Getting +####### + +Requirements +------------ + +pyHDLParser requires either Python 2.7 or Python 3.x and no additional libraries. + +The installation script depends on setuptools. The source is written in +Python 2.7 syntax but will convert cleanly to Python 3 when the installer +passes it through ``2to3``. + +Download +-------- + +You can access the pyHDLParser Git repository from `Github `_. +You can install direct from PyPI with the ``pip`` command if you have it available. + +Installation +------------ + +pyHDLParser is a Python library. +You must have Python installed first to use it. +Most modern Linux distributions and OS/X have it available by default. +There are a number of options available for Windows. +If you don't already have a favorite, I recommend getting one of the `"full-stack" Python distros `_ that are geared toward scientific computing such as Anaconda or Python(x,y). + +You need to have the Python setuptools installed first. +If your OS has a package manager, it may be preferable to install setuptools through that tool. +Otherwise you can use Pip: + +.. code-block:: sh + + > pip install setuptools + +The easiest way to install pyHDLParser is from `PyPI `_. + +.. code-block:: sh + + > pip install --upgrade hdlparse + +This will download and install the latest release, upgrading if you already have it installed. +If you don't have ``pip`` you may have the ``easy_install`` command available which can be used to install ``pip`` on +your system: + +.. code-block:: sh + + > easy_install pip + +You can also use ``pip`` to get the latest development code from Github: + +.. code-block:: sh + + > pip install --upgrade https://github.com/hdl/pyHDLParser/tarball/master + +If you manually downloaded a source package or created a clone with Git you can install with the following command run +from the base pyHDLParser directory: + +.. code-block:: sh + + > python setup.py install + +On Linux systems you may need to install with root privileges using the *sudo* command. + +After a successful install the pyHDLParser library will be available. diff --git a/doc/index.rst b/doc/index.rst index ed57c68..8b9fc52 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,274 +1,18 @@ -.. HdlParse documentation master file, created by - sphinx-quickstart on Sun Oct 15 14:19:42 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +pyHDLParser +########### -======== -Hdlparse -======== +pyHDLParser is a simple package implementing a rudimentary parser for VHDL and Verilog. +It is not capable of fully parsing the entire language. +Rather, it is meant to extract enough key information from a source file to create generated documentation. -Hdlparse is a simple package implementing a rudimentary parser for VHDL and Verilog. It is not capable of fully parsing the entire language. Rather, it is meant to extract enough key information from a source file to create generated documentation. - -This library is used by the `Symbolator `_ diagram generator. - -For VHDL this library can extract component, subprogram, type, subtype, and constant declarations from a package. For Verilog it can extract module declarations (both 1995 and 2001 syntax). - - -Requirements ------------- - -Hdlparse requires either Python 2.7 or Python 3.x and no additional libraries. - -The installation script depends on setuptools. The source is written in -Python 2.7 syntax but will convert cleanly to Python 3 when the installer -passes it through ``2to3``. - - -Licensing ---------- - -Opbasm and the included VHDL source is licensed for free commercial and non-commercial use under the terms of the MIT license. - - -Download --------- - -You can access the Hdlparse Git repository from `Github -`_. You can install direct from PyPI with the ``pip`` -command if you have it available. - -Installation ------------- - -Hdlparse is a Python library. You must have Python installed first to use it. Most modern Linux distributions and OS/X have it available by default. There are a number of options available for Windows. If you don't already have a favorite, I recommend getting one of the `"full-stack" Python distros `_ that are geared toward scientific computing such as Anaconda or Python(x,y). - -You need to have the Python setuptools installed first. If your OS has a package manager, it may be preferable to install setuptools through that tool. Otherwise you can use Pip: - -.. code-block:: sh - - > pip install setuptools - -The easiest way to install Hdlparse is from `PyPI `_. - -.. code-block:: sh - - > pip install --upgrade hdlparse - -This will download and install the latest release, upgrading if you already have it installed. If you don't have ``pip`` you may have the ``easy_install`` command available which can be used to install ``pip`` on your system: - -.. code-block:: sh - - > easy_install pip - - -You can also use ``pip`` to get the latest development code from Github: - -.. code-block:: sh - - > pip install --upgrade https://github.com/kevinpt/hdlparse/tarball/master - -If you manually downloaded a source package or created a clone with Git you can install with the following command run from the base Hdlparse directory: - -.. code-block:: sh - - > python setup.py install - -On Linux systems you may need to install with root privileges using the *sudo* command. - -After a successful install the Hdlparse library will be available. - - -Using Hdlparse --------------- - -The Hdlparse library has two main modules :py:mod:`~hdlparse.vhdl_parser` and :py:mod:`~hdlparse.verilog_parser`. You import one or both of them as needed. - -.. code-block:: python - - import hdlparse.vhdl_parser as vhdl - import hdlparse.verilog_parser as vlog - -Within each module are extractor classes :py:class:`~hdlparse.vhdl_parser.VhdlExtractor` and :py:class:`~hdlparse.verilog_parser.VerilogExtractor` that are the central mechanisms for using Hdlparse. - -.. code-block:: python - - vhdl_ex = vhdl.VhdlExtractor() - vlog_ex = vlog.VerilogExtractor() - - -VHDL -~~~~ - -The VHDL parser can extract a variety of different objects from sourec code. It can be used to access package definitions and component declarations,type and subtype definitions, functions, and procedures found within a package. It will not process entity declarations or nested subprograms and types. - -Extraction proceeds as follows: - -.. code-block:: python - - with io.open(fname, 'rt', encoding='latin-1') as fh: - code = fh.read() - vhdl_objs = vhdl_ex.extract_objects_from_source(code) - - vhdl_objs = vhdl_ex.extract_objects(fname) - -These will extract a list of all supported object types. The result is a list of objects subclassed from :py:class:`~hdlparse.vhdl_parser.VhdlObject`. You can pass an optional subclass of ``VhdlObject`` to filter the results for just that type. Repeated calls are more efficient when using :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.extract_objects` which maintains a cache of all previously parsed objects in the extractor. - -.. code-block:: vhdl - - package example is - component demo is - generic ( - GENERIC1: boolean := false; - GENERIC2: integer := 100 - ); - port ( - a, b : in std_ulogic := '1'; - c, d : out std_ulogic_vector(7 downto 0); - e, f : inout unsigned(7 downto 0) - ); - end component; - end package; - -Each port and generic is an instance of :py:class:`~hdlparse.vhdl_parser.VhdlParameter` containing the name, mode (input, output, inout), and type. - -.. code-block:: python - - import hdlparse.vhdl_parser as vhdl - from hdlparse.vhdl_parser import VhdlComponent - - vhdl_ex = vhdl.VhdlExtractor() - vhdl_comps = vhdl_ex.extract_objects('example.vhdl', VhdlComponent) - - for c in vhdl_comps: - print('Component "{}":'.format(c.name)) - - print(' Generics:') - for p in c.generics: - print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type)) - - print(' Ports:') - for p in c.ports: - print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type )) - -When run against the example code produces the following: - -.. code-block: console - - Component "demo": - Generics: - GENERIC1 in boolean - GENERIC2 in integer - Ports: - a in std_ulogic - b in std_ulogic - c out std_ulogic_vector(7 downto 0) - d out std_ulogic_vector(7 downto 0) - e inout unsigned(7 downto 0) - f inout unsigned(7 downto 0) - - -VHDL arrays -~~~~~~~~~~~ - -It can be useful to know which data types are an array. The :py:class:`~hdlparse.vhdl_parser.VhdlExtractor` class will keep track of all visited array type definitions it sees. The :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.is_array` method lets you query the internal list to check if a type is for an array. All IEEE standard array types are supported by default. Any subtypes derived from an array type will also be considered as arrays. - -.. code-block:: python - - import hdlparse.vhdl_parser as vhdl - - vhdl_ex = vhdl.VhdlExtractor() - - code = ''' - package foobar is - type custom_array is array(integer range <>) of boolean; - subtype custom_subtype is custom_array(1 to 10); - end package; - ''' - vhdl_comps = vhdl_ex.extract_objects(code) - - # These all return true: - print(vhdl_ex.is_array('unsigned')) - print(vhdl_ex.is_array('custom_array')) - print(vhdl_ex.is_array('custom_subtype')) - -Parsed array data can be saved to a file with :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.save_array_types` and restored with :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.load_array_types`. This lets you parse one set of files for type definitions and use the saved info for parsing other code at a different time. - - -Verilog -~~~~~~~ - -The Verilog parser is only able to extract module definitions with a port and optional parameter list. Verilog modules are extracted using the :py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects` and :py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects_from_source` methods. The latter is used when you have the code in a string. The former when you want to read the Veirlog source from a file. When parsing a file, a cache of objects is maintained so you can repeatedly call :py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects` without reparsing the file. - -.. code-block:: python - - with open(fname, 'rt') as fh: - code = fh.read() - vlog_mods = vlog_ex.extract_objects_from_source(code) - - vlog_mods = vlog_ex.extract_objects(fname) - -The result is a list of extracted :py:class:`~hdlparse.verilog_parser.VerilogModule` objects. Each instance of this class has ``name``, ``generics``, and ``ports`` attributes. The ``name`` attribute is the name of the module. The ``generics`` attribute is a list of extracted parameters and ``ports`` is a list of the ports on the module. - -.. code-block:: verilog - - module newstyle // This is a new style module def - #(parameter real foo = 8, bar=1, baz=2, - parameter signed [7:0] zip = 100) - ( - input x, x2, inout y, y2_long_output, - output wire [4:1] z, z2 - ); - endmodule - -Each port and generic is an instance of :py:class:`~hdlparse.verilog_parser.VerilogParameter` containing the name, mode (input, output, inout), and type. - -.. code-block:: python - - import hdlparse.verilog_parser as vlog - - vlog_ex = vlog.VerilogExtractor() - vlog_mods = vlog_ex.extract_objects_from_source('example.v') - - for m in vlog_mods: - print('Module "{}":'.format(m.name)) - - print(' Parameters:') - for p in m.generics: - print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type)) - - print(' Ports:') - for p in m.ports: - print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type)) - - -When run against the example code produces the following: - -.. code-block:: console - - Module "newstyle": - Parameters: - foo in real - bar in real - baz in real - zip in signed [7:0] - Ports: - x input - x2 input - y inout - y2_long_output inout - z output wire [4:1] - z2 output wire [4:1] +This library is used by the `Symbolator `_ diagram generator. +For VHDL this library can extract component, subprogram, type, subtype, and constant declarations from a package. +For Verilog it can extract module declarations (both 1995 and 2001 syntax). .. toctree:: - :hidden: - :maxdepth: 2 - - apidoc/modules - - -Indices and tables ------------------- -* :ref:`genindex` -* :ref:`search` + about + getting + usage + genindex diff --git a/doc/usage.rst b/doc/usage.rst new file mode 100644 index 0000000..7458d6e --- /dev/null +++ b/doc/usage.rst @@ -0,0 +1,241 @@ +Usage +##### + +The pyHDLParser library has two main modules :py:mod:`~hdlparse.vhdl_parser` and :py:mod:`~hdlparse.verilog_parser`. +You import one or both of them as needed. + +.. code-block:: python + + import hdlparse.vhdl_parser as vhdl + import hdlparse.verilog_parser as vlog + +Within each module are extractor classes :py:class:`~hdlparse.vhdl_parser.VhdlExtractor` and +:py:class:`~hdlparse.verilog_parser.VerilogExtractor` that are the central mechanisms for using pyHDLParser. + +.. code-block:: python + + vhdl_ex = vhdl.VhdlExtractor() + vlog_ex = vlog.VerilogExtractor() + + +VHDL +==== + +The VHDL parser can extract a variety of different objects from sourec code. +It can be used to access package definitions and component declarations,type and subtype definitions, functions, and +procedures found within a package. +It will not process entity declarations or nested subprograms and types. + +Extraction proceeds as follows: + +.. code-block:: python + + with io.open(fname, 'rt', encoding='latin-1') as fh: + code = fh.read() + vhdl_objs = vhdl_ex.extract_objects_from_source(code) + + vhdl_objs = vhdl_ex.extract_objects(fname) + +These will extract a list of all supported object types. +The result is a list of objects subclassed from :py:class:`~hdlparse.vhdl_parser.VhdlObject`. +You can pass an optional subclass of ``VhdlObject`` to filter the results for just that type. +Repeated calls are more efficient when using :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.extract_objects` which +maintains a cache of all previously parsed objects in the extractor. + +.. code-block:: vhdl + + package example is + component demo is + generic ( + GENERIC1: boolean := false; + GENERIC2: integer := 100 + ); + port ( + a, b : in std_ulogic := '1'; + c, d : out std_ulogic_vector(7 downto 0); + e, f : inout unsigned(7 downto 0) + ); + end component; + end package; + +Each port and generic is an instance of :py:class:`~hdlparse.vhdl_parser.VhdlParameter` containing the name, mode +(input, output, inout), and type. + +.. code-block:: python + + import hdlparse.vhdl_parser as vhdl + from hdlparse.vhdl_parser import VhdlComponent + + vhdl_ex = vhdl.VhdlExtractor() + vhdl_comps = vhdl_ex.extract_objects('example.vhdl', VhdlComponent) + + for c in vhdl_comps: + print('Component "{}":'.format(c.name)) + + print(' Generics:') + for p in c.generics: + print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type)) + + print(' Ports:') + for p in c.ports: + print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type )) + +When run against the example code produces the following: + +.. code-block: console + + Component "demo": + Generics: + GENERIC1 in boolean + GENERIC2 in integer + Ports: + a in std_ulogic + b in std_ulogic + c out std_ulogic_vector(7 downto 0) + d out std_ulogic_vector(7 downto 0) + e inout unsigned(7 downto 0) + f inout unsigned(7 downto 0) + + +VHDL arrays +----------- + +It can be useful to know which data types are an array. The :py:class:`~hdlparse.vhdl_parser.VhdlExtractor` class will +keep track of all visited array type definitions it sees. +The :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.is_array` method lets you query the internal list to check if a type +is for an array. +All IEEE standard array types are supported by default. +Any subtypes derived from an array type will also be considered as arrays. + +.. code-block:: python + + import hdlparse.vhdl_parser as vhdl + + vhdl_ex = vhdl.VhdlExtractor() + + code = ''' + package foobar is + type custom_array is array(integer range <>) of boolean; + subtype custom_subtype is custom_array(1 to 10); + end package; + ''' + vhdl_comps = vhdl_ex.extract_objects(code) + + # These all return true: + print(vhdl_ex.is_array('unsigned')) + print(vhdl_ex.is_array('custom_array')) + print(vhdl_ex.is_array('custom_subtype')) + +Parsed array data can be saved to a file with :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.save_array_types` and +restored with :py:meth:`~hdlparse.vhdl_parser.VhdlExtractor.load_array_types`. +This lets you parse one set of files for type definitions and use the saved info for parsing other code at a different +time. + + +Verilog +======= + +The Verilog parser is only able to extract module definitions with a port and optional parameter list. +Verilog modules are extracted using the :py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects` and +:py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects_from_source` methods. +The latter is used when you have the code in a string. +The former when you want to read the Veirlog source from a file. +When parsing a file, a cache of objects is maintained so you can repeatedly call +:py:meth:`~hdlparse.verilog_parser.VerilogExtractor.extract_objects` without reparsing the file. + +.. code-block:: python + + with open(fname, 'rt') as fh: + code = fh.read() + vlog_mods = vlog_ex.extract_objects_from_source(code) + + vlog_mods = vlog_ex.extract_objects(fname) + +The result is a list of extracted :py:class:`~hdlparse.verilog_parser.VerilogModule` objects. +Each instance of this class has ``name``, ``generics``, and ``ports`` attributes. +The ``name`` attribute is the name of the module. +The ``generics`` attribute is a list of extracted parameters and ``ports`` is a list of the ports on the module. + +.. code-block:: verilog + + module newstyle // This is a new style module def + #(parameter real foo = 8, bar=1, baz=2, + parameter signed [7:0] zip = 100) + ( + input x, x2, inout y, y2_long_output, + output wire [4:1] z, z2 + ); + endmodule + +Each port and generic is an instance of :py:class:`~hdlparse.verilog_parser.VerilogParameter` containing the name, mode +(input, output, inout), and type. + +.. code-block:: python + + import hdlparse.verilog_parser as vlog + + vlog_ex = vlog.VerilogExtractor() + vlog_mods = vlog_ex.extract_objects_from_source('example.v') + + for m in vlog_mods: + print('Module "{}":'.format(m.name)) + + print(' Parameters:') + for p in m.generics: + print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type)) + + print(' Ports:') + for p in m.ports: + print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type)) + + +When run against the example code produces the following: + +.. code-block:: console + + Module "newstyle": + Parameters: + foo in real + bar in real + baz in real + zip in signed [7:0] + Ports: + x input + x2 input + y inout + y2_long_output inout + z output wire [4:1] + z2 output wire [4:1] + + +Reference +========= + +.. automodule:: hdlparse + :members: + :undoc-members: + :show-inheritance: + +hdlparse\.minilexer +------------------- + +.. automodule:: hdlparse.minilexer + :members: + :undoc-members: + :show-inheritance: + +hdlparse\.verilog\_parser +------------------------- + +.. automodule:: hdlparse.verilog_parser + :members: + :undoc-members: + :show-inheritance: + +hdlparse\.vhdl\_parser +---------------------- + +.. automodule:: hdlparse.vhdl_parser + :members: + :undoc-members: + :show-inheritance: From c19e1f01c151e11af990c8bc65c622092f45ceb3 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Fri, 24 Sep 2021 15:44:42 -0500 Subject: [PATCH 2/2] fix documentation bug extract_objects_from_source -> extract_objects --- doc/usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage.rst b/doc/usage.rst index 7458d6e..a051159 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -175,7 +175,7 @@ Each port and generic is an instance of :py:class:`~hdlparse.verilog_parser.Veri import hdlparse.verilog_parser as vlog vlog_ex = vlog.VerilogExtractor() - vlog_mods = vlog_ex.extract_objects_from_source('example.v') + vlog_mods = vlog_ex.extract_objects('example.v') for m in vlog_mods: print('Module "{}":'.format(m.name))