def get_nonterminals(self) -> tuple[(list[NontermSpec], NontermSpec)]:
    if (self._cache_nonterminals is not None):
        return self._cache_nonterminals
    result = []
    startSym: (NontermSpec | None) = None
    for (module, k, v, dirtoks) in self.named_objs:
        if (issubclass(v, Nonterm) and (dirtoks[0] in ['%start', '%nonterm'])):
            (nonterm, is_start) = NontermSpec.from_class(v)
            result.append(nonterm)
            if is_start:
                if (startSym is not None):
                    raise SpecError(('Only one start non-terminal allowed: %s' % v.__doc__))
                startSym = nonterm
    assert (startSym is not None)
    self._cache_nonterminals = (result, startSym)
    return (result, startSym)
def get_nonterminals(self) -> tuple[(list[NontermSpec], NontermSpec)]:
    if (self._cache_nonterminals is not None):
        return self._cache_nonterminals
    result = []
    startSym: (NontermSpec | None) = None
    for (module, k, v, dirtoks) in self.named_objs:
        if (issubclass(v, Nonterm) and (dirtoks[0] in ['%start', '%nonterm'])):
            (nonterm, is_start) = NontermSpec.from_class(v)
            result.append(nonterm)
            if is_start:
                if (startSym is not None):
                    raise SpecError(('Only one start non-terminal allowed: %s' % v.__doc__))
                startSym = nonterm
    assert (startSym is not None)
    self._cache_nonterminals = (result, startSym)
    return (result, startSym)