protected void validate(ExpressionNode e, Object expC, Object[][] opCs, boolean types) {
    Object toCompare; // comparing types or expressions
    if (types) toCompare = e.get_type();
    else toCompare = e.getClass();

    // top level exp/type must match expC
    if (types) {
      assertTrue(((TypeNode) toCompare).equal_types((TypeNode) (expC)));
    } else assertTrue(toCompare.equals(expC));

    // look at operands
    for (int i = 0; i < opCs.length; i++) {
      // looking at operand [i]
      ExpressionNode currExp = e.child_exp(i);
      for (int j = 0; j < opCs[i].length; j++) {

        toCompare = (types) ? (Object) currExp.get_type() : (Object) currExp.getClass();

        try {
          if (types) {
            assertTrue(((TypeNode) toCompare).equal_types((TypeNode) (opCs[i][j])));
          } else assertTrue(toCompare.equals(opCs[i][j]));

        } catch (AssertionFailedError afe) {
          String actual, expected;
          if (types) {
            actual = ((TypeNode) toCompare).typeId();
            expected = ((TypeNode) opCs[i][j]).typeId();
          } else {
            actual = ((Class) toCompare).getName();
            expected = ((Class) opCs[i][j]).getName();
          }
          d.msg(Debug.COMPILE, "Expecting " + expected + ", got " + actual);
          throw afe;
        }

        if (currExp.childCount() > 0) currExp = currExp.child_exp(0);
        else break;
      }
    }
  }
  protected void doValidate(ExpressionNode e, Expect et, boolean types) {
    Object toCompare; // comparing types or expressions
    if (types) toCompare = e.get_type();
    else toCompare = e.getClass();

    boolean matched = false;
    try {
      // top level exp/type must match expected
      if (types) {
        assertTrue(((TypeNode) toCompare).equal_types((TypeNode) (et.expected)));
      } else assertTrue(toCompare.equals(et.expected));
      matched = true;
      // look at sub expressions
      // subexpression counts must match OR we are testing less than is
      // there
      assertTrue(et.subCount() <= e.childCount());
    } catch (AssertionFailedError afe) {
      if (!matched) {
        String actual, expected;
        if (types) {
          actual = ((TypeNode) toCompare).typeId();
          expected = ((TypeNode) et.expected).typeId();
        } else {
          actual = ((Class) toCompare).getName();
          expected = ((Class) et.expected).getName();
        }
        d.msg(Debug.COMPILE, "Expecting " + expected + ", got " + actual);
      } else {
        d.msg(
            Debug.COMPILE, "Have " + e.childCount() + " subexpressions, expected " + et.subCount());
      }
      throw afe;
    }

    for (int i = 0; i < et.subCount(); i++) {
      ExpressionNode currExp = e.child_exp(i);
      Expect currC = et.sub(i);
      doValidate(currExp, currC, types);
    }
  }