private ASMOclAny exp(StackFrame frame, ASMTuple args) throws IOException {
    ASMOclAny ret = null;
    Token t = null;

    t = next();
    if (t.type == Token.LPAREN) {
      ret = exp(frame, args);
      match(Token.RPAREN);
      return ret;
    } else if ((t.type == Token.STRING) || (t.type == Token.INT)) {
      ret = convValue(t);
    } else {
      unread(t);
      ret = simpleExp(frame, args);
    }
    t = next();
    if (t.type == Token.PLUS) {
      ASMOclAny right = exp(frame, args);
      if (right == null) {
        ret = null;
      } else if (ret instanceof ASMInteger) {
        ret = ASMInteger.operatorPlus(frame, (ASMInteger) ret, (ASMInteger) right);
      } else if (ret instanceof ASMString) {
        if (right instanceof ASMString) {
          ret = ASMString.operatorPlus(frame, (ASMString) ret, (ASMString) right);
        } else {
          ret = ASMString.operatorPlus(frame, (ASMString) ret, new ASMString(right.toString()));
        }
      } else {
        System.out.println("ERROR: could not add type " + ASMOclAny.oclType(frame, ret) + ".");
      }
    } else {
      unread(t);
    }

    return ret;
  }
  private ASMOclAny simpleExp(StackFrame frame, ASMTuple args) throws IOException {
    Token t = null;
    ASMOclAny ret = null;

    t = match(Token.IDENT);
    ret = args.get(frame, t.value);

    boolean done = false;
    do {
      if (debug)
        System.out.println(
            "\tcontext = " + ret + ((ret != null) ? " : " + ASMOclAny.oclType(frame, ret) : ""));
      t = next();
      ASMModelElement ame = null;
      ASMSequence col = null;
      ASMOclAny value = null;
      switch (t.type) {
        case Token.EOF:
          done = true;
          break;
        case Token.DOT:
          t = next();

          if ((t.type != Token.IDENT) && (t.type != Token.STRING)) error(t);

          ret = toCollection(ret);

          col = new ASMSequence();

          Token n = next();
          if (n.type == Token.LPAREN) {
            match(Token.RPAREN);

            for (Iterator i = ((ASMSequence) ret).iterator(); i.hasNext(); ) {
              ASMOclAny o = (ASMOclAny) i.next();
              Operation oper = ((ASMExecEnv) frame.getExecEnv()).getOperation(o.getType(), t.value);

              if (oper != null) {
                ASMOclAny v = oper.exec(frame.enterFrame(oper, Arrays.asList(new Object[] {o})));
                col.add(v);
              } else {
                frame.printStackTrace(
                    "ERROR: could not find operation "
                        + t.value
                        + " on "
                        + o.getType()
                        + " having supertypes: "
                        + o.getType().getSupertypes());
              }
            }
          } else {
            unread(n);

            for (Iterator i = ((ASMSequence) ret).iterator(); i.hasNext(); ) {
              ame = (ASMModelElement) i.next();
              if (t.type == Token.IDENT) {
                ASMOclAny v = ame.get(frame, t.value);
                if (!(v instanceof ASMOclUndefined)) col.add(v);
              } else col.add(new ASMString(t.value));
            }
          }
          ret = ASMSequence.flatten(frame, col);
          break;
        case Token.COMA:
          //					t = next();
          //					if(!(t.type == Token.INT) && !(t.type == Token.STRING)) {
          //						error(t);
          //					}
          if ((ret == null)
              || ((ret instanceof ASMSequence)
                  && (ASMSequence.size(frame, (ASMSequence) ret).getSymbol() == 0))) {
            value = exp(frame, args);
            ret = value;
          }
          break;
        case Token.LSQUARE:
          t = next();

          ret = toCollection(ret);
          col = new ASMSequence();

          if (t.type == Token.ISA) {
            match(Token.LPAREN);
            String mname = match(Token.IDENT).value;
            match(Token.EXCL);
            String mename = match(Token.IDENT).value;
            match(Token.RPAREN);
            String expectedTypeName = mname + "!" + mename;
            for (Iterator i = ((ASMSequence) ret).iterator(); i.hasNext(); ) {
              ame = (ASMModelElement) i.next();
              String typeName = ASMOclAny.oclType(frame, ame).toString();
              if (typeName.equals(expectedTypeName)) {
                col.add(ame);
              }
            }
            ret = col;
          } else if (t.type == Token.INT) {
            unread(t);
            int val = ((ASMInteger) exp(frame, args)).getSymbol();
            if (ASMSequence.size(frame, (ASMSequence) ret).getSymbol() > 0)
              ret =
                  (ASMOclAny)
                      ((ASMSequence) ret).iterator().next(); // TODO: index rather than first
            else ret = null;
          } else {
            if (t.type != Token.IDENT) error(t);
            String propName = t.value;
            match(Token.EQ);
            //						t = next();
            //						if(!(t.type == Token.INT) && !(t.type == Token.STRING)) {
            //							error(t);
            //						}
            //						ASMOclAny value = convValue(t);
            value = exp(frame, args);
            for (Iterator i = ((ASMCollection) ret).iterator(); i.hasNext(); ) {
              ame = (ASMModelElement) i.next();
              if (ame.get(frame, propName).equals(value)) {
                col.add(ame);
              }
            }
            ret = col;
          }
          match(Token.RSQUARE);
          break;
        default:
          unread(t);
          done = true;
          break;
      }
    } while (!done);

    if (debug) System.out.println("\tpartial return value = " + ret);
    return ret;
  }