docs: public static CcgUnaryRule parseFrom(String line) {
      String[] chunks = new CsvParser(CsvParser.DEFAULT_SEPARATOR,
          CsvParser.DEFAULT_QUOTE, CsvParser.NULL_ESCAPE).parseLine(line.trim());
      Preconditions.checkArgument(chunks.length >= 1, "Illegal unary rule string: %s", line);
  
      String[] syntacticParts = chunks[0].split(" ");
      Preconditions.checkArgument(syntacticParts.length == 2, "Illegal unary rule string: %s", line);
      HeadedSyntacticCategory inputSyntax = HeadedSyntacticCategory.parseFrom(syntacticParts[0]);
      HeadedSyntacticCategory returnSyntax = HeadedSyntacticCategory.parseFrom(syntacticParts[1]);
  
      // Ensure that the return syntactic type is in canonical form.
      HeadedSyntacticCategory returnCanonical = returnSyntax.getCanonicalForm();
      int[] originalToCanonical = returnSyntax.unifyVariables(returnSyntax.getUniqueVariables(), returnCanonical, new int[0]);
  
      int[] inputVars = inputSyntax.getUniqueVariables();
      int[] inputRelabeling = new int[inputVars.length];
      int[] returnOriginalVars = returnSyntax.getUniqueVariables();
      int nextUnassignedVar = Ints.max(returnCanonical.getUniqueVariables()) + 1;
      for (int i = 0; i < inputVars.length; i++) {
        int index = Ints.indexOf(returnOriginalVars, inputVars[i]);
        if (index != -1) {
          inputRelabeling[i] = originalToCanonical[index];
        } else {
          inputRelabeling[i] = nextUnassignedVar;
          nextUnassignedVar++;
        }
      }
      HeadedSyntacticCategory relabeledInput = inputSyntax.relabelVariables(inputVars, inputRelabeling);
  
      Expression2 logicalForm = null;
      if (chunks.length >= 2 && chunks[1].trim().length() > 0) {
        logicalForm = ExpressionParser.expression2().parse(chunks[1]);
      }
  
      if (chunks.length >= 3) {
        throw new UnsupportedOperationException(
            "Using unfilled dependencies with unary CCG rules is not yet implemented");
        /*
         * String[] newDeps = chunks[4].split(" ");
         * Preconditions.checkArgument(newDeps.length == 3); long
         * subjectNum = Long.parseLong(newDeps[0].substring(1)); long
         * argNum = Long.parseLong(newDeps[1]); long objectNum =
         * Long.parseLong(newDeps[2].substring(1)); unfilledDeps = new
         * long[1];
         * 
         * unfilledDeps[0] =
         * CcgParser.marshalUnfilledDependency(objectNum, argNum,
         * subjectNum, 0, 0);
         */
      }
      return new CcgUnaryRule(relabeledInput, returnCanonical, logicalForm);
    }