Skip to content

syntax ¤

Direct NetlistParse syntax access, preserving symbolic expressions.

Classes:

Name Description
NetlistError

A netlist could not be parsed or resolved without changing its meaning.

Statement

One parsed statement and the library that owns its relative paths.

Functions:

Name Description
children

Return significant children, optionally selecting a syntax kind.

parameters

Return parameter names and their NetlistParse expression nodes.

parse_file

Parse original UTF-8 or legacy Latin-1 model cards and includes.

NetlistError ¤

Bases: ValueError

A netlist could not be parsed or resolved without changing its meaning.

Statement dataclass ¤

Statement(kind: str, node: Any, path: Path)

One parsed statement and the library that owns its relative paths.

children ¤

children(node: Any, kind: str | None = None) -> list[Any]

Return significant children, optionally selecting a syntax kind.

Source code in circulax/netlist_io/syntax.py
def children(node: Any, kind: str | None = None) -> list[Any]:
    """Return significant children, optionally selecting a syntax kind."""
    return [c for c in node.children if not c.is_trivia and (kind is None or c.kind == kind)]

parameters ¤

parameters(node: Any) -> dict[str, Any]

Return parameter names and their NetlistParse expression nodes.

Source code in circulax/netlist_io/syntax.py
def parameters(node: Any) -> dict[str, Any]:
    """Return parameter names and their NetlistParse expression nodes."""
    result = {}
    for p in children(node, "Parameter"):
        parts = children(p)
        name = parts[0].text
        if name in result:
            msg = f"duplicate parameter {name!r}"
            raise NetlistError(msg)
        result[name] = parts[-1]
    return result

parse_file ¤

parse_file(path: Path, dialect: str = 'ngspice') -> list[Statement]

Parse original UTF-8 or legacy Latin-1 model cards and includes.

@tags circulax-simulation

Source code in circulax/netlist_io/syntax.py
def parse_file(path: Path, dialect: str = "ngspice") -> list[Statement]:
    """Parse original UTF-8 or legacy Latin-1 model cards and includes.

    @tags circulax-simulation
    """
    try:
        import netlist_parser
    except ModuleNotFoundError as exc:
        if exc.name != "netlist_parser":
            raise
        msg = (
            "SPICE/Spectre file parsing requires NetlistParse; see "
            "https://gdsfactory.github.io/circulax/waveform_sources/#optional-spicespectre-library-files "
            "for installation instructions."
        )
        raise ImportError(msg) from exc

    data = path.read_bytes()
    try:
        text = data.decode("utf-8")
    except UnicodeDecodeError:
        text = data.decode("latin-1")
    if dialect == "ngspice":
        root = netlist_parser.parse_spice("* Circulax library\n" + text)
    elif dialect == "spectre":
        if not hasattr(netlist_parser, "parse_netlist"):
            msg = (
                "This library requires NetlistParse with the Python parse_netlist binding. "
                "See https://gdsfactory.github.io/circulax/waveform_sources/#optional-spicespectre-library-files "
                "for installation instructions."
            )
            raise ImportError(msg)
        root = netlist_parser.parse_netlist(text, "spectre")
    else:
        msg = f"unsupported dialect {dialect!r}"
        raise NetlistError(msg)
    errors = netlist_parser.errors(root)

    def incomplete(n: Any) -> bool:
        return n.kind == "Incomplete" or any(incomplete(c) for c in n.children)

    if errors or incomplete(root):
        msg = f"{path}: NetlistParse rejected syntax; spans={errors}; source={text[:100]!r}"
        raise NetlistError(msg)
    aliases = {"Parameters": "ParamStatement", "Instance": "SubcktCall", "Include": "IncludeStatement"}
    return [Statement(aliases.get(n.kind, n.kind), n, path) for n in children(root) if n.kind not in {"Title", "Notation"}]