code: static boolean isImmutableValue(Node n) {
      // TODO(johnlenz): rename this function.  It is currently being used
      // in two disjoint cases:
      // 1) We only care about the result of the expression
      //    (in which case NOT here should return true)
      // 2) We care that expression is a side-effect free and can't
      //    be side-effected by other expressions.
      // This should only be used to say the value is immutable and
      // hasSideEffects and canBeSideEffected should be used for the other case.
  
      switch (n.getToken()) {
        case STRING:
        case NUMBER:
        case NULL:
        case TRUE:
        case FALSE:
          return true;
        case CAST:
        case NOT:
        case VOID:
        case NEG:
          return isImmutableValue(n.getFirstChild());
        case NAME:
          String name = n.getString();
          // We assume here that programs don't change the value of the keyword
          // undefined to something other than the value undefined.
          return "undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name);
        case TEMPLATELIT:
          for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {
            if (child.isTemplateLitSub()) {
              if (!isImmutableValue(child.getFirstChild())) {
                return false;
              }
            }
          }
          return true;
        default:
          // TODO(yitingwang) There are probably other tokens that shouldn't get to the default branch
          checkArgument(!n.isTemplateLitString());
          break;
      }
  
      return false;
    }
docs: Returns true if this is an immutable value.