A Pygments lexer for the Accellera Portable Test and Stimulus Standard (PSS), packaged as a plugin. Installing it is the entire configuration step:
pip install pygments-pssAfter that, pss is a language Pygments knows about everywhere it looks — no
conf.py entry, no mkdocs.yml entry, no registration call:
pygmentize -l pss my_test.pss```pss
component pss_top {
action entry {
activity {
do mem_write;
}
}
}
```Targets PSS 3.1 (Draft 19), including annotations, monitors, behavioral coverage and triple-quoted target templates, and lexes earlier revisions unchanged.
Pygments ships no PSS lexer, so every documentation pipeline that shows PSS either renders it as plain text or hand-rolls a lexer. This is that lexer, once, with tests.
Sphinx — nothing to configure; the entry point is enough.
.. code-block:: pss
component pss_top { }MyST/Markdown fences (```pss) work the same way. Options go through
highlight_options:
highlight_options = {"pss": {"builtins": False}}MkDocs — install the package; pymdownx.highlight picks it up. No mkdocs.yml
change is needed beyond whatever highlighting extension you already use.
Command line
pygmentize -l pss -f html -O full,style=friendly -o out.html my_test.pss
pygmentize -S friendly -f html > pygments.css # stylesheet for fragments
pygmentize -l pss -f terminal256 my_test.pss # 256-colour terminalPython
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
print(highlight(source, get_lexer_by_name("pss"), HtmlFormatter()))| Option | Type | Default | Effect |
|---|---|---|---|
docstrings |
bool | True |
Highlight ///, //!, /** */ and /*! */ as Comment.Special. A psstools convention rather than a PSS one; costs nothing for projects that do not use it. |
builtins |
bool | True |
Highlight core-library names (Annex C: std_pkg, executor_pkg, addr_reg_pkg, sync_pkg) as Name.Builtin. |
Two further options — dialect (standard versus pssparser extensions) and
target_lexers (lex a exec body C = """…""" body as C/C++/SystemVerilog) — are
designed but not implemented in this release.
| Construct | Token |
|---|---|
// …, /* … */ |
Comment.Single, Comment.Multiline |
/// …, //! …, /** … */ |
Comment.Special |
compile if / has / assert |
Comment.Preproc |
| Type-declaring and qualifier keywords | Keyword.Declaration |
| Built-in types | Keyword.Type |
true, false, null |
Keyword.Constant |
this, super |
Name.Builtin.Pseudo |
@ann, .field in its parameters |
Name.Decorator, Name.Attribute |
| Declared name after a declaration keyword, and its base type | Name.Class |
package a::b, import a::b::* |
Name.Namespace |
foo( |
Name.Function |
| Core-library names | Name.Builtin |
8'hFF, 0xFF, 0b1010, 0755, 42 |
Number.Hex / Bin / Oct / Integer, by base |
1.5, 2e6 |
Number.Float |
"…" / """…""" |
String.Double / String.Heredoc |
{{expr}} / {% … %} in a template |
String.Interpol / Comment.Preproc, with PSS tokens inside |
Kept short and honest rather than absent:
- Whitespace-separated based literals are not supported. The LRM permits
8'h FF; supporting it costs a lookahead and risks mis-lexing8'hfollowed by an unrelated identifier.8'hFFis the supported form. - An escaped identifier runs to whitespace, so
\net1;includes the semicolon. That is Clause 4.3's rule, not a defect — the terminator is white space and nothing else. Write\net1 ;if you want the semicolon back. - A user-defined name that shadows a core-library name is highlighted as a builtin.
A
RegexLexerhas no scope information. Turn it off withbuiltins=False. numericis not treated as a keyword. It appears inpssparser's token list and in a damaged cell of the LRM's keyword table, but nowhere in the Annex B grammar. Highlighting a non-keyword is a visible error; missing one is mild.- Tool extensions are not keywords:
pyimport,pyobj,from,init,optionarepssparserreservations, not PSS. - Template parameter brackets are not special.
<and>stayOperator; distinguishing them from comparison needs a parser. One consequence: a templated declaration's base type (struct s<type T> : base_s) is not highlighted as a class. - A
typedef's declared name is an ordinaryName, because intypedef bit[3:0] nibble_t;the name comes after an arbitrary type expression.
Python 3.9+ and Pygments 2.14+. No other runtime dependency: no parser, no ANTLR, no compiler.
Apache-2.0. See LICENSE.