void WhileStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  int labelId = cg.createNewId(ar);
  cg.pushBreakScope(labelId);
  cg.indentBegin("{\n");

  bool e_order = m_condition->preOutputCPP(cg, ar, 0);

  cg.printf("while (");
  if (e_order) {
    cg.printf("true");
  } else {
    m_condition->outputCPP(cg, ar);
  }
  cg.indentBegin(") {\n");
  if (e_order) {
    m_condition->outputCPPBegin(cg, ar);
    cg.printf("if (!(");
    m_condition->outputCPP(cg, ar);
    cg.printf(")) break;\n");
    m_condition->outputCPPEnd(cg, ar);
  }
  cg.printf("LOOP_COUNTER_CHECK(%d);\n", labelId);
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg.printf("continue%d:;\n", labelId, labelId);
  }
  cg.indentEnd("}\n");
  if (cg.findLabelId("break", labelId)) {
    cg.printf("break%d:;\n", labelId);
  }
  cg.indentEnd("}\n");
  cg.popBreakScope();
}
void ForStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg_indentBegin("{\n");

  int e1_order = 0;
  if (m_exp1) {
    if (m_exp1->preOutputCPP(cg, ar, 0)) {
      e1_order = 1;
    } else if (numStringBufs()) {
      e1_order = -1;
    }
  }
  bool e2_order = m_exp2 && m_exp2->preOutputCPP(cg, ar, 0);
  bool e3_order = m_exp3 && m_exp3->preOutputCPP(cg, ar, 0);

  int labelId = cg.createNewLocalId(ar);

  cg.pushBreakScope(e3_order ? labelId | CodeGenerator::InsideSwitch : labelId);

  if (e1_order) {
    m_exp1->outputCPPUnneeded(cg, ar);
    if (e1_order < 0) cg_printf(";\n");
  }
  cppDeclareBufs(cg, ar);
  cg_printf("for (");
  if (m_exp1 && !e1_order && m_exp1->hasEffect()) {
    m_exp1->outputCPPUnneeded(cg, ar);
  }
  cg_printf("; ");
  if (m_exp2 && !e2_order) m_exp2->outputCPP(cg, ar);
  cg_printf("; ");
  if (m_exp3 && !e3_order && m_exp3->hasEffect()) {
    m_exp3->outputCPPUnneeded(cg, ar);
  }
  cg_indentBegin(") {\n");
  if (e2_order) {
    m_exp2->outputCPPBegin(cg, ar);
    cg_printf("if (!(");
    m_exp2->outputCPP(cg, ar);
    cg_printf(")) break;\n");
    m_exp2->outputCPPEnd(cg, ar);
  }
  cg_printf("LOOP_COUNTER_CHECK(%d);\n", labelId);
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  if (e3_order) {
    m_exp3->outputCPPUnneeded(cg, ar);
  }
  cg_indentEnd("}\n");
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cppEndBufs(cg, ar);
  cg_indentEnd("}\n");
  cg.popBreakScope();
}
Exemple #3
0
void DoStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg.indentBegin("{\n");
  int labelId = cg.createNewId(ar);
  cg.pushBreakScope(labelId);

  cg.indentBegin("do {\n");
  cg.printf("LOOP_COUNTER_CHECK(%d);\n", labelId);
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg.printf("continue%d:;\n", labelId);
  }
  cg.indentEnd("} while (");
  m_condition->outputCPP(cg, ar);
  cg.printf(");\n");
  if (cg.findLabelId("break", labelId)) {
    cg.printf("break%d:;\n", labelId);
  }
  cg.indentEnd("}\n");
  cg.popBreakScope();
}
void DoStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg_indentBegin("{\n");
  bool e_order = m_condition->preOutputCPP(cg, ar, 0);

  int labelId = cg.createNewLocalId(shared_from_this());
  cg.pushBreakScope(e_order ? labelId | CodeGenerator::InsideSwitch : labelId);

  cppDeclareBufs(cg, ar);
  cg_indentBegin("do {\n");
  cg_printf("LOOP_COUNTER_CHECK(%d);\n", labelId);
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  if (e_order) {
    m_condition->outputCPPBegin(cg, ar);
    cg_printf("if (!(");
    m_condition->outputCPP(cg, ar);
    cg_printf(")) break;\n");
    m_condition->outputCPPEnd(cg, ar);
  }
  cg_indentEnd("} while (");
  if (e_order) {
    cg_printf("true");
  } else {
    m_condition->outputCPP(cg, ar);
  }
  cg_printf(");\n");
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cppEndBufs(cg, ar);
  cg_indentEnd("}\n");
  cg.popBreakScope();
}
void SwitchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  int labelId = cg.createNewLocalId(shared_from_this());

  bool staticCases = true;
  if (!m_exp->getType()->isInteger()) {
    staticCases = false;
  } else if (m_cases) {
    bool seenDefault = false;
    set<int64> seenNums;
    for (int i = 0; i < m_cases->getCount(); i++) {
      CaseStatementPtr stmt =
        dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
      if (stmt->getCondition()) {
        if (!stmt->isLiteralInteger() || seenDefault) {
          staticCases = false;
          break;
        }

        // detecting duplicate case value
        int64 num = stmt->getLiteralInteger();
        if (seenNums.find(num) != seenNums.end()) {
          staticCases = false;
          break;
        }
        seenNums.insert(num);
      } else {
        seenDefault = true;
      }
    }
  }

  labelId |= CodeGenerator::InsideSwitch;
  if (staticCases) labelId |= CodeGenerator::StaticCases;
  cg.pushBreakScope(labelId, false);
  labelId &= ~CodeGenerator::BreakScopeBitMask;
  cg_indentBegin("{\n");

  string var;
  int varId = -1;

  if (m_exp->preOutputCPP(cg, ar, 0)) {
    varId = cg.createNewLocalId(shared_from_this());
    var = string(Option::SwitchPrefix) + lexical_cast<string>(varId);
    m_exp->getType()->outputCPPDecl(cg, ar, getScope());
    cg_printf(" %s;\n", var.c_str());

    m_exp->outputCPPBegin(cg, ar);
    cg_printf("%s = (", var.c_str());
    m_exp->outputCPP(cg, ar);
    cg_printf(");\n");
    m_exp->outputCPPEnd(cg, ar);
  }

  if (staticCases) {
    cg_printf("switch (");
    if (!var.empty()) {
      cg_printf("%s", var.c_str());
    } else {
      m_exp->outputCPP(cg, ar);
    }
    cg_printf(") {\n");
    if (m_cases) m_cases->outputCPP(cg, ar);
    cg_printf("}\n");
  } else {
    if (var.empty()) {
      varId = cg.createNewLocalId(shared_from_this());
      if (m_exp->hasContext(Expression::LValue) &&
          m_exp->is(Expression::KindOfSimpleVariable)) {
        var = getScope()->getVariables()->getVariableName(
          cg, ar, static_pointer_cast<SimpleVariable>(m_exp)->getName());
      } else {
        var = string(Option::SwitchPrefix) + lexical_cast<string>(varId);
        m_exp->getType()->outputCPPDecl(cg, ar, getScope());
        cg_printf(" %s = (", var.c_str());
        m_exp->outputCPP(cg, ar);
        cg_printf(");\n");
      }
    }

    if (m_cases && m_cases->getCount()) {
      CaseStatementPtr defaultCase;
      int defaultCaseNum = -1;
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        if (stmt->getCondition()) {
          stmt->outputCPPAsIf(cg, ar, varId, var.c_str(), i);
        } else {
          defaultCase = stmt;
          defaultCaseNum = i;
        }
      }
      if (defaultCaseNum != -1) {
        defaultCase->outputCPPAsIf(cg, ar, varId, var.c_str(), defaultCaseNum);
      } else {
        cg_printf("goto break%d;\n", labelId);
        cg.addLabelId("break", labelId);
      }
      cg_printf("\n");
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        stmt->outputCPPByNumber(cg, ar, varId,
                                !stmt->getCondition() && defaultCaseNum != i ?
                                -1 : i);
      }
    }
  }

  // Even though switch's break/continue will never goto these labels, we need
  // them for "break/continue n" inside switches.
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cg_indentEnd("}\n");
  cg.popBreakScope();
}
void ForEachStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg_indentBegin("{\n");
  int labelId = cg.createNewLocalId(shared_from_this());
  cg.pushBreakScope(labelId);

  int mapId = cg.createNewLocalId(shared_from_this());
  bool passTemp = true;
  bool nameSimple = !m_name || m_name->is(Expression::KindOfSimpleVariable);
  bool valueSimple = m_value->is(Expression::KindOfSimpleVariable);

  if (m_ref ||
      !m_array->is(Expression::KindOfSimpleVariable) ||
      m_array->isThis()) {

    if (m_ref) {
      if (!nameSimple) {
        cg_printf("Variant %s%d_n;\n", Option::MapPrefix, mapId);
      }
      if (!valueSimple) {
        cg_printf("Variant %s%d_v;\n", Option::MapPrefix, mapId);
      }
    }
    cg_printf("Variant %s%d", Option::MapPrefix, mapId);
    TypePtr expectedType = m_array->getExpectedType();
    // Clear m_expectedType to avoid type cast (toArray).
    m_array->setExpectedType(TypePtr());
    bool wrap = m_array->preOutputCPP(cg, ar, 0);
    if (wrap) {
      cg_printf(";\n");
      m_array->outputCPPBegin(cg, ar);
      cg_printf("%s%d", Option::MapPrefix, mapId);
    }
    cg_printf(" = ");
    const char *close = ")";
    if (m_ref) {
      m_array->setContext(Expression::NoRefWrapper);
      cg_printf("strongBind(");
    } else {
      close = "";
    }
    m_array->outputCPP(cg, ar);
    cg.printf("%s;\n", close);
    if (m_ref) {
      cg.printf("%s%d.escalate(true);\n", Option::MapPrefix, mapId);
    }
    m_array->setExpectedType(expectedType);
    if (wrap) {
      m_array->outputCPPEnd(cg, ar);
    }
  } else {
    passTemp = false;
  }

  /* We need to generate sets for $a[x] etc
     Without AssignmentLHS context, we get lvalAt(...) = instead.
     But if we set AssignmentLHS earlier, a simple variable can end up
     being marked "unused"
  */
  if (m_name) m_name->setContext(Expression::AssignmentLHS);
  m_value->setContext(Expression::AssignmentLHS);

  bool orderName = m_name && m_name->preOutputCPP(cg, ar, 0);
  bool orderValue = m_value->preOutputCPP(cg, ar, 0);

  cppDeclareBufs(cg, ar);
  int iterId = cg.createNewLocalId(shared_from_this());
  cg_printf("for (");
  if (m_ref) {
    cg_printf("MutableArrayIter %s%d = %s%d.begin(",
              Option::IterPrefix, iterId, Option::MapPrefix, mapId);
    if (!nameSimple) {
      cg_printf("&%s%d_n", Option::MapPrefix, mapId);
    } else if (m_name) {
      cg_printf("&");
      m_name->outputCPP(cg, ar);
    } else {
      cg_printf("NULL");
    }
    cg_printf(", ");
    if (!valueSimple) {
      cg_printf("%s%d_v", Option::MapPrefix, mapId);
    } else {
      m_value->outputCPP(cg, ar);
    }
    ClassScopePtr cls = getClassScope();
    if (cls) {
      cg_printf(", %sclass_name", Option::StaticPropertyPrefix);
    } else {
      cg_printf(", null_string");
    }
    cg_printf(", true); %s%d.advance();", Option::IterPrefix, iterId);
  } else {
    if (passTemp) {
      cg_printf("ArrayIter %s%d = %s%d.begin(",
                Option::IterPrefix, iterId,
                Option::MapPrefix, mapId);
      ClassScopePtr cls = getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      } else {
        cg_printf("null_string");
      }
      cg_printf(", true); ");
      cg_printf("!%s%d.end(); %s%d.next()",
                Option::IterPrefix, iterId,
                Option::IterPrefix, iterId);
    } else {
      cg_printf("ArrayIter %s%d = ", Option::IterPrefix, iterId);
      TypePtr expectedType = m_array->getExpectedType();
      // Clear m_expectedType to avoid type cast (toArray).
      m_array->setExpectedType(TypePtr());
      m_array->outputCPP(cg, ar);
      m_array->setExpectedType(expectedType);
      cg_printf(".begin(");
      ClassScopePtr cls = getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      } else {
        cg_printf("null_string");
      }
      cg_printf(", true); ");
      cg_printf("!%s%d.end(); ", Option::IterPrefix, iterId);
      cg_printf("++%s%d", Option::IterPrefix, iterId);
    }
  }
  cg_indentBegin(") {\n");
  cg_printf("LOOP_COUNTER_CHECK(%d);\n", labelId);

  /*
    The order of evaluation here is.
    - second() (if !m_ref)
    - first() (if !m_ref && m_name is set)
    - side effects of m_name (if set)
    - side effects of m_value
    - assignment to m_value
    - assignment to m_name
    This order is observable, and we have tests to prove it.

    Optimize for the usual case, where m_name and m_value are
    simple variables.
  */

  string valueStr, nameStr;

  if (!m_ref) {
    Util::string_printf(valueStr, "%s%d.second()",
                        Option::IterPrefix, iterId);
    Util::string_printf(nameStr, "%s%d.first()",
                        Option::IterPrefix, iterId);
    if (valueSimple) {
      cg_printf("%s%d.second(", Option::IterPrefix, iterId);
      m_value->outputCPP(cg, ar);
      cg_printf(");\n");
    } else if (m_name || m_value->hasEffect()) {
      string tmp;
      Util::string_printf(tmp, "%s%d_v", Option::MapPrefix, mapId);
      cg_printf("CVarRef %s = %s;\n",
                tmp.c_str(), valueStr.c_str());
      valueStr = tmp;
    }
    if (m_name && m_name->hasEffect()) {
      string tmp;
      Util::string_printf(tmp, "%s%d_n", Option::MapPrefix, mapId);
      cg_printf("CVarRef %s = %s;\n",
                tmp.c_str(), nameStr.c_str());
      nameStr = tmp;
    }
  } else {
    Util::string_printf(valueStr, "%s%d_v", Option::MapPrefix, mapId);
    Util::string_printf(nameStr, "%s%d_n", Option::MapPrefix, mapId);
  }

  bool wrap = false;
  if (m_name) {
    if (orderName || m_value->hasEffect()) {
      cg.setInExpression(true);
      m_name->preOutputCPP(cg, ar,
                           m_value->hasEffect() ? Expression::FixOrder: 0);
      wrap = true;
    }
  }

  if (!valueSimple) {
    if (orderValue) {
      m_value->outputCPPBegin(cg, ar);
      wrap = true;
    }
    if (!AssignmentExpression::SpecialAssignment(
          cg, ar, m_value, ExpressionPtr(), valueStr.c_str(), m_ref)) {
      m_value->outputCPP(cg, ar);
      cg_printf(".assign%s(%s)", m_ref ? "Ref" : "Val", valueStr.c_str());
    }
    cg_printf(";\n");
  }

  if (m_name && (!nameSimple || !m_ref)) {
    if (orderName) {
      m_name->outputCPPBegin(cg, ar);
    }
    if (!AssignmentExpression::SpecialAssignment(
          cg, ar, m_name, ExpressionPtr(), nameStr.c_str(), m_ref)) {
      m_name->outputCPP(cg, ar);
      cg_printf(".assign%s(%s)", m_ref ? "Ref" : "Val", nameStr.c_str());
    }
    cg_printf(";\n");
  }
  if (wrap) {
    cg.wrapExpressionEnd();
    cg.setInExpression(false);
  }

  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  cg_indentEnd("}\n");
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cg.popBreakScope();
  cppEndBufs(cg, ar);
  cg_indentEnd("}\n");
}
void ForEachStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  cg_indentBegin("{\n");
  int labelId = cg.createNewLocalId(ar);
  cg.pushBreakScope(labelId);

  int mapId = cg.createNewLocalId(ar);
  bool passTemp = true;
  bool isArray = false;

  if (m_ref ||
      !m_array->is(Expression::KindOfSimpleVariable) ||
      m_array->isThis()) {
    cg_printf("Variant %s%d", Option::MapPrefix, mapId);
    bool wrap = m_array->preOutputCPP(cg, ar, 0);
    if (wrap) {
      cg_printf(";\n");
      m_array->outputCPPBegin(cg, ar);
      cg_printf("%s%d", Option::MapPrefix, mapId);
    }
    if (m_ref) {
      cg_printf(" = ref(");
      m_array->outputCPPImpl(cg, ar);
      cg.printf(");\n");
      cg.printf("%s%d.escalate(true);\n", Option::MapPrefix, mapId);
    } else {
      TypePtr expectedType = m_array->getExpectedType();
      // Clear m_expectedType to avoid type cast (toArray).
      m_array->setExpectedType(TypePtr());
      cg_printf(" = ");
      m_array->outputCPP(cg, ar);
      cg_printf(";\n");
      m_array->setExpectedType(expectedType);
    }
    if (wrap) {
      m_array->outputCPPEnd(cg, ar);
    }
  } else {
    passTemp = false;
  }

  cppDeclareBufs(cg, ar);
  int iterId = cg.createNewLocalId(ar);
  cg_printf("for (");
  if (m_ref) {
    cg_printf("MutableArrayIterPtr %s%d = %s%d.begin(",
              Option::IterPrefix, iterId, Option::MapPrefix, mapId);
    if (m_name) {
      cg_printf("&");
      m_name->outputCPP(cg, ar);
    } else {
      cg_printf("NULL");
    }
    cg_printf(", ");
    m_value->outputCPP(cg, ar);
    cg_printf("); %s%d->advance();", Option::IterPrefix, iterId);
  } else {
    if (passTemp) {
      cg_printf("ArrayIterPtr %s%d = %s%d.begin(",
                Option::IterPrefix, iterId,
                Option::MapPrefix, mapId);
      ClassScopePtr cls = ar->getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      }
      cg_printf("); ");
      cg_printf("!%s%d->end(); %s%d->next()",
                Option::IterPrefix, iterId,
                Option::IterPrefix, iterId);
    } else {
      TypePtr actualType = m_array->getActualType();
      if (actualType && actualType->is(Type::KindOfArray)) {
        isArray = true;
        cg_printf("ArrayIter %s%d = ", Option::IterPrefix, iterId);
      } else {
        cg_printf("ArrayIterPtr %s%d = ", Option::IterPrefix, iterId);
      }
      TypePtr expectedType = m_array->getExpectedType();
      // Clear m_expectedType to avoid type cast (toArray).
      m_array->setExpectedType(TypePtr());
      m_array->outputCPP(cg, ar);
      m_array->setExpectedType(expectedType);
      cg_printf(".begin(");
      ClassScopePtr cls = ar->getClassScope();
      if (cls) {
        cg_printf("%sclass_name", Option::StaticPropertyPrefix);
      }
      cg_printf("); ");
      if (isArray) {
        cg_printf("!%s%d.end(); ", Option::IterPrefix, iterId);
        cg_printf("++%s%d", Option::IterPrefix, iterId);
      } else {
        cg_printf("!%s%d->end(); ", Option::IterPrefix, iterId);
        cg_printf("%s%d->next()", Option::IterPrefix, iterId);
      }
    }
  }
  cg_indentBegin(") {\n");
  cg_printf("LOOP_COUNTER_CHECK(%d);\n", labelId);

  if (!m_ref) {
    cg_printf(isArray ? "%s%d.second(" : "%s%d->second(",
              Option::IterPrefix, iterId);
    m_value->outputCPP(cg, ar);
    cg_printf(");\n");
    if (m_name) {
      m_name->outputCPP(cg, ar);
      cg_printf(isArray ? " = %s%d.first();\n" : " = %s%d->first();\n",
                Option::IterPrefix, iterId);
    }
  }
  if (m_stmt) {
    m_stmt->outputCPP(cg, ar);
  }
  if (cg.findLabelId("continue", labelId)) {
    cg_printf("continue%d:;\n", labelId);
  }
  cg_indentEnd("}\n");
  if (cg.findLabelId("break", labelId)) {
    cg_printf("break%d:;\n", labelId);
  }
  cg.popBreakScope();
  cppEndBufs(cg, ar);
  cg_indentEnd("}\n");
}