static Array HHVM_METHOD(Closure, __debugInfo) { auto closure = c_Closure::fromObject(this_); Array ret = Array::Create(); // Serialize 'use' parameters. if (auto useVars = closure->getUseVars()) { Array use; auto cls = this_->getVMClass(); auto propsInfo = cls->declProperties(); auto nProps = cls->numDeclProperties(); for (size_t i = 0; i < nProps; ++i) { auto value = &useVars[i]; use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value)); } if (!use.empty()) { ret.set(s_static, use); } } auto const func = closure->getInvokeFunc(); // Serialize function parameters. if (auto nParams = func->numParams()) { Array params; auto lNames = func->localNames(); for (int i = 0; i < nParams; ++i) { auto str = String::attach( StringData::Make(s_varprefix.get(), lNames[i]) ); bool optional = func->params()[i].phpCode; if (auto mi = func->methInfo()) { optional = optional || mi->parameters[i]->valueText; } params.set(str, optional ? s_optional : s_required); } ret.set(s_parameter, params); } // Serialize 'this' object. if (closure->hasThis()) { ret.set(s_this, Object(closure->getThis())); } return ret; }
Array c_Closure::t___debuginfo() { Array ret = Array::Create(); // Serialize 'use' parameters. if (auto propValues = propVec()) { Array use; auto propsInfo = getVMClass()->declProperties(); for (size_t i = 0; i < getVMClass()->numDeclProperties(); ++i) { auto value = &propValues[i]; use.setWithRef(Variant(StrNR(propsInfo[i].name)), tvAsCVarRef(value)); } if (!use.empty()) { ret.set(s_static, use); } } auto const func = getInvokeFunc(); // Serialize function parameters. if (func->numParams()) { Array params; for (int i = 0; i < func->numParams(); ++i) { auto str = String::attach( StringData::Make(s_varprefix.get(), func->localNames()[i]) ); bool optional = func->params()[i].phpCode; if (auto mi = func->methInfo()) { optional = optional || mi->parameters[i]->valueText; } params.set(str, optional ? s_optional : s_required); } ret.set(s_parameter, params); } // Serialize 'this' object. if (hasThis()) { ret.set(s_this, Object(getThis())); } return ret; }
//------------------------------------------------------------------------------ /*virtual*/ bool FunctionForEach::ParseFunction( NodeGraph & nodeGraph, const BFFIterator & functionNameStart, const BFFIterator * functionBodyStartToken, const BFFIterator * functionBodyStopToken, const BFFIterator * functionHeaderStartToken, const BFFIterator * functionHeaderStopToken ) const { // build array for each pair to loop through Array< AString > localNames( 4, true ); Array< const BFFVariable * > arrayVars( 4, true ); int loopLen = -1; // parse it all out BFFIterator pos( *functionHeaderStartToken ); pos++; // skip opening token while ( pos < *functionHeaderStopToken ) { pos.SkipWhiteSpace(); if ( *pos != BFFParser::BFF_DECLARE_VAR_INTERNAL ) { Error::Error_1200_ExpectedVar( pos, this ); return false; } const BFFIterator arrayVarNameBegin = pos; AStackString< BFFParser::MAX_VARIABLE_NAME_LENGTH > localName; bool localParentScope = false; // always false thanks to the previous test if ( BFFParser::ParseVariableName( pos, localName, localParentScope ) == false ) { return false; } ASSERT( false == localParentScope ); localNames.Append( localName ); pos.SkipWhiteSpace(); // check for "in" token bool foundIn = false; if ( *pos == 'i' ) { pos++; if ( *pos == 'n' ) { foundIn = true; } } if ( foundIn == false ) { Error::Error_1201_MissingIn( pos, this ); return false; } pos++; pos.SkipWhiteSpace(); if ( *pos != BFFParser::BFF_DECLARE_VAR_INTERNAL && *pos != BFFParser::BFF_DECLARE_VAR_PARENT /* tolerant with parent vars */ ) { Error::Error_1202_ExpectedVarFollowingIn( pos, this ); return false; } const BFFIterator arrayNameStart( pos ); AStackString< BFFParser::MAX_VARIABLE_NAME_LENGTH > arrayVarName; bool arrayParentScope = false; if ( BFFParser::ParseVariableName( pos, arrayVarName, arrayParentScope ) == false ) { return false; } const BFFVariable * var = nullptr; BFFStackFrame * const arrayFrame = ( arrayParentScope ) ? BFFStackFrame::GetParentDeclaration( arrayVarName, BFFStackFrame::GetCurrent()->GetParent(), var ) : nullptr; if ( false == arrayParentScope ) { var = BFFStackFrame::GetVar( arrayVarName, nullptr ); } if ( ( arrayParentScope && ( nullptr == arrayFrame ) ) || ( var == nullptr ) ) { Error::Error_1009_UnknownVariable( arrayNameStart, this, arrayVarName ); return false; } // it can be of any supported type if ( ( var->IsArrayOfStrings() == false ) && ( var->IsArrayOfStructs() == false ) ) { Error::Error_1050_PropertyMustBeOfType( arrayVarNameBegin, this, arrayVarName.Get(), var->GetType(), BFFVariable::VAR_ARRAY_OF_STRINGS, BFFVariable::VAR_ARRAY_OF_STRUCTS ); return false; } // is this the first variable? int thisArrayLen( -1 ); if ( var->GetType() == BFFVariable::VAR_ARRAY_OF_STRINGS ) { thisArrayLen = (int)var->GetArrayOfStrings().GetSize(); } else if ( var->GetType() == BFFVariable::VAR_ARRAY_OF_STRUCTS ) { thisArrayLen = (int)var->GetArrayOfStructs().GetSize(); } else { ASSERT( false ); } if ( loopLen == -1 ) { // it will set the length of looping loopLen = thisArrayLen; } else { // variables after the first must match length of the first if ( loopLen != thisArrayLen ) { Error::Error_1204_LoopVariableLengthsDiffer( arrayVarNameBegin, this, arrayVarName.Get(), (uint32_t)thisArrayLen, (uint32_t)loopLen ); return false; } } arrayVars.Append( var ); // skip optional separator pos.SkipWhiteSpace(); if ( *pos == ',' ) { pos++; } } ASSERT( localNames.GetSize() == arrayVars.GetSize() ); // gracefully allow empty loops if ( loopLen < 1 ) { return true; } // freeze the variable to avoid modifications while looping for ( uint32_t j=0; j<arrayVars.GetSize(); ++j ) { arrayVars[ j ]->Freeze(); FLOG_INFO( "Freezing loop array '%s' of type <%s>", arrayVars[j]->GetName().Get(), BFFVariable::GetTypeName( arrayVars[j]->GetType() ) ); } bool succeed = true; for ( uint32_t i=0; i<(uint32_t)loopLen; ++i ) { // create local loop variables BFFStackFrame loopStackFrame; for ( uint32_t j=0; j<localNames.GetSize(); ++j ) { if ( arrayVars[ j ]->GetType() == BFFVariable::VAR_ARRAY_OF_STRINGS ) { BFFStackFrame::SetVarString( localNames[ j ], arrayVars[ j ]->GetArrayOfStrings()[ i ], &loopStackFrame ); } else if ( arrayVars[ j ]->GetType() == BFFVariable::VAR_ARRAY_OF_STRUCTS ) { BFFStackFrame::SetVarStruct( localNames[ j ], arrayVars[ j ]->GetArrayOfStructs()[ i ]->GetStructMembers(), &loopStackFrame ); } else { ASSERT( false ); } } // parse the function body BFFParser subParser( nodeGraph ); BFFIterator subIter( *functionBodyStartToken ); subIter++; // skip opening token subIter.SetMax( functionBodyStopToken->GetCurrent() ); // limit to closing token if ( subParser.Parse( subIter ) == false ) { succeed = false; break; } // complete the function if ( Commit( nodeGraph, functionNameStart ) == false ) { succeed = false; break; } } // unfreeze all array variables for ( uint32_t j=0; j<arrayVars.GetSize(); ++j ) { arrayVars[ j ]->Unfreeze(); FLOG_INFO( "Unfreezing loop array '%s' of type <%s>", arrayVars[j]->GetName().Get(), BFFVariable::GetTypeName( arrayVars[j]->GetType() ) ); } return succeed; }