void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { // This is that much we can do during parse phase. TypePtr type; if (m_value->is(Expression::KindOfScalarExpression)) { type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl( ar, Type::Some, false); } else if (m_value->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value); if (uexp->getOp() == T_ARRAY) { type = Type::Array; } } if (!type) type = Type::Some; if (m_variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement // We are handling this one here, not in ClassConstant, purely because // we need "value" to store in constant table. ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(m_variable); scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable); } else if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); scope->getVariables()->add(var->getName(), type, true, ar, shared_from_this(), scope->getModifiers()); var->clearContext(Declaration); // to avoid wrong CodeError } else { ASSERT(false); // parse phase shouldn't handle anything else } }
TypePtr AssignmentExpression:: inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce, ExpressionPtr variable, ExpressionPtr value /* = ExpressionPtr() */) { TypePtr ret = type; if (value) { if (coerce) { ret = value->inferAndCheck(ar, type, coerce); } else { ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce); } } BlockScopePtr scope = ar->getScope(); if (variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(variable); bool p; scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p); } else if (variable->is(Expression::KindOfDynamicVariable)) { // simptodo: not too sure about this ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable); } else if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (var->getName() == "this" && ar->getClassScope()) { if (ar->isFirstPass()) { ar->getCodeError()->record(variable, CodeError::ReassignThis, variable); } } if (ar->getPhase() == AnalysisResult::LastInference && value) { if (!value->getExpectedType()) { value->setExpectedType(variable->getActualType()); } } } // if the value may involve object, consider the variable as "referenced" // so that objects are not destructed prematurely. bool referenced = true; if (value && value->isScalar()) referenced = false; if (ret && ret->isNoObjectInvolved()) referenced = false; if (referenced && variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); const std::string &name = var->getName(); VariableTablePtr variables = ar->getScope()->getVariables(); variables->addReferenced(name); } TypePtr vt = variable->inferAndCheck(ar, ret, true); if (!coerce && type->is(Type::KindOfAny)) { ret = vt; } return ret; }
void ClassConstant::onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) { ConstantTablePtr constants = scope->getConstants(); if (scope->isTrait()) { parseTimeFatal(Compiler::InvalidTraitStatement, "Traits cannot have constants"); } if (isAbstract()) { for (int i = 0; i < m_exp->getCount(); i++) { ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>((*m_exp)[i]); const std::string &name = exp->getName(); if (constants->isPresent(name)) { exp->parseTimeFatal(Compiler::DeclaredConstantTwice, "Cannot redeclare %s::%s", scope->getOriginalName().c_str(), name.c_str()); } // HACK: break attempts to write global constants here; // see ConstantExpression::preOptimize exp->setContext(Expression::LValue); // Unlike with assignment expression below, nothing needs to be added // to the scope's constant table } } else { for (int i = 0; i < m_exp->getCount(); i++) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]); ExpressionPtr var = assignment->getVariable(); const std::string &name = dynamic_pointer_cast<ConstantExpression>(var)->getName(); if (constants->isPresent(name)) { assignment->parseTimeFatal(Compiler::DeclaredConstantTwice, "Cannot redeclare %s::%s", scope->getOriginalName().c_str(), name.c_str()); } else { if (isTypeconst()) { // We do not want type constants to be available at run time. // To ensure this we do not want them to be added to the constants // table. The constants table is used to inline values for expressions // See ClassConstantExpression::preOptimize. // AssignmentExpression::onParseRecur essentially adds constants to // the constant table so we skip it. continue; } assignment->onParseRecur(ar, scope); } } } }
ExpressionPtr Parser::getDynamicVariable(ExpressionPtr exp, bool encap) { if (encap) { ConstantExpressionPtr var = exp->unsafe_cast<ConstantExpression>(); NamePtr n; if (var) { n = Name::fromString(this, var->getName()); } return NEW_EXP(Variable, n); } return createDynamicVariable(exp); }
ExpressionPtr Parser::getDynamicVariable(ExpressionPtr exp, bool encap) { NamePtr n; if (encap) { ConstantExpressionPtr var = exp->cast<ConstantExpression>(); if (var) { n = Name::fromString(this, var->getName()); } } else { n = Name::fromExp(this, exp); } return NEW_EXP(Variable, n); }
ExpressionPtr Parser::getDynamicVariable(ExpressionPtr exp, bool encap) { if (encap) { ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp); if (var) { return NEW_EXP(SimpleVariable, var->getName()); } } else { ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(exp); if (var) { return NEW_EXP(SimpleVariable, var->getString()); } } return createDynamicVariable(exp); }
void AssignmentExpression::analyzeProgram(AnalysisResultPtr ar) { m_variable->analyzeProgram(ar); m_value->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (m_ref && m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); const std::string &name = var->getName(); VariableTablePtr variables = ar->getScope()->getVariables(); variables->addUsed(name); } if (m_variable->is(Expression::KindOfConstantExpression)) { ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(m_variable); if (!m_value->isScalar()) { ar->getScope()->getConstants()->setDynamic(ar, exp->getName()); } } } }
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (cg.getContext() != CodeGenerator::CppClassConstantsDecl && cg.getContext() != CodeGenerator::CppClassConstantsImpl) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_exp->getCount(); i++) { AssignmentExpressionPtr exp = dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]); ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp->getVariable()); TypePtr type = scope->getConstants()->getFinalType(var->getName()); ExpressionPtr value = exp->getValue(); if (scope->getConstants()->isDynamic(var->getName())) { continue; } switch (cg.getContext()) { case CodeGenerator::CppClassConstantsDecl: cg_printf("extern const "); if (type->is(Type::KindOfString)) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s%s%s;\n", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); break; case CodeGenerator::CppClassConstantsImpl: { bool isString = type->is(Type::KindOfString); bool isVariant = Type::IsMappedToVariant(type); ScalarExpressionPtr scalarExp = dynamic_pointer_cast<ScalarExpression>(value); bool stringForVariant = false; if (isVariant && scalarExp && scalarExp->getActualType() && scalarExp->getActualType()->is(Type::KindOfString)) { cg_printf("static const StaticString %s%s%s%s%sv(LITSTR_INIT(%s));\n", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), Option::IdPrefix.c_str(), scalarExp->getCPPLiteralString().c_str()); stringForVariant = true; } cg_printf("const "); if (isString) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } value->outputCPPBegin(cg, ar); cg_printf(" %s%s%s%s", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); cg_printf(isString ? "(" : " = "); if (stringForVariant) { cg_printf("%s%s%s%s%sv", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), Option::IdPrefix.c_str()); } else if (isString && scalarExp) { cg_printf("LITSTR_INIT(%s)", scalarExp->getCPPLiteralString().c_str()); } else { value->outputCPP(cg, ar); } cg_printf(isString ? ");\n" : ";\n"); value->outputCPPEnd(cg, ar); break; } default: assert(false); } } }
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool lazyInit = cg.getContext() == CodeGenerator::CppLazyStaticInitializer; if (cg.getContext() != CodeGenerator::CppClassConstantsDecl && cg.getContext() != CodeGenerator::CppClassConstantsImpl && !lazyInit) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_exp->getCount(); i++) { AssignmentExpressionPtr exp = dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]); ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp->getVariable()); TypePtr type = scope->getConstants()->getFinalType(var->getName()); ExpressionPtr value = exp->getValue(); if (!scope->getConstants()->isDynamic(var->getName()) == lazyInit) { continue; } switch (cg.getContext()) { case CodeGenerator::CppClassConstantsDecl: cg_printf("extern const "); if (type->is(Type::KindOfString)) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s_%s;\n", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); break; case CodeGenerator::CppClassConstantsImpl: { cg_printf("const "); bool isString = type->is(Type::KindOfString); if (isString) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } value->outputCPPBegin(cg, ar); cg_printf(" %s%s_%s", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); cg_printf(isString ? "(" : " = "); ScalarExpressionPtr scalarExp = dynamic_pointer_cast<ScalarExpression>(value); if (isString && scalarExp) { cg_printf("LITSTR_INIT(%s)", scalarExp->getCPPLiteralString(cg).c_str()); } else { value->outputCPP(cg, ar); } cg_printf(isString ? ");\n" : ";\n"); value->outputCPPEnd(cg, ar); break; } case CodeGenerator::CppLazyStaticInitializer: value->outputCPPBegin(cg, ar); cg_printf("g->%s%s_%s = ", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(";\n"); value->outputCPPEnd(cg, ar); break; default: ASSERT(false); } } }