private void addEvaluateRootMethod(IRClass irClass) {
    // Only bother adding in the method if the fragment's root is an IMemberAccessExpression;
    // otherwise the method
    // is already implemented to return null on FragmentInstance
    IExpression expr = maybeUnwrap(_fragment.getExpression());
    if (expr instanceof IMemberAccessExpression) {
      // public abstract Object evaluateRootExpression(IExternalSymbolMap symbols);
      IRSymbol symbolsParam =
          new IRSymbol(SYMBOLS_PARAM_NAME, getDescriptor(IExternalSymbolMap.class), false);

      _context.initBodyContext(false);
      _context.pushScope(true);
      _context.putSymbol(symbolsParam);

      List<IRStatement> statements = new ArrayList<IRStatement>();
      IRExpression returnValue =
          ExpressionTransformer.compile(
              ((IMemberAccessExpression) expr).getRootExpression(), _context);
      if (returnValue.getType().isPrimitive()) {
        returnValue = boxValue(returnValue.getType(), returnValue);
      }
      statements.add(new IRReturnStatement(null, returnValue));

      IRMethodStatement methodStatement =
          new IRMethodStatement(
              new IRStatementList(true, statements),
              "evaluateRootExpression",
              Opcodes.ACC_PUBLIC,
              IRTypeConstants.OBJECT(),
              Collections.singletonList(symbolsParam));

      irClass.addMethod(methodStatement);
    }
  }
  private void addEvaluateMethod(IRClass irClass) {
    // public abstract Object evaluate(IExternalSymbolMap symbols);
    IRSymbol symbolsParam =
        new IRSymbol(SYMBOLS_PARAM_NAME, getDescriptor(IExternalSymbolMap.class), false);

    _context.initBodyContext(false);
    _context.pushScope(true);
    _context.putSymbol(symbolsParam);

    List<IRStatement> statements = new ArrayList<IRStatement>();

    IExpression expression = _fragment.getExpression();
    if (expression instanceof IProgram) {
      Statement mainStatement = (Statement) ((IProgram) expression).getMainStatement();
      statements.add(StatementTransformer.compile(_context, mainStatement));

      // If the program doesn't terminate, then add in an explicit return null at the end.
      // This is likely in the case of a program that doesn't actually return a value
      boolean[] bAbsolute = {false};
      ITerminalStatement terminalStmt =
          mainStatement.getLeastSignificantTerminalStatement(bAbsolute);
      if (!bAbsolute[0]
          || !(terminalStmt instanceof ReturnStatement)
              && !(terminalStmt instanceof ThrowStatement)) {
        statements.add(new IRReturnStatement(null, nullLiteral()));
      }
    } else if (expression.getType().equals(JavaTypes.pVOID())) {
      // If the expression has a void type, such as if it's a method call with no return value, then
      // compile
      // it as a synthetic statement and explicitly insert a return null
      statements.add(new IRSyntheticStatement(ExpressionTransformer.compile(expression, _context)));
      statements.add(new IRReturnStatement(null, nullLiteral()));
    } else {
      // If the expression has a value, just return that (after boxing it, if necessary)
      IRExpression returnValue = ExpressionTransformer.compile(expression, _context);
      if (returnValue.getType().isPrimitive()) {
        returnValue = boxValue(returnValue.getType(), returnValue);
      }
      statements.add(new IRReturnStatement(null, returnValue));
    }

    IRMethodStatement methodStatement =
        new IRMethodStatement(
            new IRStatementList(true, statements),
            "evaluate",
            Opcodes.ACC_PUBLIC,
            IRTypeConstants.OBJECT(),
            Collections.singletonList(symbolsParam));

    irClass.addMethod(methodStatement);
  }