# PTSubcircuitDefinition

Represents both an actual `subckt`/`ends` definition *and*, doing double duty, the toplevel netlist itself - what [the parser](dflparser.md)'s `subckt_build` builds into from either of its two seed rules (`TITLE NEWLINE` or `SUBCKT IDENTIFIER (...) NEWLINE`). It inherits from [`PTModel`](ptmodel.md) (reusing its name/parameters storage), and additionally holds a terminal list, a `root_` [`PTBlock`](ptblock.md) for the definition's own top-level content, and a vector of `unique_ptr<PTSubcircuitDefinition>` for subcircuits nested directly inside it.

The toplevel/subcircuit distinction isn't stored as an explicit flag here (contrast the parser's own `isToplevel` on `subckt_build`): `dump()` computes `isToplevel = !modelName_` on the fly - a subcircuit definition is toplevel exactly when its name `Id` is the default-constructed "none" identifier, matching how the toplevel seed rule constructs one with `Id()`. The name-only/name-plus-terminals constructors bind `deviceName_` to the literal `"__hierarchical__"` - a sentinel distinguishing "this master is a subcircuit" from an ordinary device-backed `PTModel`, while reusing the same `device()` accessor either way.

`add(PTSubcircuitDefinition&&)` heap-allocates a fresh target (`new PTSubcircuitDefinition`) and move-assigns into it before storing the `unique_ptr`, rather than `make_unique<PTSubcircuitDefinition>(std::move(subDef))` directly - the default-construct-then-move-assign sequence works with just the class's defaulted move-assignment operator rather than needing a dedicated single-argument move constructor overload. Every other `add(PTModel/PTInstance/PTBehavioral/PTBlockSequence&&)` overload on this class simply forwards into `root_`'s or the base `PTModel`'s own `add()` - so a [`PTBehavioral`](ptbehavioral.md) added to a `PTSubcircuitDefinition` actually lands in its `root_` block, same as one added directly to a `PTBlock`.

Every parse's default (toplevel) `PTSubcircuitDefinition` is owned by [`ParserTables`](parsertables.md).
