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(); }
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"); }