@Override
	public boolean equivalentConstructState(ConstructState state) {
		ConstructState rec = getPureRecursion(state);
		if (rec != null) {
			if (state.getConstructor() == cons) {
				assert children.size() == 1;
				AssemblyResolvedPatterns recRes = (AssemblyResolvedPatterns) children.get(0);
				return recRes.equivalentConstructState(rec);
			}
			return equivalentConstructState(rec);
		}
		if (state.getConstructor() != cons) {
			return false;
		}
		int opCount = cons.getNumOperands();
		for (int opIdx = 0; opIdx < opCount; opIdx++) {
			OperandSymbol opSym = cons.getOperand(opIdx);
			Set<Integer> printed =
				Arrays.stream(cons.getOpsPrintOrder()).boxed().collect(Collectors.toSet());
			if (!(opSym.getDefiningSymbol() instanceof SubtableSymbol)) {
				AssemblyTreeResolver.DBG.println("Operand " + opSym + " is not a sub-table");
				continue;
			}
			if (!printed.contains(opIdx)) {
				AssemblyTreeResolver.DBG.println("Operand " + opSym + " is hidden");
				continue;
			}
			AssemblyResolvedPatterns child = (AssemblyResolvedPatterns) children.get(opIdx);
			ConstructState subState = state.getSubState(opIdx);
			if (!child.equivalentConstructState(subState)) {
				return false;
			}
		}
		return true;
	}
If the construct state is a {@code ^instruction} or other purely-recursive constructor, get
its single child.

@param state the parent state
@return the child state if recursive, or null
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/sem/DefaultAssemblyResolvedPatterns.java