static bool
RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& op)
{
    if (!c.buffer.append("("))
      return false;

    const char* opStr;
    switch (op.expr()) {
      case Expr::I32Eqz:     opStr = "i32.eqz"; break;
      case Expr::I32Clz:     opStr = "i32.clz"; break;
      case Expr::I32Ctz:     opStr = "i32.ctz"; break;
      case Expr::I32Popcnt:  opStr = "i32.popcnt"; break;
      case Expr::I64Clz:     opStr = "i64.clz"; break;
      case Expr::I64Ctz:     opStr = "i64.ctz"; break;
      case Expr::I64Popcnt:  opStr = "i64.popcnt"; break;
      case Expr::F32Abs:     opStr = "f32.abs"; break;
      case Expr::F32Neg:     opStr = "f32.neg"; break;
      case Expr::F32Ceil:    opStr = "f32.ceil"; break;
      case Expr::F32Floor:   opStr = "f32.floor"; break;
      case Expr::F32Sqrt:    opStr = "f32.sqrt"; break;
      case Expr::F32Trunc:   opStr = "f32.trunc"; break;
      case Expr::F32Nearest: opStr = "f32.nearest"; break;
      case Expr::F64Abs:     opStr = "f64.abs"; break;
      case Expr::F64Neg:     opStr = "f64.neg"; break;
      case Expr::F64Ceil:    opStr = "f64.ceil"; break;
      case Expr::F64Floor:   opStr = "f64.floor"; break;
      case Expr::F64Sqrt:    opStr = "f64.sqrt"; break;
      case Expr::GrowMemory: opStr = "grow_memory"; break;
      default: return false;
    }
    if (!c.buffer.append(opStr, strlen(opStr)))
        return false;

    if (!c.buffer.append(" "))
        return false;

    if (!RenderExpr(c, *op.op()))
        return false;

    return c.buffer.append(")");
}
static bool
RenderUnaryOperator(WasmRenderContext& c, AstUnaryOperator& unary)
{
    if (!RenderExpr(c, *unary.operand()))
        return false;

    if (!RenderIndent(c))
        return false;

    MAP_AST_EXPR(c, unary);
    const char* opStr;
    switch (unary.op()) {
      case Op::I32Eqz:     opStr = "i32.eqz"; break;
      case Op::I32Clz:     opStr = "i32.clz"; break;
      case Op::I32Ctz:     opStr = "i32.ctz"; break;
      case Op::I32Popcnt:  opStr = "i32.popcnt"; break;
      case Op::I64Clz:     opStr = "i64.clz"; break;
      case Op::I64Ctz:     opStr = "i64.ctz"; break;
      case Op::I64Popcnt:  opStr = "i64.popcnt"; break;
      case Op::F32Abs:     opStr = "f32.abs"; break;
      case Op::F32Neg:     opStr = "f32.neg"; break;
      case Op::F32Ceil:    opStr = "f32.ceil"; break;
      case Op::F32Floor:   opStr = "f32.floor"; break;
      case Op::F32Sqrt:    opStr = "f32.sqrt"; break;
      case Op::F32Trunc:   opStr = "f32.trunc"; break;
      case Op::F32Nearest: opStr = "f32.nearest"; break;
      case Op::F64Abs:     opStr = "f64.abs"; break;
      case Op::F64Neg:     opStr = "f64.neg"; break;
      case Op::F64Ceil:    opStr = "f64.ceil"; break;
      case Op::F64Floor:   opStr = "f64.floor"; break;
      case Op::F64Nearest: opStr = "f64.nearest"; break;
      case Op::F64Sqrt:    opStr = "f64.sqrt"; break;
      case Op::F64Trunc:   opStr = "f64.trunc"; break;
      default:               return Fail(c, "unexpected unary operator");
    }

    return c.buffer.append(opStr, strlen(opStr));
}