/**
  * Asserts the given variable name is valid within the given LegalScope. It will be managed by the
  * given FormatManager.
  *
  * <p>If no previous definition for the given variable name was encountered, then the assertion
  * automatically passes, and the given LegalScope and FormatManager are stored as the definition
  * for the given variable name.
  *
  * <p>If a previous FormatManager exists for the given variable name, then this will return true
  * if and only if the given LegalScope is equal to the already stored LegalScope.
  *
  * @param varName The variable name for which the given FormatManager and LegalScope is being
  *     asserted as valid
  * @param legalScope The asserted LegalScope for the given variable name
  * @param formatManager The FormatManager for the given variable
  * @return true if the assertion of this being a valid LegalScope for the given variable
  *     FormatManager and name passes; false otherwise
  * @throws IllegalArgumentException if any argument is null of if the variable name is otherwise
  *     illegal (is empty or starts/ends with whitespace)
  */
 public boolean assertLegalVariableID(
     String varName, LegalScope legalScope, FormatManager<?> formatManager) {
   if (formatManager == null) {
     throw new IllegalArgumentException("FormatManager cannot be null");
   }
   if (legalScope == null) {
     throw new IllegalArgumentException("LegalScope cannot be null");
   }
   VariableID.checkLegalVarName(varName);
   if (!variableDefs.containsKey(varName)) {
     // Can't be a conflict
     addLegalVariable(varName, legalScope, formatManager);
     return true;
   }
   FormatManager<?> currentFormat = variableDefs.get(varName, legalScope);
   if (currentFormat != null) {
     // Asserted Format Already there
     return formatManager.equals(currentFormat);
   }
   // Now, need to check for conflicts
   boolean hasConflict =
       hasParentConflict(varName, legalScope)
           || hasChildConflict(varName, legalScope, formatManager);
   if (!hasConflict) {
     addLegalVariable(varName, legalScope, formatManager);
   }
   return !hasConflict;
 }
 /**
  * Returns a VariableID for the given name that is valid in the given ScopeInstance (or any parent
  * ScopeInstance - recursively).
  */
 private VariableID<?> getVarIDMessaged(
     ScopeInstance scopeInst, String varName, ScopeInstance messageScope) {
   if (scopeInst == null) {
     throw new IllegalArgumentException(
         "Cannot get VariableID "
             + varName
             + " for "
             + messageScope.getLegalScope().getName()
             + " scope");
   }
   VariableID.checkLegalVarName(varName);
   FormatManager<?> formatManager = variableDefs.get(varName, scopeInst.getLegalScope());
   if (formatManager != null) {
     return new VariableID<>(scopeInst, formatManager, varName);
   }
   // Recursively check parent scope
   return getVarIDMessaged(scopeInst.getParentScope(), varName, messageScope);
 }
 /**
  * Returns a non-null set of known LegalScope objects for the given FormatManager and variable
  * name.
  *
  * <p>This is typically used for debugging (e.g. to list potential conflicts)
  *
  * <p>Ownership of the returned set is transferred to the calling object and no reference to it is
  * maintained by VariableLibrary. Changing the returned set will not alter the VariableLibrary.
  *
  * @param varName The Variable name for which the relevant LegalScope objects should be returned
  * @return The Set of LegalScope objects asserted for the given variable name
  * @throws IllegalArgumentException if given variable name is not legal
  */
 public Set<LegalScope> getKnownLegalScopes(String varName) {
   VariableID.checkLegalVarName(varName);
   return variableDefs.getSecondaryKeySet(varName);
 }