void CodeGenerator::printExpressionVector(ExpressionListPtr el) { printf("V:9:\"HH\\Vector\":%d:{", el->getCount()); if (el->getCount() > 0) { el->outputCodeModel(*this); } printf("}"); }
ClosureExpression::ClosureExpression (EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func, ExpressionListPtr vars) : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)), m_func(func) { if (vars) { m_vars = ExpressionListPtr (new ExpressionList(vars->getScope(), vars->getLocation())); // push the vars in reverse order, not retaining duplicates std::set<string> seenBefore; // Because PHP is insane you can have a use variable with the same // name as a param name. // In that case, params win (which is different than zend but much easier) ExpressionListPtr bodyParams = m_func->getParams(); if (bodyParams) { int nParams = bodyParams->getCount(); for (int i = 0; i < nParams; i++) { ParameterExpressionPtr par( static_pointer_cast<ParameterExpression>((*bodyParams)[i])); seenBefore.insert(par->getName()); } } for (int i = vars->getCount() - 1; i >= 0; i--) { ParameterExpressionPtr param( dynamic_pointer_cast<ParameterExpression>((*vars)[i])); assert(param); if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } if (m_vars) { m_values = ExpressionListPtr (new ExpressionList(m_vars->getScope(), m_vars->getLocation())); for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); SimpleVariablePtr var(new SimpleVariable(param->getScope(), param->getLocation(), name)); if (param->isRef()) { var->setContext(RefValue); } m_values->addElement(var); } assert(m_vars->getCount() == m_values->getCount()); } } }
ExpressionPtr Expression::unneededHelper() { ExpressionListPtr elist = ExpressionListPtr (new ExpressionList(getScope(), getRange(), ExpressionList::ListKindWrapped)); bool change = false; for (int i=0, n = getKidCount(); i < n; i++) { ExpressionPtr kid = getNthExpr(i); if (kid && kid->getContainedEffects()) { ExpressionPtr rep = kid->unneeded(); if (rep != kid) change = true; if (rep->is(Expression::KindOfExpressionList)) { for (int j=0, m = rep->getKidCount(); j < m; j++) { elist->addElement(rep->getNthExpr(j)); } } else { elist->addElement(rep); } } } if (change) { getScope()->addUpdates(BlockScope::UseKindCaller); } int n = elist->getCount(); assert(n); if (n == 1) { return elist->getNthExpr(0); } else { return elist; } }
void InterfaceStatement::checkArgumentsToPromote( FileScopeRawPtr scope, ExpressionListPtr promotedParams, int type) { if (!m_stmt) { return; } for (int i = 0; i < m_stmt->getCount(); i++) { MethodStatementPtr meth = dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]); if (meth && meth->isNamed("__construct")) { ExpressionListPtr params = meth->getParams(); if (params) { for (int i = 0; i < params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); if (param->getModifier() != 0) { if (type == T_TRAIT || type == T_INTERFACE) { param->parseTimeFatal(scope, Compiler::InvalidAttribute, "Constructor parameter promotion " "not allowed on traits or interfaces"); } if (promotedParams) { promotedParams->addElement(param); } } } } return; // nothing else to look at } } }
void Symbol::beginLocal(BlockScopeRawPtr scope) { m_prevCoerced = m_coerced; if (isClosureVar()) { ExpressionListPtr useVars = scope->getContainingFunction()->getClosureVars(); assert(useVars); // linear scan for now, since most use var lists are // fairly short bool found = false; for (int i = 0; i < useVars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*useVars)[i]); if (m_name == param->getName()) { // bootstrap use var with parameter type m_coerced = param->getType(); found = true; break; } } if (!found) assert(false); assert(!isRefClosureVar() || (m_coerced && m_coerced->is(Type::KindOfVariant))); } else { m_coerced.reset(); } }
void ClosureExpression::initializeFromUseList(ExpressionListPtr vars) { m_vars = ExpressionListPtr( new ExpressionList(vars->getScope(), vars->getRange())); // Because PHP is insane you can have a use variable with the same // name as a param name. // In that case, params win (which is different than zend but much easier) auto seenBefore = collectParamNames(); for (int i = vars->getCount() - 1; i >= 0; i--) { auto param = dynamic_pointer_cast<ParameterExpression>((*vars)[i]); assert(param); if (param->getName() == "this") { // "this" is automatically included. // Once we get rid of all the callsites, make this an error continue; } if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } initializeValuesFromVars(); }
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp, bool &hasVoid) { if (!exp->hasCPPTemp()) { if (exp->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp); if (u->getOp() == '(') { return getConcatList(ev, u->getExpression(), hasVoid); } } else if (exp->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp); if (b->getOp() == '.') { return getConcatList(ev, b->getExp1(), hasVoid) + getConcatList(ev, b->getExp2(), hasVoid); } } else if (exp->is(Expression::KindOfEncapsListExpression)) { EncapsListExpressionPtr e = static_pointer_cast<EncapsListExpression>(exp); if (e->getType() != '`') { ExpressionListPtr el = e->getExpressions(); int num = 0; for (int i = 0, s = el->getCount(); i < s; i++) { ExpressionPtr exp = (*el)[i]; num += getConcatList(ev, exp, hasVoid); } return num; } } } ev.push_back(exp); bool isVoid = !exp->getActualType(); hasVoid |= isVoid; return isVoid ? 0 : 1; }
void CodeGenerator::printExpressionVector(ExpressionListPtr el) { auto count = el == nullptr ? 0 : el->getCount(); printf("V:9:\"HH\\Vector\":%d:{", count); if (count > 0) { el->outputCodeModel(*this); } printf("}"); }
void CodeGenerator::printTypeExpressionVector(ExpressionListPtr el) { auto count = el == nullptr ? 0 : el->getCount(); printf("V:9:\"HH\\Vector\":%d:{", count); for (int i = 0; i < count; i++) { auto te = (*el)[i]; printTypeExpression(te); } printf("}"); }
void BinaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { m_exp1->outputPHP(cg, ar); switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_CONCAT_EQUAL: cg_printf(" .= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" or "); break; case T_LOGICAL_AND: cg_printf(" and "); break; case T_LOGICAL_XOR: cg_printf(" xor "); break; case '|': cg_printf(" | "); break; case '&': cg_printf(" & "); break; case '^': cg_printf(" ^ "); break; case '.': cg_printf(" . "); break; case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case '/': cg_printf(" / "); break; case '%': cg_printf(" %% "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; case T_IS_IDENTICAL: cg_printf(" === "); break; case T_IS_NOT_IDENTICAL: cg_printf(" !== "); break; case T_IS_EQUAL: cg_printf(" == "); break; case T_IS_NOT_EQUAL: cg_printf(" != "); break; case '<': cg_printf(" < "); break; case T_IS_SMALLER_OR_EQUAL: cg_printf(" <= "); break; case '>': cg_printf(" > "); break; case T_IS_GREATER_OR_EQUAL: cg_printf(" >= "); break; case T_INSTANCEOF: cg_printf(" instanceof "); break; case T_COLLECTION: { ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2); if (el->getCount() == 0) { cg_printf(" {}"); } else { cg_printf(" { "); el->outputPHP(cg, ar); cg_printf(" }"); } return; } default: assert(false); } m_exp2->outputPHP(cg, ar); }
/** * Rewrites any expression query clauses in this list of clauses, taking care * to track variables local to the query. */ ExpressionListPtr CaptureExtractor::rewriteExpressionList(ExpressionListPtr l) { int np = 0; int nc = l->getCount(); auto newList = std::make_shared<ExpressionList>(l->getScope(), l->getRange()); bool noRewrites = true; for (int i = 0; i < nc; i++) { auto e = (*l)[i]; assert(e != nullptr); auto kind = e->getKindOf(); switch (kind) { case Expression::KindOfIntoClause: { // The into expression is in the scope of the into clause SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e)); m_boundVars.push_back(qcp->getIdentifier()); np++; break; } case Expression::KindOfJoinClause: { JoinClausePtr jcp(static_pointer_cast<JoinClause>(e)); m_boundVars.push_back(jcp->getVar()); np++; break; } default: break; } auto ne = rewrite(e); if (ne != e) noRewrites = false; newList->addElement(ne); // deal with clauses that introduce names for subsequent clauses switch (kind) { case Expression::KindOfFromClause: case Expression::KindOfLetClause: { SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e)); m_boundVars.push_back(qcp->getIdentifier()); np++; break; } case Expression::KindOfJoinClause: { JoinClausePtr jcp(static_pointer_cast<JoinClause>(e)); auto groupId = jcp->getGroup(); if (!groupId.empty()) { m_boundVars.push_back(groupId); np++; } break; } default: break; } } while (np-- > 0) m_boundVars.pop_back(); if (noRewrites) return l; return newList; }
void UnaryOpExpression::setExistContext() { if (m_exp) { if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); for (int i = 0; i < exps->getCount(); i++) { (*exps)[i]->setContext(Expression::ExistContext); } } else { m_exp->setContext(Expression::ExistContext); } } }
void FunctionScope::outputCPPEffectiveArguments(ExpressionListPtr params, CodeGenerator &cg, AnalysisResultPtr ar) { int paramCount = params ? params->getCount() : 0; for (int i = 0; i < paramCount; i++) { ExpressionPtr param = (*params)[i]; if (param->hasEffect()) { param->outputCPP(cg, ar); cg.printf(", "); } } }
void UnaryOpExpression::setExistContext() { if (m_exp) { if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (exps->getListKind() == ExpressionList::ListKindParam) { for (int i = 0; i < exps->getCount(); i++) { (*exps)[i]->setContext(Expression::ExistContext); } return; } } m_exp->setContext(Expression::ExistContext); } }
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp, bool &hasVoid) { if (!exp->hasCPPTemp()) { if (exp->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp); if (u->getOp() == '(') { return getConcatList(ev, u->getExpression(), hasVoid); } } else if (exp->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp); if (b->getOp() == '.') { if (b->getExp1()->is(Expression::KindOfSimpleVariable) && b->getExp1()->isLocalExprAltered() && !b->getExp1()->hasCPPTemp() && b->getExp2()->hasEffect() && !b->getExp2()->hasCPPTemp()) { /* In this case, the simple variable must be evaluated after b->getExp2(). But when we output a concat list we explicitly order the expressions from left to right. */ } else { return getConcatList(ev, b->getExp1(), hasVoid) + getConcatList(ev, b->getExp2(), hasVoid); } } } else if (exp->is(Expression::KindOfEncapsListExpression)) { EncapsListExpressionPtr e = static_pointer_cast<EncapsListExpression>(exp); if (e->getType() != '`') { ExpressionListPtr el = e->getExpressions(); int num = 0; for (int i = 0, s = el->getCount(); i < s; i++) { ExpressionPtr exp = (*el)[i]; num += getConcatList(ev, exp, hasVoid); } return num; } } } else if (!exp->getActualType()) { return 0; } ev.push_back(exp); bool isVoid = !exp->getActualType(); hasVoid |= isVoid; return isVoid ? 0 : 1; }
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); int count = exps->getCount(); if (count > 1) { bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0); bool inExpression = ar->inExpression(); ar->setInExpression(false); bool fix_en = false; for (int i = 1; i < count; i++) { if ((*exps)[i]->preOutputCPP(cg, ar, 0)) { fix_en = true; break; } } ar->setInExpression(inExpression); if (inExpression && fix_en) { ar->wrapExpressionBegin(cg); std::string tmp = genCPPTemp(cg, ar); cg.printf("bool %s = (", tmp.c_str()); (*exps)[0]->outputCPPExistTest(cg, ar, m_op); cg.printf(");\n"); for (int i = 1; i < count; i++) { cg.indentBegin("if (%s) {\n", tmp.c_str()); ExpressionPtr e = (*exps)[i]; e->preOutputCPP(cg, ar, 0); cg.printf("%s = (", tmp.c_str()); e->outputCPPExistTest(cg, ar, m_op); cg.printf(");\n"); } for (int i = 1; i < count; i++) { cg.indentEnd("}\n"); } m_cppTemp = tmp; } else if (state & FixOrder) { preOutputStash(cg, ar, state); fix_e1 = true; } return fix_e1 || fix_en; } } return Expression::preOutputCPP(cg, ar, state); }
static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) { for (int i = 0; i < vars->getCount(); i++) { ExpressionPtr v = (*vars)[i]; if (!v) continue; if (v->is(Expression::KindOfSimpleVariable) && v->canonCompare(var)) { return true; } if (v->is(Expression::KindOfDynamicVariable)) return true; if (v->is(Expression::KindOfListAssignment) && AssignmentCouldSet(static_pointer_cast<ListAssignment>(v)-> getVariables(), var)) { return true; } } return false; }
ClosureExpression::ClosureExpression (EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func, ExpressionListPtr vars) : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)), m_func(func) { if (vars) { m_vars = ExpressionListPtr (new ExpressionList(vars->getScope(), vars->getLocation())); // push the vars in reverse order, not retaining duplicates std::set<string> seenBefore; for (int i = vars->getCount() - 1; i >= 0; i--) { ParameterExpressionPtr param( dynamic_pointer_cast<ParameterExpression>((*vars)[i])); assert(param); if (param->getName() == "this") { // "this" is automatically included. // Once we get rid of all the callsites, make this an error continue; } if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } if (m_vars) { m_values = ExpressionListPtr (new ExpressionList(m_vars->getScope(), m_vars->getLocation())); for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); SimpleVariablePtr var(new SimpleVariable(param->getScope(), param->getLocation(), name)); if (param->isRef()) { var->setContext(RefValue); } m_values->addElement(var); } assert(m_vars->getCount() == m_values->getCount()); } } }
bool Option::Load(map<string, int> &option, ExpressionPtr value) { ExpressionListPtr elements; if (!GetArrayElements(value, elements)) return false; for (int i = 0; i < elements->getCount(); i++) { ExpressionPtr e = (*elements)[i]; ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e); bool negative = false; ScalarExpressionPtr n, v; if (pair) n = dynamic_pointer_cast<ScalarExpression>(pair->getName()); if (pair) { if (pair->getValue()->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr una = dynamic_pointer_cast<UnaryOpExpression>(pair->getValue()); if (una->getOp() != '+' && una->getOp() != '-') { Logger::Error("Line %d: invalid integer: %s", una->getLocation()->line1, una->getText().c_str()); return false; } v = dynamic_pointer_cast<ScalarExpression>(una->getExpression()); if (una->getOp() == '-') { negative = true; } } else { v = dynamic_pointer_cast<ScalarExpression>(pair->getValue()); } } if (!pair || !n || !v || !n->isLiteralString() || !v->isLiteralInteger()) { Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1, e->getText().c_str()); return false; } if (negative) { option[n->getLiteralString()] = - v->getLiteralInteger(); } else { option[n->getLiteralString()] = v->getLiteralInteger(); } } return true; }
ClosureExpression::ClosureExpression (EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func, ExpressionListPtr vars) : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES), m_func(func) { if (vars) { m_vars = ExpressionListPtr (new ExpressionList(vars->getScope(), vars->getLocation(), KindOfExpressionList)); // push the vars in reverse order, not retaining duplicates set<string> seenBefore; for (int i = vars->getCount() - 1; i >= 0; i--) { ParameterExpressionPtr param( dynamic_pointer_cast<ParameterExpression>((*vars)[i])); ASSERT(param); if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } if (m_vars) { m_values = ExpressionListPtr (new ExpressionList(m_vars->getScope(), m_vars->getLocation(), KindOfExpressionList)); for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); string name = param->getName(); SimpleVariablePtr var(new SimpleVariable(param->getScope(), param->getLocation(), KindOfSimpleVariable, name)); if (param->isRef()) { var->setContext(RefValue); } m_values->addElement(var); } } } }
bool Option::Load(vector<string> &option, ExpressionPtr value) { ExpressionListPtr elements; if (!GetArrayElements(value, elements)) return false; for (int i = 0; i < elements->getCount(); i++) { ExpressionPtr e = (*elements)[i]; ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e); ScalarExpressionPtr v; if (pair) v = dynamic_pointer_cast<ScalarExpression>(pair->getValue()); if (!pair || !v || !v->isLiteralString()) { Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1, e->getText().c_str()); return false; } option.push_back(v->getLiteralString()); } return true; }
TypePtr UnaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr et; // expected m_exp's type TypePtr rt; // return type switch (m_op) { case '!': et = rt = Type::Boolean; break; case '+': case '-': et = Type::Numeric; rt = Type::Numeric; break; case T_INC: case T_DEC: case '~': et = rt = Type::Primitive; break; case T_CLONE: et = Type::Some; rt = Type::Object; break; case '@': et = type; rt = Type::Variant; break; case T_INT_CAST: et = rt = Type::Int64; break; case T_DOUBLE_CAST: et = rt = Type::Double; break; case T_STRING_CAST: et = rt = Type::String; break; case T_ARRAY: et = Type::Some; rt = Type::Array; break; case T_ARRAY_CAST: et = rt = Type::Array; break; case T_OBJECT_CAST: et = rt = Type::Object; break; case T_BOOL_CAST: et = rt = Type::Boolean; break; case T_UNSET_CAST: et = Type::Some; rt = Type::Variant; break; case T_UNSET: et = Type::Null; rt = Type::Variant; break; case T_EXIT: et = Type::Primitive; rt = Type::Variant; break; case T_PRINT: et = Type::String; rt = Type::Int64; break; case T_ISSET: et = Type::Variant; rt = Type::Boolean; setExistContext(); break; case T_EMPTY: et = Type::Some; rt = Type::Boolean; setExistContext(); break; case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: et = Type::String; rt = Type::Variant; break; case T_EVAL: et = Type::String; rt = Type::Any; getScope()->getVariables()->forceVariants(ar, VariableTable::AnyVars); break; case T_DIR: case T_FILE: et = rt = Type::String; break; default: assert(false); } if (m_exp) { TypePtr expType = m_exp->inferAndCheck(ar, et, false); if (Type::SameType(expType, Type::String) && (m_op == T_INC || m_op == T_DEC)) { rt = expType = m_exp->inferAndCheck(ar, Type::Variant, true); } switch (m_op) { case '+': case '-': if (Type::SameType(expType, Type::Int64) || Type::SameType(expType, Type::Double)) { rt = expType; } break; case T_INC: case T_DEC: case '~': if (Type::SameType(expType, Type::Int64) || Type::SameType(expType, Type::Double) || Type::SameType(expType, Type::String)) { rt = expType; } break; case T_ISSET: case T_EMPTY: if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (exps->getListKind() == ExpressionList::ListKindParam) { for (int i = 0; i < exps->getCount(); i++) { SetExpTypeForExistsContext(ar, (*exps)[i], m_op == T_EMPTY); } } } else { SetExpTypeForExistsContext(ar, m_exp, m_op == T_EMPTY); } break; default: break; } } return rt; }
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) { return; } if (m_op == T_ARRAY && (getContext() & (RefValue|LValue)) == 0 && !ar->getInsideScalarArray()) { int id = -1; int hash = -1; int index = -1; string text; if (m_exp) { ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp); Variant v; if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) { id = ar->registerScalarArray(getFileScope(), m_exp, hash, index, text); } } else { id = ar->registerScalarArray(getFileScope(), m_exp, hash, index, text); // empty array } if (id != -1) { if (Option::UseNamedScalarArray && cg.getContext() == CodeGenerator::CppParameterDefaultValueDecl) { getFileScope()->addUsedDefaultValueScalarArray(text); } ar->outputCPPScalarArrayId(cg, id, hash, index); return; } } if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) { if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (exps->getListKind() == ExpressionList::ListKindParam) { int count = exps->getCount(); if (count > 1) { cg_printf("("); } for (int i = 0; i < count; i++) { if (m_op == T_UNSET) { if (i > 0) cg_printf(", "); (*exps)[i]->outputCPPUnset(cg, ar); } else { if (i > 0) cg_printf(" && "); (*exps)[i]->outputCPPExistTest(cg, ar, m_op); } } if (exps->getCount() > 1) { cg_printf(")"); } return; } } if (m_op == T_UNSET) { m_exp->outputCPPUnset(cg, ar); } else { m_exp->outputCPPExistTest(cg, ar, m_op); } return; } if (m_front) { switch (m_op) { case T_CLONE: cg_printf("f_clone("); break; case T_INC: cg_printf("++"); break; case T_DEC: cg_printf("--"); break; case '+': cg_printf("+"); break; case '-': cg_printf("negate("); break; case '!': cg_printf("!("); break; case '~': cg_printf("~"); break; case '(': cg_printf("("); break; case T_INT_CAST: cg_printf("("); break; case T_DOUBLE_CAST: cg_printf("("); break; case T_STRING_CAST: cg_printf("("); break; case T_ARRAY_CAST: cg_printf("("); break; case T_OBJECT_CAST: cg_printf("("); break; case T_BOOL_CAST: cg_printf("("); break; case T_UNSET_CAST: if (m_exp->hasCPPTemp()) { cg_printf("(id("); } else { cg_printf("("); } break; case T_EXIT: cg_printf("f_exit("); break; case T_ARRAY: cg_printf("Array("); break; case T_PRINT: cg_printf("print("); break; case T_EVAL: if (Option::EnableEval > Option::NoEval) { bool instance; if (getClassScope()) { FunctionScopePtr fs = getFunctionScope(); instance = fs && !fs->isStatic(); } else { instance = false; } cg_printf("eval(%s, Object(%s), ", getScope()->inPseudoMain() ? "get_variable_table()" : "variables", instance ? "this" : ""); } else { cg_printf("f_eval("); } break; case '@': if (m_silencer >= 0) { cg_printf("(%s%d.enable(),%s%d.disable(", Option::SilencerPrefix, m_silencer, Option::SilencerPrefix, m_silencer); } break; case T_FILE: cg_printf("get_source_filename(\"%s\")", getLocation()->file); break; break; default: ASSERT(false); } } if (m_exp) { switch (m_op) { case '+': case '-': if (m_exp->getActualType() && (m_exp->getActualType()->is(Type::KindOfString) || m_exp->getActualType()->is(Type::KindOfArray))) { cg_printf("(Variant)("); m_exp->outputCPP(cg, ar); cg_printf(")"); } else { m_exp->outputCPP(cg, ar); } break; case '@': if (m_silencer < 0 && isUnused()) { m_exp->outputCPPUnneeded(cg, ar); } else if (!m_exp->hasCPPTemp() && !m_exp->getActualType()) { // Void needs to return something to silenceDec cg_printf("("); m_exp->outputCPP(cg, ar); cg_printf(",null)"); } else { m_exp->outputCPP(cg, ar); } break; default: m_exp->outputCPP(cg, ar); break; } } if (m_front) { switch (m_op) { case T_ARRAY: { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (!exps) { cg_printf("ArrayData::Create()"); } cg_printf(")"); } break; case T_UNSET_CAST: if (m_exp->hasCPPTemp()) { cg_printf("),null"); } else { cg_printf(",null"); } case T_CLONE: case '!': case '(': case '-': case T_INT_CAST: case T_DOUBLE_CAST: case T_STRING_CAST: case T_ARRAY_CAST: case T_OBJECT_CAST: case T_BOOL_CAST: case T_EXIT: case T_PRINT: case T_EVAL: case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: cg_printf(")"); break; case '@': if (m_silencer >= 0) { cg_printf("))"); } break; default: break; } } else { switch (m_op) { case T_INC: cg_printf("++"); break; case T_DEC: cg_printf("--"); break; default: ASSERT(false); } } }
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_arrayId != -1) { if (cg.getOutput() == CodeGenerator::SystemCPP) { cg.printf("SystemScalarArrays::%s[%d]", Option::SystemScalarArrayName, m_arrayId); } else { cg.printf("ScalarArrays::%s[%d]", Option::ScalarArrayName, m_arrayId); } return; } if ((m_op == T_ISSET || m_op == T_EMPTY) && m_exp) { if (m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (exps->getCount() > 1) { cg.printf("("); } for (int i = 0; i < exps->getCount(); i++) { if (i > 0) cg.printf(" && "); (*exps)[i]->outputCPPExistTest(cg, ar, m_op); } if (exps->getCount() > 1) { cg.printf(")"); } } else { m_exp->outputCPPExistTest(cg, ar, m_op); } return; } if (m_front) { switch (m_op) { case T_CLONE: cg.printf("f_clone("); break; case T_INC: cg.printf("++"); break; case T_DEC: cg.printf("--"); break; case '+': cg.printf("+"); break; case '-': cg.printf("negate("); break; case '!': cg.printf("!("); break; case '~': cg.printf("~"); break; case '(': cg.printf("("); break; case T_INT_CAST: cg.printf("("); break; case T_DOUBLE_CAST: cg.printf("("); break; case T_STRING_CAST: cg.printf("("); break; case T_ARRAY_CAST: cg.printf("("); break; case T_OBJECT_CAST: cg.printf("("); break; case T_BOOL_CAST: cg.printf("("); break; case T_UNSET_CAST: cg.printf("unset("); break; case T_EXIT: cg.printf("f_exit("); break; case T_ARRAY: if (ar->getInsideScalarArray()) { cg.printf("StaticArray("); } else { cg.printf("Array("); } break; case T_PRINT: cg.printf("print("); break; case T_EVAL: if (Option::EnableEval > Option::NoEval) { cg.printf("eval(%s, Object(%s), ", ar->getScope()->inPseudoMain() ? "get_variable_table()" : "variables", ar->getClassScope() ? "this" : ""); } else { cg.printf("f_eval("); } break; case '@': cg.printf("(%s%d.enable(),%s%d.disable(", Option::SilencerPrefix, m_silencer, Option::SilencerPrefix, m_silencer); break; case T_FILE: cg.printf("get_source_filename(\"%s\")", getLocation()->file); break; break; default: ASSERT(false); } } if (m_exp) { switch (m_op) { case '+': case '-': if (m_exp->getActualType() && (m_exp->getActualType()->is(Type::KindOfString) || m_exp->getActualType()->is(Type::KindOfArray))) { cg.printf("(Variant)("); m_exp->outputCPP(cg, ar); cg.printf(")"); } else { m_exp->outputCPP(cg, ar); } break; case '@': // Void needs to return something to silenceDec if (!m_exp->getActualType()) { cg.printf("("); m_exp->outputCPP(cg, ar); cg.printf(",null)"); } else { m_exp->outputCPP(cg, ar); } break; default: m_exp->outputCPP(cg, ar); break; } } if (m_front) { switch (m_op) { case T_ARRAY: { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); if (!exps) { cg.printf("ArrayData::Create()"); } cg.printf(")"); } break; case T_CLONE: case '!': case '(': case '-': case T_INT_CAST: case T_DOUBLE_CAST: case T_STRING_CAST: case T_ARRAY_CAST: case T_OBJECT_CAST: case T_BOOL_CAST: case T_UNSET_CAST: case T_EXIT: case T_PRINT: case T_EVAL: case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: cg.printf(")"); break; case '@': cg.printf("))"); break; default: break; } } else { switch (m_op) { case T_INC: cg.printf("++"); break; case T_DEC: cg.printf("--"); break; default: ASSERT(false); } } }
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); int count = exps->getCount(); if (count > 1) { bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0); bool inExpression = ar->inExpression(); ar->setInExpression(false); bool fix_en = false; for (int i = 1; i < count; i++) { if ((*exps)[i]->preOutputCPP(cg, ar, 0)) { fix_en = true; break; } } ar->setInExpression(inExpression); if (inExpression && fix_en) { ar->wrapExpressionBegin(cg); std::string tmp = genCPPTemp(cg, ar); cg_printf("bool %s = (", tmp.c_str()); (*exps)[0]->outputCPPExistTest(cg, ar, m_op); cg_printf(");\n"); for (int i = 1; i < count; i++) { cg_indentBegin("if (%s) {\n", tmp.c_str()); ExpressionPtr e = (*exps)[i]; e->preOutputCPP(cg, ar, 0); cg_printf("%s = (", tmp.c_str()); e->outputCPPExistTest(cg, ar, m_op); cg_printf(");\n"); } for (int i = 1; i < count; i++) { cg_indentEnd("}\n"); } m_cppTemp = tmp; } else if (state & FixOrder) { preOutputStash(cg, ar, state); fix_e1 = true; } return fix_e1 || fix_en; } } if (m_op == '@') { if (isUnused()) m_exp->setUnused(true); bool inExpression = ar->inExpression(); bool doit = state & FixOrder; if (!doit) { ar->setInExpression(false); if (m_exp->preOutputCPP(cg, ar, state)) { doit = true; } ar->setInExpression(inExpression); } if (doit && inExpression) { cg_printf("%s%d.enable();\n", Option::SilencerPrefix, m_silencer); m_exp->preOutputCPP(cg, ar, 0); int s = m_silencer; m_silencer = -1; this->preOutputStash(cg, ar, state | FixOrder); m_silencer = s; cg_printf("%s%d.disable();\n", Option::SilencerPrefix, m_silencer); } return doit; } else if (m_op == T_PRINT && m_exp && !m_exp->hasEffect()) { ExpressionPtrVec ev; bool hasVoid = false; if (BinaryOpExpression::getConcatList(ev, m_exp, hasVoid) > 1 || hasVoid ) { if (!ar->inExpression()) return true; ar->wrapExpressionBegin(cg); for (int i = 0, s = ev.size(); i < s; i++) { ExpressionPtr e = ev[i]; e->preOutputCPP(cg, ar, 0); cg_printf("print("); e->outputCPP(cg, ar); cg_printf(");\n"); } m_cppTemp = "1"; return true; } } return Expression::preOutputCPP(cg, ar, state); }
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp, ExpressionListPtr params, bool &valid) { if (!params) { if (m_minParam > 0) { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooFewArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } return 0; } int ret = 0; if (params->getCount() < m_minParam) { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooFewArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } if (params->getCount() > m_maxParam) { if (isVariableArgument()) { ret = params->getCount() - m_maxParam; } else { if (exp->getScope()->isFirstPass()) { Compiler::Error(Compiler::TooManyArgument, exp, m_stmt); } valid = false; if (!Option::AllDynamic) setDynamic(); } } bool canSetParamType = isUserFunction() && !m_overriding && !m_perfectVirtual; for (int i = 0; i < params->getCount(); i++) { ExpressionPtr param = (*params)[i]; if (i < m_maxParam && param->hasContext(Expression::RefParameter)) { /** * This should be very un-likely, since call time pass by ref is a * deprecated, not very widely used (at least in FB codebase) feature. */ TRY_LOCK_THIS(); Symbol *sym = getVariables()->addSymbol(m_paramNames[i]); sym->setLvalParam(); sym->setCallTimeRef(); } if (valid && param->hasContext(Expression::InvokeArgument)) { param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::RefValue); param->clearContext(Expression::NoRefWrapper); } bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument()); if ((i < m_maxParam && isRefParam(i)) || isRefVararg) { param->setContext(Expression::LValue); param->setContext(Expression::RefValue); param->inferAndCheck(ar, Type::Variant, true); } else if (!(param->getContext() & Expression::RefParameter)) { param->clearContext(Expression::LValue); param->clearContext(Expression::RefValue); param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::NoRefWrapper); } TypePtr expType; /** * Duplicate the logic of getParamType(i), w/o the mutation */ TypePtr paramType(i < m_maxParam && !isZendParamMode() ? m_paramTypes[i] : TypePtr()); if (!paramType) paramType = Type::Some; if (valid && !canSetParamType && i < m_maxParam && (!Option::HardTypeHints || !m_paramTypeSpecs[i])) { /** * What is this magic, you might ask? * * Here, we take advantage of implicit conversion from every type to * Variant. Essentially, we don't really care what type comes out of this * expression since it'll just get converted anyways. Doing it this way * allows us to generate less temporaries along the way. */ TypePtr optParamType(paramType->is(Type::KindOfVariant) ? Type::Some : paramType); expType = param->inferAndCheck(ar, optParamType, false); } else { expType = param->inferAndCheck(ar, Type::Some, false); } if (i < m_maxParam) { if (!Option::HardTypeHints || !m_paramTypeSpecs[i]) { if (canSetParamType) { if (!Type::SameType(paramType, expType) && !paramType->is(Type::KindOfVariant)) { TRY_LOCK_THIS(); paramType = setParamType(ar, i, expType); } else { // do nothing - how is this safe? well, if we ever observe // paramType == expType, then this means at some point in the past, // somebody called setParamType() with expType. thus, by calling // setParamType() again with expType, we contribute no "new" // information. this argument also still applies in the face of // concurrency } } // See note above. If we have an implemented type, however, we // should set the paramType to the implemented type to avoid an // un-necessary cast if (paramType->is(Type::KindOfVariant)) { TypePtr it(param->getImplementedType()); paramType = it ? it : expType; } if (valid) { if (!Type::IsLegalCast(ar, expType, paramType) && paramType->isNonConvertibleType()) { param->inferAndCheck(ar, paramType, true); } param->setExpectedType(paramType); } } } // we do a best-effort check for bad pass-by-reference and do not report // error for some vararg case (e.g., array_multisort can have either ref // or value for the same vararg). if (!isRefVararg || !isMixedVariableArgument()) { Expression::CheckPassByReference(ar, param); } } return ret; }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic() && !isStaticMethodAutoFixed()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (!m_docComment.empty()) attribute |= ClassInfo::HasDocComment; // Use the original cased name, for reflection to work correctly. cg.printf("(const char *)0x%04X, \"%s\", NULL, NULL,\n", attribute, getOriginalName().c_str()); if (!m_docComment.empty()) { char *dc = string_cplus_escape(m_docComment.c_str()); cg.printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; cg.printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(m_paramTypes[i]->getPHPName()).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); if (!def->isScalar() || !def->getScalarValue(defArg)) { defArg = "1"; } } else { defArg = "1"; } char *s = string_cplus_escape(f_serialize(defArg).data()); cg.printf("\"%s\",\n", s); free(s); } else { cg.printf("\"\",\n"); } } cg.printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp, ExpressionListPtr params, bool &valid) { if (!params) { if (m_minParam > 0) { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt); } valid = false; setDynamic(); } return 0; } int ret = 0; if (params->getCount() < m_minParam) { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt); } valid = false; setDynamic(); } if (params->getCount() > m_maxParam) { if (isVariableArgument()) { ret = params->getCount() - m_maxParam; } else { if (ar->isFirstPass()) { ar->getCodeError()->record(CodeError::TooManyArgument, exp, m_stmt); } valid = false; setDynamic(); } } bool canSetParamType = isUserFunction() && !m_overriding; for (int i = 0; i < params->getCount(); i++) { ExpressionPtr param = (*params)[i]; if (valid && param->hasContext(Expression::InvokeArgument)) { param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::RefValue); param->clearContext(Expression::NoRefWrapper); } TypePtr expType; if (!canSetParamType && i < m_maxParam) { expType = param->inferAndCheck(ar, getParamType(i), false); } else { expType = param->inferAndCheck(ar, NEW_TYPE(Some), false); } bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument()); if ((i < m_maxParam && isRefParam(i)) || isRefVararg) { param->setContext(Expression::LValue); param->setContext(Expression::RefValue); param->inferAndCheck(ar, Type::Variant, true); } else if (!(param->getContext() & Expression::RefParameter)) { param->clearContext(Expression::LValue); param->clearContext(Expression::RefValue); param->clearContext(Expression::InvokeArgument); param->clearContext(Expression::NoRefWrapper); } if (i < m_maxParam) { if (m_paramTypeSpecs[i] && ar->isFirstPass()) { if (!Type::Inferred(ar, expType, m_paramTypeSpecs[i])) { const char *file = m_stmt->getLocation()->file; Logger::Error("%s: parameter %d of %s requires %s, called with %s", file, i, m_name.c_str(), m_paramTypeSpecs[i]->toString().c_str(), expType->toString().c_str()); ar->getCodeError()->record(CodeError::BadArgumentType, m_stmt); } } TypePtr paramType = getParamType(i); if (canSetParamType) { paramType = setParamType(ar, i, expType); } if (!Type::IsLegalCast(ar, expType, paramType) && paramType->isNonConvertibleType()) { param->inferAndCheck(ar, paramType, true); } param->setExpectedType(paramType); } // we do a best-effort check for bad pass-by-reference and do not report // error for some vararg case (e.g., array_multisort can have either ref // or value for the same vararg). if (!isRefVararg || !isMixedVariableArgument()) { Expression::checkPassByReference(ar, param); } } return ret; }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (isVariableArgument()) { attribute |= ClassInfo::VariableArguments; } if (isReferenceVariableArgument()) { attribute |= ClassInfo::RefVariableArguments; } if (isMixedVariableArgument()) { attribute |= ClassInfo::MixedVariableArguments; } attribute |= m_attributeClassInfo; if (!m_docComment.empty() && Option::GenerateDocComments) { attribute |= ClassInfo::HasDocComment; } else { attribute &= ~ClassInfo::HasDocComment; } // Use the original cased name, for reflection to work correctly. cg_printf("(const char *)0x%04X, \"%s\", \"%s\", (const char *)%d, " "(const char *)%d, NULL, NULL,\n", attribute, getOriginalName().c_str(), m_stmt ? m_stmt->getLocation()->file : "", m_stmt ? m_stmt->getLocation()->line0 : 0, m_stmt ? m_stmt->getLocation()->line1 : 0); if (!m_docComment.empty() && Option::GenerateDocComments) { char *dc = string_cplus_escape(m_docComment.c_str(), m_docComment.size()); cg_printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; const std::string &tname = m_paramTypeSpecs[i] ? m_paramTypeSpecs[i]->getPHPName() : ""; cg_printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(tname).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); string sdef = def->getText(); char *esdef = string_cplus_escape(sdef.data(), sdef.size()); if (!def->isScalar() || !def->getScalarValue(defArg)) { /** * Special value runtime/ext/ext_reflection.cpp can check and throw. * If we want to avoid seeing this so to make getDefaultValue() * work better for reflections, we will have to implement * getScalarValue() to greater extent under compiler/expressions. */ cg_printf("\"\x01\", \"%s\",\n", esdef); } else { String str = f_serialize(defArg); char *s = string_cplus_escape(str.data(), str.size()); cg_printf("\"%s\", \"%s\",\n", s, esdef); free(s); } free(esdef); } else { char *def = string_cplus_escape(m_paramDefaults[i].data(), m_paramDefaults[i].size()); char *defText = string_cplus_escape(m_paramDefaultTexts[i].data(), m_paramDefaultTexts[i].size()); cg_printf("\"%s\", \"%s\",\n", def, defText); free(def); free(defText); } } else { cg_printf("\"\", \"\",\n"); } } cg_printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }
void MethodStatement::inferFunctionTypes(AnalysisResultPtr ar) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getFunctionScope()); FunctionScopeRawPtr funcScope = getFunctionScope(); bool pseudoMain = funcScope->inPseudoMain(); if (m_stmt && funcScope->isFirstPass()) { if (pseudoMain || funcScope->getReturnType() || m_stmt->hasRetExp()) { bool lastIsReturn = false; if (m_stmt->getCount()) { StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1]; if (lastStmt->is(Statement::KindOfReturnStatement)) { lastIsReturn = true; } } if (!lastIsReturn) { ExpressionPtr constant = makeScalarExpression(ar, funcScope->inPseudoMain() ? Variant(1) : Variant(Variant::NullInit())); ReturnStatementPtr returnStmt = ReturnStatementPtr( new ReturnStatement(getScope(), getLocation(), constant)); m_stmt->addElement(returnStmt); } } } if (m_params) { m_params->inferAndCheck(ar, Type::Any, false); } // must also include params and use vars if this is a generator. note: we are // OK reading the params from the AST nodes of the original generator // function, since we have the dependency links set up if (funcScope->isGenerator()) { // orig function params MethodStatementRawPtr m = getOrigGeneratorFunc(); assert(m); VariableTablePtr variables = funcScope->getVariables(); ExpressionListPtr params = m->getParams(); if (params) { for (int i = 0; i < params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); const string &name = param->getName(); assert(!param->isRef() || param->getType()->is(Type::KindOfVariant)); variables->addParamLike(name, param->getType(), ar, param, funcScope->isFirstPass()); } } // use vars ExpressionListPtr useVars = m->getFunctionScope()->getClosureVars(); if (useVars) { for (int i = 0; i < useVars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*useVars)[i]); const string &name = param->getName(); assert(!param->isRef() || param->getType()->is(Type::KindOfVariant)); variables->addParamLike(name, param->getType(), ar, param, funcScope->isFirstPass()); } } } if (m_stmt) { m_stmt->inferTypes(ar); } }