void MethodStatement::onParse(AnalysisResultPtr ar, BlockScopePtr scope) { ClassScopePtr classScope = dynamic_pointer_cast<ClassScope>(scope); FunctionScopePtr fs = getFunctionScope(); fs->setParamCounts(ar, -1, -1); classScope->addFunction(ar, fs); if (m_name == "__construct") { classScope->setAttribute(ClassScope::HasConstructor); } else if (m_name == "__destruct") { classScope->setAttribute(ClassScope::HasDestructor); } if (m_name == "__call") { classScope->setAttribute(ClassScope::HasUnknownMethodHandler); } else if (m_name == "__get") { classScope->setAttribute(ClassScope::HasUnknownPropGetter); } else if (m_name == "__set") { classScope->setAttribute(ClassScope::HasUnknownPropSetter); } else if (m_name == "__call") { classScope->setAttribute(ClassScope::HasUnknownMethodHandler); } else if (m_name == "__callstatic") { classScope->setAttribute(ClassScope::HasUnknownStaticMethodHandler); } m_className = classScope->getName(); m_originalClassName = classScope->getOriginalName(); }
FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar, FileScopePtr fs) { int minParam, maxParam; ConstructPtr self = shared_from_this(); minParam = maxParam = 0; bool hasRef = false; if (m_params) { std::set<string> names, allDeclNames; int i = 0; maxParam = m_params->getCount(); for (i = maxParam; i--; ) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->isRef()) hasRef = true; if (!param->isOptional()) { if (!minParam) minParam = i + 1; } else if (minParam && !param->hasTypeHint()) { Compiler::Error(Compiler::RequiredAfterOptionalParam, param); } allDeclNames.insert(param->getName()); } for (i = maxParam-1; i >= 0; i--) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (names.find(param->getName()) != names.end()) { Compiler::Error(Compiler::RedundantParameter, param); for (int j = 0; j < 1000; j++) { string name = param->getName() + lexical_cast<string>(j); if (names.find(name) == names.end() && allDeclNames.find(name) == allDeclNames.end()) { param->rename(name); break; } } } names.insert(param->getName()); } } if (hasRef || m_ref) { m_attribute |= FileScope::ContainsReference; } vector<UserAttributePtr> attrs; if (m_attrList) { for (int i = 0; i < m_attrList->getCount(); ++i) { UserAttributePtr a = dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]); attrs.push_back(a); } } StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this()); FunctionScopePtr funcScope (new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam, maxParam, m_modifiers, m_attribute, m_docComment, fs, attrs)); if (!m_stmt) { funcScope->setVirtual(); } setBlockScope(funcScope); funcScope->setParamCounts(ar, -1, -1); return funcScope; }
// Rewrite the outermost select clause so that it references properties of // a result tuple constructed by the query provider. Then wrap this expression // in a lambda so that the query provider can invoke it as a call back every // time it produces a result tuple (row). ClosureExpressionPtr QueryExpression::clientSideRewrite(AnalysisResultPtr ar, FileScopePtr fileScope) { // Rewrite the select expression into an expression that refers to // table columns (including computed columns) via properties of an // object produced by the query provider at runtime. ClientSideSelectRewriter cs; cs.rewriteQuery(static_pointer_cast<QueryExpression>(shared_from_this())); auto csSelect = cs.getClientSideSelectClause(); // null if there is no select clause. if (csSelect == nullptr) return nullptr; ExpressionPtr selectExpr = csSelect->getExpression(); // Now wrap up the rewritten expression into a lambda expression that // is passed to the query provider. When the query result is iterated, // the closure is called for each row in the query result in order to // produce the value specified by this select expression. // Create a return statement for the lambda body auto location = this->getLocation(); LabelScopePtr labelScope(new LabelScope()); ReturnStatementPtr returnStatement( new ReturnStatement(BlockScopePtr(), labelScope, location, selectExpr) ); // Wrap up the return statement in a list for the lambda body StatementListPtr stmt( new StatementList(BlockScopePtr(), labelScope, location) ); stmt->addElement(returnStatement); // Create a function statement for the lambda: // First create a formal parameter list, consisting of a single // parameter that will receive an array from the query provider // with an element for each server-side expression of this select clause. TypeAnnotationPtr type; bool hhType = true; std::string paramName = "__query_result_row__"; bool byRefParam = false; TokenID modifier = 0; ExpressionPtr defaultValue; ExpressionPtr attributeList; ParameterExpressionPtr parameter ( new ParameterExpression(BlockScopePtr(), location, type, hhType, paramName, byRefParam, modifier, defaultValue, attributeList) ); ExpressionListPtr params(new ExpressionList(BlockScopePtr(), location)); params->addElement(parameter); // Now create a function statement object ModifierExpressionPtr modifiers( new ModifierExpression(BlockScopePtr(), location) ); bool ref = false; static int counter = 0; std::string name = "__select__#" + std::to_string(counter++); TypeAnnotationPtr retTypeAnnotation; int attr = 0; std::string docComment; ExpressionListPtr attrList; FunctionStatementPtr func( new FunctionStatement(BlockScopePtr(), labelScope, location, modifiers, ref, name, params, retTypeAnnotation, stmt, attr, docComment, attrList) ); // The function statement needs a scope std::vector<UserAttributePtr> uattrs; FunctionScopePtr funcScope (new FunctionScope(ar, false, name, func, false, 1, 1, nullptr, attr, docComment, fileScope, uattrs)); funcScope->setParamCounts(ar, 1, 1); FunctionScope::RecordFunctionInfo(name, funcScope); fileScope->addFunction(ar, funcScope); func->resetScope(funcScope, true); funcScope->setOuterScope(fileScope); // Now construct a closure expression to create the closure value to // pass to the query provider. ExpressionListPtr captures; ClosureExpressionPtr closure( new ClosureExpression(BlockScopePtr(), location, ClosureType::Short, func, captures) ); closure->getClosureFunction()->setContainingClosure(closure); return closure; }